webgl2-sdf 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- const n=32,e={};function t(n,e,t){const r=n.createShader(t);return n.shaderSource(r,e),n.compileShader(r),r}function r(n,e,t){const{gl:r,textures:o}=n;r.activeTexture(r.TEXTURE0+e);let s=o[t];return s?r.bindTexture(r.TEXTURE_2D,s.tex):(s=o[t]={tex:r.createTexture()},r.bindTexture(r.TEXTURE_2D,s.tex),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.NEAREST),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.NEAREST),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE)),s}const{BYTE:o,UNSIGNED_BYTE:s,SHORT:i,UNSIGNED_SHORT:l,INT:c,UNSIGNED_INT:u,FLOAT:a,HALF_FLOAT:d,INT_2_10_10_10_REV:f,UNSIGNED_INT_2_10_10_10_REV:g}=WebGL2RenderingContext;function h(n){return(e,t,r)=>{const{gl:o,uniformBlocks:s,program:i}=n;let l=s[e];if(void 0===s[e]){const n=o.getUniformBlockIndex(i,e);o.uniformBlockBinding(i,n,t);const r=o.createBuffer();o.bindBuffer(o.UNIFORM_BUFFER,r),l={blockName:e,blockIndex:n,buf:r},s[e]=l}else o.bindBuffer(o.UNIFORM_BUFFER,l.buf);const{buf:c}=l;o.bufferData(o.UNIFORM_BUFFER,r,o.STATIC_DRAW),o.bindBufferBase(o.UNIFORM_BUFFER,t,c)}}function x(n){const e=n[0][0],t=n[0][1];for(let r=1;r<n.length;r++)if(e!==n[r][0]||t!==n[r][1])return!1;return!0}function I(n,e){if(0===e)return n[0];if(1===e)return n[n.length-1];if(4===n.length){const[[t,r],[o,s],[i,l],[c,u]]=n,a=t+(o-t)*e,d=o+(i-o)*e,f=a+(d-a)*e,g=r+(s-r)*e,h=s+(l-s)*e,x=g+(h-g)*e;return[f+(d+(i+(c-i)*e-d)*e-f)*e,x+(h+(l+(u-l)*e-h)*e-x)*e]}if(3===n.length){const[[t,r],[o,s],[i,l]]=n,c=t+(o-t)*e,u=r+(s-r)*e;return[c+(o+(i-o)*e-c)*e,u+(s+(l-s)*e-u)*e]}if(2===n.length){const[[t,r],[o,s]]=n;return[t+(o-t)*e,r+(s-r)*e]}if(1===n.length)return n[0];throw new Error("The given bezier curve must be of order <= 3.")}const{sqrt:_}=Math;function p(n,e){const t=n[0],r=n[1],o=e[0],s=e[1],i=r-s,l=o-t,c=t*s-o*r,u=_(i*i+l*l);return function(n){const e=n[0],o=n[1];return 0!==u?(i*e+l*o+c)/u:_((e-t)**2+(o-r)**2)}}{const n=[10,1];p([6,2],[6,2])(n)}function v(n,e,t){if(4===n.length)return function(n,e,t){return 0===e?1===t?n:function(n,e){const t=n[0],r=n[1],o=n[2],s=n[3],i=t[0],l=t[1],c=r[0],u=r[1],a=o[0],d=o[1],f=i-e*(i-c),g=c-e*(c-a),h=f-e*(f-g),x=l-e*(l-u),I=u-e*(u-d),_=x-e*(x-I);return[t,[f,x],[h,_],[h-e*(h-(g-e*(g-(a-e*(a-s[0]))))),_-e*(_-(I-e*(I-(d-e*(d-s[1])))))]]}(n,t):1===t?function(n,e){const t=n[0],r=n[1],o=n[2],s=n[3],i=t[0],l=t[1],c=r[0],u=r[1],a=o[0],d=o[1],f=i-e*(i-c),g=c-e*(c-a),h=a-e*(a-s[0]),x=f-e*(f-g),I=g-e*(g-h),_=l-e*(l-u),p=u-e*(u-d),v=d-e*(d-s[1]),m=_-e*(_-p),C=p-e*(p-v);return[[x-e*(x-I),m-e*(m-C)],[I,C],[h,v],s]}(n,e):function(n,e,t){const r=n[0],o=n[1],s=n[2],i=n[3],l=r[0],c=r[1],u=o[0],a=o[1],d=s[0],f=s[1],g=e*e,h=e*g,x=t*t,I=t*x,_=e*t,p=l-u,v=d-u,m=p+v,C=e*p,S=t*p,R=i[0]-l-3*v,E=c-a,T=f-a,b=E+T,P=e*E,w=t*E,A=i[1]-c-3*T;return[[h*R+(3*e*(e*m-p)+l),h*A+(3*e*(e*b-E)+c)],[_*(e*R+2*m)+(g*m+l-(S+2*C)),_*(e*A+2*b)+(g*b+c-(w+2*P))],[_*(t*R+2*m)+(x*m+l-(2*S+C)),_*(t*A+2*b)+(x*b+c-(2*w+P))],[I*R+(3*t*(t*m-p)+l),I*A+(3*t*(t*b-E)+c)]]}(n,e,t)}(n,e,t);if(3===n.length)return function(n,e,t){return 0===e?1===t?n:function(n,e){const t=n[0],r=n[1],o=n[2],s=t[0],i=t[1],l=r[0],c=r[1],u=e*e,a=s-l,d=i-c;return[t,[-e*a+s,-e*d+i],[u*(a+(o[0]-l))-(2*e*a-s),u*(d+(o[1]-c))-(2*e*d-i)]]}(n,t):1===t?function(n,e){const t=n[0],r=n[1],o=n[2],s=t[0],i=t[1],l=r[0],c=r[1],u=e*e,a=s-l,d=o[0]-l,f=i-c,g=o[1]-c;return[[u*(a+d)-(2*e*a-s),u*(f+g)-(2*e*f-i)],[e*d+l,e*g+c],o]}(n,e):function(n,e,t){const r=n[0],o=n[1],s=n[2],i=r[0],l=r[1],c=o[0],u=o[1],a=e*e,d=t*t,f=e*t,g=i-c,h=g+(s[0]-c),x=l-u,I=x+(s[1]-u);return[[a*h-(2*e*g-i),a*I-(2*e*x-l)],[f*h-(g*(t+e)-i),f*I-(x*(t+e)-l)],[d*h-(2*t*g-i),d*I-(2*t*x-l)]]}(n,e,t)}(n,e,t);throw new Error("The given bezier curve must be of order 2 or 3.")}function m(n,e){return[e[0]-n[0],e[1]-n[1]]}function C(n,e){return n[0]*e[0]+n[1]*e[1]}function S(n){const e=m(n[0],n[1]),t=m(n[1],n[3]),r=m(n[3],n[0]),o=m(n[0],n[2]),s=m(n[2],n[3]);return C(r,e)>0||C(t,r)>0||C(r,o)>0||C(s,r)>0}const{abs:R,max:E}=Math;function T(n){const e=p(n[0],n[3]),t=e(n[1]),r=e(n[2]);return(t*r<=0?4/9:3/4)*E(R(t),R(r))}function b(n){const e=m(n[0],n[1]),t=m(n[1],n[2]),r=m(n[2],n[0]);return C(r,e)>0||C(t,r)>0}const{abs:P}=Math;function w(n){if(n[0][0]===n[1][0]&&n[0][1]===n[1][1])return 0;const e=I(n,.5),t=p(n[0],n[2]);return P(t(e))}function A(n){const e=3===n.length?function(n){const e=[0],t=[1];for(;;){const r=e[e.length-1],o=t[t.length-1],s=v(n,r,o);if(!b(s)&&w(s)<=.5){if(e.push(t.pop()),1===o)return e;continue}const i=(r+o)/2;t.push(i)}}(n):function(n){const e=[0],t=[1];for(;;){const r=e[e.length-1],o=t[t.length-1],s=v(n,r,o);if(!S(s)&&T(s)<=.5){if(e.push(t.pop()),1===o)return e;continue}const i=(r+o)/2;t.push(i)}}(n),t=[];for(let r=0;r<e.length-1;r++){const o=I(n,e[r]),s=I(n,e[r+1]);t.push([o,s])}return t}function D(n){return Math.sqrt(n[0]*n[0]+n[1]*n[1])}const y=function(){const e=[{from:0,u:0,v:0}];for(let t=0;t<128;t++){e.push({from:t+.5,u:t+1,v:0}),e.push({from:t+.5,u:-t-1,v:0}),e.push({from:t+.5,u:0,v:t+1}),e.push({from:t+.5,u:0,v:-t-1});for(let r=0;r<n;r++){const n=D([.5+t,.5+r]),o=t+1,s=r+1;e.push({from:n,u:o,v:s}),0!==o&&e.push({from:n,u:-o,v:s}),0!==s&&e.push({from:n,u:o,v:-s}),0!==o&&0!==s&&e.push({from:n,u:-o,v:-s})}e.sort((n,e)=>n.from-e.from)}return e}(),{max:U,E:F}=Math;const{min:N,max:M,SQRT2:k}=Math;function L(e,t,r,o,s){const i=function(e,t,r,o,s){return function(i,l,c){let u=function(n){let e=function(n){let e=0,t=y.length-1,r=0;for(;e<=t;){r=e+t>>>1;const o=y[r].from;if(o===n)return r;n>o?e=r+1:t=r-1}return r}(n);if(n=U(0,n),0===e)return 0;for(;y[e].from===y[e-1].from;)e--;return e}((c-k*r)/r),a=Number.POSITIVE_INFINITY;for(;;){if(u>=y.length){a=r*(y[y.length-1].from-k);break}const{u:c,v:d,from:f}=y[u];if(r*f>o+k*r){a=r*(f-2*k);break}const g=c+i,h=d+l;if(g<0||g>=t+2*s||h<0||h>=n+2*s){u++;continue}const{lineSegs:x}=e[g][h];if(x.length>0){a=r*(f-k);break}u++}const{closeCells:d}=e[i][l];let f=M(0,u-1);for(;f<y.length;){const{from:c,u,v:g}=y[f];if(r*c>N(a,o)+2*k*r)break;const h=u+i,x=g+l;if(h<0||h>=t+2*s||x<0||x>=n+2*s){f++;continue}const{lineSegs:I}=e[h][x];I.length>0&&d.push((2*s+n)*h+x),f++}return a}}(e,t,r,o,s);let l=0,c=0;for(let e=s;e<t+s;e++){c=l;for(let t=s;t<n+s;t++)c=i(e,t,c),t===s&&(l=c)}}const{floor:B,ceil:O}=Math;function X(n,e,t,r,o,s){const i=r*s,[[l,c],[u,a]]=o,d=e+i,f=t+i,g=function(n,e){const[t,r]=n,[o,s]=t,[i,l]=r,[[c,u],[a,d]]=e,f=i-o,g=l-s,h=[];if(0!==f){const n=(c-o)/f;if(n>=0&&n<=1){const e=s+n*g;e>=u&&e<=d&&h.push({t:n,p:[c,e]})}const e=(a-o)/f;if(e>=0&&e<=1){const n=s+e*g;n>=u&&n<=d&&h.push({t:e,p:[a,n]})}}if(0!==g){const n=(u-s)/g;if(n>=0&&n<=1){const e=o+n*f;e>=c&&e<=a&&h.push({t:n,p:[e,u]})}const e=(d-s)/g;if(e>=0&&e<=1){const n=o+e*f;n>=c&&n<=a&&h.push({t:e,p:[n,d]})}}const x=new Set,I=h.filter(n=>{const{t:e}=n;return!x.has(e)&&(x.add(e),!0)});return I.sort((n,e)=>n.t-e.t).map(n=>n.p)}(o,[[-i,-i],[d,f]]),h=l>-i&&l<d&&c>-i&&c<f,x=u>-i&&u<d&&a>-i&&a<f;if(g.length<2&&!h&&!x)return;const I=u-l,_=a-c,p=u>l?r:-r,v=a>c?r:-r;let m=l,C=c,S=0;const R=p>0,E=v>0,T=R?B:O,b=E?B:O;for(;;){let e=r*T((m+p)/r),t=r*b((C+v)/r);const o=(e-l)/I,x=(t-c)/_,P=o<x&&0!==I||0===_,w=P?e:l+x*I,A=P?c+o*_:t;if((o>1||0===I)&&(x>1||0===_)){const e=B(u/r)+s,t=B(a/r)+s;n[e]?.[t]?.lineSegs.push([[m,C],[u,a]]);break}if(w<=-i||A<=-i||w>=d||A>=f){if(!h&&0===S){[m,C]=g[0],S++;continue}{const e=T(m/r)-(R?0:1)+s,t=b(C/r)-(E?0:1)+s,o=[[m,C],g[S]];n[e]?.[t]?.lineSegs.push(o);break}}const D=T(m/r)-(R?0:1)+s,y=b(C/r)-(E?0:1)+s;n[D]?.[y]?.lineSegs.push([[m,C],[w,A]]),m=w,C=A}}const j=256,{floor:G,ceil:Y}=Math;function Q(n,e,t){const r=e/n.length,[o,s]=t,i=function(n,e){const[t,r]=n,[o,s]=t,[i,l]=r,[c,u,a]=e,d=i-o,f=l-s,g=[],h=[];if(0!==d){const n=(c-o)/d;if(n>=0&&n<=1){const e=s+n*f;e>=u&&e<=a&&(g.push(n),h.push([c,e]))}}if(0!==f){const n=(u-s)/f;if(n>=0&&n<=1){const e=o+n*d;e<=c&&(g.push(n),h.push([e,u]))}const e=(a-s)/f;if(e>=0&&e<=1){const n=o+e*d;n<=c&&(g.push(e),h.push([n,a]))}}return 2===g.length?g[0]<g[1]?h:[h[1],h[0]]:h}(t,[0,0,e]),[l,c]=o,[u,a]=s,d=u-l,f=a-c,g=l<0&&c>0&&c<e,h=u<0&&a>0&&a<e;if(i.length<2&&!g&&!h&&(0!==l||0!==d||c<=0&&a<=0||c>=e&&a>=e))return;if(0===f)return;const x=a>c?r:-r;let I=l,_=c,p=0;const v=u>l,m=a>c,C=m?G:Y;for(;;){let t=v&&I<0||!v&&I>0?0:Number.NEGATIVE_INFINITY,o=r*C((_+x)/r);const u=(t-l)/d,a=(o-c)/f,h=u<a&&0!==d,S=h?0:l+a*d,R=h?c+u*f:o;if((u>1||0===d)&&a>1){const e=G(s[1]/r);n[e]?.push([[I,_],s]);break}if(S>=0&&(0!==l||0!==d)||R<=0||R>=e){if(!g&&0===p){[I,_]=i[0],p++;continue}{const e=C(_/r)-(m?0:1),t=[[I,_],i[p]];n[e]?.push(t);break}}const E=C(_/r)-(m?0:1);n[E]?.push([[I,_],[S,R]]),I=S,_=R}}function V(e,t,o,s,i,l,c,u,f,g,I,_,p,v,m,C){const{gl:S}=e,R=[],E=.03125,T=.03125;R.push(0,0,E,0,0,T),R.push(E,0,E,T,0,T);const b=new Float32Array(R),P=(w=t,(n,e,...t)=>{const{gl:r,uniforms:o}=w,s=o[e]||(o[e]=r.getUniformLocation(w.program,e));r[`uniform${n}`](s,...t)});var w;const D=function(n){return(e,t,r,o,s,i=0,l=0,c=0)=>{const{gl:u,attributes:f}=n,g=f[e]=f[e]??{buf:u.createBuffer(),loc:u.getAttribLocation(n.program,e),data:null},{loc:h,buf:x}=g;u.bindBuffer(u.ARRAY_BUFFER,x),r===a||r===d?u.vertexAttribPointer(h,t,r,!1,l,c):u.vertexAttribIPointer(h,t,r,l,c),u.enableVertexAttribArray(h),0!==i&&u.vertexAttribDivisor(h,i),s!==g.data&&(u.bufferData(u.ARRAY_BUFFER,s,o),g.data=s)}}(t),{lineSegPtCoords_Arr:y,segIdxs_PerCell_Range_Arr:U,closeCellIdxs_PerCell_Arr:F,closeCellIdxs_PerCell_Range_Arr:N,crossCellIdxs_PerCell_Arr:M,crossCellIdxs_perCell_Range_Arr:k,segIdxs_PerStrip_Range_Arr:B}=function(e,t,r,o,s,i,l,c=[0,0,t,r],u=1){const a=function(n,e,t,r){if(0===n[0]&&0===n[1]&&n[2]===e&&n[3]===t)return r;const[o,s,i,l]=n,c=e/i,u=t/l,a=[];for(let n=0;n<r.length;n++){const e=r[n],t=[];for(let n=0;n<e.length;n++){const r=e[n],i=[];for(let n=0;n<r.length;n++){const[e,t]=r[n],l=c*e-o,a=u*t-s;i.push([l,a])}t.push(i)}a.push(t)}return a}(c,t,r/u,e),d=function(n){let e=[];for(let t=0;t<n.length;t++){const r=n[t];for(let n=0;n<r.length;n++){const t=r[n];if(x(t))continue;if(2===t.length){e.push(t);continue}const o=A(t);e.push(...o.filter(n=>!x(n)))}}return e}(a),f=function(e,t){const r=[];for(let o=0;o<e+2*t;o++){const e=[];for(let r=0;r<n+2*t;r++)e.push({lineSegs:[],closeCells:[],crossingCells:[]});r.push(e)}return r}(o,l),g=new Array(n).fill(void 0).map(n=>[]);for(let n=0;n<d.length;n++){const e=d[n];X(f,t,r,s,e,l),Q(g,r,e)}L(f,o,s,i,l),function(e,t,r){for(let o=r;o<t+r;o++)for(let t=r;t<n+r;t++){const s=e[o][t].crossingCells;for(let i=r;i<=o;i++)0!==e[i][t].lineSegs.length&&s.push((n+2*r)*i+t)}}(f,o,l);const h=[],I=[],_=[],p=[],v=[],m=[];let C=0,S=0,R=0;for(let e=0;e<o+2*l;e++)for(let t=0;t<n+2*l;t++){const r=f[e][t];if(e>=l&&e<o+l&&t>=l&&t<n+l){const{closeCells:n,crossingCells:e}=r,t=e.length,o=n.length;v.push(...e),_.push(...n),m.push(C,t),p.push(S,o),C+=t,S+=o}const{lineSegs:s}=r,i=s.length;I.push(R,i),R+=i,h.push(...s.flat(2))}const E=[];for(let e=0;e<n;e++){const n=g[e],t=n.length;E.push([R,t]),R+=t,h.push(...n.flat(2))}for(;_.length%j!==0;)_.push(0);for(;v.length%j!==0;)v.push(0);for(;h.length%1024!=0;)h.push(0);const T=new Float32Array(h),b=new Int32Array(I),P=new Int32Array(p);return{lineSegPtCoords_Arr:T,segIdxs_PerCell_Range_Arr:b,closeCellIdxs_PerCell_Arr:new Int32Array(_),closeCellIdxs_PerCell_Range_Arr:P,crossCellIdxs_PerCell_Arr:new Int32Array(v),crossCellIdxs_perCell_Range_Arr:new Int32Array(m),segIdxs_PerStrip_Range_Arr:new Int32Array(E.flat())}}(o,I,_,p,v,i,m,s,C);D("aUV",2,S.FLOAT,S.STATIC_DRAW,b),D("aCrossIdxRangePerCell",2,S.INT,S.STATIC_DRAW,k,1),D("aCloseCellIdxRangePerCell",2,S.INT,S.STATIC_DRAW,N,1),P("2f","uWidthHeight",I,_),P("1f","uMaxDistance",i),P("1i","uIncl",(l?1:0)+(c?2:0)),P("4f","uCustom",...u),h(t)("SegIdxRangePerCellBlock",0,U),h(t)("SegIdxRangePerStripBlock",1,B),r(e,0,"segs"),S.texImage2D(S.TEXTURE_2D,0,S.RGBA32F,j,y.length/4/j,0,S.RGBA,S.FLOAT,y);const O=S.getUniformLocation(t.program,"uSegs");S.uniform1i(O,0),r(e,1,"closeCellIdxsPerCell"),S.texImage2D(S.TEXTURE_2D,0,S.R32I,j,F.length/j,0,S.RED_INTEGER,S.INT,F);const G=S.getUniformLocation(t.program,"uCloseCellIdxs");S.uniform1i(G,1),r(e,2,"crossCellIdxsPerCell"),S.texImage2D(S.TEXTURE_2D,0,S.R32I,j,M.length/j,0,S.RED_INTEGER,S.INT,M);const Y=S.getUniformLocation(t.program,"uCrossCellIdxs");S.uniform1i(Y,2),C>1&&(S.enable(S.SCISSOR_TEST),S.scissor(f,g,I,_/C)),S.viewport(f,g,I,_),S.drawArraysInstanced(S.TRIANGLES,0,6,p*n),C>1&&S.disable(S.SCISSOR_TEST)}function z(n){const e=[n.p,n.initialPoint];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e}const H={c:function(n){const e=[n.p,[n.vals[0],n.vals[1]],[n.vals[2],n.vals[3]],[n.vals[4],n.vals[5]]];return n.prev2ndCubicControlPoint=e[2],n.prev2ndQuadraticControlPoint=void 0,e},h:function(n){const e=[n.p,[n.vals[0],n.p[1]]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e},l:function(n){const e=[n.p,n.vals];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e},q:function(n){const e=[n.vals[0],n.vals[1]],t=[n.vals[2],n.vals[3]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=e,[n.p,e,t]},s:function(n){const e=n.prev2ndCubicControlPoint?[n.p[0]-n.prev2ndCubicControlPoint[0]+n.p[0],n.p[1]-n.prev2ndCubicControlPoint[1]+n.p[1]]:n.p,t=[n.p,e,[n.vals[0],n.vals[1]],[n.vals[2],n.vals[3]]];return n.prev2ndCubicControlPoint=t[2],n.prev2ndQuadraticControlPoint=void 0,t},t:function(n){const e=n.prev2ndQuadraticControlPoint?[n.p[0]-n.prev2ndQuadraticControlPoint[0]+n.p[0],n.p[1]-n.prev2ndQuadraticControlPoint[1]+n.p[1]]:n.p,t=[n.vals[0],n.vals[1]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=e,[n.p,e,t]},v:function(n){const e=[n.p,[n.p[0],n.vals[0]]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e},z};function W(n){let e=0,t=0,r=1,o=0,s=1,i=1;const l=n._currentIndex;if(n._skipOptionalSpaces(),n._currentIndex<n._endIndex&&"+"===n._string[n._currentIndex]?n._currentIndex+=1:n._currentIndex<n._endIndex&&"-"===n._string[n._currentIndex]&&(n._currentIndex+=1,s=-1),n._currentIndex===n._endIndex||(n._string[n._currentIndex]<"0"||n._string[n._currentIndex]>"9")&&"."!==n._string[n._currentIndex])throw new Error("The first character of a number must be one of [0-9+-.].");const c=n._currentIndex;for(;n._currentIndex<n._endIndex&&n._string[n._currentIndex]>="0"&&n._string[n._currentIndex]<="9";)n._currentIndex+=1;if(n._currentIndex!==c){let e=n._currentIndex-1,r=1;for(;e>=c;)t+=r*(Number(n._string[e])-0),e-=1,r*=10}if(n._currentIndex<n._endIndex&&"."===n._string[n._currentIndex]){if(n._currentIndex+=1,n._currentIndex>=n._endIndex||n._string[n._currentIndex]<"0"||n._string[n._currentIndex]>"9")throw new Error("There must be a least one digit following the .");for(;n._currentIndex<n._endIndex&&n._string[n._currentIndex]>="0"&&n._string[n._currentIndex]<="9";)r*=10,o+=Number(n._string.charAt(n._currentIndex))/r,n._currentIndex+=1}if(n._currentIndex!==l&&n._currentIndex+1<n._endIndex&&("e"===n._string[n._currentIndex]||"E"===n._string[n._currentIndex])&&"x"!==n._string[n._currentIndex+1]&&"m"!==n._string[n._currentIndex+1]){if(n._currentIndex+=1,"+"===n._string[n._currentIndex]?n._currentIndex+=1:"-"===n._string[n._currentIndex]&&(n._currentIndex+=1,i=-1),n._currentIndex>=n._endIndex||n._string[n._currentIndex]<"0"||n._string[n._currentIndex]>"9")throw new Error("There must be an exponent.");for(;n._currentIndex<n._endIndex&&n._string[n._currentIndex]>="0"&&n._string[n._currentIndex]<="9";)e*=10,e+=Number(n._string[n._currentIndex]),n._currentIndex+=1}let u=t+o;if(u*=s,e&&(u*=Math.pow(10,i*e)),l===n._currentIndex)throw new Error("Internal error: startIndex === source._currentIndex");return n._skipOptionalSpacesOrDelimiter(),u}const q={Z:"Z",M:"M",L:"L",C:"C",Q:"Q",A:"A",H:"H",V:"V",S:"S",T:"T",z:"Z",m:"m",l:"l",c:"c",q:"q",a:"a",h:"h",v:"v",s:"s",t:"t"};class Z{_string;_currentIndex;_endIndex;_prevCommand;constructor(n){this._string=n,this._currentIndex=0,this._endIndex=this._string.length,this._prevCommand=void 0,this._skipOptionalSpaces()}parseSegment(){const n=this._string[this._currentIndex];let e,t=q[n];if(void 0===t){if(void 0===this._prevCommand)throw new Error("Implicit command not allowed for first commands.");if(!("+"===n||"-"===n||"."===n||n>="0"&&n<="9")||"Z"===this._prevCommand)throw new Error("Remaining coordinates not found for implicit command");t="M"===this._prevCommand?"L":"m"===this._prevCommand?"l":this._prevCommand}else this._currentIndex+=1;this._prevCommand=t;const r=t.toUpperCase();if("H"===r||"V"===r?e=[W(this)]:"M"===r||"L"===r||"T"===r?e=[W(this),W(this)]:"S"===r||"Q"===r?e=[W(this),W(this),W(this),W(this)]:"C"===r?e=[W(this),W(this),W(this),W(this),W(this),W(this)]:"A"===r?e=[W(this),W(this),W(this),this._parseArcFlag(),this._parseArcFlag(),W(this),W(this)]:"Z"===r&&(this._skipOptionalSpaces(),e=[]),void 0===e)throw new Error("Unknown command");return{type:t,values:e}}hasMoreData(){return this._currentIndex<this._endIndex}initialCommandIsMoveTo(){if(!this.hasMoreData())return!0;const n=q[this._string[this._currentIndex]];return"M"===n||"m"===n}_isCurrentSpace(){const n=this._string[this._currentIndex];return n<=" "&&(" "===n||"\n"===n||"\t"===n||"\r"===n||"\f"===n)}_skipOptionalSpaces(){for(;this._currentIndex<this._endIndex&&this._isCurrentSpace();)this._currentIndex+=1;return this._currentIndex<this._endIndex}_skipOptionalSpacesOrDelimiter(){return!(this._currentIndex<this._endIndex&&!this._isCurrentSpace()&&","!==this._string[this._currentIndex])&&(this._skipOptionalSpaces()&&this._currentIndex<this._endIndex&&","===this._string[this._currentIndex]&&(this._currentIndex+=1,this._skipOptionalSpaces()),this._currentIndex<this._endIndex)}_parseArcFlag(){if(this._currentIndex>=this._endIndex)throw new Error("Unable to parse arc flag");let n;const e=this._string[this._currentIndex];if(this._currentIndex+=1,"0"===e)n=0;else{if("1"!==e)throw new Error("Unable to parse arc flag - arc flag must be 0 or 1");n=1}return this._skipOptionalSpacesOrDelimiter(),n}}const{ceil:$,min:J,max:K}=Math;function nn(r,o,s,i,l,c=0,u=0,a,d=!0,f=!0,g,h=0){const x="string"==typeof o?function(n){if(0===n.length)return[];if("m"!==n[0].type.toLowerCase())throw new Error("Invalid SVG - every new path must start with an M or m.");const e={p:[0,0]},t=[];let r,o=[];for(let s=0;s<n.length;s++){const i=n[s],l=i.type.toLowerCase();if(e.vals=i.values,i.type===l)if("v"===l)e.vals[0]+=e.p[1];else if("a"===l)e.vals[5]+=e.p[0],e.vals[6]+=e.p[1];else for(let n=0;n<e.vals.length;n++)e.vals[n]+=e.p[n%2];if("m"===l){o.length&&("z"!==r&&o.push(z(e)),t.push(o),o=[]),e.initialPoint=e.p=e.vals,r=l;continue}const c=H[l];if(!c)throw new Error("Invalid SVG - command not recognized.");const u=c(e);e.p=u[u.length-1],o.push(u),r=l}return o.length>0&&("z"!==r&&o.push(z(e)),t.push(o)),t}(function(n){if(!n.length)return[];const e=new Z(n),t=[];if(!e.initialCommandIsMoveTo())throw new Error("Path must start with m or M");for(;e.hasMoreData();)t.push(e.parseSegment());return t}(o)):o;let I=1;if(i/l>4){const n=i/4;I=n/l,l=n}const _=l/n,p=K(i,l),v=$(i/_),m=2*$(J(a,p)/_/2),C=function(n,e,r,o){const{gl:s,programs:i}=n;if(i[e])return i[e];const l=s.createProgram(),c=t(s,"#version 300 es\n\nprecision highp float;\n\nuniform vec2 uWidthHeight;\nin vec2 aUV;\nin ivec2 aCloseCellIdxRangePerCell;\nin ivec2 aCrossIdxRangePerCell;\nout vec2 vXY;\nflat out int instanceId;\nflat out ivec2 closeCellIdxRange;\nflat out ivec2 crossCellIdxRange;\n\n\nvoid main() {\n instanceId = gl_InstanceID;\n closeCellIdxRange = aCloseCellIdxRangePerCell;\n crossCellIdxRange = aCrossIdxRangePerCell;\n\n // drawn column-by-column\n float i = float(instanceId / 32); // column index\n float j = float(instanceId % 32); // row index\n\n vec2 trans = vec2(\n i / float(32),\n j / float(32)\n );\n\n vec2 uv = aUV + trans;\n\n float width = uWidthHeight.x;\n float height = uWidthHeight.y;\n\n vXY = vec2(\n height * uv.x,\n height * uv.y\n );\n\n float aspectRatio = width / height;\n\n gl_Position = vec4(\n vec2(\n (2.0*(uv.x / aspectRatio) - 1.0),\n (2.0*uv.y - 1.0)\n ),\n 0.0, 1.0\n );\n}\n",s.VERTEX_SHADER),u=t(s,o,s.FRAGMENT_SHADER);return s.attachShader(l,c),s.attachShader(l,u),s.linkProgram(l),i[e]={gl:s,program:l,attributes:{},uniforms:{},uniformBlocks:{},vertexShader:c,fragmentShader:u},i[e]}(r,`main${v}-${m}`,0,function(t,r){const o=e[1024*t+r];if(void 0!==o)return o;const s=`#version 300 es\n\nprecision highp float;\n\nuniform float uMaxDistance;\nuniform highp sampler2D uSegs;\nuniform highp isampler2D uCloseCellIdxs;\nuniform highp isampler2D uCrossCellIdxs;\nuniform int uIncl; // bit 0 -> incl inside, bit 1 -> incl outside\n\nuniform SegIdxRangePerCellBlock {\n ivec4 uSegIdxRangePerCell[${(n+2*r)*(t+2*r)/2}];\n};\nuniform SegIdxRangePerStripBlock {\n ivec4 uSegIdxRangePerStrip[16];\n};\n\nin vec2 vXY;\nflat in int instanceId;\nflat in ivec2 closeCellIdxRange;\nflat in ivec2 crossCellIdxRange;\nout vec4 FragColor;\n\n\nfloat absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {\n vec2 lineDir = lineB - lineA;\n float lenSq = dot(lineDir, lineDir);\n float t = clamp(dot(point - lineA, lineDir) / lenSq, 0.0, 1.0);\n vec2 linePt = lineA + t*lineDir;\n\n return distance(point, linePt);\n}\n\n\nvoid main() {\n ///////////////////////////////////////////////////////////////////////////\n // Project a ray to the left to check if it crosses the segment in order\n // to find the fragment's winding number to determine whether fragment\n // is inside or outside the shape.\n\n int crossIdxS = crossCellIdxRange.x;\n int crossLen = crossCellIdxRange.y;\n float winds = 0.0;\n // Iterate over all relevant cell indexes\n for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {\n int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;\n\n ivec2 uSegIdxRange = crossIdx % 2 == 0\n ? uSegIdxRangePerCell[crossIdx / 2].xy\n : uSegIdxRangePerCell[crossIdx / 2].zw;\n\n int segIdx = uSegIdxRange.x;\n int segLen = uSegIdxRange.y;\n\n for (int j = segIdx; j < segIdx + segLen; j++) {\n // Fetch segment from texture\n vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);\n\n // line segment's min-y is excluded\n bool crossing =\n (seg.y > vXY.y != seg.w > vXY.y) &&\n (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);\n\n bool crossingUp = seg.y < seg.w;\n\n winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;\n }\n }\n\n {\n int cellIdx = (instanceId % 32);\n\n bool isEven = cellIdx % 2 == 0;\n\n ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];\n int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;\n int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;\n \n\n for (int j = segIdx; j < segIdx + segLen; j++) {\n // Fetch segment from texture\n vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);\n\n // line segment's min-y is excluded\n bool crossing =\n (seg.y > vXY.y != seg.w > vXY.y) &&\n (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);\n\n bool crossingUp = seg.y < seg.w;\n\n winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;\n }\n }\n\n\n bool inside = winds != 0.0;\n ///////////////////////////////////////////////////////////////////////////\n\n ///////////////////////////////////////////////////////////////////////////\n float res = 1.0; // sdf result\n\n if ((inside && (uIncl % 2 != 0)) || (!inside && (uIncl > 1))) {\n int cellIdxS = closeCellIdxRange.x;\n int cellLen = closeCellIdxRange.y;\n // Iterate over all relevant cell indexes\n for (int i = cellIdxS; i < cellIdxS + cellLen; i++) {\n int cellIdx = texelFetch(uCloseCellIdxs, ivec2(i%256, i/256), 0).x;\n\n ivec2 uSegIdxRange = cellIdx % 2 == 0\n ? uSegIdxRangePerCell[cellIdx / 2].xy\n : uSegIdxRangePerCell[cellIdx / 2].zw;\n\n int segIdx = uSegIdxRange.x;\n int segLen = uSegIdxRange.y;\n\n for (int j = segIdx; j < segIdx + segLen; j++) {\n // Fetch segment from texture\n vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);\n\n // Find unsigned distance to the segment; only the nearest will be kept\n float d = absDistToSegment(vXY, seg.xy, seg.zw);\n // Apply exponential transform\n float val = clamp(d / uMaxDistance, 0.0, 1.0);\n\n res = min(res, val);\n }\n }\n }\n ///////////////////////////////////////////////////////////////////////////\n\n // DEBUG!\n // float alpha = ((instanceId + instanceId/32) % 2 == 0 ? 0.3 : 0.5);\n\n\n float exponent = 2;\n res = pow(1.0 - val, exponent) * 0.5;\n\n float alpha = res == 1.0 ? 0.0 : 0.5;\n float red = inside ? 0.2 : 0.8;\n float green = abs(sin(25.0 * res));\n float blue = 0.5;\n\n FragColor = vec4(red, green, blue, alpha);\n}\n`;return e[1024*t+r]=s,s}(v,m)),{gl:S}=r;S.useProgram(C.program),V(r,C,x,s,a,d,f,g,c,u,i,l,v,_,m,I)}function en(n){if(void 0===n)return;const{gl:e,programs:t,textures:r}=n;for(let n in t){const{attributes:r,fragmentShader:o,vertexShader:s,uniformBlocks:i,program:l}=t[n];for(let n in i){const{buf:t}=i[n];e.deleteBuffer(t)}for(let n in r){const{buf:t}=r[n];e.deleteBuffer(t)}e.deleteShader(o),e.deleteShader(s),e.deleteProgram(l)}for(let n in r){const{tex:t}=r[n];e.deleteTexture(t)}}const tn=new WeakMap;function rn(n){{const e=tn.get(n);if(e)return e}const e={},t={},r={gl:n,textures:t,programs:e};return n.canvas.addEventListener("webglcontextlost",o=>{on(e),on(t),tn.delete(n),r.onContextLoss?.(o)},!1),tn.set(n,r),r}function on(n){Object.keys(n).forEach(e=>{delete n[e]})}export{en as freeGlContext,nn as generateSdf,rn as getWebGlContext};
1
+ const n=32,e="#version 300 es\n\nprecision highp float;\n\nuniform vec2 uWidthHeight;\nin vec2 aUV;\nin ivec2 aCloseCellIdxRangePerCell;\nin ivec2 aCrossIdxRangePerCell;\nout vec2 vXY;\nflat out int instanceId;\nflat out ivec2 closeCellIdxRange;\nflat out ivec2 crossCellIdxRange;\n\n\nvoid main() {\n instanceId = gl_InstanceID;\n closeCellIdxRange = aCloseCellIdxRangePerCell;\n crossCellIdxRange = aCrossIdxRangePerCell;\n\n // drawn column-by-column\n float i = float(instanceId / 32); // column index\n float j = float(instanceId % 32); // row index\n\n vec2 trans = vec2(\n i / float(32),\n j / float(32)\n );\n\n vec2 uv = aUV + trans;\n\n float width = uWidthHeight.x;\n float height = uWidthHeight.y;\n\n vXY = vec2(\n height * uv.x,\n height * uv.y\n );\n\n float aspectRatio = width / height;\n\n gl_Position = vec4(\n vec2(\n (2.0*(uv.x / aspectRatio) - 1.0),\n (2.0*uv.y - 1.0)\n ),\n 0.0, 1.0\n );\n}\n",t={};function r(e,r,o,s){const i=2**32*(256*e+r)+s,c=t[i];if(void 0!==c)return c;const l=`#version 300 es\n\nprecision highp float;\n\nuniform float uMaxDistance;\nuniform highp sampler2D uSegs;\nuniform highp isampler2D uCloseCellIdxs;\nuniform highp isampler2D uCrossCellIdxs;\n// bit 0 -> calc distance inside\n// bit 1 -> calc distance outside\n// bit 2 -> calc whether fragment is inside or outside (else outside is assumed with winds == 0.0)\nuniform int uTestInOut;\nuniform vec4 uCustom;\n\nuniform SegIdxRangePerCellBlock {\n ivec4 uSegIdxRangePerCell[${(n+2*r)*(e+2*r)/2}];\n};\nuniform SegIdxRangePerStripBlock {\n ivec4 uSegIdxRangePerStrip[16];\n};\n\nin vec2 vXY;\nflat in int instanceId;\nflat in ivec2 closeCellIdxRange;\nflat in ivec2 crossCellIdxRange;\nout vec4 FragColor;\n\n// testing!!\n// float rand(vec2 co) {\n// return mod(uCustom.w * fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453), 1.0);\n// }\n\nfloat absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {\n vec2 lineDir = lineB - lineA;\n float lenSq = dot(lineDir, lineDir);\n float t = clamp(dot(point - lineA, lineDir) / lenSq, 0.0, 1.0);\n vec2 linePt = lineA + t*lineDir;\n\n return distance(point, linePt);\n}\n\n\nvoid main() {\n ///////////////////////////////////////////////////////////////////////////\n // Calculate \`winds\`:\n //\n // Project a ray to the left to check if it crosses the segment in order\n // to find the fragment's winding number to determine whether fragment\n // is inside or outside the shape.\n ///////////////////////////////////////////////////////////////////////////\n\n float winds = 0.0;\n if ((uTestInOut & 4) == 0) {\n int crossIdxS = crossCellIdxRange.x;\n int crossLen = crossCellIdxRange.y;\n // Iterate over all relevant cell indexes\n for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {\n int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;\n\n ivec2 uSegIdxRange = crossIdx % 2 == 0\n ? uSegIdxRangePerCell[crossIdx / 2].xy\n : uSegIdxRangePerCell[crossIdx / 2].zw;\n\n int segIdx = uSegIdxRange.x;\n int segLen = uSegIdxRange.y;\n\n for (int j = segIdx; j < segIdx + segLen; j++) {\n // Fetch segment from texture\n vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);\n\n // line segment's min-y is excluded\n bool crossing =\n (seg.y > vXY.y != seg.w > vXY.y) &&\n (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);\n\n bool crossingUp = seg.y < seg.w;\n\n winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;\n }\n }\n\n {\n int cellIdx = (instanceId % 32);\n\n bool isEven = cellIdx % 2 == 0;\n\n ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];\n int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;\n int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;\n \n\n for (int j = segIdx; j < segIdx + segLen; j++) {\n // Fetch segment from texture\n vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);\n\n // line segment's min-y is excluded\n bool crossing =\n (seg.y > vXY.y != seg.w > vXY.y) &&\n (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);\n\n bool crossingUp = seg.y < seg.w;\n\n winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;\n }\n }\n }\n bool inside = winds != 0.0;\n ///////////////////////////////////////////////////////////////////////////\n // Calculate \`res\`: the distance to the nearest curve\n ///////////////////////////////////////////////////////////////////////////\n float res = 1.0; // sdf result\n\n if ((inside && ((uTestInOut & 1) != 0)) || (!inside && ((uTestInOut & 2) != 0))) {\n int cellIdxS = closeCellIdxRange.x;\n int cellLen = closeCellIdxRange.y;\n // Iterate over all relevant cell indexes\n for (int i = cellIdxS; i < cellIdxS + cellLen; i++) {\n int cellIdx = texelFetch(uCloseCellIdxs, ivec2(i%256, i/256), 0).x;\n\n ivec2 uSegIdxRange = cellIdx % 2 == 0\n ? uSegIdxRangePerCell[cellIdx / 2].xy\n : uSegIdxRangePerCell[cellIdx / 2].zw;\n\n int segIdx = uSegIdxRange.x;\n int segLen = uSegIdxRange.y;\n\n for (int j = segIdx; j < segIdx + segLen; j++) {\n // Fetch segment from texture\n vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);\n\n // Find normalized unsigned distance to the segment; only the nearest will be kept\n float d = absDistToSegment(vXY, seg.xy, seg.zw);\n float val = clamp(d / uMaxDistance, 0.0, 1.0);\n\n res = min(res, val);\n }\n }\n }\n ///////////////////////////////////////////////////////////////////////////\n\n // DEBUG!\n // float alpha = ((instanceId + instanceId/32) % 2 == 0 ? 0.3 : 0.5);\n\n \n \n float exponent = uCustom.x;\n res = pow(1.0 - res, exponent);\n float alpha = res <= 0.0 ? 0.0 : 0.5;\n float red = inside ? 0.2 : 0.8;\n float green = abs(sin(25.0 * res));\n float blue = 0.5;\n\n\n FragColor = vec4(red, green, blue, alpha);\n}\n`;return t[i]=l,l}function o(n,e,t){const r=n.createShader(t);return n.shaderSource(r,e),n.compileShader(r),r}function s(n,e,t){const{gl:r,textures:o}=n;r.activeTexture(r.TEXTURE0+e);let s=o[t];return s?r.bindTexture(r.TEXTURE_2D,s.tex):(s=o[t]={tex:r.createTexture()},r.bindTexture(r.TEXTURE_2D,s.tex),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.NEAREST),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MAG_FILTER,r.NEAREST),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE)),s}const{BYTE:i,UNSIGNED_BYTE:c,SHORT:l,UNSIGNED_SHORT:u,INT:a,UNSIGNED_INT:d,FLOAT:f,HALF_FLOAT:g,INT_2_10_10_10_REV:h,UNSIGNED_INT_2_10_10_10_REV:x}=WebGL2RenderingContext;function I(n){return(e,t,r)=>{const{gl:o,uniformBlocks:s,program:i}=n;let c=s[e];if(void 0===s[e]){const n=o.getUniformBlockIndex(i,e);o.uniformBlockBinding(i,n,t);const r=o.createBuffer();o.bindBuffer(o.UNIFORM_BUFFER,r),c={blockName:e,blockIndex:n,buf:r},s[e]=c}else o.bindBuffer(o.UNIFORM_BUFFER,c.buf);const{buf:l}=c;o.bufferData(o.UNIFORM_BUFFER,r,o.STATIC_DRAW),o.bindBufferBase(o.UNIFORM_BUFFER,t,l)}}function _(n){const e=n[0][0],t=n[0][1];for(let r=1;r<n.length;r++)if(e!==n[r][0]||t!==n[r][1])return!1;return!0}function p(n,e){if(0===e)return n[0];if(1===e)return n[n.length-1];if(4===n.length){const[[t,r],[o,s],[i,c],[l,u]]=n,a=t+(o-t)*e,d=o+(i-o)*e,f=a+(d-a)*e,g=r+(s-r)*e,h=s+(c-s)*e,x=g+(h-g)*e;return[f+(d+(i+(l-i)*e-d)*e-f)*e,x+(h+(c+(u-c)*e-h)*e-x)*e]}if(3===n.length){const[[t,r],[o,s],[i,c]]=n,l=t+(o-t)*e,u=r+(s-r)*e;return[l+(o+(i-o)*e-l)*e,u+(s+(c-s)*e-u)*e]}if(2===n.length){const[[t,r],[o,s]]=n;return[t+(o-t)*e,r+(s-r)*e]}if(1===n.length)return n[0];throw new Error("The given bezier curve must be of order <= 3.")}const{sqrt:v}=Math;function m(n,e){const t=n[0],r=n[1],o=e[0],s=e[1],i=r-s,c=o-t,l=t*s-o*r,u=v(i*i+c*c);return function(n){const e=n[0],o=n[1];return 0!==u?(i*e+c*o+l)/u:v((e-t)**2+(o-r)**2)}}{const n=[10,1];m([6,2],[6,2])(n)}function C(n,e,t){if(4===n.length)return function(n,e,t){return 0===e?1===t?n:function(n,e){const t=n[0],r=n[1],o=n[2],s=n[3],i=t[0],c=t[1],l=r[0],u=r[1],a=o[0],d=o[1],f=i-e*(i-l),g=l-e*(l-a),h=f-e*(f-g),x=c-e*(c-u),I=u-e*(u-d),_=x-e*(x-I);return[t,[f,x],[h,_],[h-e*(h-(g-e*(g-(a-e*(a-s[0]))))),_-e*(_-(I-e*(I-(d-e*(d-s[1])))))]]}(n,t):1===t?function(n,e){const t=n[0],r=n[1],o=n[2],s=n[3],i=t[0],c=t[1],l=r[0],u=r[1],a=o[0],d=o[1],f=i-e*(i-l),g=l-e*(l-a),h=a-e*(a-s[0]),x=f-e*(f-g),I=g-e*(g-h),_=c-e*(c-u),p=u-e*(u-d),v=d-e*(d-s[1]),m=_-e*(_-p),C=p-e*(p-v);return[[x-e*(x-I),m-e*(m-C)],[I,C],[h,v],s]}(n,e):function(n,e,t){const r=n[0],o=n[1],s=n[2],i=n[3],c=r[0],l=r[1],u=o[0],a=o[1],d=s[0],f=s[1],g=e*e,h=e*g,x=t*t,I=t*x,_=e*t,p=c-u,v=d-u,m=p+v,C=e*p,S=t*p,R=i[0]-c-3*v,E=l-a,T=f-a,b=E+T,w=e*E,A=t*E,P=i[1]-l-3*T;return[[h*R+(3*e*(e*m-p)+c),h*P+(3*e*(e*b-E)+l)],[_*(e*R+2*m)+(g*m+c-(S+2*C)),_*(e*P+2*b)+(g*b+l-(A+2*w))],[_*(t*R+2*m)+(x*m+c-(2*S+C)),_*(t*P+2*b)+(x*b+l-(2*A+w))],[I*R+(3*t*(t*m-p)+c),I*P+(3*t*(t*b-E)+l)]]}(n,e,t)}(n,e,t);if(3===n.length)return function(n,e,t){return 0===e?1===t?n:function(n,e){const t=n[0],r=n[1],o=n[2],s=t[0],i=t[1],c=r[0],l=r[1],u=e*e,a=s-c,d=i-l;return[t,[-e*a+s,-e*d+i],[u*(a+(o[0]-c))-(2*e*a-s),u*(d+(o[1]-l))-(2*e*d-i)]]}(n,t):1===t?function(n,e){const t=n[0],r=n[1],o=n[2],s=t[0],i=t[1],c=r[0],l=r[1],u=e*e,a=s-c,d=o[0]-c,f=i-l,g=o[1]-l;return[[u*(a+d)-(2*e*a-s),u*(f+g)-(2*e*f-i)],[e*d+c,e*g+l],o]}(n,e):function(n,e,t){const r=n[0],o=n[1],s=n[2],i=r[0],c=r[1],l=o[0],u=o[1],a=e*e,d=t*t,f=e*t,g=i-l,h=g+(s[0]-l),x=c-u,I=x+(s[1]-u);return[[a*h-(2*e*g-i),a*I-(2*e*x-c)],[f*h-(g*(t+e)-i),f*I-(x*(t+e)-c)],[d*h-(2*t*g-i),d*I-(2*t*x-c)]]}(n,e,t)}(n,e,t);throw new Error("The given bezier curve must be of order 2 or 3.")}function S(n,e){return[e[0]-n[0],e[1]-n[1]]}function R(n,e){return n[0]*e[0]+n[1]*e[1]}function E(n){const e=S(n[0],n[1]),t=S(n[1],n[3]),r=S(n[3],n[0]),o=S(n[0],n[2]),s=S(n[2],n[3]);return R(r,e)>0||R(t,r)>0||R(r,o)>0||R(s,r)>0}const{abs:T,max:b}=Math;function w(n){const e=m(n[0],n[3]),t=e(n[1]),r=e(n[2]);return(t*r<=0?4/9:3/4)*b(T(t),T(r))}function A(n){const e=S(n[0],n[1]),t=S(n[1],n[2]),r=S(n[2],n[0]);return R(r,e)>0||R(t,r)>0}const{abs:P}=Math;function D(n){if(n[0][0]===n[1][0]&&n[0][1]===n[1][1])return 0;const e=p(n,.5),t=m(n[0],n[2]);return P(t(e))}function y(n){const e=3===n.length?function(n){const e=[0],t=[1];for(;;){const r=e[e.length-1],o=t[t.length-1],s=C(n,r,o);if(!A(s)&&D(s)<=.5){if(e.push(t.pop()),1===o)return e;continue}const i=(r+o)/2;t.push(i)}}(n):function(n){const e=[0],t=[1];for(;;){const r=e[e.length-1],o=t[t.length-1],s=C(n,r,o);if(!E(s)&&w(s)<=.5){if(e.push(t.pop()),1===o)return e;continue}const i=(r+o)/2;t.push(i)}}(n),t=[];for(let r=0;r<e.length-1;r++){const o=p(n,e[r]),s=p(n,e[r+1]);t.push([o,s])}return t}function F(n){return Math.sqrt(n[0]*n[0]+n[1]*n[1])}const U=function(){const e=[{from:0,u:0,v:0}];for(let t=0;t<128;t++){e.push({from:t+.5,u:t+1,v:0}),e.push({from:t+.5,u:-t-1,v:0}),e.push({from:t+.5,u:0,v:t+1}),e.push({from:t+.5,u:0,v:-t-1});for(let r=0;r<n;r++){const n=F([.5+t,.5+r]),o=t+1,s=r+1;e.push({from:n,u:o,v:s}),0!==o&&e.push({from:n,u:-o,v:s}),0!==s&&e.push({from:n,u:o,v:-s}),0!==o&&0!==s&&e.push({from:n,u:-o,v:-s})}e.sort((n,e)=>n.from-e.from)}return e}(),{max:N,E:M}=Math;const{min:L,max:O,SQRT2:k}=Math;function B(e,t,r,o,s){const i=function(e,t,r,o,s){return function(i,c,l){let u=function(n){let e=function(n){let e=0,t=U.length-1,r=0;for(;e<=t;){r=e+t>>>1;const o=U[r].from;if(o===n)return r;n>o?e=r+1:t=r-1}return r}(n);if(n=N(0,n),0===e)return 0;for(;U[e].from===U[e-1].from;)e--;return e}((l-k*r)/r),a=Number.POSITIVE_INFINITY;for(;;){if(u>=U.length){a=r*(U[U.length-1].from-k);break}const{u:l,v:d,from:f}=U[u];if(r*f>o+k*r){a=r*(f-2*k);break}const g=l+i,h=d+c;if(g<0||g>=t+2*s||h<0||h>=n+2*s){u++;continue}const{lineSegs:x}=e[g][h];if(x.length>0){a=r*(f-k);break}u++}const{closeCells:d}=e[i][c];let f=O(0,u-1);for(;f<U.length;){const{from:l,u,v:g}=U[f];if(r*l>L(a,o)+2*k*r)break;const h=u+i,x=g+c;if(h<0||h>=t+2*s||x<0||x>=n+2*s){f++;continue}const{lineSegs:I}=e[h][x];I.length>0&&d.push((2*s+n)*h+x),f++}return a}}(e,t,r,o,s);let c=0,l=0;for(let e=s;e<t+s;e++){l=c;for(let t=s;t<n+s;t++)l=i(e,t,l),t===s&&(c=l)}}const{floor:X,ceil:j}=Math;function G(n,e,t,r,o,s){const i=r*s,[[c,l],[u,a]]=o,d=e+i,f=t+i,g=function(n,e){const[t,r]=n,[o,s]=t,[i,c]=r,[[l,u],[a,d]]=e,f=i-o,g=c-s,h=[];if(0!==f){const n=(l-o)/f;if(n>=0&&n<=1){const e=s+n*g;e>=u&&e<=d&&h.push({t:n,p:[l,e]})}const e=(a-o)/f;if(e>=0&&e<=1){const n=s+e*g;n>=u&&n<=d&&h.push({t:e,p:[a,n]})}}if(0!==g){const n=(u-s)/g;if(n>=0&&n<=1){const e=o+n*f;e>=l&&e<=a&&h.push({t:n,p:[e,u]})}const e=(d-s)/g;if(e>=0&&e<=1){const n=o+e*f;n>=l&&n<=a&&h.push({t:e,p:[n,d]})}}const x=new Set,I=h.filter(n=>{const{t:e}=n;return!x.has(e)&&(x.add(e),!0)});return I.sort((n,e)=>n.t-e.t).map(n=>n.p)}(o,[[-i,-i],[d,f]]),h=c>-i&&c<d&&l>-i&&l<f,x=u>-i&&u<d&&a>-i&&a<f;if(g.length<2&&!h&&!x)return;const I=u-c,_=a-l,p=u>c?r:-r,v=a>l?r:-r;let m=c,C=l,S=0;const R=p>0,E=v>0,T=R?X:j,b=E?X:j;for(;;){let e=r*T((m+p)/r),t=r*b((C+v)/r);const o=(e-c)/I,x=(t-l)/_,w=o<x&&0!==I||0===_,A=w?e:c+x*I,P=w?l+o*_:t;if((o>1||0===I)&&(x>1||0===_)){const e=X(u/r)+s,t=X(a/r)+s;n[e]?.[t]?.lineSegs.push([[m,C],[u,a]]);break}if(A<=-i||P<=-i||A>=d||P>=f){if(!h&&0===S){[m,C]=g[0],S++;continue}{const e=T(m/r)-(R?0:1)+s,t=b(C/r)-(E?0:1)+s,o=[[m,C],g[S]];n[e]?.[t]?.lineSegs.push(o);break}}const D=T(m/r)-(R?0:1)+s,y=b(C/r)-(E?0:1)+s;n[D]?.[y]?.lineSegs.push([[m,C],[A,P]]),m=A,C=P}}const Y=256,{floor:Q,ceil:V}=Math;function z(n,e,t){const r=e/n.length,[o,s]=t,i=function(n,e){const[t,r]=n,[o,s]=t,[i,c]=r,[l,u,a]=e,d=i-o,f=c-s,g=[],h=[];if(0!==d){const n=(l-o)/d;if(n>=0&&n<=1){const e=s+n*f;e>=u&&e<=a&&(g.push(n),h.push([l,e]))}}if(0!==f){const n=(u-s)/f;if(n>=0&&n<=1){const e=o+n*d;e<=l&&(g.push(n),h.push([e,u]))}const e=(a-s)/f;if(e>=0&&e<=1){const n=o+e*d;n<=l&&(g.push(e),h.push([n,a]))}}return 2===g.length?g[0]<g[1]?h:[h[1],h[0]]:h}(t,[0,0,e]),[c,l]=o,[u,a]=s,d=u-c,f=a-l,g=c<0&&l>0&&l<e,h=u<0&&a>0&&a<e;if(i.length<2&&!g&&!h&&(0!==c||0!==d||l<=0&&a<=0||l>=e&&a>=e))return;if(0===f)return;const x=a>l?r:-r;let I=c,_=l,p=0;const v=u>c,m=a>l,C=m?Q:V;for(;;){let t=v&&I<0||!v&&I>0?0:Number.NEGATIVE_INFINITY,o=r*C((_+x)/r);const u=(t-c)/d,a=(o-l)/f,h=u<a&&0!==d,S=h?0:c+a*d,R=h?l+u*f:o;if((u>1||0===d)&&a>1){const e=Q(s[1]/r);n[e]?.push([[I,_],s]);break}if(S>=0&&(0!==c||0!==d)||R<=0||R>=e){if(!g&&0===p){[I,_]=i[0],p++;continue}{const e=C(_/r)-(m?0:1),t=[[I,_],i[p]];n[e]?.push(t);break}}const E=C(_/r)-(m?0:1);n[E]?.push([[I,_],[S,R]]),I=S,_=R}}function H(e,t,r,o,i,c,l,u,a,d,h,x){const{gl:p}=e,{x:v=0,y:m=0,testInteriorExterior:C=!0,calcSdfForInside:S=!0,calcSdfForOutside:R=!0,customData:E=[1,0,0,0],glslRgbaCalcStr:T}=u,b=[],w=.03125,A=.03125;b.push(0,0,w,0,0,A),b.push(w,0,w,A,0,A);const P=new Float32Array(b),D=(F=t,(n,e,...t)=>{const{gl:r,uniforms:o}=F,s=o[e]||(o[e]=r.getUniformLocation(F.program,e));r[`uniform${n}`](s,...t)});var F;const U=function(n){return(e,t,r,o,s,i=0,c=0,l=0)=>{const{gl:u,attributes:a}=n,d=a[e]=a[e]??{buf:u.createBuffer(),loc:u.getAttribLocation(n.program,e),data:null},{loc:h,buf:x}=d;u.bindBuffer(u.ARRAY_BUFFER,x),r===f||r===g?u.vertexAttribPointer(h,t,r,!1,c,l):u.vertexAttribIPointer(h,t,r,c,l),u.enableVertexAttribArray(h),0!==i&&u.vertexAttribDivisor(h,i),s!==d.data&&(u.bufferData(u.ARRAY_BUFFER,s,o),d.data=s)}}(t),{lineSegPtCoords_Arr:N,segIdxs_PerCell_Range_Arr:M,closeCellIdxs_PerCell_Arr:L,closeCellIdxs_PerCell_Range_Arr:O,crossCellIdxs_PerCell_Arr:k,crossCellIdxs_perCell_Range_Arr:X,segIdxs_PerStrip_Range_Arr:j}=function(e,t,r,o,s,i,c,l=[0,0,t,r],u=1){const a=function(n,e,t,r){if(0===n[0]&&0===n[1]&&n[2]===e&&n[3]===t)return r;const[o,s,i,c]=n,l=e/i,u=t/c,a=[];for(let n=0;n<r.length;n++){const e=r[n],t=[];for(let n=0;n<e.length;n++){const r=e[n],i=[];for(let n=0;n<r.length;n++){const[e,t]=r[n],c=l*e-o,a=u*t-s;i.push([c,a])}t.push(i)}a.push(t)}return a}(l,t,r/u,e),d=function(n){let e=[];for(let t=0;t<n.length;t++){const r=n[t];for(let n=0;n<r.length;n++){const t=r[n];if(_(t))continue;if(2===t.length){e.push(t);continue}const o=y(t);e.push(...o.filter(n=>!_(n)))}}return e}(a),f=function(e,t){const r=[];for(let o=0;o<e+2*t;o++){const e=[];for(let r=0;r<n+2*t;r++)e.push({lineSegs:[],closeCells:[],crossingCells:[]});r.push(e)}return r}(o,c),g=new Array(n).fill(void 0).map(n=>[]);for(let n=0;n<d.length;n++){const e=d[n];G(f,t,r,s,e,c),z(g,r,e)}B(f,o,s,i,c),function(e,t,r){for(let o=r;o<t+r;o++)for(let t=r;t<n+r;t++){const s=e[o][t].crossingCells;for(let i=r;i<=o;i++)0!==e[i][t].lineSegs.length&&s.push((n+2*r)*i+t)}}(f,o,c);const h=[],x=[],I=[],p=[],v=[],m=[];let C=0,S=0,R=0;for(let e=0;e<o+2*c;e++)for(let t=0;t<n+2*c;t++){const r=f[e][t];if(e>=c&&e<o+c&&t>=c&&t<n+c){const{closeCells:n,crossingCells:e}=r,t=e.length,o=n.length;v.push(...e),I.push(...n),m.push(C,t),p.push(S,o),C+=t,S+=o}const{lineSegs:s}=r,i=s.length;x.push(R,i),R+=i,h.push(...s.flat(2))}const E=[];for(let e=0;e<n;e++){const n=g[e],t=n.length;E.push([R,t]),R+=t,h.push(...n.flat(2))}for(;I.length%Y!==0;)I.push(0);for(;v.length%Y!==0;)v.push(0);for(;h.length%1024!=0;)h.push(0);const T=new Float32Array(h),b=new Int32Array(x),w=new Int32Array(p);return{lineSegPtCoords_Arr:T,segIdxs_PerCell_Range_Arr:b,closeCellIdxs_PerCell_Arr:new Int32Array(I),closeCellIdxs_PerCell_Range_Arr:w,crossCellIdxs_PerCell_Arr:new Int32Array(v),crossCellIdxs_perCell_Range_Arr:new Int32Array(m),segIdxs_PerStrip_Range_Arr:new Int32Array(E.flat())}}(r,c,l,a,d,i,h,o,x);U("aUV",2,p.FLOAT,p.STATIC_DRAW,P),U("aCrossIdxRangePerCell",2,p.INT,p.STATIC_DRAW,X,1),U("aCloseCellIdxRangePerCell",2,p.INT,p.STATIC_DRAW,O,1),D("2f","uWidthHeight",c,l),D("1f","uMaxDistance",i),D("1i","uTestInOut",(S?1:0)+(R?2:0)+(C?4:0)),D("4f","uCustom",...E),I(t)("SegIdxRangePerCellBlock",0,M),I(t)("SegIdxRangePerStripBlock",1,j),s(e,0,"segs"),p.texImage2D(p.TEXTURE_2D,0,p.RGBA32F,Y,N.length/4/Y,0,p.RGBA,p.FLOAT,N);const Q=p.getUniformLocation(t.program,"uSegs");p.uniform1i(Q,0),s(e,1,"closeCellIdxsPerCell"),p.texImage2D(p.TEXTURE_2D,0,p.R32I,Y,L.length/Y,0,p.RED_INTEGER,p.INT,L);const V=p.getUniformLocation(t.program,"uCloseCellIdxs");p.uniform1i(V,1),s(e,2,"crossCellIdxsPerCell"),p.texImage2D(p.TEXTURE_2D,0,p.R32I,Y,k.length/Y,0,p.RED_INTEGER,p.INT,k);const H=p.getUniformLocation(t.program,"uCrossCellIdxs");p.uniform1i(H,2),x>1&&(p.enable(p.SCISSOR_TEST),p.scissor(v,m,c,l/x)),p.viewport(v,m,c,l),p.colorMask(!0,!0,!0,!0),p.drawArraysInstanced(p.TRIANGLES,0,6,a*n),x>1&&p.disable(p.SCISSOR_TEST)}function W(n){const e=[n.p,n.initialPoint];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e}const q={c:function(n){const e=[n.p,[n.vals[0],n.vals[1]],[n.vals[2],n.vals[3]],[n.vals[4],n.vals[5]]];return n.prev2ndCubicControlPoint=e[2],n.prev2ndQuadraticControlPoint=void 0,e},h:function(n){const e=[n.p,[n.vals[0],n.p[1]]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e},l:function(n){const e=[n.p,n.vals];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e},q:function(n){const e=[n.vals[0],n.vals[1]],t=[n.vals[2],n.vals[3]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=e,[n.p,e,t]},s:function(n){const e=n.prev2ndCubicControlPoint?[n.p[0]-n.prev2ndCubicControlPoint[0]+n.p[0],n.p[1]-n.prev2ndCubicControlPoint[1]+n.p[1]]:n.p,t=[n.p,e,[n.vals[0],n.vals[1]],[n.vals[2],n.vals[3]]];return n.prev2ndCubicControlPoint=t[2],n.prev2ndQuadraticControlPoint=void 0,t},t:function(n){const e=n.prev2ndQuadraticControlPoint?[n.p[0]-n.prev2ndQuadraticControlPoint[0]+n.p[0],n.p[1]-n.prev2ndQuadraticControlPoint[1]+n.p[1]]:n.p,t=[n.vals[0],n.vals[1]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=e,[n.p,e,t]},v:function(n){const e=[n.p,[n.p[0],n.vals[0]]];return n.prev2ndCubicControlPoint=void 0,n.prev2ndQuadraticControlPoint=void 0,e},z:W};function Z(n){let e=0,t=0,r=1,o=0,s=1,i=1;const c=n._currentIndex;if(n._skipOptionalSpaces(),n._currentIndex<n._endIndex&&"+"===n._string[n._currentIndex]?n._currentIndex+=1:n._currentIndex<n._endIndex&&"-"===n._string[n._currentIndex]&&(n._currentIndex+=1,s=-1),n._currentIndex===n._endIndex||(n._string[n._currentIndex]<"0"||n._string[n._currentIndex]>"9")&&"."!==n._string[n._currentIndex])throw new Error("The first character of a number must be one of [0-9+-.].");const l=n._currentIndex;for(;n._currentIndex<n._endIndex&&n._string[n._currentIndex]>="0"&&n._string[n._currentIndex]<="9";)n._currentIndex+=1;if(n._currentIndex!==l){let e=n._currentIndex-1,r=1;for(;e>=l;)t+=r*(Number(n._string[e])-0),e-=1,r*=10}if(n._currentIndex<n._endIndex&&"."===n._string[n._currentIndex]){if(n._currentIndex+=1,n._currentIndex>=n._endIndex||n._string[n._currentIndex]<"0"||n._string[n._currentIndex]>"9")throw new Error("There must be a least one digit following the .");for(;n._currentIndex<n._endIndex&&n._string[n._currentIndex]>="0"&&n._string[n._currentIndex]<="9";)r*=10,o+=Number(n._string.charAt(n._currentIndex))/r,n._currentIndex+=1}if(n._currentIndex!==c&&n._currentIndex+1<n._endIndex&&("e"===n._string[n._currentIndex]||"E"===n._string[n._currentIndex])&&"x"!==n._string[n._currentIndex+1]&&"m"!==n._string[n._currentIndex+1]){if(n._currentIndex+=1,"+"===n._string[n._currentIndex]?n._currentIndex+=1:"-"===n._string[n._currentIndex]&&(n._currentIndex+=1,i=-1),n._currentIndex>=n._endIndex||n._string[n._currentIndex]<"0"||n._string[n._currentIndex]>"9")throw new Error("There must be an exponent.");for(;n._currentIndex<n._endIndex&&n._string[n._currentIndex]>="0"&&n._string[n._currentIndex]<="9";)e*=10,e+=Number(n._string[n._currentIndex]),n._currentIndex+=1}let u=t+o;if(u*=s,e&&(u*=Math.pow(10,i*e)),c===n._currentIndex)throw new Error("Internal error: startIndex === source._currentIndex");return n._skipOptionalSpacesOrDelimiter(),u}const $={Z:"Z",M:"M",L:"L",C:"C",Q:"Q",A:"A",H:"H",V:"V",S:"S",T:"T",z:"Z",m:"m",l:"l",c:"c",q:"q",a:"a",h:"h",v:"v",s:"s",t:"t"};class J{_string;_currentIndex;_endIndex;_prevCommand;constructor(n){this._string=n,this._currentIndex=0,this._endIndex=this._string.length,this._prevCommand=void 0,this._skipOptionalSpaces()}parseSegment(){const n=this._string[this._currentIndex];let e,t=$[n];if(void 0===t){if(void 0===this._prevCommand)throw new Error("Implicit command not allowed for first commands.");if(!("+"===n||"-"===n||"."===n||n>="0"&&n<="9")||"Z"===this._prevCommand)throw new Error("Remaining coordinates not found for implicit command");t="M"===this._prevCommand?"L":"m"===this._prevCommand?"l":this._prevCommand}else this._currentIndex+=1;this._prevCommand=t;const r=t.toUpperCase();if("H"===r||"V"===r?e=[Z(this)]:"M"===r||"L"===r||"T"===r?e=[Z(this),Z(this)]:"S"===r||"Q"===r?e=[Z(this),Z(this),Z(this),Z(this)]:"C"===r?e=[Z(this),Z(this),Z(this),Z(this),Z(this),Z(this)]:"A"===r?e=[Z(this),Z(this),Z(this),this._parseArcFlag(),this._parseArcFlag(),Z(this),Z(this)]:"Z"===r&&(this._skipOptionalSpaces(),e=[]),void 0===e)throw new Error("Unknown command");return{type:t,values:e}}hasMoreData(){return this._currentIndex<this._endIndex}initialCommandIsMoveTo(){if(!this.hasMoreData())return!0;const n=$[this._string[this._currentIndex]];return"M"===n||"m"===n}_isCurrentSpace(){const n=this._string[this._currentIndex];return n<=" "&&(" "===n||"\n"===n||"\t"===n||"\r"===n||"\f"===n)}_skipOptionalSpaces(){for(;this._currentIndex<this._endIndex&&this._isCurrentSpace();)this._currentIndex+=1;return this._currentIndex<this._endIndex}_skipOptionalSpacesOrDelimiter(){return!(this._currentIndex<this._endIndex&&!this._isCurrentSpace()&&","!==this._string[this._currentIndex])&&(this._skipOptionalSpaces()&&this._currentIndex<this._endIndex&&","===this._string[this._currentIndex]&&(this._currentIndex+=1,this._skipOptionalSpaces()),this._currentIndex<this._endIndex)}_parseArcFlag(){if(this._currentIndex>=this._endIndex)throw new Error("Unable to parse arc flag");let n;const e=this._string[this._currentIndex];if(this._currentIndex+=1,"0"===e)n=0;else{if("1"!==e)throw new Error("Unable to parse arc flag - arc flag must be 0 or 1");n=1}return this._skipOptionalSpacesOrDelimiter(),n}}const{ceil:K,min:nn,max:en}=Math,tn={x:0,y:0,testInteriorExterior:!0,calcSdfForInside:!0,calcSdfForOutside:!0,customData:[1,0,0,0]};function rn(t,s,i,c,l,u,a=tn){const d="string"==typeof s?function(n){if(0===n.length)return[];if("m"!==n[0].type.toLowerCase())throw new Error("Invalid SVG - every new path must start with an M or m.");const e={p:[0,0]},t=[];let r,o=[];for(let s=0;s<n.length;s++){const i=n[s],c=i.type.toLowerCase();if(e.vals=i.values,i.type===c)if("v"===c)e.vals[0]+=e.p[1];else if("a"===c)e.vals[5]+=e.p[0],e.vals[6]+=e.p[1];else for(let n=0;n<e.vals.length;n++)e.vals[n]+=e.p[n%2];if("m"===c){o.length&&("z"!==r&&o.push(W(e)),t.push(o),o=[]),e.initialPoint=e.p=e.vals,r=c;continue}const l=q[c];if(!l)throw new Error("Invalid SVG - command not recognized.");const u=l(e);e.p=u[u.length-1],o.push(u),r=c}return o.length>0&&("z"!==r&&o.push(W(e)),t.push(o)),t}(function(n){if(!n.length)return[];const e=new J(n),t=[];if(!e.initialCommandIsMoveTo())throw new Error("Path must start with m or M");for(;e.hasMoreData();)t.push(e.parseSegment());return t}(s)):s;let f=1;if(c/l>4){const n=c/4;f=n/l,l=n}const g=l/n,h=en(c,l),x=K(c/g),I=2*K(nn(u,h)/g/2),{glslRgbaCalcStr:_}=a,p=function(n){if(!n)return 0;let e=5381;for(let t=0;t<n.length;t++)e=(e<<5)+e+n.charCodeAt(t);return e>>>0}(_||""),v=function(n,e,t,r){const{gl:s,programs:i}=n;if(i[e])return i[e];const c=s.createProgram(),l=o(s,t,s.VERTEX_SHADER),u=o(s,r,s.FRAGMENT_SHADER);return s.attachShader(c,l),s.attachShader(c,u),s.linkProgram(c),i[e]={gl:s,program:c,attributes:{},uniforms:{},uniformBlocks:{},vertexShader:l,fragmentShader:u},i[e]}(t,`main${x}-${I}-${p}`,e,r(x,I,0,p)),{gl:m}=t;m.useProgram(v.program),H(t,v,d,i,u,c,l,a,x,g,I,f)}function on(n){if(void 0===n)return;const{gl:e,programs:t,textures:r}=n;for(let n in t){const{attributes:r,fragmentShader:o,vertexShader:s,uniformBlocks:i,program:c}=t[n];for(let n in i){const{buf:t}=i[n];e.deleteBuffer(t)}for(let n in r){const{buf:t}=r[n];e.deleteBuffer(t)}e.deleteShader(o),e.deleteShader(s),e.deleteProgram(c)}for(let n in r){const{tex:t}=r[n];e.deleteTexture(t)}}function sn(n,e,t){const r=n.createShader(e);if(n.shaderSource(r,t),n.compileShader(r),!n.getShaderParameter(r,n.COMPILE_STATUS))throw new Error(n.getShaderInfoLog(r))}const cn=new WeakMap;function ln(n){{const e=cn.get(n);if(e)return e}!function(n){try{sn(n,n.VERTEX_SHADER,e),sn(n,n.FRAGMENT_SHADER,r(32,2,0,0))}catch(n){throw console.log(n),n}}(n);const t={},o={},s={gl:n,textures:o,programs:t};return n.canvas.addEventListener("webglcontextlost",e=>{un(t),un(o),cn.delete(n),s.onContextLoss?.(e)},!1),cn.set(n,s),s}function un(n){Object.keys(n).forEach(e=>{delete n[e]})}export{on as freeGlContext,rn as generateSdf,ln as getWebGlContext};
@@ -1,4 +1,4 @@
1
- import { getFragment } from "./shaders/fragment.js";
1
+ import { getFragment, GLSL_DEFAULT } from "./shaders/fragment.js";
2
2
  import { vertex } from "./shaders/vertex.js";
3
3
  /**
4
4
  *
@@ -17,7 +17,7 @@ function debugGlsl(gl, type, shaderStr) {
17
17
  function debugShaders(gl) {
18
18
  try {
19
19
  debugGlsl(gl, gl.VERTEX_SHADER, vertex);
20
- debugGlsl(gl, gl.FRAGMENT_SHADER, getFragment(32, 4));
20
+ debugGlsl(gl, gl.FRAGMENT_SHADER, getFragment(32, 2, GLSL_DEFAULT, 0));
21
21
  }
22
22
  catch (e) {
23
23
  console.log(e);
@@ -1 +1 @@
1
- {"version":3,"file":"debug-shaders.js","sourceRoot":"","sources":["../src/debug-shaders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG7C;;;;;GAKG;AACH,SAAS,SAAS,CACV,EAA0B,EAC1B,IAAyD,EACzD,SAAiB;IAErB,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAE,CAAC;IACjC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC9B,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAE,CAAC,CAAC;IAC7C,CAAC;AACL,CAAC;AAGD,SAAS,YAAY,CACb,EAA0B;IAE9B,IAAI,CAAC;QACD,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACxC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,EAAE,WAAW,CAAC,EAAE,EAAC,CAAC,CAAC,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACf,MAAM,CAAC,CAAC;IACZ,CAAC;AACL,CAAC;AAGD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAA"}
1
+ {"version":3,"file":"debug-shaders.js","sourceRoot":"","sources":["../src/debug-shaders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAG7C;;;;;GAKG;AACH,SAAS,SAAS,CACV,EAA0B,EAC1B,IAAyD,EACzD,SAAiB;IAErB,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAE,CAAC;IACjC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC9B,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAE,CAAC,CAAC;IAC7C,CAAC;AACL,CAAC;AAGD,SAAS,YAAY,CACb,EAA0B;IAE9B,IAAI,CAAC;QACD,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACxC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,EAAE,WAAW,CAAC,EAAE,EAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACf,MAAM,CAAC,CAAC;IACZ,CAAC;AACL,CAAC;AAGD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAA"}
@@ -1,4 +1,14 @@
1
1
  import { GlContext } from './types/gl-context.js';
2
+ interface SdfOptions {
3
+ /** the position where to draw, x-coordinate */
4
+ readonly x?: number | undefined;
5
+ readonly y?: number | undefined;
6
+ readonly testInteriorExterior?: boolean | undefined;
7
+ readonly calcSdfForInside?: boolean | undefined;
8
+ readonly calcSdfForOutside?: boolean | undefined;
9
+ readonly customData?: [number, number, number, number] | undefined;
10
+ readonly glslRgbaCalcStr?: string | undefined;
11
+ }
2
12
  /**
3
13
  * Generates an sdf (signed distance field) from the given bezier curves,
4
14
  * viewbox, etc. and renders the result
@@ -9,16 +19,77 @@ import { GlContext } from './types/gl-context.js';
9
19
  * thereof) given by given by their ordered control points,
10
20
  * e.g. `[ [[0,0],[1,1],[2,1],[2,0]], [[2,0],[7,2],[1,5],[8,6]], ... ]` **OR**
11
21
  * * an SVG string, e.g. "M26.53 478.83 C028.89 481.61 031.33 484.32 ..."
22
+ * @param viewbox the viewbox given as `[x1,x2,y1,y2]` (**not as** `[x,y,widht,height]`)
12
23
  * @param width the width of the drawing rectangle
13
24
  * @param height the height of the drawing rectangle
14
- * @param viewbox the viewbox
15
25
  * @param maxDistance maximum sdf distance
16
- * @param sdfExponent TODO
17
- * @param inclInside if `true` the sdf will be calculate for the inside of the shape
18
- * @param inclOutside if `true` the sdf will be calculate for the outside of the shape
19
- * @param x the position where to draw, x-coordinate
20
- * @param y the position where to draw, y-coordinate
21
- * @param channel TODO
26
+ * @param options additional options (see below)
27
+ *
28
+ * **The following are properties of the `options` parameters**
29
+ * @param x defaults to `0`; the position where to draw on the canvas, x-coordinate
30
+ * @param y defaults to `0`; the position where to draw on the canvas, y-coordinate
31
+ * @param testInteriorExterior defaults to `true`;
32
+ * if `false` winds will always be `0.0` and only an un-signed sdf can be calculated since all
33
+ * fragments are considered outside
34
+ * @param calcSdfForInside defaults to `true`;
35
+ * if `false` the sdf will not be calculate for the inside of the shape, in the shader, `res` will always be `1.0`
36
+ * @param calcSdfForOutside defaults to `true`;
37
+ * if `false` the sdf will not be calculate for the outside of the shape, in the shader, `res` will always be `1.0`
38
+ * @param customData optional custom data (must be an array of 4 numbers) to send to
39
+ * the fragment shader as a uniform, e.g. exponent, scale, a timer, or whatever
40
+ * @param glslRgbaCalcStr a glsl string (#version 300 es) inserted at the end of
41
+ * the fragment shader to modify the output frag color in any way (you can also discard the fragment);
42
+ * see below for available variables that can be used;
43
+ *
44
+ * defaults to (designed to match webgl-sdf-generator)
45
+ * ```glsl
46
+ * float exponent = uCustom.x;
47
+ * res = (pow(1.0 - res, exponent) * 0.5) * (inside ? -1.0 : 1.0);
48
+ * float red = res;
49
+ * float green = res;
50
+ * float blue = res;
51
+ * float alpha = res;
52
+ *
53
+ * ```
54
+ * You must define and assign \`red\`, \`green\`, \`blue\` and \`alpha\`.
55
+ *
56
+ * Usable variables:
57
+ * ```glsl
58
+ * // the result of the distance calculation for this fragment, a value from 0.0 to 1.0
59
+ * // with 1.0 occuring when the fragment is >= maxDistance away and 0.0 when the
60
+ * // fragment is exactly on a curve
61
+ * float res
62
+ *
63
+ * // the number of anti-clockwise winds around the fragment, a value != 0
64
+ * // means the fragment is inside the shape
65
+ * float winds
66
+ *
67
+ * // 4 custom values set via an options parameter of `generateSdf`; defaults to `[1,0,0,0]`;
68
+ * // the first value is used as the exponent within the default `glslRgbaCalcStr`
69
+ * vec4 uCustom;
70
+ *
71
+ * // the max distance value supplied via `generateSdf`
72
+ * float uMaxDistance
73
+ *
74
+ * // bit 0 -> calc sdf when fragment is inside; defaults to 1,
75
+ * // bit 1 -> calc sdf when fragment is outside; defaults to 1
76
+ * // bit 1 -> calc `winds` (required for signing the distance); defaults to 1
77
+ * // note: when the distance calculation is not done (via options from `generateSdf`),
78
+ * `res` will be set to 1.0 (max distance away)
79
+ * int uTestInOut
80
+ *
81
+ * // the original x,y coordinates of the fragment in the original space provided
82
+ * // via the `viewbox` in `generateSdf`, e.g. the very bottom-left fragment
83
+ * // will have vXY == (viebox[0], viebox[1]) and the very top right will have
84
+ * // coordinates vXY == (viebox[2], viebox[3])
85
+ * vec2 vXY
86
+ *
87
+ * // whether the point is inside or outside the shape, often used to sign `res`
88
+ * // it is identical to `winds != 0`
89
+ * bool inside
90
+ *
91
+ * // pretty much useless unless you want to create a checkerboard pattern for no good reason
92
+ * int instanceId
22
93
  */
23
- declare function generateSdf(glContext: GlContext, bezierCurves_or_svgStr: (number[][])[][] | string, viewbox: [number, number, number, number], width: number, height: number, x: number | undefined, y: number | undefined, maxDistance: number, inclInside: boolean | undefined, inclOutside: boolean | undefined, customData: [number, number, number, number], channel?: number): void;
24
- export { generateSdf };
94
+ declare function generateSdf(glContext: GlContext, bezierCurves_or_svgStr: (number[][])[][] | string, viewbox: [number, number, number, number], width: number, height: number, maxDistance: number, options?: SdfOptions): void;
95
+ export { generateSdf, SdfOptions };
@@ -1,12 +1,18 @@
1
1
  // import { getWebGLContext } from './webgl-utils/get-gl-context.js';
2
2
  import { vertex } from './shaders/vertex.js';
3
- import { getFragment } from './shaders/fragment.js';
3
+ import { getFragment, GLSL_DEFAULT } from './shaders/fragment.js';
4
4
  import { initProgram } from './webgl-utils/use-program.js';
5
5
  import { mainProgram } from './main-program.js';
6
6
  import { ROW_COUNT } from './row-count.js';
7
7
  import { getPathsFromStr } from './svg/get-paths-from-str.js';
8
8
  import { MAX_ASPECT_RATIO_BEFORE_STRETCH } from './max-aspect-ratio-before-stretch.js';
9
9
  const { ceil, min, max } = Math;
10
+ const defaultSdfOptions = {
11
+ x: 0, y: 0,
12
+ testInteriorExterior: true,
13
+ calcSdfForInside: true, calcSdfForOutside: true,
14
+ customData: [1, 0, 0, 0]
15
+ };
10
16
  /**
11
17
  * Generates an sdf (signed distance field) from the given bezier curves,
12
18
  * viewbox, etc. and renders the result
@@ -17,24 +23,82 @@ const { ceil, min, max } = Math;
17
23
  * thereof) given by given by their ordered control points,
18
24
  * e.g. `[ [[0,0],[1,1],[2,1],[2,0]], [[2,0],[7,2],[1,5],[8,6]], ... ]` **OR**
19
25
  * * an SVG string, e.g. "M26.53 478.83 C028.89 481.61 031.33 484.32 ..."
26
+ * @param viewbox the viewbox given as `[x1,x2,y1,y2]` (**not as** `[x,y,widht,height]`)
20
27
  * @param width the width of the drawing rectangle
21
28
  * @param height the height of the drawing rectangle
22
- * @param viewbox the viewbox
23
29
  * @param maxDistance maximum sdf distance
24
- * @param sdfExponent TODO
25
- * @param inclInside if `true` the sdf will be calculate for the inside of the shape
26
- * @param inclOutside if `true` the sdf will be calculate for the outside of the shape
27
- * @param x the position where to draw, x-coordinate
28
- * @param y the position where to draw, y-coordinate
29
- * @param channel TODO
30
+ * @param options additional options (see below)
31
+ *
32
+ * **The following are properties of the `options` parameters**
33
+ * @param x defaults to `0`; the position where to draw on the canvas, x-coordinate
34
+ * @param y defaults to `0`; the position where to draw on the canvas, y-coordinate
35
+ * @param testInteriorExterior defaults to `true`;
36
+ * if `false` winds will always be `0.0` and only an un-signed sdf can be calculated since all
37
+ * fragments are considered outside
38
+ * @param calcSdfForInside defaults to `true`;
39
+ * if `false` the sdf will not be calculate for the inside of the shape, in the shader, `res` will always be `1.0`
40
+ * @param calcSdfForOutside defaults to `true`;
41
+ * if `false` the sdf will not be calculate for the outside of the shape, in the shader, `res` will always be `1.0`
42
+ * @param customData optional custom data (must be an array of 4 numbers) to send to
43
+ * the fragment shader as a uniform, e.g. exponent, scale, a timer, or whatever
44
+ * @param glslRgbaCalcStr a glsl string (#version 300 es) inserted at the end of
45
+ * the fragment shader to modify the output frag color in any way (you can also discard the fragment);
46
+ * see below for available variables that can be used;
47
+ *
48
+ * defaults to (designed to match webgl-sdf-generator)
49
+ * ```glsl
50
+ * float exponent = uCustom.x;
51
+ * res = (pow(1.0 - res, exponent) * 0.5) * (inside ? -1.0 : 1.0);
52
+ * float red = res;
53
+ * float green = res;
54
+ * float blue = res;
55
+ * float alpha = res;
56
+ *
57
+ * ```
58
+ * You must define and assign \`red\`, \`green\`, \`blue\` and \`alpha\`.
59
+ *
60
+ * Usable variables:
61
+ * ```glsl
62
+ * // the result of the distance calculation for this fragment, a value from 0.0 to 1.0
63
+ * // with 1.0 occuring when the fragment is >= maxDistance away and 0.0 when the
64
+ * // fragment is exactly on a curve
65
+ * float res
66
+ *
67
+ * // the number of anti-clockwise winds around the fragment, a value != 0
68
+ * // means the fragment is inside the shape
69
+ * float winds
70
+ *
71
+ * // 4 custom values set via an options parameter of `generateSdf`; defaults to `[1,0,0,0]`;
72
+ * // the first value is used as the exponent within the default `glslRgbaCalcStr`
73
+ * vec4 uCustom;
74
+ *
75
+ * // the max distance value supplied via `generateSdf`
76
+ * float uMaxDistance
77
+ *
78
+ * // bit 0 -> calc sdf when fragment is inside; defaults to 1,
79
+ * // bit 1 -> calc sdf when fragment is outside; defaults to 1
80
+ * // bit 1 -> calc `winds` (required for signing the distance); defaults to 1
81
+ * // note: when the distance calculation is not done (via options from `generateSdf`),
82
+ * `res` will be set to 1.0 (max distance away)
83
+ * int uTestInOut
84
+ *
85
+ * // the original x,y coordinates of the fragment in the original space provided
86
+ * // via the `viewbox` in `generateSdf`, e.g. the very bottom-left fragment
87
+ * // will have vXY == (viebox[0], viebox[1]) and the very top right will have
88
+ * // coordinates vXY == (viebox[2], viebox[3])
89
+ * vec2 vXY
90
+ *
91
+ * // whether the point is inside or outside the shape, often used to sign `res`
92
+ * // it is identical to `winds != 0`
93
+ * bool inside
94
+ *
95
+ * // pretty much useless unless you want to create a checkerboard pattern for no good reason
96
+ * int instanceId
30
97
  */
31
- function generateSdf(glContext, bezierCurves_or_svgStr, viewbox, width, height, x = 0, y = 0, maxDistance, inclInside = true, inclOutside = true, customData,
32
- // TODO
33
- channel = 0) {
98
+ function generateSdf(glContext, bezierCurves_or_svgStr, viewbox, width, height, maxDistance, options = defaultSdfOptions) {
34
99
  const psss = typeof bezierCurves_or_svgStr === 'string'
35
100
  ? getPathsFromStr(bezierCurves_or_svgStr)
36
101
  : bezierCurves_or_svgStr;
37
- // const glContext = getWebGLContext(gl);
38
102
  let stretch = 1;
39
103
  const aspectRatio = width / height;
40
104
  if (aspectRatio > MAX_ASPECT_RATIO_BEFORE_STRETCH) {
@@ -46,11 +110,24 @@ channel = 0) {
46
110
  const maxDim = max(width, height);
47
111
  const colCount = ceil(width / cellSize);
48
112
  const padCount = 2 * ceil(min(maxDistance, maxDim) / cellSize / 2);
49
- const programMain = initProgram(glContext, `main${colCount}-${padCount}`, vertex, getFragment(colCount, padCount));
113
+ const { glslRgbaCalcStr } = options;
114
+ const hash = calcStrHash(glslRgbaCalcStr || '');
115
+ const programMain = initProgram(glContext, `main${colCount}-${padCount}-${hash}`, vertex, getFragment(colCount, padCount, glslRgbaCalcStr || GLSL_DEFAULT, hash));
50
116
  const { gl } = glContext;
51
- // debugShaders(gl); // comment for production
52
117
  gl.useProgram(programMain.program);
53
- mainProgram(glContext, programMain, psss, viewbox, maxDistance, inclInside, inclOutside, customData, x, y, width, height, colCount, cellSize, padCount, stretch);
118
+ mainProgram(glContext, programMain, psss, viewbox, maxDistance, width, height, options, colCount, cellSize, padCount, stretch);
119
+ }
120
+ /**
121
+ * Calculates and returns a hash of the given string
122
+ */
123
+ function calcStrHash(str) {
124
+ if (!str)
125
+ return 0;
126
+ let hash = 5381;
127
+ for (let i = 0; i < str.length; i++) {
128
+ hash = ((hash << 5) + hash) + str.charCodeAt(i);
129
+ }
130
+ return hash >>> 0; // Convert to unsigned 32-bit integer
54
131
  }
55
132
  export { generateSdf };
56
133
  //# sourceMappingURL=generate-sdf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-sdf.js","sourceRoot":"","sources":["../src/generate-sdf.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,+BAA+B,EAAE,MAAM,sCAAsC,CAAC;AAIvF,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAGhC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,WAAW,CACZ,SAAoB,EACpB,sBAAiD,EACjD,OAAsC,EACtC,KAAa,EACb,MAAc,EACd,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EACZ,WAAmB,EACnB,UAAU,GAAG,IAAI,EACjB,WAAW,GAAG,IAAI,EAClB,UAAyC;AAEzC,OAAO;AACP,OAAO,GAAG,CAAC;IAEf,MAAM,IAAI,GAAG,OAAO,sBAAsB,KAAK,QAAQ;QACnD,CAAC,CAAC,eAAe,CAAC,sBAAsB,CAAC;QACzC,CAAC,CAAC,sBAAsB,CAAC;IAE7B,yCAAyC;IAEzC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,WAAW,GAAG,KAAK,GAAC,MAAM,CAAC;IACjC,IAAI,WAAW,GAAG,+BAA+B,EAAE,CAAC;QAChD,MAAM,CAAC,GAAG,KAAK,GAAC,+BAA+B,CAAC;QAChD,OAAO,GAAG,CAAC,GAAC,MAAM,CAAC;QACnB,MAAM,GAAG,CAAC,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,GAAC,SAAS,CAAC;IAElC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,GAAC,QAAQ,CAAC,CAAC;IAEtC,MAAM,QAAQ,GAAG,CAAC,GAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,GAAC,QAAQ,GAAC,CAAC,CAAC,CAAC;IAE7D,MAAM,WAAW,GAAG,WAAW,CAC3B,SAAS,EAAE,OAAO,QAAQ,IAAI,QAAQ,EAAE,EACxC,MAAM,EAAE,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAC1C,CAAC;IAEF,MAAM,EAAE,EAAE,EAAE,GAAG,SAAS,CAAC;IAEzB,+CAA+C;IAE/C,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,WAAW,CACP,SAAS,EAAE,WAAW,EACtB,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAC/D,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CACxC,CAAC;AACN,CAAC;AAGD,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"generate-sdf.js","sourceRoot":"","sources":["../src/generate-sdf.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { Program } from './types/program.js';
2
2
  import { GlContext } from './types/gl-context.js';
3
- declare function mainProgram(glContext: GlContext, programMain: Program, psss: number[][][][], viewbox: [number, number, number, number], maxDistance: number, inclInside: boolean, inclOutside: boolean, customData: [number, number, number, number], x: number, y: number, width: number, height: number, colCount: number, cellSize: number, padCount: number, stretch: number): void;
3
+ import { SdfOptions } from './generate-sdf.js';
4
+ declare function mainProgram(glContext: GlContext, programMain: Program, psss: number[][][][], viewbox: [number, number, number, number], maxDistance: number, width: number, height: number, options: SdfOptions, colCount: number, cellSize: number, padCount: number, stretch: number): void;
4
5
  export { mainProgram };
@@ -8,8 +8,9 @@ import { ROW_COUNT } from './row-count.js';
8
8
  const SEG_TEX_INDEX = 0;
9
9
  const CELL_TEX_INDEX = 1;
10
10
  const CROSS_TEX_INDEX = 2;
11
- function mainProgram(glContext, programMain, psss, viewbox, maxDistance, inclInside, inclOutside, customData, x, y, width, height, colCount, cellSize, padCount, stretch) {
11
+ function mainProgram(glContext, programMain, psss, viewbox, maxDistance, width, height, options, colCount, cellSize, padCount, stretch) {
12
12
  const { gl } = glContext;
13
+ const { x = 0, y = 0, testInteriorExterior = true, calcSdfForInside = true, calcSdfForOutside = true, customData = [1, 0, 0, 0], glslRgbaCalcStr } = options;
13
14
  const vertices = [];
14
15
  const x0 = 0;
15
16
  const y0 = 0;
@@ -33,7 +34,9 @@ function mainProgram(glContext, programMain, psss, viewbox, maxDistance, inclIns
33
34
  // Init/update uniforms
34
35
  setUniform_('2f', 'uWidthHeight', width, height);
35
36
  setUniform_('1f', 'uMaxDistance', maxDistance);
36
- setUniform_('1i', 'uIncl', (inclInside ? 1 : 0) + (inclOutside ? 2 : 0));
37
+ setUniform_('1i', 'uTestInOut', (calcSdfForInside ? 1 : 0) +
38
+ (calcSdfForOutside ? 2 : 0) +
39
+ (testInteriorExterior ? 4 : 0));
37
40
  setUniform_('4f', 'uCustom', ...customData);
38
41
  setUniformBlock(programMain)('SegIdxRangePerCellBlock', 0, segIdxs_PerCell_Range_Arr);
39
42
  setUniformBlock(programMain)('SegIdxRangePerStripBlock', 1, segIdxs_PerStrip_Range_Arr);
@@ -89,6 +92,7 @@ function mainProgram(glContext, programMain, psss, viewbox, maxDistance, inclIns
89
92
  gl.scissor(x, y, width, height / stretch);
90
93
  }
91
94
  gl.viewport(x, y, width, height);
95
+ gl.colorMask(true, true, true, true);
92
96
  // draw a square colCount * ROW_COUNT times - 6 vertics
93
97
  gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, colCount * ROW_COUNT);
94
98
  if (stretch > 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"main-program.js","sourceRoot":"","sources":["../src/main-program.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,MAAM,eAAe,GAAG,CAAC,CAAC;AAG1B,SAAS,WAAW,CACZ,SAAoB,EACpB,WAAoB,EAEpB,IAAoB,EACpB,OAAsC,EACtC,WAAmB,EACnB,UAAmB,EACnB,WAAoB,EACpB,UAA4C,EAE5C,CAAS,EACT,CAAS,EACT,KAAa,EACb,MAAc,EACd,QAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,OAAe;IAEnB,MAAM,EAAE,EAAE,EAAE,GAAG,SAAS,CAAC;IAEzB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,EAAE,GAAG,CAAC,CAAC;IACb,MAAM,EAAE,GAAG,CAAC,CAAC;IACb,MAAM,EAAE,GAAG,CAAC,GAAC,SAAS,CAAC;IACvB,MAAM,EAAE,GAAG,CAAC,GAAC,SAAS,CAAC;IAEvB,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAC,EAAE,EAAE,EAAE,EAAC,EAAE,EAAE,EAAE,EAAC,EAAE,CAAC,CAAC,CAAE,4CAA4C;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAC,EAAE,EAAE,EAAE,EAAC,EAAE,EAAE,EAAE,EAAC,EAAE,CAAC,CAAC,CAAE,6CAA6C;IAClF,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEzC,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,aAAa,GAAG,YAAY,CAAC,WAAW,CAAC,CAAC;IAEhD,MAAM,EACF,mBAAmB,EAAE,yBAAyB,EAC9C,yBAAyB,EAAE,+BAA+B,EAC1D,yBAAyB,EAAE,+BAA+B,EAC1D,0BAA0B,EAC7B,GAAG,cAAc,CACd,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EACpD,QAAQ,EAAE,OAAO,EAAE,OAAO,CAC7B,CAAC;IAEF,yBAAyB;IACzB,aAAa,CACT,KAAK,EAAE,CAAC,EAAG,yCAAyC;IACpD,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,EAAE,KAAK,CAClC,CAAC;IAEF,aAAa,CACT,uBAAuB,EACvB,CAAC,EAAG,QAAQ;IACZ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,EAAE,+BAA+B,EACvD,CAAC,CAAE,wCAAwC;KAC9C,CAAC;IAEF,aAAa,CACT,2BAA2B,EAC3B,CAAC,EAAG,QAAQ;IACZ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,EAAE,+BAA+B,EACvD,CAAC,CAAE,wCAAwC;KAC9C,CAAC;IAEF,uBAAuB;IACvB,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACjD,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IAC/C,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,CAAC;IAE5C,eAAe,CAAC,WAAW,CAAC,CAAC,yBAAyB,EAAE,CAAC,EAAE,yBAAyB,CAAC,CAAC;IACtF,eAAe,CAAC,WAAW,CAAC,CAAC,0BAA0B,EAAE,CAAC,EAAE,0BAA0B,CAAC,CAAC;IAExF,uCAAuC;IACvC,sCAAsC;IACtC,UAAU,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IAC7C,EAAE,CAAC,UAAU,CACT,EAAE,CAAC,UAAU,EACb,CAAC,EAAa,qBAAqB;IACnC,EAAE,CAAC,OAAO,EAAI,yEAAyE;IAEvF,SAAS,EAAG,cAAc;IAC1B,mBAAmB,CAAC,MAAM,GAAG,CAAC,GAAG,SAAS,EAAG,yCAAyC;IACtF,gCAAgC;IAChC,KAAK;IAEL,CAAC,EAAa,oBAAoB;IAClC,EAAE,CAAC,IAAI,EAAO,SAAS;IACvB,EAAE,CAAC,KAAK,EAAM,kBAAkB;IAChC,mBAAmB,CAAE,eAAe;KACvC,CAAC;IACF,MAAM,SAAS,GAAG,EAAE,CAAC,kBAAkB,CAAC,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtE,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACvC,+CAA+C;IAE/C,+CAA+C;IAC/C,gDAAgD;IAChD,UAAU,CAAC,SAAS,EAAE,cAAc,EAAE,sBAAsB,CAAC,CAAC;IAC9D,EAAE,CAAC,UAAU,CACT,EAAE,CAAC,UAAU,EACb,CAAC,EAAY,qBAAqB;IAClC,EAAE,CAAC,IAAI,EAAM,+DAA+D;IAC5E,SAAS,EAAI,cAAc;IAC3B,yBAAyB,CAAC,MAAM,GAAG,SAAS,EAAG,+BAA+B;IAC9E,CAAC,EAAY,oBAAoB;IACjC,EAAE,CAAC,WAAW,EAAG,SAAS;IAC1B,EAAE,CAAC,GAAG,EAAK,gBAAgB;IAC3B,yBAAyB,CAAE,eAAe;KAC7C,CAAC;IAEF,MAAM,UAAU,GAAG,EAAE,CAAC,kBAAkB,CAAC,WAAW,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAChF,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACzC,+CAA+C;IAE/C,+CAA+C;IAC/C,mDAAmD;IACnD,UAAU,CAAC,SAAS,EAAE,eAAe,EAAE,sBAAsB,CAAC,CAAC;IAC/D,EAAE,CAAC,UAAU,CACT,EAAE,CAAC,UAAU,EACb,CAAC,EAAY,qBAAqB;IAClC,EAAE,CAAC,IAAI,EAAM,+DAA+D;IAC5E,SAAS,EAAI,cAAc;IAC3B,yBAAyB,CAAC,MAAM,GAAG,SAAS,EAAG,+BAA+B;IAC9E,CAAC,EAAY,oBAAoB;IACjC,EAAE,CAAC,WAAW,EAAG,SAAS;IAC1B,EAAE,CAAC,GAAG,EAAK,gBAAgB;IAC3B,yBAAyB,CAAE,eAAe;KAC7C,CAAC;IACF,MAAM,WAAW,GAAG,EAAE,CAAC,kBAAkB,CAAC,WAAW,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACjF,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IAC3C,+CAA+C;IAE/C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QACd,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;QAC3B,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAC,OAAO,CAAC,CAAA;IAC3C,CAAC;IAED,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAEjC,uDAAuD;IACvD,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAC,SAAS,CAAC,CAAC;IAE/D,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QACd,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;AACL,CAAC;AAGD,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"main-program.js","sourceRoot":"","sources":["../src/main-program.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,4 @@
1
- declare function getFragment(colCount: number, padCount: number): string;
2
- export { getFragment };
1
+ declare const GLSL_PATTERN1 = "\n float exponent = uCustom.x;\n res = pow(1.0 - res, exponent);\n float alpha = res <= 0.0 ? 0.0 : 0.5;\n float red = inside ? 0.2 : 0.8;\n float green = abs(sin(25.0 * res));\n float blue = 0.5;\n";
2
+ declare const GLSL_DEFAULT = "\n float exponent = uCustom.x;\n res = (pow(1.0 - res, exponent) * 0.5) * (inside ? -1.0 : 1.0);\n float red = res;\n float green = res;\n float blue = res;\n float alpha = res;\n";
3
+ declare function getFragment(colCount: number, padCount: number, calcFragColorStr: string, hash: number): string;
4
+ export { getFragment, GLSL_PATTERN1, GLSL_DEFAULT };
@@ -1,7 +1,26 @@
1
1
  import { ROW_COUNT } from "../row-count.js";
2
2
  const cache = {};
3
- function getFragment(colCount, padCount) {
4
- const fragment = cache[1024 * colCount + padCount];
3
+ const GLSL_PATTERN1 = `
4
+ float exponent = uCustom.x;
5
+ res = pow(1.0 - res, exponent);
6
+ float alpha = res <= 0.0 ? 0.0 : 0.5;
7
+ float red = inside ? 0.2 : 0.8;
8
+ float green = abs(sin(25.0 * res));
9
+ float blue = 0.5;
10
+ `;
11
+ const GLSL_DEFAULT = `
12
+ float exponent = uCustom.x;
13
+ res = (pow(1.0 - res, exponent) * 0.5) * (inside ? -1.0 : 1.0);
14
+ float red = res;
15
+ float green = res;
16
+ float blue = res;
17
+ float alpha = res;
18
+ `;
19
+ function getFragment(colCount, padCount, calcFragColorStr, hash) {
20
+ // `colCount` and `padCount` can take at most 8 bits and `has` 32 bits and
21
+ // we have at least 53 bits to play with so we're fine
22
+ const key = (2 ** 32) * (256 * colCount + padCount) + hash;
23
+ const fragment = cache[key];
5
24
  if (fragment !== undefined) {
6
25
  return fragment;
7
26
  }
@@ -14,7 +33,11 @@ uniform float uMaxDistance;
14
33
  uniform highp sampler2D uSegs;
15
34
  uniform highp isampler2D uCloseCellIdxs;
16
35
  uniform highp isampler2D uCrossCellIdxs;
17
- uniform int uIncl; // bit 0 -> incl inside, bit 1 -> incl outside
36
+ // bit 0 -> calc distance inside
37
+ // bit 1 -> calc distance outside
38
+ // bit 2 -> calc whether fragment is inside or outside (else outside is assumed with winds == 0.0)
39
+ uniform int uTestInOut;
40
+ uniform vec4 uCustom;
18
41
 
19
42
  uniform SegIdxRangePerCellBlock {
20
43
  ivec4 uSegIdxRangePerCell[${(ROW_COUNT + 2 * padCount) * (colCount + 2 * padCount) / 2}];
@@ -29,6 +52,10 @@ flat in ivec2 closeCellIdxRange;
29
52
  flat in ivec2 crossCellIdxRange;
30
53
  out vec4 FragColor;
31
54
 
55
+ // testing!!
56
+ // float rand(vec2 co) {
57
+ // return mod(uCustom.w * fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453), 1.0);
58
+ // }
32
59
 
33
60
  float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
34
61
  vec2 lineDir = lineB - lineA;
@@ -42,72 +69,75 @@ float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
42
69
 
43
70
  void main() {
44
71
  ///////////////////////////////////////////////////////////////////////////
72
+ // Calculate \`winds\`:
73
+ //
45
74
  // Project a ray to the left to check if it crosses the segment in order
46
75
  // to find the fragment's winding number to determine whether fragment
47
76
  // is inside or outside the shape.
77
+ ///////////////////////////////////////////////////////////////////////////
48
78
 
49
- int crossIdxS = crossCellIdxRange.x;
50
- int crossLen = crossCellIdxRange.y;
51
79
  float winds = 0.0;
52
- // Iterate over all relevant cell indexes
53
- for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
54
- int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
80
+ if ((uTestInOut & 4) == 0) {
81
+ int crossIdxS = crossCellIdxRange.x;
82
+ int crossLen = crossCellIdxRange.y;
83
+ // Iterate over all relevant cell indexes
84
+ for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
85
+ int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
55
86
 
56
- ivec2 uSegIdxRange = crossIdx % 2 == 0
57
- ? uSegIdxRangePerCell[crossIdx / 2].xy
58
- : uSegIdxRangePerCell[crossIdx / 2].zw;
87
+ ivec2 uSegIdxRange = crossIdx % 2 == 0
88
+ ? uSegIdxRangePerCell[crossIdx / 2].xy
89
+ : uSegIdxRangePerCell[crossIdx / 2].zw;
59
90
 
60
- int segIdx = uSegIdxRange.x;
61
- int segLen = uSegIdxRange.y;
91
+ int segIdx = uSegIdxRange.x;
92
+ int segLen = uSegIdxRange.y;
62
93
 
63
- for (int j = segIdx; j < segIdx + segLen; j++) {
64
- // Fetch segment from texture
65
- vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
94
+ for (int j = segIdx; j < segIdx + segLen; j++) {
95
+ // Fetch segment from texture
96
+ vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
66
97
 
67
- // line segment's min-y is excluded
68
- bool crossing =
69
- (seg.y > vXY.y != seg.w > vXY.y) &&
70
- (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
98
+ // line segment's min-y is excluded
99
+ bool crossing =
100
+ (seg.y > vXY.y != seg.w > vXY.y) &&
101
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
71
102
 
72
- bool crossingUp = seg.y < seg.w;
103
+ bool crossingUp = seg.y < seg.w;
73
104
 
74
- winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
105
+ winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
106
+ }
75
107
  }
76
- }
77
108
 
78
- {
79
- int cellIdx = (instanceId % ${ROW_COUNT});
109
+ {
110
+ int cellIdx = (instanceId % ${ROW_COUNT});
80
111
 
81
- bool isEven = cellIdx % 2 == 0;
112
+ bool isEven = cellIdx % 2 == 0;
82
113
 
83
- ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];
84
- int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
85
- int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
86
-
114
+ ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];
115
+ int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
116
+ int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
117
+
87
118
 
88
- for (int j = segIdx; j < segIdx + segLen; j++) {
89
- // Fetch segment from texture
90
- vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
119
+ for (int j = segIdx; j < segIdx + segLen; j++) {
120
+ // Fetch segment from texture
121
+ vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
91
122
 
92
- // line segment's min-y is excluded
93
- bool crossing =
94
- (seg.y > vXY.y != seg.w > vXY.y) &&
95
- (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
123
+ // line segment's min-y is excluded
124
+ bool crossing =
125
+ (seg.y > vXY.y != seg.w > vXY.y) &&
126
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
96
127
 
97
- bool crossingUp = seg.y < seg.w;
128
+ bool crossingUp = seg.y < seg.w;
98
129
 
99
- winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
130
+ winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
131
+ }
100
132
  }
101
133
  }
102
-
103
-
104
134
  bool inside = winds != 0.0;
105
135
  ///////////////////////////////////////////////////////////////////////////
106
-
136
+ // Calculate \`res\`: the distance to the nearest curve
107
137
  ///////////////////////////////////////////////////////////////////////////
108
138
  float res = 1.0; // sdf result
109
139
 
110
- if ((inside && (uIncl % 2 != 0)) || (!inside && (uIncl > 1))) {
140
+ if ((inside && ((uTestInOut & 1) != 0)) || (!inside && ((uTestInOut & 2) != 0))) {
111
141
  int cellIdxS = closeCellIdxRange.x;
112
142
  int cellLen = closeCellIdxRange.y;
113
143
  // Iterate over all relevant cell indexes
@@ -125,9 +155,8 @@ void main() {
125
155
  // Fetch segment from texture
126
156
  vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
127
157
 
128
- // Find unsigned distance to the segment; only the nearest will be kept
158
+ // Find normalized unsigned distance to the segment; only the nearest will be kept
129
159
  float d = absDistToSegment(vXY, seg.xy, seg.zw);
130
- // Apply exponential transform
131
160
  float val = clamp(d / uMaxDistance, 0.0, 1.0);
132
161
 
133
162
  res = min(res, val);
@@ -139,20 +168,15 @@ void main() {
139
168
  // DEBUG!
140
169
  // float alpha = ((instanceId + instanceId/${ROW_COUNT}) % 2 == 0 ? 0.3 : 0.5);
141
170
 
142
-
143
- float exponent = 2;
144
- res = pow(1.0 - val, exponent) * 0.5;
145
-
146
- float alpha = res == 1.0 ? 0.0 : 0.5;
147
- float red = inside ? 0.2 : 0.8;
148
- float green = abs(sin(25.0 * res));
149
- float blue = 0.5;
171
+
172
+ ${GLSL_PATTERN1}
150
173
 
151
174
  FragColor = vec4(red, green, blue, alpha);
152
175
  }
153
176
  `;
154
- cache[1024 * colCount + padCount] = main_Fragment;
177
+ cache[key] = main_Fragment;
155
178
  return main_Fragment;
156
179
  }
157
- export { getFragment };
180
+ // ${calcFragColorStr}
181
+ export { getFragment, GLSL_PATTERN1, GLSL_DEFAULT };
158
182
  //# sourceMappingURL=fragment.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fragment.js","sourceRoot":"","sources":["../../src/shaders/fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,KAAK,GAAkD,EAAE,CAAC;AAGhE,SAAS,WAAW,CACZ,QAAgB,EAChB,QAAgB;IAEpB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,GAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACjD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAAC,OAAO,QAAQ,CAAC;IAAC,CAAC;IAEpD,MAAM,aAAa;IACnB,QAAQ,CAAA;;;;;;;;;;;gCAWwB,CAAC,SAAS,GAAG,CAAC,GAAC,QAAQ,CAAC,GAAC,CAAC,QAAQ,GAAG,CAAC,GAAC,QAAQ,CAAC,GAAG,CAAC;;;iCAGnD,SAAS,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCAwDR,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDA6DE,SAAS;;;;;;;;;;;;;CAazD,CAAA;IAEG,KAAK,CAAC,IAAI,GAAC,QAAQ,GAAG,QAAQ,CAAC,GAAG,aAAa,CAAC;IAChD,OAAO,aAAa,CAAC;AACzB,CAAC;AAGD,OAAO,EAAE,WAAW,EAAE,CAAA"}
1
+ {"version":3,"file":"fragment.js","sourceRoot":"","sources":["../../src/shaders/fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,KAAK,GAAkD,EAAE,CAAC;AAGhE,MAAM,aAAa,GAAG;;;;;;;CAOrB,CAAC;AAGF,MAAM,YAAY,GAAG;;;;;;;CAOpB,CAAC;AAGF,SAAS,WAAW,CACZ,QAAgB,EAChB,QAAgB,EAChB,gBAAwB,EACxB,IAAY;IAEhB,0EAA0E;IAC1E,sDAAsD;IACtD,MAAM,GAAG,GAAG,CAAC,CAAC,IAAE,EAAE,CAAC,GAAC,CAAC,GAAG,GAAC,QAAQ,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC;IACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAAC,OAAO,QAAQ,CAAC;IAAC,CAAC;IAEpD,MAAM,aAAa;IACnB,QAAQ,CAAA;;;;;;;;;;;;;;;gCAewB,CAAC,SAAS,GAAG,CAAC,GAAC,QAAQ,CAAC,GAAC,CAAC,QAAQ,GAAG,CAAC,GAAC,QAAQ,CAAC,GAAG,CAAC;;;iCAGnD,SAAS,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0CAgEJ,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDA2DF,SAAS;;;MAGpD,aAAa;;;;CAIlB,CAAA;IAEG,KAAK,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC;IAC3B,OAAO,aAAa,CAAC;AACzB,CAAC;AAED,sBAAsB;AACtB,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { debugShaders } from "../debug-shaders.js";
1
2
  const cache = new WeakMap();
2
3
  /**
3
4
  * Returns a `GlContext` by reference via a cache of `WebGL2RenderingContext`s.
@@ -13,6 +14,7 @@ function getWebGlContext(gl) {
13
14
  return glContext;
14
15
  }
15
16
  }
17
+ debugShaders(gl);
16
18
  const programs = {};
17
19
  const textures = {};
18
20
  const glContext = { gl, textures, programs };
@@ -1 +1 @@
1
- {"version":3,"file":"get-web-gl-context.js","sourceRoot":"","sources":["../../src/webgl-utils/get-web-gl-context.ts"],"names":[],"mappings":"AAKA,MAAM,KAAK,GAAG,IAAI,OAAO,EAAqC,CAAC;AAG/D;;;;;;GAMG;AACH,SAAS,eAAe,CAChB,EAA0B;IAE9B,CAAC;QACG,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,SAAS,EAAE,CAAC;YAAC,OAAO,SAAS,CAAC;QAAC,CAAC;IACxC,CAAC;IAED,MAAM,QAAQ,GAAgC,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAgC,EAAE,CAAC;IAEjD,MAAM,SAAS,GAAc,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAExD,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,KAAK,CAAC,EAAE;QACnD,iGAAiG;QAEjG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACzB,cAAc,CAAC,QAAQ,CAAC,CAAC;QACzB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEjB,SAAS,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEV,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAEzB,OAAO,SAAS,CAAC;AACrB,CAAC;AAGD,SAAS,cAAc,CAAC,CAA6B;IACjD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAGD,OAAO,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"get-web-gl-context.js","sourceRoot":"","sources":["../../src/webgl-utils/get-web-gl-context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,KAAK,GAAG,IAAI,OAAO,EAAqC,CAAC;AAG/D;;;;;;GAMG;AACH,SAAS,eAAe,CAChB,EAA0B;IAE9B,CAAC;QACG,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,SAAS,EAAE,CAAC;YAAC,OAAO,SAAS,CAAC;QAAC,CAAC;IACxC,CAAC;IAED,YAAY,CAAC,EAAE,CAAC,CAAC;IAEjB,MAAM,QAAQ,GAAgC,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAgC,EAAE,CAAC;IAEjD,MAAM,SAAS,GAAc,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAExD,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,KAAK,CAAC,EAAE;QACnD,iGAAiG;QAEjG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACzB,cAAc,CAAC,QAAQ,CAAC,CAAC;QACzB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEjB,SAAS,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC,EAAE,KAAK,CAAC,CAAC;IAEV,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAEzB,OAAO,SAAS,CAAC;AACrB,CAAC;AAGD,SAAS,cAAc,CAAC,CAA6B;IACjD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAGD,OAAO,EAAE,eAAe,EAAE,CAAA"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "webgl2-sdf",
3
3
  "sideEffects": false,
4
4
  "description": "Fast sdf generator from bezier curves or svg string.",
5
- "version": "0.0.7",
5
+ "version": "0.0.8",
6
6
  "author": {
7
7
  "name": "Floris Steenkamp"
8
8
  },
@@ -1,4 +1,4 @@
1
- import { getFragment } from "./shaders/fragment.js";
1
+ import { getFragment, GLSL_DEFAULT } from "./shaders/fragment.js";
2
2
  import { vertex } from "./shaders/vertex.js";
3
3
 
4
4
 
@@ -27,7 +27,7 @@ function debugShaders(
27
27
 
28
28
  try {
29
29
  debugGlsl(gl, gl.VERTEX_SHADER, vertex);
30
- debugGlsl(gl, gl.FRAGMENT_SHADER, getFragment(32,4));
30
+ debugGlsl(gl, gl.FRAGMENT_SHADER, getFragment(32,2, GLSL_DEFAULT, 0));
31
31
  } catch (e) {
32
32
  console.log(e);
33
33
  throw e;
@@ -1,17 +1,36 @@
1
1
  // import { getWebGLContext } from './webgl-utils/get-gl-context.js';
2
2
  import { vertex } from './shaders/vertex.js';
3
- import { getFragment } from './shaders/fragment.js';
3
+ import { getFragment, GLSL_DEFAULT } from './shaders/fragment.js';
4
4
  import { initProgram } from './webgl-utils/use-program.js';
5
5
  import { mainProgram } from './main-program.js';
6
6
  import { ROW_COUNT } from './row-count.js';
7
7
  import { getPathsFromStr } from './svg/get-paths-from-str.js';
8
8
  import { MAX_ASPECT_RATIO_BEFORE_STRETCH } from './max-aspect-ratio-before-stretch.js';
9
9
  import { GlContext } from './types/gl-context.js';
10
- import { debugShaders } from './debug-shaders.js';
11
10
 
12
11
  const { ceil, min, max } = Math;
13
12
 
14
13
 
14
+ interface SdfOptions {
15
+ /** the position where to draw, x-coordinate */
16
+ readonly x?: number | undefined;
17
+ readonly y?: number | undefined;
18
+ readonly testInteriorExterior?: boolean | undefined;
19
+ readonly calcSdfForInside?: boolean | undefined;
20
+ readonly calcSdfForOutside?: boolean | undefined;
21
+ readonly customData?: [number,number,number,number] | undefined;
22
+ readonly glslRgbaCalcStr?: string | undefined;
23
+ }
24
+
25
+
26
+ const defaultSdfOptions: SdfOptions = {
27
+ x: 0, y: 0,
28
+ testInteriorExterior: true,
29
+ calcSdfForInside: true, calcSdfForOutside: true,
30
+ customData: [1,0,0,0]
31
+ }
32
+
33
+
15
34
  /**
16
35
  * Generates an sdf (signed distance field) from the given bezier curves,
17
36
  * viewbox, etc. and renders the result
@@ -22,16 +41,77 @@ const { ceil, min, max } = Math;
22
41
  * thereof) given by given by their ordered control points,
23
42
  * e.g. `[ [[0,0],[1,1],[2,1],[2,0]], [[2,0],[7,2],[1,5],[8,6]], ... ]` **OR**
24
43
  * * an SVG string, e.g. "M26.53 478.83 C028.89 481.61 031.33 484.32 ..."
44
+ * @param viewbox the viewbox given as `[x1,x2,y1,y2]` (**not as** `[x,y,widht,height]`)
25
45
  * @param width the width of the drawing rectangle
26
46
  * @param height the height of the drawing rectangle
27
- * @param viewbox the viewbox
28
47
  * @param maxDistance maximum sdf distance
29
- * @param sdfExponent TODO
30
- * @param inclInside if `true` the sdf will be calculate for the inside of the shape
31
- * @param inclOutside if `true` the sdf will be calculate for the outside of the shape
32
- * @param x the position where to draw, x-coordinate
33
- * @param y the position where to draw, y-coordinate
34
- * @param channel TODO
48
+ * @param options additional options (see below)
49
+ *
50
+ * **The following are properties of the `options` parameters**
51
+ * @param x defaults to `0`; the position where to draw on the canvas, x-coordinate
52
+ * @param y defaults to `0`; the position where to draw on the canvas, y-coordinate
53
+ * @param testInteriorExterior defaults to `true`;
54
+ * if `false` winds will always be `0.0` and only an un-signed sdf can be calculated since all
55
+ * fragments are considered outside
56
+ * @param calcSdfForInside defaults to `true`;
57
+ * if `false` the sdf will not be calculate for the inside of the shape, in the shader, `res` will always be `1.0`
58
+ * @param calcSdfForOutside defaults to `true`;
59
+ * if `false` the sdf will not be calculate for the outside of the shape, in the shader, `res` will always be `1.0`
60
+ * @param customData optional custom data (must be an array of 4 numbers) to send to
61
+ * the fragment shader as a uniform, e.g. exponent, scale, a timer, or whatever
62
+ * @param glslRgbaCalcStr a glsl string (#version 300 es) inserted at the end of
63
+ * the fragment shader to modify the output frag color in any way (you can also discard the fragment);
64
+ * see below for available variables that can be used;
65
+ *
66
+ * defaults to (designed to match webgl-sdf-generator)
67
+ * ```glsl
68
+ * float exponent = uCustom.x;
69
+ * res = (pow(1.0 - res, exponent) * 0.5) * (inside ? -1.0 : 1.0);
70
+ * float red = res;
71
+ * float green = res;
72
+ * float blue = res;
73
+ * float alpha = res;
74
+ *
75
+ * ```
76
+ * You must define and assign \`red\`, \`green\`, \`blue\` and \`alpha\`.
77
+ *
78
+ * Usable variables:
79
+ * ```glsl
80
+ * // the result of the distance calculation for this fragment, a value from 0.0 to 1.0
81
+ * // with 1.0 occuring when the fragment is >= maxDistance away and 0.0 when the
82
+ * // fragment is exactly on a curve
83
+ * float res
84
+ *
85
+ * // the number of anti-clockwise winds around the fragment, a value != 0
86
+ * // means the fragment is inside the shape
87
+ * float winds
88
+ *
89
+ * // 4 custom values set via an options parameter of `generateSdf`; defaults to `[1,0,0,0]`;
90
+ * // the first value is used as the exponent within the default `glslRgbaCalcStr`
91
+ * vec4 uCustom;
92
+ *
93
+ * // the max distance value supplied via `generateSdf`
94
+ * float uMaxDistance
95
+ *
96
+ * // bit 0 -> calc sdf when fragment is inside; defaults to 1,
97
+ * // bit 1 -> calc sdf when fragment is outside; defaults to 1
98
+ * // bit 1 -> calc `winds` (required for signing the distance); defaults to 1
99
+ * // note: when the distance calculation is not done (via options from `generateSdf`),
100
+ * `res` will be set to 1.0 (max distance away)
101
+ * int uTestInOut
102
+ *
103
+ * // the original x,y coordinates of the fragment in the original space provided
104
+ * // via the `viewbox` in `generateSdf`, e.g. the very bottom-left fragment
105
+ * // will have vXY == (viebox[0], viebox[1]) and the very top right will have
106
+ * // coordinates vXY == (viebox[2], viebox[3])
107
+ * vec2 vXY
108
+ *
109
+ * // whether the point is inside or outside the shape, often used to sign `res`
110
+ * // it is identical to `winds != 0`
111
+ * bool inside
112
+ *
113
+ * // pretty much useless unless you want to create a checkerboard pattern for no good reason
114
+ * int instanceId
35
115
  */
36
116
  function generateSdf(
37
117
  glContext: GlContext,
@@ -39,21 +119,13 @@ function generateSdf(
39
119
  viewbox: [number,number,number,number],
40
120
  width: number,
41
121
  height: number,
42
- x = 0, y = 0,
43
122
  maxDistance: number,
44
- inclInside = true,
45
- inclOutside = true,
46
- customData: [number,number,number,number],
47
-
48
- // TODO
49
- channel = 0) {
123
+ options: SdfOptions = defaultSdfOptions) {
50
124
 
51
125
  const psss = typeof bezierCurves_or_svgStr === 'string'
52
126
  ? getPathsFromStr(bezierCurves_or_svgStr)
53
127
  : bezierCurves_or_svgStr;
54
128
 
55
- // const glContext = getWebGLContext(gl);
56
-
57
129
  let stretch = 1;
58
130
  const aspectRatio = width/height;
59
131
  if (aspectRatio > MAX_ASPECT_RATIO_BEFORE_STRETCH) {
@@ -69,23 +141,41 @@ function generateSdf(
69
141
 
70
142
  const padCount = 2*ceil(min(maxDistance, maxDim)/cellSize/2);
71
143
 
144
+ const { glslRgbaCalcStr } = options;
145
+ const hash = calcStrHash(glslRgbaCalcStr || '');
146
+
72
147
  const programMain = initProgram(
73
- glContext, `main${colCount}-${padCount}`,
74
- vertex, getFragment(colCount, padCount)
148
+ glContext, `main${colCount}-${padCount}-${hash}`,
149
+ vertex, getFragment(colCount, padCount, glslRgbaCalcStr || GLSL_DEFAULT, hash)
75
150
  );
76
151
 
77
152
  const { gl } = glContext;
78
153
 
79
- // debugShaders(gl); // comment for production
80
-
81
154
  gl.useProgram(programMain.program);
82
155
  mainProgram(
83
156
  glContext, programMain,
84
- psss, viewbox, maxDistance, inclInside, inclOutside, customData,
85
- x, y, width, height,
86
- colCount, cellSize, padCount, stretch
157
+ psss, viewbox, maxDistance,
158
+ width, height,
159
+ options,
160
+ colCount, cellSize, padCount, stretch,
161
+
87
162
  );
88
163
  }
89
164
 
90
165
 
91
- export { generateSdf }
166
+ /**
167
+ * Calculates and returns a hash of the given string
168
+ */
169
+ function calcStrHash(str: string) {
170
+ if (!str) return 0;
171
+
172
+ let hash = 5381;
173
+ for (let i=0; i<str.length; i++) {
174
+ hash = ((hash << 5) + hash) + str.charCodeAt(i);
175
+ }
176
+
177
+ return hash >>> 0; // Convert to unsigned 32-bit integer
178
+ }
179
+
180
+
181
+ export { generateSdf, SdfOptions }
@@ -7,6 +7,7 @@ import { GlContext } from './types/gl-context.js';
7
7
  import { prepareBuffers } from './prepare-buffers.js';
8
8
  import { TEX_WIDTH } from './tex-width.js';
9
9
  import { ROW_COUNT } from './row-count.js';
10
+ import { SdfOptions } from './generate-sdf.js';
10
11
 
11
12
 
12
13
  const SEG_TEX_INDEX = 0;
@@ -21,14 +22,11 @@ function mainProgram(
21
22
  psss: number[][][][],
22
23
  viewbox: [number,number,number,number],
23
24
  maxDistance: number,
24
- inclInside: boolean,
25
- inclOutside: boolean,
26
- customData: [number, number, number, number],
27
-
28
- x: number,
29
- y: number,
30
25
  width: number,
31
26
  height: number,
27
+
28
+ options: SdfOptions,
29
+
32
30
  colCount: number,
33
31
  cellSize: number,
34
32
  padCount: number,
@@ -36,6 +34,13 @@ function mainProgram(
36
34
 
37
35
  const { gl } = glContext;
38
36
 
37
+ const {
38
+ x = 0, y = 0, testInteriorExterior = true,
39
+ calcSdfForInside = true, calcSdfForOutside = true,
40
+ customData = [1,0,0,0],
41
+ glslRgbaCalcStr
42
+ } = options;
43
+
39
44
  const vertices: number[] = [];
40
45
  const x0 = 0;
41
46
  const y0 = 0;
@@ -82,7 +87,11 @@ function mainProgram(
82
87
  // Init/update uniforms
83
88
  setUniform_('2f', 'uWidthHeight', width, height);
84
89
  setUniform_('1f', 'uMaxDistance', maxDistance);
85
- setUniform_('1i', 'uIncl', (inclInside ? 1 : 0) + (inclOutside ? 2 : 0));
90
+ setUniform_('1i', 'uTestInOut',
91
+ (calcSdfForInside ? 1 : 0) +
92
+ (calcSdfForOutside ? 2 : 0) +
93
+ (testInteriorExterior ? 4 : 0)
94
+ );
86
95
  setUniform_('4f', 'uCustom', ...customData);
87
96
 
88
97
  setUniformBlock(programMain)('SegIdxRangePerCellBlock', 0, segIdxs_PerCell_Range_Arr);
@@ -154,6 +163,8 @@ function mainProgram(
154
163
 
155
164
  gl.viewport(x, y, width, height);
156
165
 
166
+ gl.colorMask(true, true, true, true);
167
+
157
168
  // draw a square colCount * ROW_COUNT times - 6 vertics
158
169
  gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, colCount*ROW_COUNT);
159
170
 
@@ -4,11 +4,36 @@ import { ROW_COUNT } from "../row-count.js";
4
4
  const cache: { [padCount_times_colCount: number]: string } = {};
5
5
 
6
6
 
7
+ const GLSL_PATTERN1 = `
8
+ float exponent = uCustom.x;
9
+ res = pow(1.0 - res, exponent);
10
+ float alpha = res <= 0.0 ? 0.0 : 0.5;
11
+ float red = inside ? 0.2 : 0.8;
12
+ float green = abs(sin(25.0 * res));
13
+ float blue = 0.5;
14
+ `;
15
+
16
+
17
+ const GLSL_DEFAULT = `
18
+ float exponent = uCustom.x;
19
+ res = (pow(1.0 - res, exponent) * 0.5) * (inside ? -1.0 : 1.0);
20
+ float red = res;
21
+ float green = res;
22
+ float blue = res;
23
+ float alpha = res;
24
+ `;
25
+
26
+
7
27
  function getFragment(
8
28
  colCount: number,
9
- padCount: number): string {
10
-
11
- const fragment = cache[1024*colCount + padCount];
29
+ padCount: number,
30
+ calcFragColorStr: string,
31
+ hash: number): string {
32
+
33
+ // `colCount` and `padCount` can take at most 8 bits and `has` 32 bits and
34
+ // we have at least 53 bits to play with so we're fine
35
+ const key = (2**32)*(256*colCount + padCount) + hash;
36
+ const fragment = cache[key];
12
37
  if (fragment !== undefined) { return fragment; }
13
38
 
14
39
  const main_Fragment =
@@ -20,7 +45,11 @@ uniform float uMaxDistance;
20
45
  uniform highp sampler2D uSegs;
21
46
  uniform highp isampler2D uCloseCellIdxs;
22
47
  uniform highp isampler2D uCrossCellIdxs;
23
- uniform int uIncl; // bit 0 -> incl inside, bit 1 -> incl outside
48
+ // bit 0 -> calc distance inside
49
+ // bit 1 -> calc distance outside
50
+ // bit 2 -> calc whether fragment is inside or outside (else outside is assumed with winds == 0.0)
51
+ uniform int uTestInOut;
52
+ uniform vec4 uCustom;
24
53
 
25
54
  uniform SegIdxRangePerCellBlock {
26
55
  ivec4 uSegIdxRangePerCell[${(ROW_COUNT + 2*padCount)*(colCount + 2*padCount) / 2}];
@@ -35,6 +64,10 @@ flat in ivec2 closeCellIdxRange;
35
64
  flat in ivec2 crossCellIdxRange;
36
65
  out vec4 FragColor;
37
66
 
67
+ // testing!!
68
+ // float rand(vec2 co) {
69
+ // return mod(uCustom.w * fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453), 1.0);
70
+ // }
38
71
 
39
72
  float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
40
73
  vec2 lineDir = lineB - lineA;
@@ -48,72 +81,75 @@ float absDistToSegment(vec2 point, vec2 lineA, vec2 lineB) {
48
81
 
49
82
  void main() {
50
83
  ///////////////////////////////////////////////////////////////////////////
84
+ // Calculate \`winds\`:
85
+ //
51
86
  // Project a ray to the left to check if it crosses the segment in order
52
87
  // to find the fragment's winding number to determine whether fragment
53
88
  // is inside or outside the shape.
89
+ ///////////////////////////////////////////////////////////////////////////
54
90
 
55
- int crossIdxS = crossCellIdxRange.x;
56
- int crossLen = crossCellIdxRange.y;
57
91
  float winds = 0.0;
58
- // Iterate over all relevant cell indexes
59
- for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
60
- int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
92
+ if ((uTestInOut & 4) == 0) {
93
+ int crossIdxS = crossCellIdxRange.x;
94
+ int crossLen = crossCellIdxRange.y;
95
+ // Iterate over all relevant cell indexes
96
+ for (int i = crossIdxS; i < crossIdxS + crossLen; i++) {
97
+ int crossIdx = texelFetch(uCrossCellIdxs, ivec2(i%256, i/256), 0).x;
61
98
 
62
- ivec2 uSegIdxRange = crossIdx % 2 == 0
63
- ? uSegIdxRangePerCell[crossIdx / 2].xy
64
- : uSegIdxRangePerCell[crossIdx / 2].zw;
99
+ ivec2 uSegIdxRange = crossIdx % 2 == 0
100
+ ? uSegIdxRangePerCell[crossIdx / 2].xy
101
+ : uSegIdxRangePerCell[crossIdx / 2].zw;
65
102
 
66
- int segIdx = uSegIdxRange.x;
67
- int segLen = uSegIdxRange.y;
103
+ int segIdx = uSegIdxRange.x;
104
+ int segLen = uSegIdxRange.y;
68
105
 
69
- for (int j = segIdx; j < segIdx + segLen; j++) {
70
- // Fetch segment from texture
71
- vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
106
+ for (int j = segIdx; j < segIdx + segLen; j++) {
107
+ // Fetch segment from texture
108
+ vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
72
109
 
73
- // line segment's min-y is excluded
74
- bool crossing =
75
- (seg.y > vXY.y != seg.w > vXY.y) &&
76
- (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
110
+ // line segment's min-y is excluded
111
+ bool crossing =
112
+ (seg.y > vXY.y != seg.w > vXY.y) &&
113
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
77
114
 
78
- bool crossingUp = seg.y < seg.w;
115
+ bool crossingUp = seg.y < seg.w;
79
116
 
80
- winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
117
+ winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
118
+ }
81
119
  }
82
- }
83
120
 
84
- {
85
- int cellIdx = (instanceId % ${ROW_COUNT});
121
+ {
122
+ int cellIdx = (instanceId % ${ROW_COUNT});
86
123
 
87
- bool isEven = cellIdx % 2 == 0;
124
+ bool isEven = cellIdx % 2 == 0;
88
125
 
89
- ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];
90
- int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
91
- int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
92
-
126
+ ivec4 uSegIdxRange = uSegIdxRangePerStrip[cellIdx / 2];
127
+ int segIdx = isEven ? uSegIdxRange.x : uSegIdxRange.z;
128
+ int segLen = isEven ? uSegIdxRange.y : uSegIdxRange.w;
129
+
93
130
 
94
- for (int j = segIdx; j < segIdx + segLen; j++) {
95
- // Fetch segment from texture
96
- vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
131
+ for (int j = segIdx; j < segIdx + segLen; j++) {
132
+ // Fetch segment from texture
133
+ vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
97
134
 
98
- // line segment's min-y is excluded
99
- bool crossing =
100
- (seg.y > vXY.y != seg.w > vXY.y) &&
101
- (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
135
+ // line segment's min-y is excluded
136
+ bool crossing =
137
+ (seg.y > vXY.y != seg.w > vXY.y) &&
138
+ (vXY.x > (seg.z - seg.x)*(vXY.y - seg.y) / (seg.w - seg.y) + seg.x);
102
139
 
103
- bool crossingUp = seg.y < seg.w;
140
+ bool crossingUp = seg.y < seg.w;
104
141
 
105
- winds += crossing ? (crossingUp ? 1.0 : -1.0) : 0.0;
142
+ winds += crossing ? (crossingUp ? -1.0 : 1.0) : 0.0;
143
+ }
106
144
  }
107
145
  }
108
-
109
-
110
146
  bool inside = winds != 0.0;
111
147
  ///////////////////////////////////////////////////////////////////////////
112
-
148
+ // Calculate \`res\`: the distance to the nearest curve
113
149
  ///////////////////////////////////////////////////////////////////////////
114
150
  float res = 1.0; // sdf result
115
151
 
116
- if ((inside && (uIncl % 2 != 0)) || (!inside && (uIncl > 1))) {
152
+ if ((inside && ((uTestInOut & 1) != 0)) || (!inside && ((uTestInOut & 2) != 0))) {
117
153
  int cellIdxS = closeCellIdxRange.x;
118
154
  int cellLen = closeCellIdxRange.y;
119
155
  // Iterate over all relevant cell indexes
@@ -131,9 +167,8 @@ void main() {
131
167
  // Fetch segment from texture
132
168
  vec4 seg = texelFetch(uSegs, ivec2(j%256, j/256), 0);
133
169
 
134
- // Find unsigned distance to the segment; only the nearest will be kept
170
+ // Find normalized unsigned distance to the segment; only the nearest will be kept
135
171
  float d = absDistToSegment(vXY, seg.xy, seg.zw);
136
- // Apply exponential transform
137
172
  float val = clamp(d / uMaxDistance, 0.0, 1.0);
138
173
 
139
174
  res = min(res, val);
@@ -145,22 +180,16 @@ void main() {
145
180
  // DEBUG!
146
181
  // float alpha = ((instanceId + instanceId/${ROW_COUNT}) % 2 == 0 ? 0.3 : 0.5);
147
182
 
148
-
149
- float exponent = 2;
150
- res = pow(1.0 - val, exponent) * 0.5;
151
-
152
- float alpha = res == 1.0 ? 0.0 : 0.5;
153
- float red = inside ? 0.2 : 0.8;
154
- float green = abs(sin(25.0 * res));
155
- float blue = 0.5;
183
+
184
+ ${GLSL_PATTERN1}
156
185
 
157
186
  FragColor = vec4(red, green, blue, alpha);
158
187
  }
159
188
  `
160
189
 
161
- cache[1024*colCount + padCount] = main_Fragment;
190
+ cache[key] = main_Fragment;
162
191
  return main_Fragment;
163
192
  }
164
193
 
165
-
166
- export { getFragment }
194
+ // ${calcFragColorStr}
195
+ export { getFragment, GLSL_PATTERN1, GLSL_DEFAULT }
@@ -1,6 +1,7 @@
1
1
  import type { Texture } from "../types/texture.js";
2
2
  import type { Program } from "../types/program.js";
3
3
  import type { GlContext } from "../types/gl-context.js";
4
+ import { debugShaders } from "../debug-shaders.js";
4
5
 
5
6
 
6
7
  const cache = new WeakMap<WebGL2RenderingContext, GlContext>();
@@ -21,6 +22,8 @@ function getWebGlContext(
21
22
  if (glContext) { return glContext; }
22
23
  }
23
24
 
25
+ debugShaders(gl);
26
+
24
27
  const programs: { [index:string]: Program } = {};
25
28
  const textures: { [index:string]: Texture } = {};
26
29