UNPKG

p5.asciify

Version:

Apply real-time ASCII conversion to your favorite p5.js sketches instantly.

411 lines (245 loc) 117 kB
(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 KA=Object.defineProperty;var XA=(f,h,T)=>h in f?KA(f,h,{enumerable:!0,configurable:!0,writable:!0,value:T}):f[h]=T;var o=(f,h,T)=>XA(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 O=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,J=(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},PA=(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 iA{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 I=n.pixels,u=E.pixels,l=Q.pixels,P=c.pixels,B=d.pixels,_=e.cols,C=e.rows,w=e.cellWidth,m=e.cellHeight,b=e.width,U=e.height,S=r.characters;let M=this.generateSVGHeader(b,U);if(s.includeBackgroundRectangles){const V=t,x=this._p.color(V),p=`rgba(${x._array[0]*255},${x._array[1]*255},${x._array[2]*255},${x._array[3]})`;M+=` <rect width="${b}" height="${U}" fill="${p}" />`}M+=` <g id="ascii-cells">`;let D=0;for(let V=0;V<C;V++)for(let x=0;x<_;x++){const p=D*4,$=I[p],G=I[p+1];let y=$+(G<<8);y>=S.length&&(y=S.length-1);let W={r:u[p],g:u[p+1],b:u[p+2],a:u[p+3]},K={r:l[p],g:l[p+1],b:l[p+2],a:l[p+3]};const lA=P[p],tA=P[p+1],hA=P[p+2],cA=lA===255,dA=tA===255,fA=hA===255;if(cA){const WA=W;W=K,K=WA}const uA=B[p],CA=B[p+1],DA=uA+CA/255,_A=Math.round(DA*360/255*100)/100,mA=x*w,LA=V*m;M+=this.generateSVGCellContent(y,W,K,mA,LA,w,m,_A,dA,fA,r,S[y],s),D++}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,I,u){let l="";if(u.includeBackgroundRectangles&&r.a>0){const m=`rgba(${r.r},${r.g},${r.b},${r.a/255})`;u.drawMode==="stroke"?l+=` <rect x="${t}" y="${i}" width="${s}" height="${n}" stroke="${m}" fill="none" stroke-width="${u.strokeWidth||1}" />`:l+=` <rect x="${t}" y="${i}" width="${s}" height="${n}" fill="${m}" />`}const P=t+s/2,B=i+n/2,_=`rgba(${e.r},${e.g},${e.b},${e.a/255})`,C=[];if(Q||c){const m=Q?-1:1,b=c?-1:1;C.push(`translate(${P} ${B})`),C.push(`scale(${m} ${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 m=Math.min(s,n)*.8;l+=` <text x="${P}" y="${B}" font-family="monospace" font-size="${m}px" fill="${_}" text-anchor="middle" dominant-baseline="middle"${w}>${this.escapeXml(I.character)}</text>`}else{let m=1;R(O(this._p))?m=d.fontSize/d.font.data.head.unitsPerEm:m=d.fontSize/d.font.font.unitsPerEm;const b=t+(s-I.advanceWidth*m)/2,U=i+(n+d.fontSize*.7)/2,D=I.getPath(b,U,d.fontSize).toSVG().match(/d="([^"]+)"/);if(D&&D[1]){if(w&&(l+=` <g${w}>`),u.drawMode==="stroke"){const V=u.strokeWidth||1,x=`path-${A}-${t}-${i}`.replace(/\./g,"-");l+=` <path id="${x}" d="${D[1]}" stroke="${_}" stroke-width="${V}" fill="none" />`}else l+=` <path d="${D[1]}" fill="${_}" />`;w&&(l+=` </g>`)}}return l}escapeXml(A){return A.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}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 sA{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,I=n.pixels,u=E.pixels,l=Q.pixels,P=c.pixels,B=e.cols,_=e.rows,C=r.characters,w={version:"1.0",created:new Date().toISOString(),gridSize:{cols:B,rows:_,cellWidth:e.cellWidth,cellHeight:e.cellHeight,width:e.width,height:e.height}},m=[];let b=0;for(let S=0;S<_;S++)for(let M=0;M<B;M++){const D=b*4,V=d[D],x=d[D+1];let p=V+(x<<8);p>=C.length&&(p=C.length-1);const $=C[p];if(!i.includeEmptyCells&&($.character===" "||$.character==="")){b++;continue}let G={r:I[D],g:I[D+1],b:I[D+2],a:I[D+3]},y={r:u[D],g:u[D+1],b:u[D+2],a:u[D+3]};const W=l[D],K=l[D+1],lA=l[D+2],tA=W===255,hA=K===255,cA=lA===255;if(tA){const mA=G;G=y,y=mA}const dA=P[D],fA=P[D+1],uA=dA+fA/255,CA=Math.round(uA*360/255*100)/100,DA=this.rgbaToHex(G.r,G.g,G.b,G.a),_A=this.rgbaToHex(y.r,y.g,y.b,y.a);m.push({x:M,y:S,character:$.character,unicode:$.unicode,color:DA,backgroundColor:_A,rotation:CA,inverted:tA,flipHorizontal:hA,flipVertical:cA}),b++}return JSON.stringify({metadata:w,cells:m},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 pA(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 X(){return{getBoundingBox:()=>({x1:0,y1:0,x2:0,y2:0}),toSVG:()=>""}}function IA(g,A,e,r,t){if(!A||!A.xs||A.xs.length===0)return X();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:()=>bA(A,e,r,i)}}function bA(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 I=A+t[Q]*r,u=e-i[Q]*r;E+=`M${I.toFixed(2)},${u.toFixed(2)}`;let l=Q+1;for(;l<=d;)if((n[l]&1)!==0){const B=A+t[l]*r,_=e-i[l]*r;E+=`L${B.toFixed(2)},${_.toFixed(2)}`,l++}else{const B=A+t[l]*r,_=e-i[l]*r;let C=l+1>d?Q:l+1;if((n[C]&1)!==0){const m=A+t[C]*r,b=e-i[C]*r;E+=`Q${B.toFixed(2)},${_.toFixed(2)} ${m.toFixed(2)},${b.toFixed(2)}`,l=C+1}else{const m=A+t[C]*r,b=e-i[C]*r,U=(B+m)/2,S=(_+b)/2;E+=`Q${B.toFixed(2)},${_.toFixed(2)} ${U.toFixed(2)},${S.toFixed(2)}`,l=C}}E+="Z"}Q=d+1}}return`<path d="${E}" />`}const VA=Object.freeze(Object.defineProperty({__proto__:null,P5AsciifyJSONExporter:sA,P5AsciifySVGExporter:iA,compareVersions:j,createEmptyPath:X,createGlyphPath:IA,detectP5Version:O,getGlyphIndex:pA,glyphToSVGPath:bA,isP5AsyncCapable:R,isValidP5Color:J,isValidP5Font:PA},Symbol.toStringTag,{value:"Module"}));class Y extends Error{constructor(e,r){super(e);o(this,"originalError");this.name="P5AsciifyError",this.originalError=r}}var oA=(g=>(g[g.SILENT=0]="SILENT",g[g.WARNING=1]="WARNING",g[g.ERROR=2]="ERROR",g[g.THROW=3]="THROW",g))(oA||{});const H=class H{constructor(){o(this,"_options",{globalLevel:3,consolePrefix:"[p5.asciify]"})}static getInstance(){return H._instance||(H._instance=new H),H._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(H,"_instance",null);let Z=H;const a=Z.getInstance(),kA=Object.freeze(Object.defineProperty({__proto__:null,P5AsciifyError:Y,P5AsciifyErrorHandler:Z,P5AsciifyErrorLevel:oA,errorHandler:a},Symbol.toStringTag,{value:"Module"}));class wA{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(O(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=pA(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:(I,u,l)=>{if(n===void 0)return X();const P=this._font.data.glyf[n];return P?IA(this._font,P,I,u,l):X()},advanceWidth:E,color:this._p.color(Q,c,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,color:this._p.color(i,s,n)})})}}loadFont(A){a.validate(PA(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 this._p.color(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.color:this._p.color(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[this._p.color(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 nA{constructor(A,e,r,t,i){o(this,"_primaryColorFramebuffer");o(this,"_secondaryColorFramebuffer");o(this,"_characterFramebuffer");o(this,"_transformFramebuffer");o(this,"_rotationFramebuffer");o(this,"_framebufferOptions");this._p=A,this._captureFramebuffer=e,this._grid=r,this._fontManager=t,this._options=i,this._framebufferOptions={antialias:!1,textureFiltering:this._p.NEAREST,depthFormat:this._p.UNSIGNED_INT,density:1,width:this._grid.cols,height:this._grid.rows},this._recreateFramebuffers()}_recreateFramebuffers(){const A={...this._framebufferOptions,density:1,width:this._grid.cols,height:this._grid.rows};this._primaryColorFramebuffer=this._p.createFramebuffer(A),this._secondaryColorFramebuffer=this._p.createFramebuffer(A),this._transformFramebuffer=this._p.createFramebuffer(A),this._characterFramebuffer=this._p.createFramebuffer(A),this._rotationFramebuffer=this._p.createFramebuffer(A)}update(A){return(A==null?void 0:A.enabled)!==void 0&&this.enabled(A.enabled),this}setCaptureTexture(A){return this._captureFramebuffer=A,this.resizeFramebuffers(),this.resetShaders(),this}enabled(A){if(A===void 0)return this;if(!a.validate(typeof A=="boolean","Enabled must be a boolean.",{providedValue:A,method:"enabled"}))return this;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}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 framebufferOptions(){return this._framebufferOptions}get characterFramebuffer(){return this._characterFramebuffer}get grid(){return this._grid}}const aA={enabled:!1};class L extends nA{constructor(A,e,r,t,i=aA){super(A,e,r,t,{...aA,...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 xA{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._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 z extends L{constructor(e,r,t,i,s){super(e,r,t,i,s);o(this,"_characterColorPalette");this._characterColorPalette=new xA(this._p,this._fontManager.glyphColors(this._options.characters)),this.update(this._options)}characters(e){return!a.validate(typeof e=="string","Characters must be a string.",{providedValue:e,method:"characters"})||e===this._options.characters?this:(this._characterColorPalette.setColors(this._fontManager.glyphColors(e)),this.resetShaders(),this._options.characters=e,this)}invert(e){return a.validate(typeof e=="boolean","Invert mode must be a boolean.",{providedValue:e,method:"invert"})?(this._options.invert=e,this):this}rotation(e){if(!a.validate(typeof e=="number"&&!isNaN(e),"Rotation angle must be a valid number.",{providedValue:e,method:"rotation"}))return this;e=e%360,e<0&&(e+=360);const t=e*255/360,i=Math.floor(t),s=Math.round((t-i)*255);return this._options.rotation=this._p.color(i,s,0),this}characterColor(e){return a.validate(J(this._p,e),"Character color must be a valid p5.Color object.",{providedValue:e,method:"characterColor"})?(this._options.characterColor=e,this):this}flipHorizontally(e){return a.validate(typeof e=="boolean","Flip horizontally must be a boolean.",{providedValue:e,method:"flipHorizontally"})?(this._options.flipHorizontally=e,this):this}flipVertically(e){return a.validate(typeof e=="boolean","Flip vertically must be a boolean.",{providedValue:e,method:"flipVertically"})?(this._options.flipVertically=e,this):this}backgroundColor(e){return a.validate(J(this._p,e),"Background color must be a valid p5.Color object.",{providedValue:e,method:"backgroundColor"})?(this._options.backgroundColor=e,this):this}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"});return!r||!t?this:(e==="sampled"?this._options.characterColorMode=0:e==="fixed"&&(this._options.characterColorMode=1),this)}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"});return!r||!t?this:(e==="sampled"?this._options.backgroundColorMode=0:e==="fixed"&&(this._options.backgroundColorMode=1),this)}update(e){return 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.invert)!==void 0&&this.invert(e.invert),(e==null?void 0:e.rotation)!==void 0&&this.rotation(e.rotation),(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),this}get characterColorPalette(){return this._characterColorPalette}}var F=`precision mediump float; attribute vec3 aPosition; attribute vec2 aTexCoord; varying vec2 v_texCoord; void main() { vec4 positionVec4 = vec4(aPosition, 1.0); positionVec4.xy = positionVec4.xy * 2.0 - 1.0; gl_Position = positionVec4; v_texCoord = aTexCoord; }`,GA=`precision mediump float; uniform sampler2D u_sketchTexture; uniform vec2 u_gridCellDimensions; void main() { 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; }`,TA=`precision mediump float; uniform sampler2D u_colorSampleFramebuffer; uniform sampler2D u_charPaletteTexture; uniform vec2 u_charPaletteSize; uniform vec2 u_textureSize; uniform ivec2 u_brightnessRange; void main() { vec2 pos = (floor(gl_FragCoord.xy) + 0.5) / u_textureSize; vec4 inputColor = texture2D(u_colorSampleFramebuffer, pos); if (inputColor.a == 0.0) { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); return; } float brightness = dot(inputColor.rgb, vec3(0.299, 0.587, 0.114)); float brightness255 = brightness * 255.0; if (brightness255 < float(u_brightnessRange.x) || brightness255 > float(u_brightnessRange.y)) { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); return; } float normalizedBrightness = (brightness255 - float(u_brightnessRange.x)) / (float(u_brightnessRange.y) - float(u_brightnessRange.x)); float index = clamp(floor(normalizedBrightness * u_charPaletteSize.x), 0.0, u_charPaletteSize.x - 1.0); vec3 charColor = texture2D(u_charPaletteTexture, vec2((index + 0.5) / u_charPaletteSize.x, 0.0)).rgb; gl_FragColor = vec4(charColor, inputColor.a); }`;const gA={enabled:!0,characters:" .:-=+*%@#",characterColor:"#FFFFFF",characterColorMode:"sampled",backgroundColor:"#000000",backgroundColorMode:"fixed",invert:!1,rotation:0,flipHorizontally:!1,flipVertically:!1,brightnessRange:[0,255]};class BA extends z{constructor(e,r,t,i,s=gA){super(e,r,t,i,{...gA,...s});o(this,"colorSampleShader");o(this,"asciiCharacterShader");o(this,"colorSampleFramebuffer");this.colorSampleShader=this._p.createShader(F,GA),this.asciiCharacterShader=this._p.createShader(F,TA),this.colorSampleFramebuffer=this._p.createFramebuffer(this._framebufferOptions)}resetShaders(){}_recreateFramebuffers(){const e={...this._framebufferOptions,density:1,width:this._grid.cols,height:this._grid.rows};this.colorSampleFramebuffer=this._p.createFramebuffer(e),super._recreateFramebuffers()}resizeFramebuffers(){super.resizeFramebuffers(),this.colorSampleFramebuffer.resize(this._grid.cols,this._grid.rows)}update(e){return super.update(e),e.brightnessRange!==void 0&&this.brightnessRange(e.brightnessRange),this}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 this;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"});return!s||!n?this:(this._options.brightnessRange=[t,i],this)}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.invert?255:0,this._options.flipHorizontally?255:0,this._options.flipVertically?255:0),this._transformFramebuffer.end(),this._rotationFramebuffer.begin(),this._p.background(this._options.rotation),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 RA=`precision mediump float; uniform sampler2D u_sketchTexture; uniform sampler2D u_sampleTexture; uniform vec2 u_gridCellDimensions; uniform int u_sampleMode; uniform vec4 u_staticColor; void main() { 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)) { if(u_sampleMode == 0) { finalColor = texture2D(u_sketchTexture, cellCenterTexCoord); } else { finalColor = u_staticColor; } } gl_FragColor = finalColor; }`,YA=`precision mediump float; uniform sampler2D u_sampleTexture; uniform vec2 u_gridCellDimensions; uniform bool u_invert; uniform bool u_flipH; uniform bool u_flipV; uniform vec3 u_compareColor; void main() { 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) { float r = u_invert ? 1.0 : 0.0; float g = u_flipH ? 1.0 : 0.0; float b = u_flipV ? 1.0 : 0.0; gl_FragColor = vec4(r, g, b, 1.0); } else { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); } }`,zA=`precision mediump float; uniform sampler2D u_sampleTexture; uniform vec2 u_gridCellDimensions; uniform vec3 u_rotationColor; uniform vec3 u_compareColor; void main() { 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) { gl_FragColor = vec4(u_rotationColor, 1.0); } else { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); } }`,HA=`precision mediump float; uniform sampler2D u_sketchTexture; uniform vec2 u_gridCellDimensions; void main() { vec2 cellCoord = floor(gl_FragCoord.xy); vec2 cellSizeInTexCoords = vec2(1.0) / u_gridCellDimensions; vec2 cellCenterTexCoord = (cellCoord + vec2(0.5)) * cellSizeInTexCoords; gl_FragColor = texture2D(u_sketchTexture, cellCenterTexCoord); }`,UA=`precision mediump float; varying vec2 v_texCoord; uniform sampler2D u_texture; uniform vec2 u_textureSize; uniform float u_threshold; uniform sampler2D u_colorPaletteTexture; void main() { vec2 texelSize = 1.0 / u_textureSize; float kernelX[9]; float kernelY[9]; kernelX[0] = -1.0; kernelX[1] = 0.0; kernelX[2] = 1.0; kernelX[3] = -2.0; kernelX[4] = 0.0; kernelX[5] = 2.0; kernelX[6] = -1.0; kernelX[7] = 0.0; kernelX[8] = 1.0; kernelY[0] = -1.0; kernelY[1] = -2.0; kernelY[2] = -1.0; kernelY[3] = 0.0; kernelY[4] = 0.0; kernelY[5] = 0.0; kernelY[6] = 1.0; kernelY[7] = 2.0; kernelY[8] = 1.0; vec3 texColor[9]; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { texColor[i * 3 + j] = texture2D(u_texture, v_texCoord + vec2(float(i - 1), float(j - 1)) * texelSize).rgb; } } vec3 sobelX = vec3(0.0); vec3 sobelY = vec3(0.0); for(int i = 0; i < 9; i++) { sobelX += kernelX[i] * texColor[i]; sobelY += kernelY[i] * texColor[i]; } vec3 sobel = sqrt(sobelX * sobelX + sobelY * sobelY); float intensity = length(sobel) / sqrt(3.0); vec4 edgeColor = vec4(0.0); if(intensity > u_threshold) { float angleDeg = degrees(atan(sobelY.r, sobelX.r)); int charIndex = 0; if(angleDeg >= -22.5 && angleDeg < 22.5) charIndex = 0; else if(angleDeg >= 22.5 && angleDeg < 67.5) charIndex = 1; else if(angleDeg >= 67.5 && angleDeg < 112.5) charIndex = 2; else if(angleDeg >= 112.5 && angleDeg < 157.5) charIndex = 3; else if(angleDeg >= 157.5 || angleDeg < -157.5) charIndex = 4; else if(angleDeg >= -157.5 && angleDeg < -112.5) charIndex = 5; else if(angleDeg >= -112.5 && angleDeg < -67.5) charIndex = 6; else if(angleDeg >= -67.5 && angleDeg < -22.5) charIndex = 7; float paletteCoord = (float(charIndex) + 0.5) / 8.0; edgeColor = texture2D(u_colorPaletteTexture, vec2(paletteCoord, 0.5)); } gl_FragColor = edgeColor; }`;const vA=(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);} `,QA={enabled:!1,characters:"-/|\\-/|\\",characterColor:"#FFFFFF",characterColorMode:"sampled",backgroundColor:"#000000",backgroundColorMode:"fixed",invert:!1,sobelThreshold:.5,sampleThreshold:16,rotation:0,flipHorizontally:!1,flipVertically:!1};class EA extends z{constructor(e,r,t,i,s=QA){super(e,r,t,i,{...QA,...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,UA),this.sampleShader=this._p.createShader(F,vA(16,this._grid.cellHeight,this._grid.cellWidth)),this.colorSampleShader=this._p.createShader(F,RA),this.transformShader=this._p.createShader(F,YA),this.rotationShader=this._p.createShader(F,zA),this.asciiCharacterShader=this._p.createShader(F,HA),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(this._framebufferOptions)}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,vA(16,this._grid.cellHeight,this._grid.cellWidth))}_recreateFramebuffers(){const e={...this._framebufferOptions,density:1,width:this._grid.cols,height:this._grid.rows};this.sampleFramebuffer=this._p.createFramebuffer(e),super._recreateFramebuffers()}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"});return!r||!t?this:(this._options.sobelThreshold=e,this)}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"});return!r||!t?this:(this._options.sampleThreshold=e,this)}update(e){return super.update(e),e.sobelThreshold!==void 0&&this.sobelThreshold(e.sobelThreshold),e.sampleThreshold!==void 0&&this.sampleThreshold(e.sampleThreshold),this}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.invert),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.rotation._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 NA=`precision mediump float; uniform sampler2D u_characterTexture; uniform vec2 u_charsetDimensions; uniform sampler2D u_primaryColorTexture; uniform sampler2D u_secondaryColorTexture; uniform sampler2D u_transformTexture; uniform sampler2D u_asciiCharacterTexture; uniform sampler2D u_rotationTexture; uniform sampler2D u_captureTexture; uniform vec2 u_captureDimensions; uniform int u_backgroundMode; uniform vec2 u_gridCellDimensions; uniform vec2 u_gridPixelDimensions; uniform float u_pixelRatio; mat2 rotate2D(float angle) { float s = sin(angle); float c = cos(angle); return mat2(c, -s, s, c); } void main() { vec2 logicalFragCoord = gl_FragCoord.xy / u_pixelRatio; vec2 adjustedCoord = (logicalFragCoord) / u_gridPixelDimensions; vec2 gridCoord = adjustedCoord * u_gridCellDimensions; 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); 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) { if(u_backgroundMode == 0) { gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); } else if(u_backgroundMode == 1) { vec2 captureTexCoord = logicalFragCoord / u_captureDimensions; gl_FragColor = texture2D(u_captureTexture, captureTexCoord); } return; } 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); 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 redValue = rotationColor.r * 255.0; float greenValue = rotationColor.g * 255.0; float scaledAngle = redValue + (greenValue / 255.0); float angleDegrees = (scaledAngle * 360.0) / 255.0; float rotationAngle = angleDegrees * 3.14159265359 / 180.0; vec2 fractionalPart = fract(gridCoord) - 0.5; if(flipHorizontal) { fractionalPart.x = -fractionalPart.x; } if(flipVertical) { fractionalPart.y = -fractionalPart.y; } fractionalPart = rotate2D(rotationAngle) * fractionalPart; fractionalPart += 0.5; vec2 cellMin = charCoord; vec2 cellMax = charCoord + vec2(1.0 / u_charsetDimensions.x, 1.0 / u_charsetDimensions.y); 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) { gl_FragColor = isInverted ? primaryColor : secondaryColor; return; } vec4 charTexel = texture2D(u_characterTexture, texCoord); float inv = isInverted ? 1.0 : 0.0; charTexel.rgb = mix(charTexel.rgb, 1.0 - charTexel.rgb, inv); gl_FragColor = mix(secondaryColor, primaryColor, charTexel); }`;class yA{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,NA),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 q={brightness:BA,edge:EA,custom2D:L};class FA{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);o(this,"_framebufferOptions");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 L(this._p,this._captureFramebuffer,this._grid,this._fontManager)},{name:"edge",renderer:new EA(this._p,this._captureFramebuffer,this._grid,this._fontManager)},{name:"brightness",renderer:new BA(this._p,this._captureFramebuffer,this._grid,this._fontManager)}],this._framebufferOptions={antialias:!1,textureFiltering:this._p.NEAREST,depthFormat:this._p.UNSIGNED_INT,density:1,width:this._grid.cols,height:this._grid.rows},this._asciiDisplayRenderer2D=new yA(this._p,this._grid,this._fontManager),this._recreateFramebuffers()}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 z&&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)})}_recreateFramebuffers(){const A={...this._framebufferOptions,density:1,width:this._grid.cols,height:this._grid.rows};this._primaryColorFramebuffer=this._p.createFramebuffer(A),this._secondaryColorFramebuffer=this._p.createFramebuffer(A),this._transformFramebuffer=this._p.createFramebuffer(A),this._characterFramebuffer=this._p.createFramebuffer(A),this._rotationFramebuffer=this._p.createFramebuffer(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 z&&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=q[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(q),...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:nul