p5.asciify
Version:
Apply real-time ASCII conversion to your favorite p5.js sketches instantly.
404 lines (261 loc) • 116 kB
JavaScript
(function(f,h){typeof exports=="object"&&typeof module<"u"?h(exports,require("p5")):typeof define=="function"&&define.amd?define(["exports","p5"],h):(f=typeof globalThis<"u"?globalThis:f||self,h((f.p5=f.p5||{},f.p5.asciify={}),f.p5))})(this,function(f,h){"use strict";var JA=Object.defineProperty;var jA=(f,h,T)=>h in f?JA(f,h,{enumerable:!0,configurable:!0,writable:!0,value:T}):f[h]=T;var o=(f,h,T)=>jA(f,typeof h!="symbol"?h+"":h,T);class T{constructor(A,e,r){o(this,"_cols");o(this,"_rows");o(this,"_width");o(this,"_height");o(this,"_offsetX");o(this,"_offsetY");o(this,"_fixedDimensions",!1);this._texture=A,this._cellWidth=e,this._cellHeight=r,this.reset()}reset(){this._fixedDimensions||([this._cols,this._rows]=[Math.floor(this._texture.width/this._cellWidth),Math.floor(this._texture.height/this._cellHeight)]),this._resizeGrid()}_resizeGrid(){this._width=this._cols*this._cellWidth,this._height=this._rows*this._cellHeight,this._offsetX=Math.floor((this._texture.width-this._width)/2),this._offsetY=Math.floor((this._texture.height-this._height)/2)}resizeCellPixelDimensions(A,e){[this._cellWidth,this._cellHeight]=[A,e],this.reset()}resizeGridDimensions(A,e){this._fixedDimensions=!0,[this._cols,this._rows]=[A,e],this._resizeGrid()}resetGridDimensions(){this._fixedDimensions=!1,this.reset()}updateTexture(A){this._texture=A,this._fixedDimensions?this._resizeGrid():this.reset()}get cellWidth(){return this._cellWidth}get cellHeight(){return this._cellHeight}get cols(){return this._cols}get rows(){return this._rows}get width(){return this._width}get height(){return this._height}get offsetX(){return this._offsetX}get offsetY(){return this._offsetY}get fixedDimensions(){return this._fixedDimensions}set fixedDimensions(A){this._fixedDimensions=A}}const $=g=>{const A=[()=>g==null?void 0:g.VERSION,()=>typeof h<"u"&&h.VERSION?h.VERSION:void 0,()=>{var e;return typeof window<"u"&&((e=window.p5)!=null&&e.VERSION)?window.p5.VERSION:void 0},()=>{var e;return(e=g==null?void 0:g.constructor)==null?void 0:e.VERSION},()=>{var e,r;return(r=(e=Object.getPrototypeOf(g))==null?void 0:e.constructor)==null?void 0:r.VERSION}];for(const e of A)try{const r=e();if(r&&typeof r=="string"&&/^\d+\.\d+/.test(r))return r}catch{continue}return"1.0.0"},R=g=>J(g,"2.0.0")>=0,O=(g,A)=>{var e;return A?!!((e=g==null?void 0:g.constructor)!=null&&e.Color&&A instanceof g.constructor.Color||typeof h<"u"&&h.Color&&A instanceof h.Color):!1},uA=(g,A)=>{var e;return A?!!((e=g==null?void 0:g.constructor)!=null&&e.Font&&A instanceof g.constructor.Font||typeof h<"u"&&h.Font&&A instanceof h.Font):!1},J=(g,A)=>{const[e,r]=[g,A].map(t=>t.split(".").map(Number));for(let t=0;t<Math.max(e.length,r.length);t++){const i=e[t]??0,s=r[t]??0;if(i!==s)return i>s?1:-1}return 0};class tA{constructor(A){o(this,"_p");this._p=A}generateSVG(A,e,r,t,i={}){const s={includeBackgroundRectangles:!0,drawMode:"fill",strokeWidth:1,...i},n=A.characterFramebuffer,E=A.primaryColorFramebuffer,Q=A.secondaryColorFramebuffer,c=A.transformFramebuffer,d=A.rotationFramebuffer;n.loadPixels(),E.loadPixels(),Q.loadPixels(),c.loadPixels(),d.loadPixels();const P=n.pixels,u=E.pixels,l=Q.pixels,p=c.pixels,B=d.pixels,D=e.cols,C=e.rows,w=e.cellWidth,_=e.cellHeight,b=e.width,H=e.height,S=r.characters;let M=this.generateSVGHeader(b,H);if(s.includeBackgroundRectangles){const G=t,x=this._p.color(G),I=`rgba(${x._array[0]*255},${x._array[1]*255},${x._array[2]*255},${x._array[3]})`;M+=`
<rect width="${b}" height="${H}" fill="${I}" />`}M+=`
<g id="ascii-cells">`;let m=0;for(let G=0;G<C;G++)for(let x=0;x<D;x++){const I=m*4,U=P[I],k=P[I+1];let y=U+(k<<8);y>=S.length&&(y=S.length-1);let L={r:u[I],g:u[I+1],b:u[I+2],a:u[I+3]},W={r:l[I],g:l[I+1],b:l[I+2],a:l[I+3]};const EA=p[I],rA=p[I+1],lA=p[I+2],hA=EA===255,yA=rA===255,cA=lA===255;if(hA){const OA=L;L=W,W=OA}const dA=B[I]*(360/256),fA=x*w,$A=G*_;M+=this.generateSVGCellContent(y,L,W,fA,$A,w,_,dA,yA,cA,r,S[y],s),m++}return M+=`
</g>
</svg>`,M}saveSVG(A,e,r,t,i){if(!i.filename){const n=new Date,E=n.toISOString().split("T")[0],Q=n.toTimeString().split(" ")[0].replace(/:/g,"-");i.filename=`asciify_output_${E}_${Q}`}const s=this.generateSVG(A,e,r,t,i);this.downloadSVG(s,i.filename)}generateSVGHeader(A,e){return`<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="${A}" height="${e}" viewBox="0 0 ${A} ${e}"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>ascii art generated via p5.asciify</title>
<desc>ascii art visualization of a p5.js sketch</desc>`}generateSVGCellContent(A,e,r,t,i,s,n,E,Q,c,d,P,u){let l="";if(u.includeBackgroundRectangles&&r.a>0){const _=`rgba(${r.r},${r.g},${r.b},${r.a/255})`;u.drawMode==="stroke"?l+=`
<rect x="${t}" y="${i}" width="${s}" height="${n}" stroke="${_}" fill="none" stroke-width="${u.strokeWidth||1}" />`:l+=`
<rect x="${t}" y="${i}" width="${s}" height="${n}" fill="${_}" />`}const p=t+s/2,B=i+n/2,D=`rgba(${e.r},${e.g},${e.b},${e.a/255})`,C=[];if(Q||c){const _=Q?-1:1,b=c?-1:1;C.push(`translate(${p} ${B})`),C.push(`scale(${_} ${b})`),C.push(`translate(${-p} ${-B})`)}E&&C.push(`rotate(${E} ${p} ${B})`);const w=C.length?` transform="${C.join(" ")}"`:"";if(u.drawMode==="text"){const _=Math.min(s,n)*.8;l+=`
<text x="${p}" y="${B}" font-family="monospace" font-size="${_}px" fill="${D}" text-anchor="middle" dominant-baseline="middle"${w}>${this.escapeXml(P.character)}</text>`}else{let _=1;R($(this._p))?_=d.fontSize/d.font.data.head.unitsPerEm:_=d.fontSize/d.font.font.unitsPerEm;const b=t+(s-P.advanceWidth*_)/2,H=i+(n+d.fontSize*.7)/2,m=P.getPath(b,H,d.fontSize).toSVG().match(/d="([^"]+)"/);if(m&&m[1]){if(w&&(l+=`
<g${w}>`),u.drawMode==="stroke"){const G=u.strokeWidth||1,x=`path-${A}-${t}-${i}`.replace(/\./g,"-");l+=`
<path id="${x}" d="${m[1]}" stroke="${D}" stroke-width="${G}" fill="none" />`}else l+=`
<path d="${m[1]}" fill="${D}" />`;w&&(l+=`
</g>`)}}return l}escapeXml(A){return A.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}downloadSVG(A,e){const r=new Blob([A],{type:"image/svg+xml"}),t=URL.createObjectURL(r),i=document.createElement("a");i.href=t,i.download=`${e}.svg`,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(t)}}class iA{constructor(A){o(this,"p");this.p=A}generateJSON(A,e,r,t={}){const i={includeEmptyCells:!0,prettyPrint:!0,...t},s=A.characterFramebuffer,n=A.primaryColorFramebuffer,E=A.secondaryColorFramebuffer,Q=A.transformFramebuffer,c=A.rotationFramebuffer;s.loadPixels(),n.loadPixels(),E.loadPixels(),Q.loadPixels(),c.loadPixels();const d=s.pixels,P=n.pixels,u=E.pixels,l=Q.pixels,p=c.pixels,B=e.cols,D=e.rows,C=r.characters,w={version:"1.0",created:new Date().toISOString(),gridSize:{cols:B,rows:D,cellWidth:e.cellWidth,cellHeight:e.cellHeight,width:e.width,height:e.height}},_=[];let b=0;for(let S=0;S<D;S++)for(let M=0;M<B;M++){const m=b*4,G=d[m],x=d[m+1];let I=G+(x<<8);I>=C.length&&(I=C.length-1);const U=C[I];if(!i.includeEmptyCells&&(U.character===" "||U.character==="")){b++;continue}let k={r:P[m],g:P[m+1],b:P[m+2],a:P[m+3]},y={r:u[m],g:u[m+1],b:u[m+2],a:u[m+3]};const L=l[m],W=l[m+1],EA=l[m+2],rA=L===255,lA=W===255,hA=EA===255;if(rA){const fA=k;k=y,y=fA}const cA=p[m]*(360/256),FA=this.rgbaToHex(k.r,k.g,k.b,k.a),dA=this.rgbaToHex(y.r,y.g,y.b,y.a);_.push({x:M,y:S,character:U.character,unicode:U.unicode,color:FA,backgroundColor:dA,rotation:cA,inverted:rA,flipHorizontal:lA,flipVertical:hA}),b++}return JSON.stringify({metadata:w,cells:_},null,i.prettyPrint?2:0)}saveJSON(A,e,r,t={}){if(!t.filename){const s=new Date,n=s.toISOString().split("T")[0],E=s.toTimeString().split(" ")[0].replace(/:/g,"-");t.filename=`asciify_output_${n}_${E}`}const i=this.generateJSON(A,e,r,t);this.downloadJSON(i,t.filename)}rgbaToHex(A,e,r,t){const i=s=>{const n=Math.round(s).toString(16);return n.length===1?"0"+n:n};return`#${i(A)}${i(e)}${i(r)}${i(t)}`}downloadJSON(A,e){const r=new Blob([A],{type:"application/json"}),t=URL.createObjectURL(r),i=document.createElement("a");i.href=t,i.download=`${e}.json`,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(t)}}function CA(g,A){const e=g.data.cmap;if(!e||!e.tables)return 0;for(const r of e.tables)if(r.format===4){for(let t=0;t<r.startCount.length;t++)if(A>=r.startCount[t]&&A<=r.endCount[t]){if(r.idRangeOffset[t]===0)return A+r.idDelta[t]&65535;{const i=r.idRangeOffset[t]/2+(A-r.startCount[t])-(r.startCount.length-t);if(i>=0&&i<r.glyphIdArray.length){const s=r.glyphIdArray[i];if(s!==0)return s+r.idDelta[t]&65535}}}}return 0}function K(){return{getBoundingBox:()=>({x1:0,y1:0,x2:0,y2:0}),toSVG:()=>""}}function DA(g,A,e,r,t){if(!A||!A.xs||A.xs.length===0)return K();const i=t/g.data.head.unitsPerEm;return{getBoundingBox:()=>({x1:e+A.xMin*i,y1:r+-A.yMax*i,x2:e+A.xMax*i,y2:r+-A.yMin*i}),toSVG:()=>_A(A,e,r,i)}}function _A(g,A,e,r){if(!g||!g.xs)return"";const{xs:t,ys:i,endPts:s,flags:n}=g;if(!t||!i||!s||!n)return"";let E="",Q=0;for(let c=0;c<s.length;c++){const d=s[c];if(!(d<Q)){if(d>=Q){const P=A+t[Q]*r,u=e-i[Q]*r;E+=`M${P.toFixed(2)},${u.toFixed(2)}`;let l=Q+1;for(;l<=d;)if((n[l]&1)!==0){const B=A+t[l]*r,D=e-i[l]*r;E+=`L${B.toFixed(2)},${D.toFixed(2)}`,l++}else{const B=A+t[l]*r,D=e-i[l]*r;let C=l+1>d?Q:l+1;if((n[C]&1)!==0){const _=A+t[C]*r,b=e-i[C]*r;E+=`Q${B.toFixed(2)},${D.toFixed(2)} ${_.toFixed(2)},${b.toFixed(2)}`,l=C+1}else{const _=A+t[C]*r,b=e-i[C]*r,H=(B+_)/2,S=(D+b)/2;E+=`Q${B.toFixed(2)},${D.toFixed(2)} ${H.toFixed(2)},${S.toFixed(2)}`,l=C}}E+="Z"}Q=d+1}}return`<path d="${E}" />`}const SA=Object.freeze(Object.defineProperty({__proto__:null,P5AsciifyJSONExporter:iA,P5AsciifySVGExporter:tA,compareVersions:J,createEmptyPath:K,createGlyphPath:DA,detectP5Version:$,getGlyphIndex:CA,glyphToSVGPath:_A,isP5AsyncCapable:R,isValidP5Color:O,isValidP5Font:uA},Symbol.toStringTag,{value:"Module"}));class Y extends Error{constructor(e,r){super(e);o(this,"originalError");this.name="P5AsciifyError",this.originalError=r}}var sA=(g=>(g[g.SILENT=0]="SILENT",g[g.WARNING=1]="WARNING",g[g.ERROR=2]="ERROR",g[g.THROW=3]="THROW",g))(sA||{});const z=class z{constructor(){o(this,"_options",{globalLevel:3,consolePrefix:"[p5.asciify]"})}static getInstance(){return z._instance||(z._instance=new z),z._instance}_handle(A,e,r){switch(this._options.globalLevel,this._options.globalLevel){case 0:return!1;case 1:return console.warn(`${this._options.consolePrefix} ${A}`,e),!1;case 2:return console.error(`${this._options.consolePrefix} ${A}`,e),!1;case 3:default:throw new Y(A,r)}}validate(A,e,r){return A?!0:(this._handle(e,r),!1)}setGlobalLevel(A){this._options.globalLevel=A}};o(z,"_instance",null);let X=z;const a=X.getInstance(),MA=Object.freeze(Object.defineProperty({__proto__:null,P5AsciifyError:Y,P5AsciifyErrorHandler:X,P5AsciifyErrorLevel:sA,errorHandler:a},Symbol.toStringTag,{value:"Module"}));class mA{constructor(A,e){o(this,"_characters",[]);o(this,"_maxGlyphDimensions");o(this,"_texture");o(this,"_textureColumns");o(this,"_textureRows");o(this,"_fontSize",16);this._p=A,this._font=e,this._initializeGlyphsAndCharacters()}async setup(A){return this._fontSize=A,this.reset()}_initializeGlyphsAndCharacters(){if(R($(this._p))){const A=[],e=new Map;this._font.data.cmap.tables.forEach(t=>{if(t.format===4)for(let i=0;i<t.startCount.length;i++){const s=t.startCount[i],n=t.endCount[i];if(!(s===65535&&n===65535))for(let E=s;E<=n;E++){const Q=String.fromCodePoint(E),c=CA(this._font,E);c&&c>0&&(A.push(Q),e.set(Q,c))}}});const r=[...new Set(A)];this._characters=r.map((t,i)=>{const s=t.codePointAt(0),n=e.get(t);let E=0;n!==void 0&&this._font.data.hmtx&&this._font.data.hmtx.aWidth&&(E=this._font.data.hmtx.aWidth[n]);const Q=i%256,c=Math.floor(i/256)%256,d=Math.floor(i/65536);return{character:t,unicode:s,getPath:(P,u,l)=>{if(n===void 0)return K();const p=this._font.data.glyf[n];return p?DA(this._font,p,P,u,l):K()},advanceWidth:E,r:Q,g:c,b:d}})}else{const A=Object.values(this._font.font.glyphs.glyphs);this._characters=[],A.forEach((e,r)=>{if(!e.unicode&&(!e.unicodes||!e.unicodes.length))return;const t=this._characters.length,i=t%256,s=Math.floor(t/256)%256,n=Math.floor(t/65536),E=e.unicode??e.unicodes[0];this._characters.push({character:String.fromCodePoint(E),unicode:E,getPath:(Q,c,d)=>e.getPath(Q,c,d),advanceWidth:e.advanceWidth,r:i,g:s,b:n})})}}loadFont(A){a.validate(uA(this._p,A),"Invalid font parameter. Expected a p5.Font object.",{providedValue:A,method:"loadFont"})&&(this._font=A,this._initializeGlyphsAndCharacters())}glyphColor(A){if(!a.validate(typeof A=="string"&&A.length>0,"Character must be a non-empty string.",{providedValue:A,method:"glyphColor"}))return[0,0,0];const r=this._characters.find(i=>i.character===A);return a.validate(r!==void 0,(()=>{const i=A.codePointAt(0),s=i?i.toString(16).padStart(4,"0"):"unknown";return`Could not find character in character set: ${A} (U+${s})`})(),{providedValue:A,method:"glyphColor"})?[r.r,r.g,r.b]:[0,0,0]}glyphColors(A=""){if(!a.validate(typeof A=="string"||Array.isArray(A),"Characters must be a string or array of strings.",{providedValue:A,method:"glyphColors"}))return[[0,0,0]];const r=[];for(const t of Array.from(A)){const i=this.glyphColor(t);r.push(i)}return r}_getMaxGlyphDimensions(A){this._p.textFont(this._font),this._p.textSize(A);let e=0,r=0;for(const t of this._characters){const i=this._font.textBounds(t.character,0,0,A),s=i.h,n=i.w;e=Math.max(e,n),r=Math.max(r,s)}return{width:Math.ceil(e),height:Math.ceil(r)}}async reset(){return this._maxGlyphDimensions=this._getMaxGlyphDimensions(this._fontSize),this._createTexture(this._fontSize)}async setFontSize(A){return this._fontSize=A,this._maxGlyphDimensions=this._getMaxGlyphDimensions(this._fontSize),this._createTexture(this._fontSize)}async _createTexture(A){this._textureColumns=Math.ceil(Math.sqrt(this.characters.length)),this._textureRows=Math.ceil(this.characters.length/this._textureColumns),this._texture?this._texture.resize(this._maxGlyphDimensions.width*this._textureColumns,this._maxGlyphDimensions.height*this._textureRows):this._texture=this._p.createFramebuffer({width:this._maxGlyphDimensions.width*this._textureColumns,height:this._maxGlyphDimensions.height*this._textureRows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this._texture.begin(),this._p.clear(),this._p.textFont(this._font),this._p.fill(255),this._p.textSize(A),this._p.textAlign(this._p.LEFT,this._p.TOP),this._p.noStroke();for(let e=0;e<this._characters.length;e++){const r=e%this._textureColumns,t=Math.floor(e/this._textureColumns),i=this._maxGlyphDimensions.width*r-this._maxGlyphDimensions.width*this._textureColumns/2,s=this._maxGlyphDimensions.height*t-this._maxGlyphDimensions.height*this._textureRows/2;this._p.text(this._characters[e].character,i,s)}this._texture.end()}get maxGlyphDimensions(){return this._maxGlyphDimensions}get texture(){return this._texture}get textureColumns(){return this._textureColumns}get textureRows(){return this._textureRows}get fontSize(){return this._fontSize}get font(){return this._font}get characters(){return this._characters}get charactersString(){return this._characters.map(A=>A.character).join("")}}class oA{constructor(A,e,r,t,i,s){o(this,"_primaryColorFramebuffer");o(this,"_secondaryColorFramebuffer");o(this,"_characterFramebuffer");o(this,"_transformFramebuffer");o(this,"_rotationFramebuffer");this._p=A,this._captureFramebuffer=e,this._grid=r,this.initialFramebufferDimensions=t,this._fontManager=i,this._options=s;const n={density:1,antialias:!1,width:t.width,height:t.height,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST};this._primaryColorFramebuffer=this._p.createFramebuffer(n),this._secondaryColorFramebuffer=this._p.createFramebuffer(n),this._transformFramebuffer=this._p.createFramebuffer(n),this._characterFramebuffer=this._p.createFramebuffer(n),this._rotationFramebuffer=this._p.createFramebuffer(n)}update(A){(A==null?void 0:A.enabled)!==void 0&&this.enabled(A.enabled)}setCaptureTexture(A){this._captureFramebuffer=A,this.resizeFramebuffers(),this.resetShaders()}enabled(A){if(A===void 0)return this._options.enabled;if(!a.validate(typeof A=="boolean","Enabled must be a boolean.",{providedValue:A,method:"enabled"}))return this._options.enabled;if(this._options.enabled=A,!A){const r=[this._primaryColorFramebuffer,this._secondaryColorFramebuffer,this._transformFramebuffer,this._rotationFramebuffer,this._characterFramebuffer];for(const t of r)t.draw(()=>{this._p.clear()})}return this._options.enabled}enable(){return this.enabled(!0)}disable(){return this.enabled(!1)}get options(){return this._options}get primaryColorFramebuffer(){return this._primaryColorFramebuffer}get secondaryColorFramebuffer(){return this._secondaryColorFramebuffer}get transformFramebuffer(){return this._transformFramebuffer}get rotationFramebuffer(){return this._rotationFramebuffer}get characterFramebuffer(){return this._characterFramebuffer}}const nA={enabled:!1};class j extends oA{constructor(A,e,r,t,i=nA){super(A,e,r,{width:r.cols,height:r.rows},t,{...nA,...i})}resetShaders(){}resizeFramebuffers(){this._primaryColorFramebuffer.resize(this._grid.cols,this._grid.rows),this._secondaryColorFramebuffer.resize(this._grid.cols,this._grid.rows),this._transformFramebuffer.resize(this._grid.cols,this._grid.rows),this._rotationFramebuffer.resize(this._grid.cols,this._grid.rows),this._characterFramebuffer.resize(this._grid.cols,this._grid.rows)}}class PA{constructor(A,e){o(this,"_framebuffer");this._p=A,this._colors=e;const r=Math.max(this._colors.length,1);this._framebuffer=this._p.createFramebuffer({density:1,width:r,height:1,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this._updateFramebuffer()}_updateFramebuffer(){if(!this._framebuffer||!this._p)return;const A=Math.max(this._colors.length,1);this._framebuffer.resize(A,1),this._framebuffer.loadPixels();for(let r=0;r<A;r++){const t=r<this._colors.length?this._p.color(this._colors[r]):this._p.color(0,0,0,0),i=4*r;this._framebuffer.pixels[i]=this._p.red(t),this._framebuffer.pixels[i+1]=this._p.green(t),this._framebuffer.pixels[i+2]=this._p.blue(t),this._framebuffer.pixels[i+3]=this._p.alpha(t)}this._framebuffer.updatePixels()}setColors(A){this._colors=A,this._updateFramebuffer()}get colors(){return this._colors}get framebuffer(){return this._framebuffer}}class N extends j{constructor(e,r,t,i,s){super(e,r,t,i,s);o(this,"_characterColorPalette");this._characterColorPalette=new PA(this._p,this._fontManager.glyphColors(this._options.characters)),this.update(this._options)}characters(e){!a.validate(typeof e=="string","Characters must be a string.",{providedValue:e,method:"characters"})||e===this._options.characters||(this._characterColorPalette.setColors(this._fontManager.glyphColors(e)),this.resetShaders(),this._options.characters=e)}invert(e){a.validate(typeof e=="boolean","Invert mode must be a boolean.",{providedValue:e,method:"invert"})&&(this._options.invertMode=e)}rotation(e){if(!a.validate(typeof e=="number","Rotation angle must be a number.",{providedValue:e,method:"rotation"}))return;e=e%360,e<0&&(e+=360);const t=e/360,i=Math.round(t*255);this._options.rotationAngle=this._p.color(i,0,0)}characterColor(e){a.validate(O(this._p,e),"Character color must be a valid p5.Color object.",{providedValue:e,method:"characterColor"})&&(this._options.characterColor=e)}flipHorizontally(e){a.validate(typeof e=="boolean","Flip horizontally must be a boolean.",{providedValue:e,method:"flipHorizontally"})&&(this._options.flipHorizontally=e)}flipVertically(e){a.validate(typeof e=="boolean","Flip vertically must be a boolean.",{providedValue:e,method:"flipVertically"})&&(this._options.flipVertically=e)}backgroundColor(e){a.validate(O(this._p,e),"Background color must be a valid p5.Color object.",{providedValue:e,method:"backgroundColor"})&&(this._options.backgroundColor=e)}characterColorMode(e){const r=a.validate(typeof e=="string","Character color mode must be a string.",{providedValue:e,method:"characterColorMode"}),t=a.validate(e==="sampled"||e==="fixed","Character color mode must be either 'sampled' or 'fixed'.",{providedValue:e,method:"characterColorMode"});!r||!t||(e==="sampled"?this._options.characterColorMode=0:e==="fixed"&&(this._options.characterColorMode=1))}backgroundColorMode(e){const r=a.validate(typeof e=="string","Background color mode must be a string.",{providedValue:e,method:"backgroundColorMode"}),t=a.validate(e==="sampled"||e==="fixed","Background color mode must be either 'sampled' or 'fixed'.",{providedValue:e,method:"backgroundColorMode"});!r||!t||(e==="sampled"?this._options.backgroundColorMode=0:e==="fixed"&&(this._options.backgroundColorMode=1))}update(e){super.update(e),(e==null?void 0:e.enabled)!==void 0&&this.enabled(e.enabled),(e==null?void 0:e.characterColor)!==void 0&&(e.characterColor=this._p.color(e.characterColor),this.characterColor(e.characterColor)),(e==null?void 0:e.backgroundColor)!==void 0&&(e.backgroundColor=this._p.color(e.backgroundColor),this.backgroundColor(e.backgroundColor)),(e==null?void 0:e.characters)!==void 0&&this.characters(e.characters),(e==null?void 0:e.invertMode)!==void 0&&this.invert(e.invertMode),(e==null?void 0:e.rotationAngle)!==void 0&&this.rotation(e.rotationAngle),(e==null?void 0:e.characterColorMode)!==void 0&&this.characterColorMode(e.characterColorMode),(e==null?void 0:e.backgroundColorMode)!==void 0&&this.backgroundColorMode(e.backgroundColorMode),(e==null?void 0:e.flipHorizontally)!==void 0&&this.flipHorizontally(e.flipHorizontally),(e==null?void 0:e.flipVertically)!==void 0&&this.flipVertically(e.flipVertically)}get characterColorPalette(){return this._characterColorPalette}}var F=`precision mediump float;
attribute vec3 aPosition;\r
attribute vec2 aTexCoord;
varying vec2 v_texCoord;
void main() {\r
vec4 positionVec4 = vec4(aPosition, 1.0);
positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
gl_Position = positionVec4;
v_texCoord = aTexCoord;\r
}`,GA=`precision mediump float;
uniform sampler2D u_sketchTexture;
uniform vec2 u_gridCellDimensions;
void main() {\r
vec2 cellCoord = floor(gl_FragCoord.xy);
vec2 cellSizeInTexCoords = 1.0 / u_gridCellDimensions;
vec2 cellCenterTexCoord = (cellCoord + vec2(0.5)) * cellSizeInTexCoords;
vec4 finalColor;
finalColor = texture2D(u_sketchTexture, cellCenterTexCoord);
gl_FragColor = finalColor;\r
}`,VA=`precision mediump float;
uniform sampler2D u_colorSampleFramebuffer;\r
uniform sampler2D u_charPaletteTexture;\r
uniform vec2 u_charPaletteSize;\r
uniform vec2 u_textureSize;\r
uniform ivec2 u_brightnessRange;
void main() {\r
vec2 pos = (floor(gl_FragCoord.xy) + 0.5) / u_textureSize;\r
\r
vec4 inputColor = texture2D(u_colorSampleFramebuffer, pos);\r
\r
if (inputColor.a == 0.0) {\r
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\r
return;\r
}\r
\r
float brightness = dot(inputColor.rgb, vec3(0.299, 0.587, 0.114));\r
\r
float brightness255 = brightness * 255.0;\r
\r
if (brightness255 < float(u_brightnessRange.x) || brightness255 > float(u_brightnessRange.y)) {\r
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\r
return;\r
}\r
\r
float normalizedBrightness = (brightness255 - float(u_brightnessRange.x)) / \r
(float(u_brightnessRange.y) - float(u_brightnessRange.x));\r
\r
float index = clamp(floor(normalizedBrightness * u_charPaletteSize.x), 0.0, u_charPaletteSize.x - 1.0);\r
\r
vec3 charColor = texture2D(u_charPaletteTexture, vec2((index + 0.5) / u_charPaletteSize.x, 0.0)).rgb;\r
gl_FragColor = vec4(charColor, inputColor.a);\r
}`;const aA={enabled:!0,characters:" .:-=+*%@#",characterColor:"#FFFFFF",characterColorMode:"sampled",backgroundColor:"#000000",backgroundColorMode:"fixed",invertMode:!1,rotationAngle:0,flipHorizontally:!1,flipVertically:!1,brightnessRange:[0,255]};class gA extends N{constructor(e,r,t,i,s=aA){super(e,r,t,i,{...aA,...s});o(this,"colorSampleShader");o(this,"asciiCharacterShader");o(this,"colorSampleFramebuffer");this.colorSampleShader=this._p.createShader(F,GA),this.asciiCharacterShader=this._p.createShader(F,VA),this.colorSampleFramebuffer=this._p.createFramebuffer({density:1,width:this._grid.cols,height:this._grid.rows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST})}resetShaders(){}resizeFramebuffers(){super.resizeFramebuffers(),this.colorSampleFramebuffer.resize(this._grid.cols,this._grid.rows)}update(e){super.update(e),e.brightnessRange!==void 0&&this.brightnessRange(e.brightnessRange)}brightnessRange(e){if(!a.validate(Array.isArray(e)&&e.length===2&&typeof e[0]=="number"&&typeof e[1]=="number"&&!isNaN(e[0])&&!isNaN(e[1]),"Brightness range must be an array with exactly two numbers.",{providedValue:e,method:"brightnessRange"}))return;const[t,i]=e,s=a.validate(t>=0&&t<=255&&i>=0&&i<=255,"Brightness values must be between 0 and 255.",{providedValue:e,method:"brightnessRange"}),n=a.validate(t<=i,"Start value must be less than or equal to the end value.",{providedValue:e,method:"brightnessRange"});!s||!n||(this._options.brightnessRange=[t,i])}render(){this.colorSampleFramebuffer.begin(),this._p.clear(),this._p.shader(this.colorSampleShader),this.colorSampleShader.setUniform("u_sketchTexture",this._captureFramebuffer),this.colorSampleShader.setUniform("u_gridCellDimensions",[this._grid.cols,this._grid.rows]),this._p.rect(0,0,this.colorSampleFramebuffer.width,this.colorSampleFramebuffer.height),this.colorSampleFramebuffer.end(),this._primaryColorFramebuffer.begin(),this._options.characterColorMode===1?this._p.background(this._options.characterColor):(this._p.clear(),this._p.image(this.colorSampleFramebuffer,-this._grid.cols/2,-this._grid.rows/2,this._grid.cols,this._grid.rows)),this._primaryColorFramebuffer.end(),this._secondaryColorFramebuffer.begin(),this._options.backgroundColorMode===1?this._p.background(this._options.backgroundColor):(this._p.clear(),this._p.image(this.colorSampleFramebuffer,-this._grid.cols/2,-this._grid.rows/2,this._grid.cols,this._grid.rows)),this._secondaryColorFramebuffer.end(),this._transformFramebuffer.begin(),this._p.background(this._options.invertMode?255:0,this._options.flipHorizontally?255:0,this._options.flipVertically?255:0),this._transformFramebuffer.end(),this._rotationFramebuffer.begin(),this._p.background(this._options.rotationAngle),this._rotationFramebuffer.end(),this._characterFramebuffer.begin(),this._p.clear(),this._p.shader(this.asciiCharacterShader),this.asciiCharacterShader.setUniform("u_textureSize",[this._grid.cols,this._grid.rows]),this.asciiCharacterShader.setUniform("u_colorSampleFramebuffer",this.colorSampleFramebuffer),this.asciiCharacterShader.setUniform("u_charPaletteTexture",this._characterColorPalette.framebuffer),this.asciiCharacterShader.setUniform("u_charPaletteSize",[this._characterColorPalette.colors.length,1]),this.asciiCharacterShader.setUniform("u_brightnessRange",this._options.brightnessRange),this._p.rect(0,0,this._characterFramebuffer.width,this._characterFramebuffer.height),this._characterFramebuffer.end()}}var kA=`precision mediump float;
uniform sampler2D u_sketchTexture;\r
uniform sampler2D u_sampleTexture;
uniform vec2 u_gridCellDimensions;
uniform int u_sampleMode;
uniform vec4 u_staticColor;
void main() {\r
vec2 cellCoord = floor(gl_FragCoord.xy);
vec2 cellSizeInTexCoords = 1.0 / u_gridCellDimensions;
vec2 cellCenterTexCoord = (cellCoord + vec2(0.5)) * cellSizeInTexCoords;
vec4 finalColor;
vec4 sampleColor = texture2D(u_sampleTexture, cellCenterTexCoord);
if(sampleColor != vec4(0.0, 0.0, 0.0, 0.0)) {\r
if(u_sampleMode == 0) {\r
finalColor = texture2D(u_sketchTexture, cellCenterTexCoord);\r
} else {\r
finalColor = u_staticColor;\r
}\r
}
gl_FragColor = finalColor;\r
}`,TA=`precision mediump float;
uniform sampler2D u_sampleTexture;\r
uniform vec2 u_gridCellDimensions;\r
uniform bool u_invert;\r
uniform bool u_flipH;\r
uniform bool u_flipV;\r
uniform vec3 u_compareColor;
void main() {\r
vec2 cellCoord = floor(gl_FragCoord.xy);
vec2 cellSizeInTexCoords = vec2(1.0) / u_gridCellDimensions;
vec2 cellCenterTexCoord = (cellCoord + vec2(0.5)) * cellSizeInTexCoords;
bool shouldInvert;
shouldInvert = texture2D(u_sampleTexture, cellCenterTexCoord).rgb != u_compareColor;
if(shouldInvert) {\r
float r = u_invert ? 1.0 : 0.0;\r
float g = u_flipH ? 1.0 : 0.0;\r
float b = u_flipV ? 1.0 : 0.0;\r
\r
gl_FragColor = vec4(r, g, b, 1.0);\r
} else {\r
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\r
}\r
}`,RA=`precision mediump float;
uniform sampler2D u_sampleTexture;\r
uniform vec2 u_gridCellDimensions;\r
uniform vec3 u_rotationColor;\r
uniform vec3 u_compareColor;
void main() {\r
vec2 cellCoord = floor(gl_FragCoord.xy);
vec2 cellSizeInTexCoords = vec2(1.0) / u_gridCellDimensions;
vec2 cellCenterTexCoord = (cellCoord + vec2(0.5)) * cellSizeInTexCoords;
bool shouldRotate;
shouldRotate = texture2D(u_sampleTexture, cellCenterTexCoord).rgb != u_compareColor;
if(shouldRotate) {\r
gl_FragColor = vec4(u_rotationColor, 1.0);\r
} else {\r
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\r
}\r
}`,YA=`precision mediump float;
uniform sampler2D u_sketchTexture;\r
uniform vec2 u_gridCellDimensions;
void main() {\r
vec2 cellCoord = floor(gl_FragCoord.xy);\r
\r
vec2 cellSizeInTexCoords = vec2(1.0) / u_gridCellDimensions;\r
\r
vec2 cellCenterTexCoord = (cellCoord + vec2(0.5)) * cellSizeInTexCoords;\r
\r
gl_FragColor = texture2D(u_sketchTexture, cellCenterTexCoord);\r
}`,NA=`precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D u_texture;\r
uniform vec2 u_textureSize;\r
uniform float u_threshold;
uniform sampler2D u_colorPaletteTexture;
void main() {\r
vec2 texelSize = 1.0 / u_textureSize;
float kernelX[9];\r
float kernelY[9];
kernelX[0] = -1.0; kernelX[1] = 0.0; kernelX[2] = 1.0;\r
kernelX[3] = -2.0; kernelX[4] = 0.0; kernelX[5] = 2.0;\r
kernelX[6] = -1.0; kernelX[7] = 0.0; kernelX[8] = 1.0;
kernelY[0] = -1.0; kernelY[1] = -2.0; kernelY[2] = -1.0;\r
kernelY[3] = 0.0; kernelY[4] = 0.0; kernelY[5] = 0.0;\r
kernelY[6] = 1.0; kernelY[7] = 2.0; kernelY[8] = 1.0;
vec3 texColor[9];\r
for(int i = 0; i < 3; i++) {\r
for(int j = 0; j < 3; j++) {\r
texColor[i * 3 + j] = texture2D(u_texture, v_texCoord + vec2(float(i - 1), float(j - 1)) * texelSize).rgb;\r
}\r
}
vec3 sobelX = vec3(0.0);\r
vec3 sobelY = vec3(0.0);\r
for(int i = 0; i < 9; i++) {\r
sobelX += kernelX[i] * texColor[i];\r
sobelY += kernelY[i] * texColor[i];\r
}
vec3 sobel = sqrt(sobelX * sobelX + sobelY * sobelY);\r
float intensity = length(sobel) / sqrt(3.0);\r
\r
vec4 edgeColor = vec4(0.0);\r
\r
if(intensity > u_threshold) {\r
float angleDeg = degrees(atan(sobelY.r, sobelX.r));\r
\r
int charIndex = 0;\r
\r
if(angleDeg >= -22.5 && angleDeg < 22.5) charIndex = 0;\r
else if(angleDeg >= 22.5 && angleDeg < 67.5) charIndex = 1;\r
else if(angleDeg >= 67.5 && angleDeg < 112.5) charIndex = 2;\r
else if(angleDeg >= 112.5 && angleDeg < 157.5) charIndex = 3;\r
else if(angleDeg >= 157.5 || angleDeg < -157.5) charIndex = 4;\r
else if(angleDeg >= -157.5 && angleDeg < -112.5) charIndex = 5;\r
else if(angleDeg >= -112.5 && angleDeg < -67.5) charIndex = 6;\r
else if(angleDeg >= -67.5 && angleDeg < -22.5) charIndex = 7;\r
\r
float paletteCoord = (float(charIndex) + 0.5) / 8.0;\r
edgeColor = texture2D(u_colorPaletteTexture, vec2(paletteCoord, 0.5));\r
}
gl_FragColor = edgeColor;\r
}`;const pA=(g,A,e)=>`
precision mediump float;uniform sampler2D u_image;uniform vec2 u_imageSize,u_gridCellDimensions;uniform int u_threshold;const vec3 i=vec3(0);vec3 f[${g}];int u[${g}];float r(float i){return floor(i+.5);}void main(){vec2 v=floor(gl_FragCoord.xy);ivec2 b=ivec2(v);v=u_imageSize/u_gridCellDimensions;b=ivec2(r(float(b.x)*v.x),r(float(b.y)*v.y));int m=0;for(int b=0;b<${g};b++)f[b]=i,u[b]=0;for(int v=0;v<${e};v++)for(int r=0;r<${A};r++){ivec2 y=b+ivec2(r,v);if(y.x<0||y.y<0||y.x>=int(u_imageSize.x)||y.y>=int(u_imageSize.y))continue;vec3 e=texture2D(u_image,(vec2(y)+.5)/u_imageSize).xyz;if(length(e-i)<.001)continue;m++;bool x=false;for(int b=0;b<${g};b++)if(length(e-f[b])<.001){u[b]++;x=true;break;}if(!x)for(int b=0;b<${g};b++)if(u[b]==0){f[b]=e;u[b]=1;break;}}vec3 e=i;int x=0;for(int b=0;b<${g};b++)if(u[b]>x)e=f[b],x=u[b];gl_FragColor=m<u_threshold?vec4(i,0):vec4(e,1);}
`,BA={enabled:!1,characters:"-/|\\-/|\\",characterColor:"#FFFFFF",characterColorMode:"sampled",backgroundColor:"#000000",backgroundColorMode:"fixed",invertMode:!1,sobelThreshold:.5,sampleThreshold:16,rotationAngle:0,flipHorizontally:!1,flipVertically:!1};class QA extends N{constructor(e,r,t,i,s=BA){super(e,r,t,i,{...BA,...s});o(this,"sobelShader");o(this,"sampleShader");o(this,"colorSampleShader");o(this,"transformShader");o(this,"rotationShader");o(this,"asciiCharacterShader");o(this,"sobelFramebuffer");o(this,"sampleFramebuffer");this.sobelShader=this._p.createShader(F,NA),this.sampleShader=this._p.createShader(F,pA(16,this._grid.cellHeight,this._grid.cellWidth)),this.colorSampleShader=this._p.createShader(F,kA),this.transformShader=this._p.createShader(F,TA),this.rotationShader=this._p.createShader(F,RA),this.asciiCharacterShader=this._p.createShader(F,YA),this.sobelFramebuffer=this._p.createFramebuffer({density:1,width:this._captureFramebuffer.width,height:this._captureFramebuffer.height,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this.sampleFramebuffer=this._p.createFramebuffer({density:1,width:this._grid.cols,height:this._grid.rows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST})}resizeFramebuffers(){super.resizeFramebuffers(),this.sampleFramebuffer.resize(this._grid.cols,this._grid.rows),this.sobelFramebuffer.resize(this._captureFramebuffer.width,this._captureFramebuffer.height)}resetShaders(){this.sampleShader=this._p.createShader(F,pA(16,this._grid.cellHeight,this._grid.cellWidth))}sobelThreshold(e){const r=a.validate(typeof e=="number"&&!Number.isNaN(e)&&Number.isFinite(e),"Sobel threshold must be a valid number",{providedValue:e,method:"sobelThreshold"}),t=a.validate(e>=0&&e<=1,"Sobel threshold must be between 0 and 1",{providedValue:e,method:"sobelThreshold"});!r||!t||(this._options.sobelThreshold=e)}sampleThreshold(e){const r=a.validate(typeof e=="number"&&!Number.isNaN(e)&&Number.isFinite(e),"Sample threshold must be a valid number",{providedValue:e,method:"sampleThreshold"}),t=a.validate(e>=0,"Sample threshold must be greater than or equal to 0",{providedValue:e,method:"sampleThreshold"});!r||!t||(this._options.sampleThreshold=e)}update(e){super.update(e),e.sobelThreshold!==void 0&&this.sobelThreshold(e.sobelThreshold),e.sampleThreshold!==void 0&&this.sampleThreshold(e.sampleThreshold)}render(){this.sobelFramebuffer.begin(),this._p.clear(),this._p.shader(this.sobelShader),this.sobelShader.setUniform("u_texture",this._captureFramebuffer),this.sobelShader.setUniform("u_textureSize",[this._captureFramebuffer.width,this._captureFramebuffer.height]),this.sobelShader.setUniform("u_threshold",this._options.sobelThreshold),this.sobelShader.setUniform("u_colorPaletteTexture",this._characterColorPalette.framebuffer),this.sobelShader.setUniform("u_totalChars",this._options.characters.length),this._p.rect(0,0,this.sobelFramebuffer.width,this.sobelFramebuffer.height),this.sobelFramebuffer.end(),this.sampleFramebuffer.begin(),this._p.clear(),this._p.shader(this.sampleShader),this.sampleShader.setUniform("u_imageSize",[this._captureFramebuffer.width,this._captureFramebuffer.height]),this.sampleShader.setUniform("u_image",this.sobelFramebuffer),this.sampleShader.setUniform("u_gridCellDimensions",[this._grid.cols,this._grid.rows]),this.sampleShader.setUniform("u_threshold",this._options.sampleThreshold),this._p.rect(0,0,this.sampleFramebuffer.width,this.sampleFramebuffer.height),this.sampleFramebuffer.end(),this._primaryColorFramebuffer.begin(),this._p.clear(),this._p.shader(this.colorSampleShader),this.colorSampleShader.setUniform("u_sketchTexture",this._captureFramebuffer),this.colorSampleShader.setUniform("u_sampleTexture",this.sampleFramebuffer),this.colorSampleShader.setUniform("u_gridCellDimensions",[this._grid.cols,this._grid.rows]),this.colorSampleShader.setUniform("u_sampleMode",this._options.characterColorMode),this.colorSampleShader.setUniform("u_staticColor",this._options.characterColor._array),this._p.rect(0,0,this._primaryColorFramebuffer.width,this._primaryColorFramebuffer.height),this._primaryColorFramebuffer.end(),this._secondaryColorFramebuffer.begin(),this._p.clear(),this._p.shader(this.colorSampleShader),this.colorSampleShader.setUniform("u_sketchTexture",this._captureFramebuffer),this.colorSampleShader.setUniform("u_sampleTexture",this.sampleFramebuffer),this.colorSampleShader.setUniform("u_gridCellDimensions",[this._grid.cols,this._grid.rows]),this.colorSampleShader.setUniform("u_sampleMode",this._options.backgroundColorMode),this.colorSampleShader.setUniform("u_staticColor",this._options.backgroundColor._array),this._p.rect(0,0,this._secondaryColorFramebuffer.width,this._secondaryColorFramebuffer.height),this._secondaryColorFramebuffer.end(),this._transformFramebuffer.begin(),this._p.clear(),this._p.shader(this.transformShader),this.transformShader.setUniform("u_invert",this._options.invertMode),this.transformShader.setUniform("u_flipH",this._options.flipHorizontally),this.transformShader.setUniform("u_flipV",this._options.flipVertically),this.transformShader.setUniform("u_sampleTexture",this.sampleFramebuffer),this.transformShader.setUniform("u_compareColor",[0,0,0]),this.transformShader.setUniform("u_gridCellDimensions",[this._grid.cols,this._grid.rows]),this._p.rect(0,0,this._transformFramebuffer.width,this._transformFramebuffer.height),this._transformFramebuffer.end(),this._rotationFramebuffer.begin(),this._p.clear(),this._p.shader(this.rotationShader),this.rotationShader.setUniform("u_rotationColor",this._options.rotationAngle._array),this.rotationShader.setUniform("u_sampleTexture",this.sampleFramebuffer),this.rotationShader.setUniform("u_compareColor",[0,0,0]),this.rotationShader.setUniform("u_gridCellDimensions",[this._grid.cols,this._grid.rows]),this._p.rect(0,0,this._rotationFramebuffer.width,this._rotationFramebuffer.height),this._rotationFramebuffer.end(),this._characterFramebuffer.begin(),this._p.clear(),this._p.shader(this.asciiCharacterShader),this.asciiCharacterShader.setUniform("u_sketchTexture",this.sampleFramebuffer),this.asciiCharacterShader.setUniform("u_gridCellDimensions",[this._grid.cols,this._grid.rows]),this._p.rect(0,0,this._characterFramebuffer.width,this._characterFramebuffer.height),this._characterFramebuffer.end()}}var zA=`precision mediump float;
uniform sampler2D u_characterTexture;\r
uniform vec2 u_charsetDimensions;
uniform sampler2D u_primaryColorTexture;\r
uniform sampler2D u_secondaryColorTexture;\r
uniform sampler2D u_transformTexture;\r
uniform sampler2D u_asciiCharacterTexture;\r
uniform sampler2D u_rotationTexture;
uniform sampler2D u_captureTexture;\r
uniform vec2 u_captureDimensions;\r
uniform int u_backgroundMode;
uniform vec2 u_gridCellDimensions;\r
uniform vec2 u_gridPixelDimensions;
uniform float u_pixelRatio;
mat2 rotate2D(float angle) {\r
float s = sin(angle);\r
float c = cos(angle);\r
return mat2(c, -s, s, c);\r
}
void main() {\r
vec2 logicalFragCoord = gl_FragCoord.xy / u_pixelRatio;
vec2 adjustedCoord = (logicalFragCoord) / u_gridPixelDimensions;
vec2 gridCoord = adjustedCoord * u_gridCellDimensions;\r
vec2 cellCoord = floor(gridCoord);
vec2 charIndexTexCoord = (cellCoord + vec2(0.5)) / u_gridCellDimensions;
vec4 primaryColor = texture2D(u_primaryColorTexture, charIndexTexCoord);
vec4 secondaryColor = texture2D(u_secondaryColorTexture, charIndexTexCoord);
vec4 transformColor = texture2D(u_transformTexture, charIndexTexCoord);\r
bool isInverted = transformColor.r > 0.5;
bool flipHorizontal = transformColor.g > 0.5;
bool flipVertical = transformColor.b > 0.5;
vec4 encodedIndexVec = texture2D(u_asciiCharacterTexture, charIndexTexCoord);
if(encodedIndexVec.a < 0.01) {\r
if(u_backgroundMode == 0) {\r
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\r
} else if(u_backgroundMode == 1) {\r
vec2 captureTexCoord = logicalFragCoord / u_captureDimensions;\r
gl_FragColor = texture2D(u_captureTexture, captureTexCoord);\r
}\r
return;\r
}
int charIndex = int(encodedIndexVec.r * 255.0 + 0.5) + int(encodedIndexVec.g * 255.0 + 0.5) * 256;
int charCol = charIndex - (charIndex / int(u_charsetDimensions.x)) * int(u_charsetDimensions.x);\r
int charRow = charIndex / int(u_charsetDimensions.x);
vec2 charCoord = vec2(float(charCol) / u_charsetDimensions.x, float(charRow) / u_charsetDimensions.y);
vec4 rotationColor = texture2D(u_rotationTexture, charIndexTexCoord);
float rotationAngle = rotationColor.r * 2.0 * 3.14159265359;
vec2 fractionalPart = fract(gridCoord) - 0.5;
if(flipHorizontal) {\r
fractionalPart.x = -fractionalPart.x;\r
}\r
if(flipVertical) {\r
fractionalPart.y = -fractionalPart.y;\r
}
fractionalPart = rotate2D(rotationAngle) * fractionalPart;\r
fractionalPart += 0.5;
vec2 cellMin = charCoord;\r
vec2 cellMax = charCoord + vec2(1.0 / u_charsetDimensions.x, 1.0 / u_charsetDimensions.y);\r
vec2 texCoord = charCoord + fractionalPart * vec2(1.0 / u_charsetDimensions.x, 1.0 / u_charsetDimensions.y);
bool outsideBounds = any(lessThan(texCoord, cellMin)) || any(greaterThan(texCoord, cellMax));
if(outsideBounds) {\r
gl_FragColor = isInverted ? primaryColor : secondaryColor;\r
return;\r
}
vec4 charTexel = texture2D(u_characterTexture, texCoord);
bool isFullyWhite = all(greaterThanEqual(charTexel.rgb, vec3(0.99)));
if(isInverted) {\r
gl_FragColor = isFullyWhite ? secondaryColor : primaryColor;\r
} else {\r
gl_FragColor = isFullyWhite ? primaryColor : secondaryColor;\r
}\r
}`;class IA{constructor(A,e,r){o(this,"_resultFramebuffer");o(this,"_shader");o(this,"_backgroundMode",0);this._p=A,this._grid=e,this._fontManager=r,this._shader=this._p.createShader(F,zA),this._resultFramebuffer=this._p.createFramebuffer({width:this._grid.width,height:this._grid.height,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST})}render(A,e,r,t,i,s,n="#000000"){this._resultFramebuffer.begin(),this._p.background(n),this._p.shader(this._shader);const E={u_pixelRatio:this._p.pixelDensity(),u_characterTexture:this._fontManager.texture,u_charsetDimensions:[this._fontManager.textureColumns,this._fontManager.textureRows],u_primaryColorTexture:e,u_secondaryColorTexture:r,u_transformTexture:t,u_rotationTexture:i,u_captureTexture:s,u_captureDimensions:[s.width,s.height],u_asciiCharacterTexture:A,u_gridPixelDimensions:[this._grid.width,this._grid.height],u_gridCellDimensions:[this._grid.cols,this._grid.rows],u_backgroundMode:this._backgroundMode||0};for(const[Q,c]of Object.entries(E))this._shader.setUniform(Q,c);this._p.rect(0,0,this._resultFramebuffer.width,this._resultFramebuffer.height),this._resultFramebuffer.end()}resizeFramebuffers(){this._resultFramebuffer.resize(this._grid.width,this._grid.height)}backgroundMode(A){this._backgroundMode=A}get resultFramebuffer(){return this._resultFramebuffer}}const Z={brightness:gA,edge:QA,custom2D:j};class bA{constructor(A,e,r,t,i){o(this,"_currentCanvasDimensions");o(this,"_renderers");o(this,"_primaryColorFramebuffer");o(this,"_secondaryColorFramebuffer");o(this,"_characterFramebuffer");o(this,"_transformFramebuffer");o(this,"_rotationFramebuffer");o(this,"_asciiDisplayRenderer2D");o(this,"_hasEnabledRenderers",!1);this._p=A,this._captureFramebuffer=e,this._grid=r,this._fontManager=t,this._pluginRegistry=i,this._currentCanvasDimensions={width:this._captureFramebuffer.width,height:this._captureFramebuffer.height},this._renderers=[{name:"custom2D",renderer:new j(this._p,this._captureFramebuffer,this._grid,this._fontManager)},{name:"edge",renderer:new QA(this._p,this._captureFramebuffer,this._grid,this._fontManager)},{name:"brightness",renderer:new gA(this._p,this._captureFramebuffer,this._grid,this._fontManager)}],this._primaryColorFramebuffer=this._p.createFramebuffer({density:1,antialias:!1,width:this._grid.cols,height:this._grid.rows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this._secondaryColorFramebuffer=this._p.createFramebuffer({density:1,antialias:!1,width:this._grid.cols,height:this._grid.rows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this._transformFramebuffer=this._p.createFramebuffer({density:1,antialias:!1,width:this._grid.cols,height:this._grid.rows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this._characterFramebuffer=this._p.createFramebuffer({density:1,antialias:!1,width:this._grid.cols,height:this._grid.rows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this._rotationFramebuffer=this._p.createFramebuffer({density:1,antialias:!1,width:this._grid.cols,height:this._grid.rows,depthFormat:this._p.UNSIGNED_INT,textureFiltering:this._p.NEAREST}),this._asciiDisplayRenderer2D=new IA(this._p,this._grid,this._fontManager)}render(A="#000000"){this._characterFramebuffer.draw(()=>this._p.clear()),this._primaryColorFramebuffer.draw(()=>this._p.clear()),this._secondaryColorFramebuffer.draw(()=>this._p.clear()),this._transformFramebuffer.draw(()=>this._p.clear()),this._rotationFramebuffer.draw(()=>this._p.clear()),this._hasEnabledRenderers=!1;for(let e=this._renderers.length-1;e>=0;e--){const r=this._renderers[e];if(r.renderer.options.enabled){r.renderer instanceof N&&r.renderer.render();const t=-this._grid.cols/2,i=-this._grid.rows/2;this._characterFramebuffer.draw(()=>this._p.image(r.renderer.characterFramebuffer,t,i)),this._primaryColorFramebuffer.draw(()=>this._p.image(r.renderer.primaryColorFramebuffer,t,i)),this._secondaryColorFramebuffer.draw(()=>this._p.image(r.renderer.secondaryColorFramebuffer,t,i)),this._transformFramebuffer.draw(()=>this._p.image(r.renderer.transformFramebuffer,t,i)),this._rotationFramebuffer.draw(()=>this._p.image(r.renderer.rotationFramebuffer,t,i)),this._hasEnabledRenderers=!0}}this._asciiDisplayRenderer2D.render(this._characterFramebuffer,this._primaryColorFramebuffer,this._secondaryColorFramebuffer,this._transformFramebuffer,this._rotationFramebuffer,this._captureFramebuffer,A),this.checkCanvasDimensions()}checkCanvasDimensions(){(this._currentCanvasDimensions.width!==this._captureFramebuffer.width||this._currentCanvasDimensions.height!==this._captureFramebuffer.height)&&(this._currentCanvasDimensions.width=this._captureFramebuffer.width,this._currentCanvasDimensions.height=this._captureFramebuffer.height,this._grid.reset(),this.resetRendererDimensions())}setCaptureTexture(A){this._captureFramebuffer=A,this.resetRendererDimensions(),this._renderers.forEach(e=>{e.renderer.setCaptureTexture(A)})}resetRendererDimensions(){this._primaryColorFramebuffer.resize(this._grid.cols,this._grid.rows),this._secondaryColorFramebuffer.resize(this._grid.cols,this._grid.rows),this._characterFramebuffer.resize(this._grid.cols,this._grid.rows),this._transformFramebuffer.resize(this._grid.cols,this._grid.rows),this._rotationFramebuffer.resize(this._grid.cols,this._grid.rows),this._renderers.forEach(A=>{A.renderer.resizeFramebuffers(),A.renderer instanceof N&&A.renderer.resetShaders()}),this._asciiDisplayRenderer2D.resizeFramebuffers()}add(A,e,r){const t=a.validate(typeof A=="string"&&A.trim()!=="","Renderer name must be a non-empty string.",{providedValue:A,method:"add"}),i=a.validate(typeof e=="string"&&e.trim()!=="","Renderer type must be a non-empty string.",{providedValue:e,method:"add"});if(!t||!i)return null;let s;const n=Z[e];if(n)s=new n(this._p,this._captureFramebuffer,this._grid,this._fontManager,r);else{const Q=this._pluginRegistry.get(e);Q&&(s=Q.create(this._p,this._captureFramebuffer,this._grid,this._fontManager,r))}return a.validate(s!==void 0,(()=>{const Q=[...Object.keys(Z),...this._pluginRegistry.getIds()].join(", ");return`Invalid renderer type: ${e}. Valid types are: ${Q}`})(),{providedValue:e,method:"add"})?(this._renderers.unshift({name:A,renderer:s}),s):null}get(A){var i;if(!a.validate(typeof A=="string"&&A.trim()!=="","Renderer name must be a non-empty string.",{providedValue:A,method:"get"}))return null;const r=(i=this._renderers.find(s=>s.name===A))==null?void 0:i.renderer;return a.validate(r!==void 0,`Renderer '${A}' not found. Available renderers: ${this._renderers.map(s=>s.name).join(", ")}`,{providedValue:A,method:"get"})?r:null}getAvailableRendererTypes(){return[...Object.keys(Z),...this._pluginRegistry.getIds()]}moveDown(A){const e=this._getRendererIndex(A),r=a.validate(e>=0&&e<this._renderers.length,"Renderer not found in the renderer list.",{providedValue:A,method:"