@utsp/render 0.13.0 → 0.14.0-nightly.20251221141916.9580af2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/2d/index.cjs +8 -8
- package/dist/2d/index.d.ts +53 -3
- package/dist/2d/index.mjs +7 -7
- package/dist/gl/index.cjs +7 -7
- package/dist/gl/index.d.ts +45 -0
- package/dist/gl/index.mjs +7 -7
- package/dist/index.cjs +13 -13
- package/dist/index.d.ts +98 -3
- package/dist/index.mjs +13 -13
- package/package.json +2 -2
package/dist/gl/index.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var y=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var N=(f,e,t)=>e in f?y(f,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):f[e]=t;var C=(f,e)=>y(f,"name",{value:e,configurable:!0});var X=(f,e)=>{for(var t in e)y(f,t,{get:e[t],enumerable:!0})},q=(f,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of k(e))!z.call(f,i)&&i!==t&&y(f,i,{get:()=>e[i],enumerable:!(s=Y(e,i))||s.enumerable});return f};var j=f=>q(y({},"__esModule",{value:!0}),f);var r=(f,e,t)=>(N(f,typeof e!="symbol"?e+"":e,t),t);var Q={};X(Q,{DEFAULT_PALETTE:()=>D,GridOverlay:()=>I,ScalingMode:()=>x.ScalingMode,TerminalGL:()=>_,colorToPaletteIndex:()=>V,getAtlasColumns:()=>B,getCharGridPosition:()=>L,getMaxCharCode:()=>F,paletteIndexToColor:()=>$});module.exports=j(Q);var M=class M{constructor(e,t){r(this,"canvas");r(this,"ctx");r(this,"container");r(this,"cols",0);r(this,"rows",0);r(this,"cellWidth",0);r(this,"cellHeight",0);r(this,"offsetX",0);r(this,"offsetY",0);r(this,"strokeColor","rgba(80, 80, 80, 0.4)");r(this,"lineWidth",1);this.container=e,this.canvas=document.createElement("canvas"),this.canvas.className="grid-overlay-canvas";let s=t?.zIndex??10;this.canvas.style.cssText=`
|
|
2
2
|
display: block !important;
|
|
3
3
|
position: absolute !important;
|
|
4
4
|
pointer-events: none !important;
|
|
5
5
|
image-rendering: pixelated !important;
|
|
6
6
|
image-rendering: crisp-edges !important;
|
|
7
|
-
z-index: ${
|
|
8
|
-
`,this.container.appendChild(this.canvas);let i=this.canvas.getContext("2d");if(!i)throw new Error("[GridOverlay] Impossible de cr\xE9er le contexte 2D");this.ctx=i,t&&(t.strokeColor&&(this.strokeColor=t.strokeColor),t.lineWidth!==void 0&&(this.lineWidth=t.lineWidth))}setDimensions(e,t,
|
|
7
|
+
z-index: ${s} !important;
|
|
8
|
+
`,this.container.appendChild(this.canvas);let i=this.canvas.getContext("2d");if(!i)throw new Error("[GridOverlay] Impossible de cr\xE9er le contexte 2D");this.ctx=i,t&&(t.strokeColor&&(this.strokeColor=t.strokeColor),t.lineWidth!==void 0&&(this.lineWidth=t.lineWidth))}setDimensions(e,t,s,i,n=0,a=0){this.cols=e,this.rows=t,this.cellWidth=s,this.cellHeight=i,this.offsetX=n,this.offsetY=a}setCanvasSize(e,t){this.canvas.width=e,this.canvas.height=t,this.ctx.setTransform(1,0,0,1,0,0)}setStyle(e){e.strokeColor&&(this.strokeColor=e.strokeColor),e.lineWidth!==void 0&&(this.lineWidth=e.lineWidth)}setTransform(e,t,s,i,n){let a=i.left-n.left,l=i.top-n.top,o=i.width,c=i.height;(this.canvas.width!==o||this.canvas.height!==c)&&(this.canvas.width=o,this.canvas.height=c);let d=this.canvas.style;d.width=`${o}px`,d.height=`${c}px`,d.left=`${a}px`,d.top=`${l}px`}render(){if(!this.ctx)return;let e=this.cols*this.cellWidth,t=this.rows*this.cellHeight,s=e>0?this.canvas.width/e:1,i=t>0?this.canvas.height/t:1,n=Math.min(s,i),a=this.cellWidth*n,l=this.cellHeight*n,o=this.cols*a,c=this.rows*l,d=this.offsetX*n,h=this.offsetY*n;if(!(o===0||c===0)){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.strokeStyle=this.strokeColor,this.ctx.lineWidth=Math.max(1,this.lineWidth*n),this.ctx.beginPath();for(let m=0;m<=this.cols;m++){let b=d+m*a+.5;this.ctx.moveTo(b,h),this.ctx.lineTo(b,h+c)}for(let m=0;m<=this.rows;m++){let b=h+m*l+.5;this.ctx.moveTo(d,b),this.ctx.lineTo(d+o,b)}this.ctx.stroke()}}update(e,t,s,i,n,a,l=0,o=0){this.setDimensions(e,t,s,i,l,o),this.setCanvasSize(n,a),this.render()}setVisible(e){this.canvas.style.display=e?"block":"none"}destroy(){this.canvas.parentElement&&this.canvas.parentElement.removeChild(this.canvas)}getCanvas(){return this.canvas}};C(M,"GridOverlay");var I=M;function B(f){return Math.sqrt(f)*16}C(B,"getAtlasColumns");function F(f){return f*256-1}C(F,"getMaxCharCode");function L(f,e){let t=Math.floor(f/256),s=f%256,i=Math.sqrt(e),n=t%i,a=Math.floor(t/i),l=s%16,o=Math.floor(s/16);return{col:n*16+l,row:a*16+o}}C(L,"getCharGridPosition");var x=require("@utsp/types");var U=class U{constructor(e,t){r(this,"canvas");r(this,"gl");r(this,"parentElement");r(this,"containerDiv");r(this,"cols");r(this,"rows");r(this,"charWidth");r(this,"charHeight");r(this,"cellWidth",8);r(this,"cellHeight",8);r(this,"glyphOffsetX",0);r(this,"glyphOffsetY",0);r(this,"canvasBgColor");r(this,"showGrid");r(this,"supportsUint32Indices",!1);r(this,"useUint16Indices",!1);r(this,"gridOverlay");r(this,"bitmapFont");r(this,"atlasTexture",null);r(this,"atlasCanvas");r(this,"atlasColumns",0);r(this,"fontLoaded",!1);r(this,"paletteTexture",null);r(this,"program",null);r(this,"positionBuffer",null);r(this,"texCoordBuffer",null);r(this,"colorIndexBuffer",null);r(this,"indexBuffer",null);r(this,"aPosition");r(this,"aTexCoord");r(this,"aColorIndex");r(this,"uResolution",null);r(this,"uTexture",null);r(this,"uPalette",null);r(this,"resizeObserver");r(this,"charCodeToAtlasIndex",new Uint16Array(65536).fill(65535));r(this,"atlasUVs",new Float32Array(0));r(this,"cachedAtlasWidth",0);r(this,"cachedAtlasHeight",0);r(this,"paletteFloat",new Float32Array(256*4));r(this,"maxCells",0);r(this,"renderPositions",new Float32Array(0));r(this,"renderTexCoords",new Float32Array(0));r(this,"renderColorIndices",new Float32Array(0));r(this,"renderIndices",new Uint32Array(0));r(this,"cachedResolution",[0,0]);r(this,"cachedTextureUnit",-1);r(this,"cachedPaletteUnit",-1);r(this,"cachedTextureUniform",!1);r(this,"cachedPaletteUniform",!1);r(this,"paletteHash",0);r(this,"currentScale",1);r(this,"scalingMode",x.ScalingMode.None);r(this,"ambientEffectEnabled",!1);r(this,"ambientEffectCanvas",null);r(this,"ambientEffectCtx",null);r(this,"ambientEffectBlur",x.POST_PROCESS_DEFAULTS.ambientEffect.blur);r(this,"ambientEffectScale",x.POST_PROCESS_DEFAULTS.ambientEffect.scale);r(this,"ambientEffectOpacity",.7);r(this,"onResizeCallback");r(this,"staticPositionsInitialized",!1);r(this,"vaoExtension",null);r(this,"vao",null);r(this,"instancedExtension",null);r(this,"useInstancing",!1);r(this,"instanceDataBuffer",null);r(this,"instanceData",new Float32Array(0));r(this,"templateQuadPositions",new Float32Array(0));r(this,"templateQuadIndices",new Uint16Array(0));r(this,"aInstanceOffset",-1);r(this,"aInstanceUVs",-1);r(this,"aInstanceColors",-1);r(this,"uCellSize",null);if(!e)throw new Error("TerminalGL: Parent element is required");if(!Number.isInteger(t.cols)||t.cols<=0)throw new Error(`TerminalGL: Invalid cols: ${t.cols}. Must be a positive integer.`);if(!Number.isInteger(t.rows)||t.rows<=0)throw new Error(`TerminalGL: Invalid rows: ${t.rows}. Must be a positive integer.`);let s=t.cols*t.rows,i=U.checkCompatibility();if(i.errors.length>0)throw new Error(`TerminalGL: WebGL incompatible - ${i.errors.join(", ")}`);let n=t.forceUint16??!1;if(n&&s>i.maxCellsUint16)throw new Error(`TerminalGL: Terminal size ${t.cols}\xD7${t.rows} (${s} cells) exceeds Uint16 limit of ${i.maxCellsUint16} cells. Maximum size with Uint16: ${Math.floor(Math.sqrt(i.maxCellsUint16))}\xD7${Math.floor(Math.sqrt(i.maxCellsUint16))} (or smaller rectangles like 127\xD764)`);if(!i.uint32Indices&&s>i.maxCellsUint16)throw new Error(`TerminalGL: Terminal size ${t.cols}\xD7${t.rows} (${s} cells) exceeds device limit of ${i.maxCellsUint16} cells (OES_element_index_uint not supported). Maximum size: ${Math.floor(Math.sqrt(i.maxCellsUint16))}\xD7${Math.floor(Math.sqrt(i.maxCellsUint16))}`);s>i.recommendedMaxCells&&console.warn(`[TerminalGL] \u26A0\uFE0F Large terminal size ${t.cols}\xD7${t.rows} (${s} cells) exceeds recommended limit of ${i.recommendedMaxCells} cells. Performance may be impacted.`),i.warnings.length>0&&console.warn("[TerminalGL] WebGL Compatibility Warnings:",i.warnings);let a=t.charWidth??8,l=t.charHeight??8;if(!Number.isFinite(a)||a<=0)throw new Error(`TerminalGL: Invalid charWidth: ${a}. Must be a positive number.`);if(!Number.isFinite(l)||l<=0)throw new Error(`TerminalGL: Invalid charHeight: ${l}. Must be a positive number.`);for(this.parentElement=e,this.cols=t.cols,this.rows=t.rows,this.charWidth=a,this.charHeight=l,this.canvasBgColor=t.canvasBgColor!==void 0?t.canvasBgColor:null,this.showGrid=t.showGrid??!1,this.scalingMode=t.scalingMode??x.ScalingMode.None,t.ambientEffect&&(this.ambientEffectEnabled=!0,typeof t.ambientEffect=="object"&&(this.ambientEffectBlur=t.ambientEffect.blur??x.POST_PROCESS_DEFAULTS.ambientEffect.blur,this.ambientEffectScale=t.ambientEffect.scale??x.POST_PROCESS_DEFAULTS.ambientEffect.scale,this.ambientEffectOpacity=t.ambientEffect.opacity??.7));this.parentElement.firstChild;)this.parentElement.removeChild(this.parentElement.firstChild);let o=window.getComputedStyle(this.parentElement).position;o!=="relative"&&o!=="absolute"&&o!=="fixed"&&(this.parentElement.style.position="relative"),this.containerDiv=document.createElement("div"),this.containerDiv.className="terminalgl-container",this.containerDiv.style.cssText=`
|
|
9
9
|
position: absolute !important;
|
|
10
10
|
top: 0 !important;
|
|
11
11
|
left: 0 !important;
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
backface-visibility: hidden !important;
|
|
33
33
|
position: relative !important;
|
|
34
34
|
z-index: 1 !important;
|
|
35
|
-
`;let c=this.canvas.getContext("webgl",{alpha:this.canvasBgColor===null,premultipliedAlpha:!1});if(!c)throw new Error("TerminalGL: WebGL not supported");this.gl=c,this.supportsUint32Indices=!!c.getExtension("OES_element_index_uint"),this.useUint16Indices=
|
|
35
|
+
`;let c=this.canvas.getContext("webgl",{alpha:this.canvasBgColor===null,premultipliedAlpha:!1});if(!c)throw new Error("TerminalGL: WebGL not supported");this.gl=c,this.supportsUint32Indices=!!c.getExtension("OES_element_index_uint"),this.useUint16Indices=n||!this.supportsUint32Indices,this.useUint16Indices?console.warn(`[TerminalGL] \u{1F4CA} Using Uint16 indices (max ${i.maxCellsUint16} cells)`):console.warn(`[TerminalGL] \u{1F4CA} Using Uint32 indices (max ${i.maxCellsUint32} cells)`),this.vaoExtension=c.getExtension("OES_vertex_array_object"),this.vaoExtension&&console.warn("[TerminalGL] \u2705 VAO extension enabled (faster attribute binding)"),this.instancedExtension=c.getExtension("ANGLE_instanced_arrays"),this.instancedExtension?(this.useInstancing=!0,console.warn("[TerminalGL] \u{1F680} Instanced rendering enabled (massive draw call reduction)")):console.warn("[TerminalGL] \u26A0\uFE0F Instanced rendering not available (fallback to standard rendering)"),this.containerDiv.appendChild(this.canvas),this.ambientEffectEnabled&&(this.createAmbientEffectCanvas(),console.warn("[TerminalGL] \u{1F308} Ambient effect enabled at startup")),this.parentElement.appendChild(this.containerDiv),this.initRenderBuffers();try{this.initWebGL()}catch(d){throw console.error("[TerminalGL] \u274C Failed to initialize WebGL:",d),d}this.showGrid&&this.initGridOverlay(),this.setupResizeObserver()}static checkCompatibility(){let e={webgl1:!1,uint32Indices:!1,maxTextureSize:0,maxViewportDims:[0,0],maxCellsUint16:0,maxCellsUint32:0,recommendedMaxCells:0,warnings:[],errors:[]},t=document.createElement("canvas"),s=t.getContext("webgl")||t.getContext("experimental-webgl");if(!s||!(s instanceof WebGLRenderingContext))return e.errors.push("\u274C WebGL 1.0 not supported by this browser/device"),e;let i=s;e.webgl1=!0;try{e.maxTextureSize=i.getParameter(i.MAX_TEXTURE_SIZE);let o=i.getParameter(i.MAX_VIEWPORT_DIMS);e.maxViewportDims=[o[0],o[1]]}catch(o){return e.errors.push(`\u274C Failed to query WebGL parameters: ${o}`),e}let n=i.getExtension("OES_element_index_uint");e.uint32Indices=!!n;let a=8;if(e.maxCellsUint16=Math.floor(65535/a),e.uint32Indices){let o=Math.floor(e.maxTextureSize*e.maxTextureSize/64);e.maxCellsUint32=Math.min(o,262144)}else e.maxCellsUint32=e.maxCellsUint16,e.warnings.push(`\u26A0\uFE0F OES_element_index_uint not supported - limited to ${e.maxCellsUint16} cells (e.g., 90\xD790 or 127\xD764)`);return e.recommendedMaxCells=Math.floor((e.uint32Indices?e.maxCellsUint32:e.maxCellsUint16)*.8),e.maxTextureSize<256?e.errors.push(`\u274C MAX_TEXTURE_SIZE too small: ${e.maxTextureSize} (minimum 256 required for font atlas)`):e.maxTextureSize<2048&&e.warnings.push(`\u26A0\uFE0F Small MAX_TEXTURE_SIZE: ${e.maxTextureSize} (may limit font atlas)`),(e.maxViewportDims[0]<1024||e.maxViewportDims[1]<768)&&e.warnings.push(`\u26A0\uFE0F Small MAX_VIEWPORT_DIMS: ${e.maxViewportDims[0]}\xD7${e.maxViewportDims[1]}`),i.getExtension("WEBGL_lose_context")||e.warnings.push("\u26A0\uFE0F WEBGL_lose_context not supported - may cause memory leaks"),e}initInstancedBuffers(){let e=this.gl;this.templateQuadPositions=new Float32Array([0,0,this.cellWidth,0,0,this.cellHeight,this.cellWidth,this.cellHeight]),this.templateQuadIndices=new Uint16Array([0,1,2,2,1,3]),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.bufferData(e.ARRAY_BUFFER,this.templateQuadPositions,e.STATIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.templateQuadIndices,e.STATIC_DRAW),this.instanceData=new Float32Array(this.maxCells*8),console.warn(`[TerminalGL] \u{1F680} initInstancedBuffers: maxCells=${this.maxCells}, instanceData.length=${this.instanceData.length}`),e.bindBuffer(e.ARRAY_BUFFER,this.instanceDataBuffer),e.bufferData(e.ARRAY_BUFFER,this.instanceData.byteLength,e.DYNAMIC_DRAW)}initRenderBuffers(){let e=this.cols*this.rows*2;this.maxCells=Math.ceil(e*2),this.renderPositions=new Float32Array(this.maxCells*4*2),this.renderTexCoords=new Float32Array(this.maxCells*4*2),this.renderColorIndices=new Float32Array(this.maxCells*4),this.useUint16Indices?this.renderIndices=new Uint16Array(this.maxCells*6):this.renderIndices=new Uint32Array(this.maxCells*6),this.staticPositionsInitialized=!1}precomputeStaticPositions(){let e=this.cellWidth,t=this.cellHeight,s=this.glyphOffsetX,i=this.glyphOffsetY,n=this.charWidth,a=this.charHeight,l=0,o=0,c=0;for(let h=0;h<this.rows;h++){let m=Math.round(h*t),b=Math.round(m+t);for(let v=0;v<this.cols;v++){let u=Math.round(v*e),g=Math.round(u+e);this.renderPositions[l++]=u,this.renderPositions[l++]=m,this.renderPositions[l++]=g,this.renderPositions[l++]=m,this.renderPositions[l++]=u,this.renderPositions[l++]=b,this.renderPositions[l++]=g,this.renderPositions[l++]=b,this.renderIndices[o++]=c,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+3,c+=4;let E=Math.round(u+s),p=Math.round(m+i),w=Math.round(E+n),A=Math.round(p+a);this.renderPositions[l++]=E,this.renderPositions[l++]=p,this.renderPositions[l++]=w,this.renderPositions[l++]=p,this.renderPositions[l++]=E,this.renderPositions[l++]=A,this.renderPositions[l++]=w,this.renderPositions[l++]=A,this.renderIndices[o++]=c,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+3,c+=4}}let d=this.gl;d.bindBuffer(d.ARRAY_BUFFER,this.positionBuffer),d.bufferSubData(d.ARRAY_BUFFER,0,this.renderPositions),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,this.indexBuffer),d.bufferSubData(d.ELEMENT_ARRAY_BUFFER,0,this.renderIndices),this.staticPositionsInitialized=!0}initWebGL(){let e=this.gl,t;this.useInstancing?t=`
|
|
36
36
|
// Per-vertex attributes (template quad)
|
|
37
37
|
attribute vec2 aPosition; // Local quad position (0,0 to cellW,cellH)
|
|
38
38
|
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
float paletteU = (aColorIndex + 0.5) / 256.0;
|
|
94
94
|
vColor = texture2D(uPalette, vec2(paletteU, 0.5));
|
|
95
95
|
}
|
|
96
|
-
`;let
|
|
96
|
+
`;let s=`
|
|
97
97
|
precision mediump float;
|
|
98
98
|
|
|
99
99
|
uniform sampler2D uTexture;
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
gl_FragColor = vec4(texColor.rgb * vColor.rgb, texColor.a);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
`,i=this.compileShader(e.VERTEX_SHADER,t),s=this.compileShader(e.FRAGMENT_SHADER,r);if(!i||!s)throw new Error("Shader compilation error");let a=e.createProgram();if(!a)throw new Error("Unable to create WebGL program");if(e.attachShader(a,i),e.attachShader(a,s),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS)){let l=e.getProgramInfoLog(a);throw new Error("Program linking error: "+l)}this.program=a,this.cachedTextureUniform=!1,this.cachedPaletteUniform=!1,this.aPosition=e.getAttribLocation(a,"aPosition"),this.useInstancing?(this.aTexCoord=e.getAttribLocation(a,"aInstanceOffset"),this.aColorIndex=e.getAttribLocation(a,"aInstanceUVs"),this.instanceDataBuffer=e.createBuffer()):(this.aTexCoord=e.getAttribLocation(a,"aTexCoord"),this.aColorIndex=e.getAttribLocation(a,"aColorIndex")),this.uResolution=e.getUniformLocation(a,"uResolution"),this.uTexture=e.getUniformLocation(a,"uTexture"),this.uPalette=e.getUniformLocation(a,"uPalette"),this.positionBuffer=e.createBuffer(),this.texCoordBuffer=e.createBuffer(),this.colorIndexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderPositions.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderTexCoords.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderColorIndices.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,e.DYNAMIC_DRAW),this.vaoExtension&&(this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.enableVertexAttribArray(this.aPosition),e.vertexAttribPointer(this.aPosition,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.enableVertexAttribArray(this.aTexCoord),e.vertexAttribPointer(this.aTexCoord,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.enableVertexAttribArray(this.aColorIndex),e.vertexAttribPointer(this.aColorIndex,1,e.FLOAT,!1,0,0),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null))),e.enable(e.BLEND),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA),e.viewport(0,0,this.canvas.width,this.canvas.height)}compileShader(e,t){let r=this.gl,i=r.createShader(e);return i?(r.shaderSource(i,t),r.compileShader(i),r.getShaderParameter(i,r.COMPILE_STATUS)?i:(console.error("Shader compilation error:",r.getShaderInfoLog(i)),r.deleteShader(i),null)):null}initGridOverlay(){this.gridOverlay=new I(this.containerDiv,{strokeColor:"rgba(144, 24, 24, 1)",lineWidth:1,zIndex:10}),this.updateGridOverlay()}updateGridOverlay(){if(!this.gridOverlay)return;let e=this.cols*this.cellWidth,t=this.rows*this.cellHeight,r=this.canvas.getBoundingClientRect(),i=this.containerDiv.getBoundingClientRect();this.gridOverlay.setDimensions(this.cols,this.rows,this.cellWidth,this.cellHeight,0,0),this.gridOverlay.setTransform(this.currentScale,e,t,r,i),this.gridOverlay.render()}setBitmapFont(e,t,r,i,s){this.bitmapFont=e,this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(r),this.cellWidth=Math.round(i),this.cellHeight=Math.round(s),this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers..."),this.initInstancedBuffers());try{this.generateAtlas()}catch(a){throw console.error("[TerminalGL] \u274C Failed to generate atlas:",a),a}this.buildCharCodeMap(),this.precomputeAtlasUVs(),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async setImageFont(e,t,r,i,s,a){this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(r),this.cellWidth=Math.round(i),this.cellHeight=Math.round(s),this.atlasColumns=F(a);let l=L(a);this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers for ImageFont..."),this.initInstancedBuffers()),await this.loadImageFontAtlas(e),this.charCodeToAtlasIndex.fill(65535);for(let o=0;o<=l;o++)this.charCodeToAtlasIndex[o]=o;this.precomputeImageFontUVs(a),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async loadImageFontAtlas(e){return new Promise((t,r)=>{let i=new Uint8Array(e),s=new Blob([i],{type:"image/png"}),a=URL.createObjectURL(s),l=new Image;l.onload=()=>{URL.revokeObjectURL(a),this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=l.width,this.atlasCanvas.height=l.height;let o=this.atlasCanvas.getContext("2d");if(!o){r(new Error("Failed to create 2D context for atlas"));return}o.drawImage(l,0,0),this.cachedAtlasWidth=l.width,this.cachedAtlasHeight=l.height,this.createAtlasTexture(),t()},l.onerror=()=>{URL.revokeObjectURL(a),r(new Error("Failed to load PNG image for ImageFont atlas"))},l.src=a})}precomputeImageFontUVs(e){let t=e*256;this.atlasUVs=new Float32Array(t*4);let r=this.cachedAtlasWidth,i=this.cachedAtlasHeight,s=.5/r,a=.5/i;for(let l=0;l<t;l++){let{col:o,row:c}=_(l,e),d=(o*this.charWidth+s)/r,h=(c*this.charHeight+a)/i,u=((o+1)*this.charWidth-s)/r,m=((c+1)*this.charHeight-a)/i,b=l*4;this.atlasUVs[b]=d,this.atlasUVs[b+1]=h,this.atlasUVs[b+2]=u,this.atlasUVs[b+3]=m}}generateAtlas(){if(!this.bitmapFont)return;let e=Array.from(this.bitmapFont.keys()).sort((o,c)=>o-c),t=e.length;this.atlasColumns=Math.ceil(Math.sqrt(t));let r=Math.ceil(t/this.atlasColumns),i=this.atlasColumns*this.charWidth,s=r*this.charHeight;this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=i,this.atlasCanvas.height=s;let a=this.atlasCanvas.getContext("2d");if(!a)throw new Error("Unable to create 2D context for atlas");a.clearRect(0,0,i,s),a.fillStyle="#ffffff";let l=0;for(let o of e){let c=this.bitmapFont.get(o);if(!c)continue;let d=l%this.atlasColumns,h=Math.floor(l/this.atlasColumns),u=d*this.charWidth,m=h*this.charHeight;for(let b=0;b<Math.min(c.length,this.charHeight);b++){let g=c[b];for(let E=0;E<this.charWidth;E++){let T=1<<7-E;g&T&&a.fillRect(u+E,m+b,1,1)}}l++}this.createAtlasTexture()}buildCharCodeMap(){if(!this.bitmapFont)return;this.charCodeToAtlasIndex.fill(65535);let e=Array.from(this.bitmapFont.keys()).sort((t,r)=>t-r);for(let t=0;t<e.length;t++)this.charCodeToAtlasIndex[e[t]]=t}precomputeAtlasUVs(){if(!this.bitmapFont)return;let e=this.bitmapFont.size;this.atlasUVs=new Float32Array(e*4),this.cachedAtlasWidth=this.atlasColumns*this.charWidth,this.cachedAtlasHeight=Math.ceil(e/this.atlasColumns)*this.charHeight;let t=this.cachedAtlasWidth,r=this.cachedAtlasHeight,i=.5/t,s=.5/r;for(let a=0;a<e;a++){let l=a%this.atlasColumns,o=Math.floor(a/this.atlasColumns),c=(l*this.charWidth+i)/t,d=(o*this.charHeight+s)/r,h=((l+1)*this.charWidth-i)/t,u=((o+1)*this.charHeight-s)/r,m=a*4;this.atlasUVs[m]=c,this.atlasUVs[m+1]=d,this.atlasUVs[m+2]=h,this.atlasUVs[m+3]=u}}createAtlasTexture(){if(this.atlasCanvas)try{let e=this.gl,t=e.createTexture();if(!t)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.atlasCanvas),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),this.atlasTexture=t}catch(e){throw console.error("[TerminalGL] \u274C Failed to create atlas texture:",e),e}}clear(){let e=this.gl;e&&e.clear(e.COLOR_BUFFER_BIT)}parseColor(e){if(e.startsWith("#")){let t=e.slice(1),r=0,i=0,s=0;return t.length===3?(r=parseInt(t[0]+t[0],16),i=parseInt(t[1]+t[1],16),s=parseInt(t[2]+t[2],16)):t.length===6&&(r=parseInt(t.slice(0,2),16),i=parseInt(t.slice(2,4),16),s=parseInt(t.slice(4,6),16)),[r/255,i/255,s/255,1]}if(e.startsWith("rgb")){let t=e.match(/rgba?\(([^)]+)\)/);if(t){let r=t[1].split(",").map(i=>parseFloat(i.trim()));return[r[0]/255,r[1]/255,r[2]/255,r[3]!==void 0?r[3]:1]}}return[1,1,1,1]}setupResizeObserver(){if(!(typeof ResizeObserver>"u"))try{this.resizeObserver=new ResizeObserver(()=>{try{this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Error in resize callback:",e)}}),this.resizeObserver.observe(this.parentElement),this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Failed to setup ResizeObserver:",e)}}updateCanvasSize(){let e=this.parentElement.clientWidth,t=this.parentElement.clientHeight;if(e===0||t===0)return;let r=this.cols*this.cellWidth,i=this.rows*this.cellHeight;if(r===0||i===0)return;let s=e/r,a=t/i,l=Math.min(s,a),o;switch(this.scalingMode){case p.ScalingMode.Integer:o=Math.max(1,Math.floor(l));break;case p.ScalingMode.Half:o=Math.max(1,Math.floor(l*2)/2);break;case p.ScalingMode.Quarter:o=Math.max(1,Math.floor(l*4)/4);break;case p.ScalingMode.Eighth:o=Math.max(1,Math.floor(l*8)/8);break;case p.ScalingMode.None:default:o=Math.max(.1,l);break}if(this.canvas.style.transform=`scale(${o})`,this.ambientEffectEnabled&&this.ambientEffectCanvas){let c=o*this.ambientEffectScale;this.ambientEffectCanvas.style.transform=`scale(${c})`}this.currentScale=o,this.onResizeCallback&&this.onResizeCallback(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}updateAmbientEffect(){!this.ambientEffectCanvas||!this.ambientEffectCtx||this.ambientEffectCtx.drawImage(this.canvas,0,0)}setPalette(e){let t=0;for(let r=0;r<Math.min(e.length,256);r++){let i=e[r];t=(t<<5)-t+i.r,t=(t<<5)-t+i.g,t=(t<<5)-t+i.b,t=(t<<5)-t+i.a,t=t|0}if(t!==this.paletteHash){this.paletteHash=t;for(let r=0;r<e.length&&r<256;r++){let i=e[r],s=r*4;this.paletteFloat[s]=i.r/255,this.paletteFloat[s+1]=i.g/255,this.paletteFloat[s+2]=i.b/255,this.paletteFloat[s+3]=i.a/255}this.updatePaletteTexture()}}updatePaletteTexture(){try{let e=this.gl;this.paletteTexture||(this.paletteTexture=e.createTexture()),e.bindTexture(e.TEXTURE_2D,this.paletteTexture);let t=new Uint8Array(256*4);for(let r=0;r<256;r++){let i=r*4;t[i]=this.paletteFloat[i]*255,t[i+1]=this.paletteFloat[i+1]*255,t[i+2]=this.paletteFloat[i+2]*255,t[i+3]=this.paletteFloat[i+3]*255}e.texImage2D(e.TEXTURE_2D,0,e.RGBA,256,1,0,e.RGBA,e.UNSIGNED_BYTE,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.bindTexture(e.TEXTURE_2D,null)}catch(e){throw console.error("[TerminalGL] \u274C Failed to update palette texture:",e),e}}renderDisplayData(e){try{if(!this.isReady()){console.warn("[TerminalGL] \u26A0\uFE0F Not ready: font not loaded yet");return}(e.width!==this.cols||e.height!==this.rows)&&this.resize(e.width,e.height),this.renderDirect(e),this.ambientEffectEnabled&&this.ambientEffectCanvas&&this.ambientEffectCtx&&this.updateAmbientEffect()}catch(t){console.error("[TerminalGL] \u274C Error rendering display data:",t)}}renderDirect(e){let t=this.gl;if(!this.staticPositionsInitialized&&!this.useInstancing&&this.precomputeStaticPositions(),this.canvasBgColor!==null){let r=this.parseColor(this.canvasBgColor);t.clearColor(r[0],r[1],r[2],r[3])}else t.clearColor(0,0,0,0);t.clear(t.COLOR_BUFFER_BIT),this.useInstancing?this.renderInstanced(e):this.renderDirectBuffers(e)}renderInstanced(e){let t=this.gl,r=this.instancedExtension;if(!this.instanceData||this.instanceData.length===0){console.warn("[TerminalGL] \u26A0\uFE0F Instance data not initialized, falling back to standard rendering"),this.useInstancing=!1,this.renderDirectBuffers(e);return}let i=e.width*e.height;if(this.useUint16Indices&&i>8191){console.warn(`[TerminalGL] \u26A0\uFE0F Terminal too large for instanced rendering with Uint16 (${i} cells > 8191). Falling back to standard rendering.`),this.useInstancing=!1,this.renderDirectBuffers(e);return}let s=0,a=this.instanceData.length/8;for(let u=0;u<e.height;u++)for(let m=0;m<e.width;m++){let b=e.cells[u*e.width+m],g=b.bgColorIndex,E=b.fgColorIndex,T=this.canvasBgColor!==null&&g===255,R=b.char===" "||E===255;if(!T){if(s>=a){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${s}, max=${a}`);break}let v=s*8;this.instanceData[v]=m,this.instanceData[v+1]=u,this.instanceData[v+2]=0,this.instanceData[v+3]=0,this.instanceData[v+4]=0,this.instanceData[v+5]=0,this.instanceData[v+6]=g,this.instanceData[v+7]=0,s++}if(!R){let v=b.char.charCodeAt(0),C=this.charCodeToAtlasIndex[v];if(C!==65535){if(s>=a){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${s}, max=${a}`);break}let w=C*4,x=s*8;this.instanceData[x]=m,this.instanceData[x+1]=u,this.instanceData[x+2]=this.atlasUVs[w],this.instanceData[x+3]=this.atlasUVs[w+1],this.instanceData[x+4]=this.atlasUVs[w+2],this.instanceData[x+5]=this.atlasUVs[w+3],this.instanceData[x+6]=0,this.instanceData[x+7]=E,s++}}}if(s===0){console.warn("[TerminalGL] \u26A0\uFE0F No instances to draw (all cells skipped)");return}t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.instanceData.subarray(0,s*8)),t.useProgram(this.program),t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),r.vertexAttribDivisorANGLE(this.aPosition,0),t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer);let l=8*Float32Array.BYTES_PER_ELEMENT,o=t.getAttribLocation(this.program,"aInstanceOffset");t.enableVertexAttribArray(o),t.vertexAttribPointer(o,2,t.FLOAT,!1,l,0),r.vertexAttribDivisorANGLE(o,1);let c=t.getAttribLocation(this.program,"aInstanceUVs");t.enableVertexAttribArray(c),t.vertexAttribPointer(c,4,t.FLOAT,!1,l,2*Float32Array.BYTES_PER_ELEMENT),r.vertexAttribDivisorANGLE(c,1);let d=t.getAttribLocation(this.program,"aInstanceColors");t.enableVertexAttribArray(d),t.vertexAttribPointer(d,2,t.FLOAT,!1,l,6*Float32Array.BYTES_PER_ELEMENT),r.vertexAttribDivisorANGLE(d,1),t.uniform2f(this.uResolution,this.canvas.width,this.canvas.height);let h=t.getUniformLocation(this.program,"uCellSize");t.uniform2f(h,this.cellWidth,this.cellHeight),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),t.uniform1i(this.uTexture,0),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),t.uniform1i(this.uPalette,1),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),r.drawElementsInstancedANGLE(t.TRIANGLES,6,t.UNSIGNED_SHORT,0,s),r.vertexAttribDivisorANGLE(this.aPosition,0),r.vertexAttribDivisorANGLE(o,0),r.vertexAttribDivisorANGLE(c,0),r.vertexAttribDivisorANGLE(d,0)}renderDirectBuffers(e){let t=this.gl,r=e.width*e.height,i=r*2;if(i>this.maxCells){console.error(`[TerminalGL] \u274C Buffer overflow detected! Trying to render ${i} quads but buffer capacity is ${this.maxCells}. This should not happen - resize() should have reallocated.`);return}let s=0,a=0,l=e.cells,o=r;for(let b=0;b<o;b++){let g=l[b],E=g.bgColorIndex,R=this.canvasBgColor!==null&&E===255?255:E,v=0;for(let x=0;x<4;x++)this.renderTexCoords[s++]=v,this.renderTexCoords[s++]=v,this.renderColorIndices[a++]=R;let C=g.fgColorIndex,w=g.char;if(w===" "||C===255)for(let x=0;x<4;x++)this.renderTexCoords[s++]=0,this.renderTexCoords[s++]=0,this.renderColorIndices[a++]=255;else{let x=w.charCodeAt(0),S=this.charCodeToAtlasIndex[x];if(S!==65535){let y=S*4,G=this.atlasUVs[y],W=this.atlasUVs[y+1],O=this.atlasUVs[y+2],H=this.atlasUVs[y+3];this.renderTexCoords[s++]=G,this.renderTexCoords[s++]=W,this.renderColorIndices[a++]=C,this.renderTexCoords[s++]=O,this.renderTexCoords[s++]=W,this.renderColorIndices[a++]=C,this.renderTexCoords[s++]=G,this.renderTexCoords[s++]=H,this.renderColorIndices[a++]=C,this.renderTexCoords[s++]=O,this.renderTexCoords[s++]=H,this.renderColorIndices[a++]=C}else for(let y=0;y<4;y++)this.renderTexCoords[s++]=0,this.renderTexCoords[s++]=0,this.renderColorIndices[a++]=255}}(s!==o*2*4*2||a!==o*2*4)&&console.error("[TerminalGL] \u274C Buffer index mismatch!",{texIdx:s,colorIdx:a,expected:o*2*4}),t.useProgram(this.program),this.vao&&this.vaoExtension?(this.vaoExtension.bindVertexArrayOES(this.vao),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,s)),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a))):(t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,s)),t.enableVertexAttribArray(this.aTexCoord),t.vertexAttribPointer(this.aTexCoord,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a)),t.enableVertexAttribArray(this.aColorIndex),t.vertexAttribPointer(this.aColorIndex,1,t.FLOAT,!1,0,0));let c=this.canvas.width,d=this.canvas.height;(this.cachedResolution[0]!==c||this.cachedResolution[1]!==d)&&(t.uniform2f(this.uResolution,c,d),this.cachedResolution[0]=c,this.cachedResolution[1]=d),this.cachedTextureUnit!==0&&(t.activeTexture(t.TEXTURE0),this.cachedTextureUnit=0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),this.cachedTextureUniform||(t.uniform1i(this.uTexture,0),this.cachedTextureUniform=!0),this.cachedPaletteUnit!==1&&(t.activeTexture(t.TEXTURE1),this.cachedPaletteUnit=1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),this.cachedPaletteUniform||(t.uniform1i(this.uPalette,1),this.cachedPaletteUniform=!0),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer);let u=e.width*e.height*2*6,m=this.useUint16Indices?t.UNSIGNED_SHORT:t.UNSIGNED_INT;t.drawElements(t.TRIANGLES,u,m,0)}resize(e,t){if(!Number.isInteger(e)||e<=0){console.error(`[TerminalGL] \u274C Invalid cols: ${e}. Must be positive integer.`);return}if(!Number.isInteger(t)||t<=0){console.error(`[TerminalGL] \u274C Invalid rows: ${t}. Must be positive integer.`);return}if(e===this.cols&&t===this.rows)return;let r=e*t,i=this.useUint16Indices?8191:262144;if(r>i){let d=Math.floor(Math.sqrt(i));console.error(`[TerminalGL] \u274C Cannot resize to ${e}\xD7${t} (${r} cells). Device limit: ${i} cells (max ~${d}\xD7${d}). ${this.useUint16Indices?"Device lacks OES_element_index_uint extension.":""}`);return}let s=B.checkCompatibility();r>s.recommendedMaxCells&&console.warn(`[TerminalGL] \u26A0\uFE0F Resizing to ${e}\xD7${t} (${r} cells) exceeds recommended limit (${s.recommendedMaxCells} cells). Performance may degrade.`),this.cols=e,this.rows=t,this.staticPositionsInitialized=!1;let a=this.cols*this.rows*2,l=Math.ceil(a*1.5),o=a>this.maxCells,c=this.maxCells>l*4;if(o||c){let d=this.maxCells;this.maxCells=l,this.renderPositions=new Float32Array(this.maxCells*4*2),this.renderTexCoords=new Float32Array(this.maxCells*4*2),this.renderColorIndices=new Float32Array(this.maxCells*4),this.useUint16Indices?this.renderIndices=new Uint16Array(this.maxCells*6):this.renderIndices=new Uint32Array(this.maxCells*6);let h=this.gl;this.useInstancing||(h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderPositions.byteLength,h.DYNAMIC_DRAW)),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderTexCoords.byteLength,h.DYNAMIC_DRAW),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderColorIndices.byteLength,h.DYNAMIC_DRAW),h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),h.bufferData(h.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,h.DYNAMIC_DRAW),this.vaoExtension&&this.vao&&(this.vaoExtension.deleteVertexArrayOES(this.vao),this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.enableVertexAttribArray(this.aPosition),h.vertexAttribPointer(this.aPosition,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.enableVertexAttribArray(this.aTexCoord),h.vertexAttribPointer(this.aTexCoord,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.enableVertexAttribArray(this.aColorIndex),h.vertexAttribPointer(this.aColorIndex,1,h.FLOAT,!1,0,0),h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null)));let u=o?"\u{1F4C8} Growing":"\u{1F4C9} Shrinking",m=d*160/1048576,b=this.maxCells*160/1048576;console.warn(`[TerminalGL] ${u} buffers: ${m.toFixed(2)}MB \u2192 ${b.toFixed(2)}MB (${d} \u2192 ${this.maxCells} quads)`)}this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.ambientEffectEnabled&&this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.width=`${this.canvas.width}px`,this.ambientEffectCanvas.style.height=`${this.canvas.height}px`),this.showGrid&&this.gridOverlay&&this.updateGridOverlay(),this.updateCanvasSize()}getCanvas(){return this.canvas}getGridSize(){return{cols:this.cols,rows:this.rows}}getCellWidth(){return this.cellWidth}getCellHeight(){return this.cellHeight}getCurrentScale(){return this.currentScale}getBaseDimensions(){return{width:this.cols*this.cellWidth,height:this.rows*this.cellHeight}}setOnResizeCallback(e){this.onResizeCallback=e}clearOnResizeCallback(){this.onResizeCallback=void 0}setScalingMode(e){this.scalingMode!==e&&(this.scalingMode=e,this.updateCanvasSize())}getScalingMode(){return this.scalingMode}setGrid(e){e.enabled?(this.gridOverlay?this.gridOverlay.setStyle({strokeColor:e.color,lineWidth:e.lineWidth}):this.gridOverlay=new I(this.containerDiv,{strokeColor:e.color??"rgba(144, 24, 24, 1)",lineWidth:e.lineWidth??1,zIndex:10}),this.showGrid=!0,this.gridOverlay.setVisible(!0),this.updateGridOverlay()):(this.showGrid=!1,this.gridOverlay&&this.gridOverlay.setVisible(!1))}isGridEnabled(){return this.showGrid}setAmbientEffect(e){typeof e=="boolean"?this.ambientEffectEnabled=e:(this.ambientEffectEnabled=!0,e.blur!==void 0&&(this.ambientEffectBlur=e.blur),e.scale!==void 0&&(this.ambientEffectScale=e.scale)),this.ambientEffectEnabled&&!this.ambientEffectCanvas&&this.createAmbientEffectCanvas(),this.ambientEffectCanvas&&(this.ambientEffectEnabled?(this.ambientEffectCanvas.style.display="block",this.ambientEffectCanvas.style.filter=`blur(${this.ambientEffectBlur}px)`,this.ambientEffectCanvas.style.transform=`scale(${this.ambientEffectScale})`,this.updateAmbientEffect()):this.ambientEffectCanvas.style.display="none")}createAmbientEffectCanvas(){this.ambientEffectCanvas||(this.ambientEffectCanvas=document.createElement("canvas"),this.ambientEffectCanvas.className="terminalgl-ambient-effect-canvas",this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.cssText=`
|
|
116
|
+
`,i=this.compileShader(e.VERTEX_SHADER,t),n=this.compileShader(e.FRAGMENT_SHADER,s);if(!i||!n)throw new Error("Shader compilation error");let a=e.createProgram();if(!a)throw new Error("Unable to create WebGL program");if(e.attachShader(a,i),e.attachShader(a,n),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS)){let l=e.getProgramInfoLog(a);throw new Error("Program linking error: "+l)}this.program=a,this.cachedTextureUniform=!1,this.cachedPaletteUniform=!1,this.aPosition=e.getAttribLocation(a,"aPosition"),this.useInstancing?(this.aInstanceOffset=e.getAttribLocation(a,"aInstanceOffset"),this.aInstanceUVs=e.getAttribLocation(a,"aInstanceUVs"),this.aInstanceColors=e.getAttribLocation(a,"aInstanceColors"),this.uCellSize=e.getUniformLocation(a,"uCellSize"),this.instanceDataBuffer=e.createBuffer(),this.aTexCoord=this.aInstanceOffset,this.aColorIndex=this.aInstanceUVs):(this.aTexCoord=e.getAttribLocation(a,"aTexCoord"),this.aColorIndex=e.getAttribLocation(a,"aColorIndex")),this.uResolution=e.getUniformLocation(a,"uResolution"),this.uTexture=e.getUniformLocation(a,"uTexture"),this.uPalette=e.getUniformLocation(a,"uPalette"),this.positionBuffer=e.createBuffer(),this.texCoordBuffer=e.createBuffer(),this.colorIndexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderPositions.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderTexCoords.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderColorIndices.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,e.DYNAMIC_DRAW),this.vaoExtension&&(this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.enableVertexAttribArray(this.aPosition),e.vertexAttribPointer(this.aPosition,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.enableVertexAttribArray(this.aTexCoord),e.vertexAttribPointer(this.aTexCoord,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.enableVertexAttribArray(this.aColorIndex),e.vertexAttribPointer(this.aColorIndex,1,e.FLOAT,!1,0,0),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null))),e.enable(e.BLEND),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA),e.viewport(0,0,this.canvas.width,this.canvas.height)}compileShader(e,t){let s=this.gl,i=s.createShader(e);return i?(s.shaderSource(i,t),s.compileShader(i),s.getShaderParameter(i,s.COMPILE_STATUS)?i:(console.error("Shader compilation error:",s.getShaderInfoLog(i)),s.deleteShader(i),null)):null}initGridOverlay(){this.gridOverlay=new I(this.containerDiv,{strokeColor:"rgba(144, 24, 24, 1)",lineWidth:1,zIndex:10}),this.updateGridOverlay()}updateGridOverlay(){if(!this.gridOverlay)return;let e=this.cols*this.cellWidth,t=this.rows*this.cellHeight,s=this.canvas.getBoundingClientRect(),i=this.containerDiv.getBoundingClientRect();this.gridOverlay.setDimensions(this.cols,this.rows,this.cellWidth,this.cellHeight,0,0),this.gridOverlay.setTransform(this.currentScale,e,t,s,i),this.gridOverlay.render()}setBitmapFont(e,t,s,i,n){this.bitmapFont=e,this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(s),this.cellWidth=Math.round(i),this.cellHeight=Math.round(n),this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers..."),this.initInstancedBuffers());try{this.generateAtlas()}catch(a){throw console.error("[TerminalGL] \u274C Failed to generate atlas:",a),a}this.buildCharCodeMap(),this.precomputeAtlasUVs(),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async setImageFont(e,t,s,i,n,a){this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(s),this.cellWidth=Math.round(i),this.cellHeight=Math.round(n),this.atlasColumns=B(a);let l=F(a);this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers for ImageFont..."),this.initInstancedBuffers()),await this.loadImageFontAtlas(e),this.charCodeToAtlasIndex.fill(65535);for(let o=0;o<=l;o++)this.charCodeToAtlasIndex[o]=o;this.precomputeImageFontUVs(a),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async loadImageFontAtlas(e){return new Promise((t,s)=>{let i=new Uint8Array(e),n=new Blob([i],{type:"image/png"}),a=URL.createObjectURL(n),l=new Image;l.onload=()=>{URL.revokeObjectURL(a),this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=l.width,this.atlasCanvas.height=l.height;let o=this.atlasCanvas.getContext("2d");if(!o){s(new Error("Failed to create 2D context for atlas"));return}o.drawImage(l,0,0),this.cachedAtlasWidth=l.width,this.cachedAtlasHeight=l.height,this.createAtlasTexture(),t()},l.onerror=()=>{URL.revokeObjectURL(a),s(new Error("Failed to load PNG image for ImageFont atlas"))},l.src=a})}precomputeImageFontUVs(e){let t=e*256;this.atlasUVs=new Float32Array(t*4);let s=this.cachedAtlasWidth,i=this.cachedAtlasHeight,n=.5/s,a=.5/i;for(let l=0;l<t;l++){let{col:o,row:c}=L(l,e),d=(o*this.charWidth+n)/s,h=(c*this.charHeight+a)/i,m=((o+1)*this.charWidth-n)/s,b=((c+1)*this.charHeight-a)/i,v=l*4;this.atlasUVs[v]=d,this.atlasUVs[v+1]=h,this.atlasUVs[v+2]=m,this.atlasUVs[v+3]=b}}generateAtlas(){if(!this.bitmapFont)return;let e=Array.from(this.bitmapFont.keys()).sort((o,c)=>o-c),t=e.length;this.atlasColumns=Math.ceil(Math.sqrt(t));let s=Math.ceil(t/this.atlasColumns),i=this.atlasColumns*this.charWidth,n=s*this.charHeight;this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=i,this.atlasCanvas.height=n;let a=this.atlasCanvas.getContext("2d");if(!a)throw new Error("Unable to create 2D context for atlas");a.clearRect(0,0,i,n),a.fillStyle="#ffffff";let l=0;for(let o of e){let c=this.bitmapFont.get(o);if(!c)continue;let d=l%this.atlasColumns,h=Math.floor(l/this.atlasColumns),m=d*this.charWidth,b=h*this.charHeight;for(let v=0;v<Math.min(c.length,this.charHeight);v++){let u=c[v];for(let g=0;g<this.charWidth;g++){let E=1<<7-g;u&E&&a.fillRect(m+g,b+v,1,1)}}l++}this.createAtlasTexture()}buildCharCodeMap(){if(!this.bitmapFont)return;this.charCodeToAtlasIndex.fill(65535);let e=Array.from(this.bitmapFont.keys()).sort((t,s)=>t-s);for(let t=0;t<e.length;t++)this.charCodeToAtlasIndex[e[t]]=t}precomputeAtlasUVs(){if(!this.bitmapFont)return;let e=this.bitmapFont.size;this.atlasUVs=new Float32Array(e*4),this.cachedAtlasWidth=this.atlasColumns*this.charWidth,this.cachedAtlasHeight=Math.ceil(e/this.atlasColumns)*this.charHeight;let t=this.cachedAtlasWidth,s=this.cachedAtlasHeight,i=.5/t,n=.5/s;for(let a=0;a<e;a++){let l=a%this.atlasColumns,o=Math.floor(a/this.atlasColumns),c=(l*this.charWidth+i)/t,d=(o*this.charHeight+n)/s,h=((l+1)*this.charWidth-i)/t,m=((o+1)*this.charHeight-n)/s,b=a*4;this.atlasUVs[b]=c,this.atlasUVs[b+1]=d,this.atlasUVs[b+2]=h,this.atlasUVs[b+3]=m}}createAtlasTexture(){if(this.atlasCanvas)try{let e=this.gl,t=e.createTexture();if(!t)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.atlasCanvas),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),this.atlasTexture=t}catch(e){throw console.error("[TerminalGL] \u274C Failed to create atlas texture:",e),e}}clear(){let e=this.gl;e&&e.clear(e.COLOR_BUFFER_BIT)}parseColor(e){if(e.startsWith("#")){let t=e.slice(1),s=0,i=0,n=0;return t.length===3?(s=parseInt(t[0]+t[0],16),i=parseInt(t[1]+t[1],16),n=parseInt(t[2]+t[2],16)):t.length===6&&(s=parseInt(t.slice(0,2),16),i=parseInt(t.slice(2,4),16),n=parseInt(t.slice(4,6),16)),[s/255,i/255,n/255,1]}if(e.startsWith("rgb")){let t=e.match(/rgba?\(([^)]+)\)/);if(t){let s=t[1].split(",").map(i=>parseFloat(i.trim()));return[s[0]/255,s[1]/255,s[2]/255,s[3]!==void 0?s[3]:1]}}return[1,1,1,1]}setupResizeObserver(){if(!(typeof ResizeObserver>"u"))try{this.resizeObserver=new ResizeObserver(()=>{try{this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Error in resize callback:",e)}}),this.resizeObserver.observe(this.parentElement),this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Failed to setup ResizeObserver:",e)}}updateCanvasSize(){let e=this.parentElement.clientWidth,t=this.parentElement.clientHeight;if(e===0||t===0)return;let s=this.cols*this.cellWidth,i=this.rows*this.cellHeight;if(s===0||i===0)return;let n=e/s,a=t/i,l=Math.min(n,a),o;switch(this.scalingMode){case x.ScalingMode.Integer:o=Math.max(1,Math.floor(l));break;case x.ScalingMode.Half:o=Math.max(1,Math.floor(l*2)/2);break;case x.ScalingMode.Quarter:o=Math.max(1,Math.floor(l*4)/4);break;case x.ScalingMode.Eighth:o=Math.max(1,Math.floor(l*8)/8);break;case x.ScalingMode.Responsive:o=1;break;case x.ScalingMode.None:default:o=Math.max(.1,l);break}if(this.canvas.style.transform=`scale(${o})`,this.ambientEffectEnabled&&this.ambientEffectCanvas){let c=o*this.ambientEffectScale;this.ambientEffectCanvas.style.transform=`scale(${c})`}this.currentScale=o,this.onResizeCallback&&this.onResizeCallback(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}updateAmbientEffect(){!this.ambientEffectCanvas||!this.ambientEffectCtx||this.ambientEffectCtx.drawImage(this.canvas,0,0)}setPalette(e){let t=0;for(let s=0;s<Math.min(e.length,256);s++){let i=e[s];t=(t<<5)-t+i.r,t=(t<<5)-t+i.g,t=(t<<5)-t+i.b,t=(t<<5)-t+i.a,t=t|0}if(t!==this.paletteHash){this.paletteHash=t;for(let s=0;s<e.length&&s<256;s++){let i=e[s],n=s*4;this.paletteFloat[n]=i.r/255,this.paletteFloat[n+1]=i.g/255,this.paletteFloat[n+2]=i.b/255,this.paletteFloat[n+3]=i.a/255}this.updatePaletteTexture()}}updatePaletteTexture(){try{let e=this.gl;this.paletteTexture||(this.paletteTexture=e.createTexture()),e.bindTexture(e.TEXTURE_2D,this.paletteTexture);let t=new Uint8Array(256*4);for(let s=0;s<256;s++){let i=s*4;t[i]=this.paletteFloat[i]*255,t[i+1]=this.paletteFloat[i+1]*255,t[i+2]=this.paletteFloat[i+2]*255,t[i+3]=this.paletteFloat[i+3]*255}e.texImage2D(e.TEXTURE_2D,0,e.RGBA,256,1,0,e.RGBA,e.UNSIGNED_BYTE,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.bindTexture(e.TEXTURE_2D,null)}catch(e){throw console.error("[TerminalGL] \u274C Failed to update palette texture:",e),e}}renderDisplayData(e){try{if(!this.isReady()){console.warn("[TerminalGL] \u26A0\uFE0F Not ready: font not loaded yet");return}(e.width!==this.cols||e.height!==this.rows)&&this.resize(e.width,e.height),this.renderDirect(e),this.ambientEffectEnabled&&this.ambientEffectCanvas&&this.ambientEffectCtx&&this.updateAmbientEffect()}catch(t){console.error("[TerminalGL] \u274C Error rendering display data:",t)}}renderDirect(e){let t=this.gl;if(!this.staticPositionsInitialized&&!this.useInstancing&&this.precomputeStaticPositions(),this.canvasBgColor!==null){let s=this.parseColor(this.canvasBgColor);t.clearColor(s[0],s[1],s[2],s[3])}else t.clearColor(0,0,0,0);t.clear(t.COLOR_BUFFER_BIT),this.useInstancing?this.renderInstanced(e):this.renderDirectBuffers(e)}renderInstanced(e){let t=this.gl,s=this.instancedExtension;if(!this.instanceData||this.instanceData.length===0){console.warn("[TerminalGL] \u26A0\uFE0F Instance data not initialized, falling back to standard rendering"),this.renderDirectBuffers(e);return}let i=0,n=this.instanceData.length/8,a=e.width*e.height*2;if(a>n){console.error(`[TerminalGL] \u274C Instance buffer too small! Need ${a}, have ${n}. Display size: ${e.width}\xD7${e.height}, buffer was sized for smaller terminal.`),this.renderDirectBuffers(e);return}for(let o=0;o<e.height;o++)for(let c=0;c<e.width;c++){let d=e.cells[o*e.width+c],h=d.bgColorIndex,m=d.fgColorIndex,b=this.canvasBgColor!==null&&h===255,v=d.char===" "||m===255;if(!b){if(i>=n){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${i}, max=${n}`);break}let u=i*8;this.instanceData[u]=c,this.instanceData[u+1]=o,this.instanceData[u+2]=0,this.instanceData[u+3]=0,this.instanceData[u+4]=0,this.instanceData[u+5]=0,this.instanceData[u+6]=h,this.instanceData[u+7]=0,i++}if(!v){let u=d.char.charCodeAt(0),g=this.charCodeToAtlasIndex[u];if(g!==65535){if(i>=n){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${i}, max=${n}`);break}let E=g*4,p=i*8;this.instanceData[p]=c,this.instanceData[p+1]=o,this.instanceData[p+2]=this.atlasUVs[E],this.instanceData[p+3]=this.atlasUVs[E+1],this.instanceData[p+4]=this.atlasUVs[E+2],this.instanceData[p+5]=this.atlasUVs[E+3],this.instanceData[p+6]=0,this.instanceData[p+7]=m,i++}}}if(i===0){console.warn("[TerminalGL] \u26A0\uFE0F No instances to draw (all cells skipped)");return}t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.instanceData.subarray(0,i*8)),t.useProgram(this.program),t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),s.vertexAttribDivisorANGLE(this.aPosition,0),t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer);let l=8*Float32Array.BYTES_PER_ELEMENT;t.enableVertexAttribArray(this.aInstanceOffset),t.vertexAttribPointer(this.aInstanceOffset,2,t.FLOAT,!1,l,0),s.vertexAttribDivisorANGLE(this.aInstanceOffset,1),t.enableVertexAttribArray(this.aInstanceUVs),t.vertexAttribPointer(this.aInstanceUVs,4,t.FLOAT,!1,l,2*Float32Array.BYTES_PER_ELEMENT),s.vertexAttribDivisorANGLE(this.aInstanceUVs,1),t.enableVertexAttribArray(this.aInstanceColors),t.vertexAttribPointer(this.aInstanceColors,2,t.FLOAT,!1,l,6*Float32Array.BYTES_PER_ELEMENT),s.vertexAttribDivisorANGLE(this.aInstanceColors,1),t.uniform2f(this.uResolution,this.canvas.width,this.canvas.height),t.uniform2f(this.uCellSize,this.cellWidth,this.cellHeight),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),t.uniform1i(this.uTexture,0),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),t.uniform1i(this.uPalette,1),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),s.drawElementsInstancedANGLE(t.TRIANGLES,6,t.UNSIGNED_SHORT,0,i),s.vertexAttribDivisorANGLE(this.aPosition,0),s.vertexAttribDivisorANGLE(this.aInstanceOffset,0),s.vertexAttribDivisorANGLE(this.aInstanceUVs,0),s.vertexAttribDivisorANGLE(this.aInstanceColors,0)}renderDirectBuffers(e){let t=this.gl,s=e.width*e.height,i=s*2;if(i>this.maxCells){console.error(`[TerminalGL] \u274C Buffer overflow detected! Trying to render ${i} quads but buffer capacity is ${this.maxCells}. This should not happen - resize() should have reallocated.`);return}let n=0,a=0,l=e.cells,o=s;for(let v=0;v<o;v++){let u=l[v],g=u.bgColorIndex,p=this.canvasBgColor!==null&&g===255?255:g,w=0;for(let T=0;T<4;T++)this.renderTexCoords[n++]=w,this.renderTexCoords[n++]=w,this.renderColorIndices[a++]=p;let A=u.fgColorIndex,S=u.char;if(S===" "||A===255)for(let T=0;T<4;T++)this.renderTexCoords[n++]=0,this.renderTexCoords[n++]=0,this.renderColorIndices[a++]=255;else{let T=S.charCodeAt(0),P=this.charCodeToAtlasIndex[T];if(P!==65535){let R=P*4,G=this.atlasUVs[R],W=this.atlasUVs[R+1],O=this.atlasUVs[R+2],H=this.atlasUVs[R+3];this.renderTexCoords[n++]=G,this.renderTexCoords[n++]=W,this.renderColorIndices[a++]=A,this.renderTexCoords[n++]=O,this.renderTexCoords[n++]=W,this.renderColorIndices[a++]=A,this.renderTexCoords[n++]=G,this.renderTexCoords[n++]=H,this.renderColorIndices[a++]=A,this.renderTexCoords[n++]=O,this.renderTexCoords[n++]=H,this.renderColorIndices[a++]=A}else for(let R=0;R<4;R++)this.renderTexCoords[n++]=0,this.renderTexCoords[n++]=0,this.renderColorIndices[a++]=255}}(n!==o*2*4*2||a!==o*2*4)&&console.error("[TerminalGL] \u274C Buffer index mismatch!",{texIdx:n,colorIdx:a,expected:o*2*4}),t.useProgram(this.program),this.vao&&this.vaoExtension?(this.vaoExtension.bindVertexArrayOES(this.vao),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,n)),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a))):(t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,n)),t.enableVertexAttribArray(this.aTexCoord),t.vertexAttribPointer(this.aTexCoord,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a)),t.enableVertexAttribArray(this.aColorIndex),t.vertexAttribPointer(this.aColorIndex,1,t.FLOAT,!1,0,0));let c=this.canvas.width,d=this.canvas.height;(this.cachedResolution[0]!==c||this.cachedResolution[1]!==d)&&(t.uniform2f(this.uResolution,c,d),this.cachedResolution[0]=c,this.cachedResolution[1]=d),this.cachedTextureUnit!==0&&(t.activeTexture(t.TEXTURE0),this.cachedTextureUnit=0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),this.cachedTextureUniform||(t.uniform1i(this.uTexture,0),this.cachedTextureUniform=!0),this.cachedPaletteUnit!==1&&(t.activeTexture(t.TEXTURE1),this.cachedPaletteUnit=1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),this.cachedPaletteUniform||(t.uniform1i(this.uPalette,1),this.cachedPaletteUniform=!0),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer);let m=e.width*e.height*2*6,b=this.useUint16Indices?t.UNSIGNED_SHORT:t.UNSIGNED_INT;t.drawElements(t.TRIANGLES,m,b,0)}resize(e,t){if(!Number.isInteger(e)||e<=0){console.error(`[TerminalGL] \u274C Invalid cols: ${e}. Must be positive integer.`);return}if(!Number.isInteger(t)||t<=0){console.error(`[TerminalGL] \u274C Invalid rows: ${t}. Must be positive integer.`);return}if(e===this.cols&&t===this.rows)return;let s=e*t,i=this.useInstancing?262144:this.useUint16Indices?8191:262144;if(s>i){let d=Math.floor(Math.sqrt(i));console.error(`[TerminalGL] \u274C Cannot resize to ${e}\xD7${t} (${s} cells). Device limit: ${i} cells (max ~${d}\xD7${d}). ${!this.useInstancing&&this.useUint16Indices?"Device lacks OES_element_index_uint extension.":""}`);return}let n=U.checkCompatibility();s>n.recommendedMaxCells&&console.warn(`[TerminalGL] \u26A0\uFE0F Resizing to ${e}\xD7${t} (${s} cells) exceeds recommended limit (${n.recommendedMaxCells} cells). Performance may degrade.`),this.cols=e,this.rows=t,this.staticPositionsInitialized=!1;let a=this.cols*this.rows*2,l=Math.ceil(a*1.5),o=a>this.maxCells,c=this.maxCells>l*4;if(console.warn(`[TerminalGL] \u{1F4D0} resize check: cols=${e}, rows=${t}, newMaxCells=${a}, this.maxCells=${this.maxCells}, needGrow=${o}, needShrink=${c}`),o||c){let d=this.maxCells;if(this.maxCells=l,console.warn(`[TerminalGL] \u{1F4D0} resize realloc: ${d} \u2192 ${this.maxCells} (needGrow=${o}, needShrink=${c})`),this.renderPositions=new Float32Array(this.maxCells*4*2),this.renderTexCoords=new Float32Array(this.maxCells*4*2),this.renderColorIndices=new Float32Array(this.maxCells*4),this.useUint16Indices?this.renderIndices=new Uint16Array(this.maxCells*6):this.renderIndices=new Uint32Array(this.maxCells*6),this.useInstancing&&this.instanceDataBuffer){this.instanceData=new Float32Array(this.maxCells*8);let u=this.gl;u.bindBuffer(u.ARRAY_BUFFER,this.instanceDataBuffer),u.bufferData(u.ARRAY_BUFFER,this.instanceData.byteLength,u.DYNAMIC_DRAW)}let h=this.gl;this.useInstancing||(h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderPositions.byteLength,h.DYNAMIC_DRAW)),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderTexCoords.byteLength,h.DYNAMIC_DRAW),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderColorIndices.byteLength,h.DYNAMIC_DRAW),this.useInstancing||(h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),h.bufferData(h.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,h.DYNAMIC_DRAW)),this.vaoExtension&&this.vao&&(this.vaoExtension.deleteVertexArrayOES(this.vao),this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.enableVertexAttribArray(this.aPosition),h.vertexAttribPointer(this.aPosition,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.enableVertexAttribArray(this.aTexCoord),h.vertexAttribPointer(this.aTexCoord,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.enableVertexAttribArray(this.aColorIndex),h.vertexAttribPointer(this.aColorIndex,1,h.FLOAT,!1,0,0),h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null)));let m=o?"\u{1F4C8} Growing":"\u{1F4C9} Shrinking",b=d*160/1048576,v=this.maxCells*160/1048576;console.warn(`[TerminalGL] ${m} buffers: ${b.toFixed(2)}MB \u2192 ${v.toFixed(2)}MB (${d} \u2192 ${this.maxCells} quads)`)}this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.canvas.style.width=`${this.canvas.width}px`,this.canvas.style.height=`${this.canvas.height}px`,this.ambientEffectEnabled&&this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.width=`${this.canvas.width}px`,this.ambientEffectCanvas.style.height=`${this.canvas.height}px`),this.showGrid&&this.gridOverlay&&this.updateGridOverlay(),this.updateCanvasSize()}getCanvas(){return this.canvas}getGridSize(){return{cols:this.cols,rows:this.rows}}getCellWidth(){return this.cellWidth}getCellHeight(){return this.cellHeight}getCurrentScale(){return this.currentScale}getBaseDimensions(){return{width:this.cols*this.cellWidth,height:this.rows*this.cellHeight}}setOnResizeCallback(e){this.onResizeCallback=e}clearOnResizeCallback(){this.onResizeCallback=void 0}getAvailableSize(){return{width:this.parentElement.clientWidth,height:this.parentElement.clientHeight}}setScalingMode(e){this.scalingMode!==e&&(this.scalingMode=e,this.updateCanvasSize())}getScalingMode(){return this.scalingMode}setCellSize(e,t){let s=Math.max(1,Math.min(255,Math.round(e))),i=Math.max(1,Math.min(255,Math.round(t)));this.cellWidth===s&&this.cellHeight===i||(this.cellWidth=s,this.cellHeight=i,this.charWidth=s,this.charHeight=i,this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.fontLoaded&&this.generateAtlas(),this.useInstancing&&this.initInstancedBuffers(),this.updateCanvasSize())}getCellSize(){return{cellWidth:this.cellWidth,cellHeight:this.cellHeight}}getMaxCells(){return this.useInstancing?262144:this.useUint16Indices?8191:262144}setGrid(e){e.enabled?(this.gridOverlay?this.gridOverlay.setStyle({strokeColor:e.color,lineWidth:e.lineWidth}):this.gridOverlay=new I(this.containerDiv,{strokeColor:e.color??"rgba(144, 24, 24, 1)",lineWidth:e.lineWidth??1,zIndex:10}),this.showGrid=!0,this.gridOverlay.setVisible(!0),this.updateGridOverlay()):(this.showGrid=!1,this.gridOverlay&&this.gridOverlay.setVisible(!1))}isGridEnabled(){return this.showGrid}setAmbientEffect(e){typeof e=="boolean"?this.ambientEffectEnabled=e:(this.ambientEffectEnabled=!0,e.blur!==void 0&&(this.ambientEffectBlur=e.blur),e.scale!==void 0&&(this.ambientEffectScale=e.scale)),this.ambientEffectEnabled&&!this.ambientEffectCanvas&&this.createAmbientEffectCanvas(),this.ambientEffectCanvas&&(this.ambientEffectEnabled?(this.ambientEffectCanvas.style.display="block",this.ambientEffectCanvas.style.filter=`blur(${this.ambientEffectBlur}px)`,this.ambientEffectCanvas.style.transform=`scale(${this.ambientEffectScale})`,this.updateAmbientEffect()):this.ambientEffectCanvas.style.display="none")}createAmbientEffectCanvas(){this.ambientEffectCanvas||(this.ambientEffectCanvas=document.createElement("canvas"),this.ambientEffectCanvas.className="terminalgl-ambient-effect-canvas",this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.cssText=`
|
|
117
117
|
display: block !important;
|
|
118
118
|
position: absolute !important;
|
|
119
119
|
width: ${this.canvas.width}px !important;
|
|
@@ -124,4 +124,4 @@
|
|
|
124
124
|
transform: scale(${this.ambientEffectScale}) !important;
|
|
125
125
|
pointer-events: none !important;
|
|
126
126
|
z-index: 0 !important;
|
|
127
|
-
`,this.ambientEffectCtx=this.ambientEffectCanvas.getContext("2d",{alpha:!0}),this.containerDiv.insertBefore(this.ambientEffectCanvas,this.canvas),console.warn("[TerminalGL] \u{1F308} ambient effect canvas created dynamically"))}isAmbientEffectEnabled(){return this.ambientEffectEnabled}getAmbientEffectConfig(){return{enabled:this.ambientEffectEnabled,blur:this.ambientEffectBlur,scale:this.ambientEffectScale}}getCols(){return this.cols}getRows(){return this.rows}isReady(){return!!(this.fontLoaded&&this.atlasTexture&&this.program)}destroy(){this.dispose()}dispose(){this.resizeObserver&&this.resizeObserver.disconnect();let e=this.gl;this.program&&e.deleteProgram(this.program),this.positionBuffer&&e.deleteBuffer(this.positionBuffer),this.texCoordBuffer&&e.deleteBuffer(this.texCoordBuffer),this.colorIndexBuffer&&e.deleteBuffer(this.colorIndexBuffer),this.indexBuffer&&e.deleteBuffer(this.indexBuffer),this.instanceDataBuffer&&e.deleteBuffer(this.instanceDataBuffer),this.atlasTexture&&e.deleteTexture(this.atlasTexture),this.paletteTexture&&e.deleteTexture(this.paletteTexture),this.vao&&this.vaoExtension&&this.vaoExtension.deleteVertexArrayOES(this.vao);let t=e.getExtension("WEBGL_lose_context");t&&t.loseContext(),this.atlasCanvas&&(this.atlasCanvas.width=0,this.atlasCanvas.height=0,this.atlasCanvas=void 0),this.containerDiv.parentElement&&this.containerDiv.parentElement.removeChild(this.containerDiv),this.canvas.width=0,this.canvas.height=0,this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=0,this.ambientEffectCanvas.height=0,this.ambientEffectCanvas=null),this.gridOverlay&&(this.gridOverlay.destroy(),this.gridOverlay=void 0),this.renderPositions=new Float32Array(0),this.renderTexCoords=new Float32Array(0),this.renderColorIndices=new Float32Array(0),this.renderIndices=new Uint32Array(0),this.paletteFloat=new Float32Array(0),this.atlasUVs=new Float32Array(0),this.instanceData=new Float32Array(0),this.templateQuadPositions=new Float32Array(0),this.templateQuadIndices=new Uint16Array(0)}};
|
|
127
|
+
`,this.ambientEffectCtx=this.ambientEffectCanvas.getContext("2d",{alpha:!0}),this.containerDiv.insertBefore(this.ambientEffectCanvas,this.canvas),console.warn("[TerminalGL] \u{1F308} ambient effect canvas created dynamically"))}isAmbientEffectEnabled(){return this.ambientEffectEnabled}getAmbientEffectConfig(){return{enabled:this.ambientEffectEnabled,blur:this.ambientEffectBlur,scale:this.ambientEffectScale}}getCols(){return this.cols}getRows(){return this.rows}isReady(){return!!(this.fontLoaded&&this.atlasTexture&&this.program)}destroy(){this.dispose()}dispose(){this.resizeObserver&&this.resizeObserver.disconnect();let e=this.gl;this.program&&e.deleteProgram(this.program),this.positionBuffer&&e.deleteBuffer(this.positionBuffer),this.texCoordBuffer&&e.deleteBuffer(this.texCoordBuffer),this.colorIndexBuffer&&e.deleteBuffer(this.colorIndexBuffer),this.indexBuffer&&e.deleteBuffer(this.indexBuffer),this.instanceDataBuffer&&e.deleteBuffer(this.instanceDataBuffer),this.atlasTexture&&e.deleteTexture(this.atlasTexture),this.paletteTexture&&e.deleteTexture(this.paletteTexture),this.vao&&this.vaoExtension&&this.vaoExtension.deleteVertexArrayOES(this.vao);let t=e.getExtension("WEBGL_lose_context");t&&t.loseContext(),this.atlasCanvas&&(this.atlasCanvas.width=0,this.atlasCanvas.height=0,this.atlasCanvas=void 0),this.containerDiv.parentElement&&this.containerDiv.parentElement.removeChild(this.containerDiv),this.canvas.width=0,this.canvas.height=0,this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=0,this.ambientEffectCanvas.height=0,this.ambientEffectCanvas=null),this.gridOverlay&&(this.gridOverlay.destroy(),this.gridOverlay=void 0),this.renderPositions=new Float32Array(0),this.renderTexCoords=new Float32Array(0),this.renderColorIndices=new Float32Array(0),this.renderIndices=new Uint32Array(0),this.paletteFloat=new Float32Array(0),this.atlasUVs=new Float32Array(0),this.instanceData=new Float32Array(0),this.templateQuadPositions=new Float32Array(0),this.templateQuadIndices=new Uint16Array(0)}};C(U,"TerminalGL");var _=U;var D=["#000000","#800000","#008000","#808000","#000080","#800080","#008080","#c0c0c0","#808080","#ff0000","#00ff00","#ffff00","#0000ff","#ff00ff","#00ffff","#ffffff","#080808","#121212","#1c1c1c","#262626","#303030","#3a3a3a","#444444","#4e4e4e","#585858","#626262","#6c6c6c","#767676","#808080","#8a8a8a","#949494","#9e9e9e","#a80000","#00a800","#a8a800","#0000a8","#a800a8","#00a8a8","#a8a8a8","#545454","#fc5454","#54fc54","#fcfc54","#5454fc","#fc54fc","#54fcfc","#fcfcfc","#000000",...Array(192).fill("#808080")];function $(f,e=D){return f<0||f>=e.length?"#ff00ff":e[f]}C($,"paletteIndexToColor");function V(f,e=D){let t=e.indexOf(f.toLowerCase());return t>=0?t:0}C(V,"colorToPaletteIndex");
|
package/dist/gl/index.d.ts
CHANGED
|
@@ -227,6 +227,10 @@ declare class TerminalGL implements IRenderer {
|
|
|
227
227
|
private instanceData;
|
|
228
228
|
private templateQuadPositions;
|
|
229
229
|
private templateQuadIndices;
|
|
230
|
+
private aInstanceOffset;
|
|
231
|
+
private aInstanceUVs;
|
|
232
|
+
private aInstanceColors;
|
|
233
|
+
private uCellSize;
|
|
230
234
|
constructor(parentDiv: HTMLDivElement, options: TerminalGLOptions);
|
|
231
235
|
/**
|
|
232
236
|
* 🚀 INSTANCING: Initialize template quad and instance buffers
|
|
@@ -524,6 +528,17 @@ declare class TerminalGL implements IRenderer {
|
|
|
524
528
|
* Clear the resize callback
|
|
525
529
|
*/
|
|
526
530
|
clearOnResizeCallback(): void;
|
|
531
|
+
/**
|
|
532
|
+
* Get the available size from the parent container.
|
|
533
|
+
* This is the actual pixel space available for rendering.
|
|
534
|
+
* Useful in Responsive mode to calculate how many cells can fit.
|
|
535
|
+
*
|
|
536
|
+
* @returns Object with width and height in pixels
|
|
537
|
+
*/
|
|
538
|
+
getAvailableSize(): {
|
|
539
|
+
width: number;
|
|
540
|
+
height: number;
|
|
541
|
+
};
|
|
527
542
|
/**
|
|
528
543
|
* Set scaling mode
|
|
529
544
|
*
|
|
@@ -539,6 +554,36 @@ declare class TerminalGL implements IRenderer {
|
|
|
539
554
|
* Get current scaling mode
|
|
540
555
|
*/
|
|
541
556
|
getScalingMode(): ScalingMode;
|
|
557
|
+
/**
|
|
558
|
+
* Set cell dimensions in pixels
|
|
559
|
+
*
|
|
560
|
+
* Changes the native pixel size of each character cell.
|
|
561
|
+
* This will trigger a canvas resize and buffer reallocation.
|
|
562
|
+
*
|
|
563
|
+
* @param cellWidth - Cell width in pixels (1-255)
|
|
564
|
+
* @param cellHeight - Cell height in pixels (1-255)
|
|
565
|
+
*/
|
|
566
|
+
setCellSize(cellWidth: number, cellHeight: number): void;
|
|
567
|
+
/**
|
|
568
|
+
* Get current cell size
|
|
569
|
+
*/
|
|
570
|
+
getCellSize(): {
|
|
571
|
+
cellWidth: number;
|
|
572
|
+
cellHeight: number;
|
|
573
|
+
};
|
|
574
|
+
/**
|
|
575
|
+
* Get the maximum number of cells this renderer can handle
|
|
576
|
+
*
|
|
577
|
+
* This depends on device capabilities:
|
|
578
|
+
* - With instanced rendering: ~262,144 cells (limited by GPU memory)
|
|
579
|
+
* - With Uint32 indices: ~262,144 cells
|
|
580
|
+
* - With Uint16 indices only: ~8,191 cells (~90×90)
|
|
581
|
+
*
|
|
582
|
+
* Use this in responsive mode to clamp calculated cols/rows.
|
|
583
|
+
*
|
|
584
|
+
* @returns Maximum cells supported by this renderer
|
|
585
|
+
*/
|
|
586
|
+
getMaxCells(): number;
|
|
542
587
|
/**
|
|
543
588
|
* Enable or configure debug grid overlay
|
|
544
589
|
*
|
package/dist/gl/index.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var
|
|
1
|
+
var $=Object.defineProperty;var V=(v,e,t)=>e in v?$(v,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):v[e]=t;var E=(v,e)=>$(v,"name",{value:e,configurable:!0});var r=(v,e,t)=>(V(v,typeof e!="symbol"?e+"":e,t),t);var B=class B{constructor(e,t){r(this,"canvas");r(this,"ctx");r(this,"container");r(this,"cols",0);r(this,"rows",0);r(this,"cellWidth",0);r(this,"cellHeight",0);r(this,"offsetX",0);r(this,"offsetY",0);r(this,"strokeColor","rgba(80, 80, 80, 0.4)");r(this,"lineWidth",1);this.container=e,this.canvas=document.createElement("canvas"),this.canvas.className="grid-overlay-canvas";let s=t?.zIndex??10;this.canvas.style.cssText=`
|
|
2
2
|
display: block !important;
|
|
3
3
|
position: absolute !important;
|
|
4
4
|
pointer-events: none !important;
|
|
5
5
|
image-rendering: pixelated !important;
|
|
6
6
|
image-rendering: crisp-edges !important;
|
|
7
|
-
z-index: ${
|
|
8
|
-
`,this.container.appendChild(this.canvas);let i=this.canvas.getContext("2d");if(!i)throw new Error("[GridOverlay] Impossible de cr\xE9er le contexte 2D");this.ctx=i,t&&(t.strokeColor&&(this.strokeColor=t.strokeColor),t.lineWidth!==void 0&&(this.lineWidth=t.lineWidth))}setDimensions(e,t,
|
|
7
|
+
z-index: ${s} !important;
|
|
8
|
+
`,this.container.appendChild(this.canvas);let i=this.canvas.getContext("2d");if(!i)throw new Error("[GridOverlay] Impossible de cr\xE9er le contexte 2D");this.ctx=i,t&&(t.strokeColor&&(this.strokeColor=t.strokeColor),t.lineWidth!==void 0&&(this.lineWidth=t.lineWidth))}setDimensions(e,t,s,i,n=0,a=0){this.cols=e,this.rows=t,this.cellWidth=s,this.cellHeight=i,this.offsetX=n,this.offsetY=a}setCanvasSize(e,t){this.canvas.width=e,this.canvas.height=t,this.ctx.setTransform(1,0,0,1,0,0)}setStyle(e){e.strokeColor&&(this.strokeColor=e.strokeColor),e.lineWidth!==void 0&&(this.lineWidth=e.lineWidth)}setTransform(e,t,s,i,n){let a=i.left-n.left,l=i.top-n.top,o=i.width,c=i.height;(this.canvas.width!==o||this.canvas.height!==c)&&(this.canvas.width=o,this.canvas.height=c);let d=this.canvas.style;d.width=`${o}px`,d.height=`${c}px`,d.left=`${a}px`,d.top=`${l}px`}render(){if(!this.ctx)return;let e=this.cols*this.cellWidth,t=this.rows*this.cellHeight,s=e>0?this.canvas.width/e:1,i=t>0?this.canvas.height/t:1,n=Math.min(s,i),a=this.cellWidth*n,l=this.cellHeight*n,o=this.cols*a,c=this.rows*l,d=this.offsetX*n,h=this.offsetY*n;if(!(o===0||c===0)){this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height),this.ctx.strokeStyle=this.strokeColor,this.ctx.lineWidth=Math.max(1,this.lineWidth*n),this.ctx.beginPath();for(let u=0;u<=this.cols;u++){let m=d+u*a+.5;this.ctx.moveTo(m,h),this.ctx.lineTo(m,h+c)}for(let u=0;u<=this.rows;u++){let m=h+u*l+.5;this.ctx.moveTo(d,m),this.ctx.lineTo(d+o,m)}this.ctx.stroke()}}update(e,t,s,i,n,a,l=0,o=0){this.setDimensions(e,t,s,i,l,o),this.setCanvasSize(n,a),this.render()}setVisible(e){this.canvas.style.display=e?"block":"none"}destroy(){this.canvas.parentElement&&this.canvas.parentElement.removeChild(this.canvas)}getCanvas(){return this.canvas}};E(B,"GridOverlay");var I=B;function F(v){return Math.sqrt(v)*16}E(F,"getAtlasColumns");function L(v){return v*256-1}E(L,"getMaxCharCode");function _(v,e){let t=Math.floor(v/256),s=v%256,i=Math.sqrt(e),n=t%i,a=Math.floor(t/i),l=s%16,o=Math.floor(s/16);return{col:n*16+l,row:a*16+o}}E(_,"getCharGridPosition");import{POST_PROCESS_DEFAULTS as U,ScalingMode as C}from"@utsp/types";var y=class y{constructor(e,t){r(this,"canvas");r(this,"gl");r(this,"parentElement");r(this,"containerDiv");r(this,"cols");r(this,"rows");r(this,"charWidth");r(this,"charHeight");r(this,"cellWidth",8);r(this,"cellHeight",8);r(this,"glyphOffsetX",0);r(this,"glyphOffsetY",0);r(this,"canvasBgColor");r(this,"showGrid");r(this,"supportsUint32Indices",!1);r(this,"useUint16Indices",!1);r(this,"gridOverlay");r(this,"bitmapFont");r(this,"atlasTexture",null);r(this,"atlasCanvas");r(this,"atlasColumns",0);r(this,"fontLoaded",!1);r(this,"paletteTexture",null);r(this,"program",null);r(this,"positionBuffer",null);r(this,"texCoordBuffer",null);r(this,"colorIndexBuffer",null);r(this,"indexBuffer",null);r(this,"aPosition");r(this,"aTexCoord");r(this,"aColorIndex");r(this,"uResolution",null);r(this,"uTexture",null);r(this,"uPalette",null);r(this,"resizeObserver");r(this,"charCodeToAtlasIndex",new Uint16Array(65536).fill(65535));r(this,"atlasUVs",new Float32Array(0));r(this,"cachedAtlasWidth",0);r(this,"cachedAtlasHeight",0);r(this,"paletteFloat",new Float32Array(256*4));r(this,"maxCells",0);r(this,"renderPositions",new Float32Array(0));r(this,"renderTexCoords",new Float32Array(0));r(this,"renderColorIndices",new Float32Array(0));r(this,"renderIndices",new Uint32Array(0));r(this,"cachedResolution",[0,0]);r(this,"cachedTextureUnit",-1);r(this,"cachedPaletteUnit",-1);r(this,"cachedTextureUniform",!1);r(this,"cachedPaletteUniform",!1);r(this,"paletteHash",0);r(this,"currentScale",1);r(this,"scalingMode",C.None);r(this,"ambientEffectEnabled",!1);r(this,"ambientEffectCanvas",null);r(this,"ambientEffectCtx",null);r(this,"ambientEffectBlur",U.ambientEffect.blur);r(this,"ambientEffectScale",U.ambientEffect.scale);r(this,"ambientEffectOpacity",.7);r(this,"onResizeCallback");r(this,"staticPositionsInitialized",!1);r(this,"vaoExtension",null);r(this,"vao",null);r(this,"instancedExtension",null);r(this,"useInstancing",!1);r(this,"instanceDataBuffer",null);r(this,"instanceData",new Float32Array(0));r(this,"templateQuadPositions",new Float32Array(0));r(this,"templateQuadIndices",new Uint16Array(0));r(this,"aInstanceOffset",-1);r(this,"aInstanceUVs",-1);r(this,"aInstanceColors",-1);r(this,"uCellSize",null);if(!e)throw new Error("TerminalGL: Parent element is required");if(!Number.isInteger(t.cols)||t.cols<=0)throw new Error(`TerminalGL: Invalid cols: ${t.cols}. Must be a positive integer.`);if(!Number.isInteger(t.rows)||t.rows<=0)throw new Error(`TerminalGL: Invalid rows: ${t.rows}. Must be a positive integer.`);let s=t.cols*t.rows,i=y.checkCompatibility();if(i.errors.length>0)throw new Error(`TerminalGL: WebGL incompatible - ${i.errors.join(", ")}`);let n=t.forceUint16??!1;if(n&&s>i.maxCellsUint16)throw new Error(`TerminalGL: Terminal size ${t.cols}\xD7${t.rows} (${s} cells) exceeds Uint16 limit of ${i.maxCellsUint16} cells. Maximum size with Uint16: ${Math.floor(Math.sqrt(i.maxCellsUint16))}\xD7${Math.floor(Math.sqrt(i.maxCellsUint16))} (or smaller rectangles like 127\xD764)`);if(!i.uint32Indices&&s>i.maxCellsUint16)throw new Error(`TerminalGL: Terminal size ${t.cols}\xD7${t.rows} (${s} cells) exceeds device limit of ${i.maxCellsUint16} cells (OES_element_index_uint not supported). Maximum size: ${Math.floor(Math.sqrt(i.maxCellsUint16))}\xD7${Math.floor(Math.sqrt(i.maxCellsUint16))}`);s>i.recommendedMaxCells&&console.warn(`[TerminalGL] \u26A0\uFE0F Large terminal size ${t.cols}\xD7${t.rows} (${s} cells) exceeds recommended limit of ${i.recommendedMaxCells} cells. Performance may be impacted.`),i.warnings.length>0&&console.warn("[TerminalGL] WebGL Compatibility Warnings:",i.warnings);let a=t.charWidth??8,l=t.charHeight??8;if(!Number.isFinite(a)||a<=0)throw new Error(`TerminalGL: Invalid charWidth: ${a}. Must be a positive number.`);if(!Number.isFinite(l)||l<=0)throw new Error(`TerminalGL: Invalid charHeight: ${l}. Must be a positive number.`);for(this.parentElement=e,this.cols=t.cols,this.rows=t.rows,this.charWidth=a,this.charHeight=l,this.canvasBgColor=t.canvasBgColor!==void 0?t.canvasBgColor:null,this.showGrid=t.showGrid??!1,this.scalingMode=t.scalingMode??C.None,t.ambientEffect&&(this.ambientEffectEnabled=!0,typeof t.ambientEffect=="object"&&(this.ambientEffectBlur=t.ambientEffect.blur??U.ambientEffect.blur,this.ambientEffectScale=t.ambientEffect.scale??U.ambientEffect.scale,this.ambientEffectOpacity=t.ambientEffect.opacity??.7));this.parentElement.firstChild;)this.parentElement.removeChild(this.parentElement.firstChild);let o=window.getComputedStyle(this.parentElement).position;o!=="relative"&&o!=="absolute"&&o!=="fixed"&&(this.parentElement.style.position="relative"),this.containerDiv=document.createElement("div"),this.containerDiv.className="terminalgl-container",this.containerDiv.style.cssText=`
|
|
9
9
|
position: absolute !important;
|
|
10
10
|
top: 0 !important;
|
|
11
11
|
left: 0 !important;
|
|
@@ -32,7 +32,7 @@ var k=Object.defineProperty;var V=(b,e,t)=>e in b?k(b,e,{enumerable:!0,configura
|
|
|
32
32
|
backface-visibility: hidden !important;
|
|
33
33
|
position: relative !important;
|
|
34
34
|
z-index: 1 !important;
|
|
35
|
-
`;let c=this.canvas.getContext("webgl",{alpha:this.canvasBgColor===null,premultipliedAlpha:!1});if(!c)throw new Error("TerminalGL: WebGL not supported");this.gl=c,this.supportsUint32Indices=!!c.getExtension("OES_element_index_uint"),this.useUint16Indices=
|
|
35
|
+
`;let c=this.canvas.getContext("webgl",{alpha:this.canvasBgColor===null,premultipliedAlpha:!1});if(!c)throw new Error("TerminalGL: WebGL not supported");this.gl=c,this.supportsUint32Indices=!!c.getExtension("OES_element_index_uint"),this.useUint16Indices=n||!this.supportsUint32Indices,this.useUint16Indices?console.warn(`[TerminalGL] \u{1F4CA} Using Uint16 indices (max ${i.maxCellsUint16} cells)`):console.warn(`[TerminalGL] \u{1F4CA} Using Uint32 indices (max ${i.maxCellsUint32} cells)`),this.vaoExtension=c.getExtension("OES_vertex_array_object"),this.vaoExtension&&console.warn("[TerminalGL] \u2705 VAO extension enabled (faster attribute binding)"),this.instancedExtension=c.getExtension("ANGLE_instanced_arrays"),this.instancedExtension?(this.useInstancing=!0,console.warn("[TerminalGL] \u{1F680} Instanced rendering enabled (massive draw call reduction)")):console.warn("[TerminalGL] \u26A0\uFE0F Instanced rendering not available (fallback to standard rendering)"),this.containerDiv.appendChild(this.canvas),this.ambientEffectEnabled&&(this.createAmbientEffectCanvas(),console.warn("[TerminalGL] \u{1F308} Ambient effect enabled at startup")),this.parentElement.appendChild(this.containerDiv),this.initRenderBuffers();try{this.initWebGL()}catch(d){throw console.error("[TerminalGL] \u274C Failed to initialize WebGL:",d),d}this.showGrid&&this.initGridOverlay(),this.setupResizeObserver()}static checkCompatibility(){let e={webgl1:!1,uint32Indices:!1,maxTextureSize:0,maxViewportDims:[0,0],maxCellsUint16:0,maxCellsUint32:0,recommendedMaxCells:0,warnings:[],errors:[]},t=document.createElement("canvas"),s=t.getContext("webgl")||t.getContext("experimental-webgl");if(!s||!(s instanceof WebGLRenderingContext))return e.errors.push("\u274C WebGL 1.0 not supported by this browser/device"),e;let i=s;e.webgl1=!0;try{e.maxTextureSize=i.getParameter(i.MAX_TEXTURE_SIZE);let o=i.getParameter(i.MAX_VIEWPORT_DIMS);e.maxViewportDims=[o[0],o[1]]}catch(o){return e.errors.push(`\u274C Failed to query WebGL parameters: ${o}`),e}let n=i.getExtension("OES_element_index_uint");e.uint32Indices=!!n;let a=8;if(e.maxCellsUint16=Math.floor(65535/a),e.uint32Indices){let o=Math.floor(e.maxTextureSize*e.maxTextureSize/64);e.maxCellsUint32=Math.min(o,262144)}else e.maxCellsUint32=e.maxCellsUint16,e.warnings.push(`\u26A0\uFE0F OES_element_index_uint not supported - limited to ${e.maxCellsUint16} cells (e.g., 90\xD790 or 127\xD764)`);return e.recommendedMaxCells=Math.floor((e.uint32Indices?e.maxCellsUint32:e.maxCellsUint16)*.8),e.maxTextureSize<256?e.errors.push(`\u274C MAX_TEXTURE_SIZE too small: ${e.maxTextureSize} (minimum 256 required for font atlas)`):e.maxTextureSize<2048&&e.warnings.push(`\u26A0\uFE0F Small MAX_TEXTURE_SIZE: ${e.maxTextureSize} (may limit font atlas)`),(e.maxViewportDims[0]<1024||e.maxViewportDims[1]<768)&&e.warnings.push(`\u26A0\uFE0F Small MAX_VIEWPORT_DIMS: ${e.maxViewportDims[0]}\xD7${e.maxViewportDims[1]}`),i.getExtension("WEBGL_lose_context")||e.warnings.push("\u26A0\uFE0F WEBGL_lose_context not supported - may cause memory leaks"),e}initInstancedBuffers(){let e=this.gl;this.templateQuadPositions=new Float32Array([0,0,this.cellWidth,0,0,this.cellHeight,this.cellWidth,this.cellHeight]),this.templateQuadIndices=new Uint16Array([0,1,2,2,1,3]),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.bufferData(e.ARRAY_BUFFER,this.templateQuadPositions,e.STATIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.templateQuadIndices,e.STATIC_DRAW),this.instanceData=new Float32Array(this.maxCells*8),console.warn(`[TerminalGL] \u{1F680} initInstancedBuffers: maxCells=${this.maxCells}, instanceData.length=${this.instanceData.length}`),e.bindBuffer(e.ARRAY_BUFFER,this.instanceDataBuffer),e.bufferData(e.ARRAY_BUFFER,this.instanceData.byteLength,e.DYNAMIC_DRAW)}initRenderBuffers(){let e=this.cols*this.rows*2;this.maxCells=Math.ceil(e*2),this.renderPositions=new Float32Array(this.maxCells*4*2),this.renderTexCoords=new Float32Array(this.maxCells*4*2),this.renderColorIndices=new Float32Array(this.maxCells*4),this.useUint16Indices?this.renderIndices=new Uint16Array(this.maxCells*6):this.renderIndices=new Uint32Array(this.maxCells*6),this.staticPositionsInitialized=!1}precomputeStaticPositions(){let e=this.cellWidth,t=this.cellHeight,s=this.glyphOffsetX,i=this.glyphOffsetY,n=this.charWidth,a=this.charHeight,l=0,o=0,c=0;for(let h=0;h<this.rows;h++){let u=Math.round(h*t),m=Math.round(u+t);for(let b=0;b<this.cols;b++){let f=Math.round(b*e),p=Math.round(f+e);this.renderPositions[l++]=f,this.renderPositions[l++]=u,this.renderPositions[l++]=p,this.renderPositions[l++]=u,this.renderPositions[l++]=f,this.renderPositions[l++]=m,this.renderPositions[l++]=p,this.renderPositions[l++]=m,this.renderIndices[o++]=c,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+3,c+=4;let g=Math.round(f+s),x=Math.round(u+i),w=Math.round(g+n),A=Math.round(x+a);this.renderPositions[l++]=g,this.renderPositions[l++]=x,this.renderPositions[l++]=w,this.renderPositions[l++]=x,this.renderPositions[l++]=g,this.renderPositions[l++]=A,this.renderPositions[l++]=w,this.renderPositions[l++]=A,this.renderIndices[o++]=c,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+2,this.renderIndices[o++]=c+1,this.renderIndices[o++]=c+3,c+=4}}let d=this.gl;d.bindBuffer(d.ARRAY_BUFFER,this.positionBuffer),d.bufferSubData(d.ARRAY_BUFFER,0,this.renderPositions),d.bindBuffer(d.ELEMENT_ARRAY_BUFFER,this.indexBuffer),d.bufferSubData(d.ELEMENT_ARRAY_BUFFER,0,this.renderIndices),this.staticPositionsInitialized=!0}initWebGL(){let e=this.gl,t;this.useInstancing?t=`
|
|
36
36
|
// Per-vertex attributes (template quad)
|
|
37
37
|
attribute vec2 aPosition; // Local quad position (0,0 to cellW,cellH)
|
|
38
38
|
|
|
@@ -93,7 +93,7 @@ var k=Object.defineProperty;var V=(b,e,t)=>e in b?k(b,e,{enumerable:!0,configura
|
|
|
93
93
|
float paletteU = (aColorIndex + 0.5) / 256.0;
|
|
94
94
|
vColor = texture2D(uPalette, vec2(paletteU, 0.5));
|
|
95
95
|
}
|
|
96
|
-
`;let
|
|
96
|
+
`;let s=`
|
|
97
97
|
precision mediump float;
|
|
98
98
|
|
|
99
99
|
uniform sampler2D uTexture;
|
|
@@ -113,7 +113,7 @@ var k=Object.defineProperty;var V=(b,e,t)=>e in b?k(b,e,{enumerable:!0,configura
|
|
|
113
113
|
gl_FragColor = vec4(texColor.rgb * vColor.rgb, texColor.a);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
|
-
`,i=this.compileShader(e.VERTEX_SHADER,t),s=this.compileShader(e.FRAGMENT_SHADER,r);if(!i||!s)throw new Error("Shader compilation error");let a=e.createProgram();if(!a)throw new Error("Unable to create WebGL program");if(e.attachShader(a,i),e.attachShader(a,s),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS)){let l=e.getProgramInfoLog(a);throw new Error("Program linking error: "+l)}this.program=a,this.cachedTextureUniform=!1,this.cachedPaletteUniform=!1,this.aPosition=e.getAttribLocation(a,"aPosition"),this.useInstancing?(this.aTexCoord=e.getAttribLocation(a,"aInstanceOffset"),this.aColorIndex=e.getAttribLocation(a,"aInstanceUVs"),this.instanceDataBuffer=e.createBuffer()):(this.aTexCoord=e.getAttribLocation(a,"aTexCoord"),this.aColorIndex=e.getAttribLocation(a,"aColorIndex")),this.uResolution=e.getUniformLocation(a,"uResolution"),this.uTexture=e.getUniformLocation(a,"uTexture"),this.uPalette=e.getUniformLocation(a,"uPalette"),this.positionBuffer=e.createBuffer(),this.texCoordBuffer=e.createBuffer(),this.colorIndexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderPositions.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderTexCoords.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderColorIndices.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,e.DYNAMIC_DRAW),this.vaoExtension&&(this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.enableVertexAttribArray(this.aPosition),e.vertexAttribPointer(this.aPosition,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.enableVertexAttribArray(this.aTexCoord),e.vertexAttribPointer(this.aTexCoord,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.enableVertexAttribArray(this.aColorIndex),e.vertexAttribPointer(this.aColorIndex,1,e.FLOAT,!1,0,0),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null))),e.enable(e.BLEND),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA),e.viewport(0,0,this.canvas.width,this.canvas.height)}compileShader(e,t){let r=this.gl,i=r.createShader(e);return i?(r.shaderSource(i,t),r.compileShader(i),r.getShaderParameter(i,r.COMPILE_STATUS)?i:(console.error("Shader compilation error:",r.getShaderInfoLog(i)),r.deleteShader(i),null)):null}initGridOverlay(){this.gridOverlay=new I(this.containerDiv,{strokeColor:"rgba(144, 24, 24, 1)",lineWidth:1,zIndex:10}),this.updateGridOverlay()}updateGridOverlay(){if(!this.gridOverlay)return;let e=this.cols*this.cellWidth,t=this.rows*this.cellHeight,r=this.canvas.getBoundingClientRect(),i=this.containerDiv.getBoundingClientRect();this.gridOverlay.setDimensions(this.cols,this.rows,this.cellWidth,this.cellHeight,0,0),this.gridOverlay.setTransform(this.currentScale,e,t,r,i),this.gridOverlay.render()}setBitmapFont(e,t,r,i,s){this.bitmapFont=e,this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(r),this.cellWidth=Math.round(i),this.cellHeight=Math.round(s),this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers..."),this.initInstancedBuffers());try{this.generateAtlas()}catch(a){throw console.error("[TerminalGL] \u274C Failed to generate atlas:",a),a}this.buildCharCodeMap(),this.precomputeAtlasUVs(),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async setImageFont(e,t,r,i,s,a){this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(r),this.cellWidth=Math.round(i),this.cellHeight=Math.round(s),this.atlasColumns=L(a);let l=_(a);this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers for ImageFont..."),this.initInstancedBuffers()),await this.loadImageFontAtlas(e),this.charCodeToAtlasIndex.fill(65535);for(let o=0;o<=l;o++)this.charCodeToAtlasIndex[o]=o;this.precomputeImageFontUVs(a),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async loadImageFontAtlas(e){return new Promise((t,r)=>{let i=new Uint8Array(e),s=new Blob([i],{type:"image/png"}),a=URL.createObjectURL(s),l=new Image;l.onload=()=>{URL.revokeObjectURL(a),this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=l.width,this.atlasCanvas.height=l.height;let o=this.atlasCanvas.getContext("2d");if(!o){r(new Error("Failed to create 2D context for atlas"));return}o.drawImage(l,0,0),this.cachedAtlasWidth=l.width,this.cachedAtlasHeight=l.height,this.createAtlasTexture(),t()},l.onerror=()=>{URL.revokeObjectURL(a),r(new Error("Failed to load PNG image for ImageFont atlas"))},l.src=a})}precomputeImageFontUVs(e){let t=e*256;this.atlasUVs=new Float32Array(t*4);let r=this.cachedAtlasWidth,i=this.cachedAtlasHeight,s=.5/r,a=.5/i;for(let l=0;l<t;l++){let{col:o,row:c}=D(l,e),d=(o*this.charWidth+s)/r,h=(c*this.charHeight+a)/i,f=((o+1)*this.charWidth-s)/r,u=((c+1)*this.charHeight-a)/i,m=l*4;this.atlasUVs[m]=d,this.atlasUVs[m+1]=h,this.atlasUVs[m+2]=f,this.atlasUVs[m+3]=u}}generateAtlas(){if(!this.bitmapFont)return;let e=Array.from(this.bitmapFont.keys()).sort((o,c)=>o-c),t=e.length;this.atlasColumns=Math.ceil(Math.sqrt(t));let r=Math.ceil(t/this.atlasColumns),i=this.atlasColumns*this.charWidth,s=r*this.charHeight;this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=i,this.atlasCanvas.height=s;let a=this.atlasCanvas.getContext("2d");if(!a)throw new Error("Unable to create 2D context for atlas");a.clearRect(0,0,i,s),a.fillStyle="#ffffff";let l=0;for(let o of e){let c=this.bitmapFont.get(o);if(!c)continue;let d=l%this.atlasColumns,h=Math.floor(l/this.atlasColumns),f=d*this.charWidth,u=h*this.charHeight;for(let m=0;m<Math.min(c.length,this.charHeight);m++){let p=c[m];for(let g=0;g<this.charWidth;g++){let A=1<<7-g;p&A&&a.fillRect(f+g,u+m,1,1)}}l++}this.createAtlasTexture()}buildCharCodeMap(){if(!this.bitmapFont)return;this.charCodeToAtlasIndex.fill(65535);let e=Array.from(this.bitmapFont.keys()).sort((t,r)=>t-r);for(let t=0;t<e.length;t++)this.charCodeToAtlasIndex[e[t]]=t}precomputeAtlasUVs(){if(!this.bitmapFont)return;let e=this.bitmapFont.size;this.atlasUVs=new Float32Array(e*4),this.cachedAtlasWidth=this.atlasColumns*this.charWidth,this.cachedAtlasHeight=Math.ceil(e/this.atlasColumns)*this.charHeight;let t=this.cachedAtlasWidth,r=this.cachedAtlasHeight,i=.5/t,s=.5/r;for(let a=0;a<e;a++){let l=a%this.atlasColumns,o=Math.floor(a/this.atlasColumns),c=(l*this.charWidth+i)/t,d=(o*this.charHeight+s)/r,h=((l+1)*this.charWidth-i)/t,f=((o+1)*this.charHeight-s)/r,u=a*4;this.atlasUVs[u]=c,this.atlasUVs[u+1]=d,this.atlasUVs[u+2]=h,this.atlasUVs[u+3]=f}}createAtlasTexture(){if(this.atlasCanvas)try{let e=this.gl,t=e.createTexture();if(!t)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.atlasCanvas),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),this.atlasTexture=t}catch(e){throw console.error("[TerminalGL] \u274C Failed to create atlas texture:",e),e}}clear(){let e=this.gl;e&&e.clear(e.COLOR_BUFFER_BIT)}parseColor(e){if(e.startsWith("#")){let t=e.slice(1),r=0,i=0,s=0;return t.length===3?(r=parseInt(t[0]+t[0],16),i=parseInt(t[1]+t[1],16),s=parseInt(t[2]+t[2],16)):t.length===6&&(r=parseInt(t.slice(0,2),16),i=parseInt(t.slice(2,4),16),s=parseInt(t.slice(4,6),16)),[r/255,i/255,s/255,1]}if(e.startsWith("rgb")){let t=e.match(/rgba?\(([^)]+)\)/);if(t){let r=t[1].split(",").map(i=>parseFloat(i.trim()));return[r[0]/255,r[1]/255,r[2]/255,r[3]!==void 0?r[3]:1]}}return[1,1,1,1]}setupResizeObserver(){if(!(typeof ResizeObserver>"u"))try{this.resizeObserver=new ResizeObserver(()=>{try{this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Error in resize callback:",e)}}),this.resizeObserver.observe(this.parentElement),this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Failed to setup ResizeObserver:",e)}}updateCanvasSize(){let e=this.parentElement.clientWidth,t=this.parentElement.clientHeight;if(e===0||t===0)return;let r=this.cols*this.cellWidth,i=this.rows*this.cellHeight;if(r===0||i===0)return;let s=e/r,a=t/i,l=Math.min(s,a),o;switch(this.scalingMode){case T.Integer:o=Math.max(1,Math.floor(l));break;case T.Half:o=Math.max(1,Math.floor(l*2)/2);break;case T.Quarter:o=Math.max(1,Math.floor(l*4)/4);break;case T.Eighth:o=Math.max(1,Math.floor(l*8)/8);break;case T.None:default:o=Math.max(.1,l);break}if(this.canvas.style.transform=`scale(${o})`,this.ambientEffectEnabled&&this.ambientEffectCanvas){let c=o*this.ambientEffectScale;this.ambientEffectCanvas.style.transform=`scale(${c})`}this.currentScale=o,this.onResizeCallback&&this.onResizeCallback(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}updateAmbientEffect(){!this.ambientEffectCanvas||!this.ambientEffectCtx||this.ambientEffectCtx.drawImage(this.canvas,0,0)}setPalette(e){let t=0;for(let r=0;r<Math.min(e.length,256);r++){let i=e[r];t=(t<<5)-t+i.r,t=(t<<5)-t+i.g,t=(t<<5)-t+i.b,t=(t<<5)-t+i.a,t=t|0}if(t!==this.paletteHash){this.paletteHash=t;for(let r=0;r<e.length&&r<256;r++){let i=e[r],s=r*4;this.paletteFloat[s]=i.r/255,this.paletteFloat[s+1]=i.g/255,this.paletteFloat[s+2]=i.b/255,this.paletteFloat[s+3]=i.a/255}this.updatePaletteTexture()}}updatePaletteTexture(){try{let e=this.gl;this.paletteTexture||(this.paletteTexture=e.createTexture()),e.bindTexture(e.TEXTURE_2D,this.paletteTexture);let t=new Uint8Array(256*4);for(let r=0;r<256;r++){let i=r*4;t[i]=this.paletteFloat[i]*255,t[i+1]=this.paletteFloat[i+1]*255,t[i+2]=this.paletteFloat[i+2]*255,t[i+3]=this.paletteFloat[i+3]*255}e.texImage2D(e.TEXTURE_2D,0,e.RGBA,256,1,0,e.RGBA,e.UNSIGNED_BYTE,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.bindTexture(e.TEXTURE_2D,null)}catch(e){throw console.error("[TerminalGL] \u274C Failed to update palette texture:",e),e}}renderDisplayData(e){try{if(!this.isReady()){console.warn("[TerminalGL] \u26A0\uFE0F Not ready: font not loaded yet");return}(e.width!==this.cols||e.height!==this.rows)&&this.resize(e.width,e.height),this.renderDirect(e),this.ambientEffectEnabled&&this.ambientEffectCanvas&&this.ambientEffectCtx&&this.updateAmbientEffect()}catch(t){console.error("[TerminalGL] \u274C Error rendering display data:",t)}}renderDirect(e){let t=this.gl;if(!this.staticPositionsInitialized&&!this.useInstancing&&this.precomputeStaticPositions(),this.canvasBgColor!==null){let r=this.parseColor(this.canvasBgColor);t.clearColor(r[0],r[1],r[2],r[3])}else t.clearColor(0,0,0,0);t.clear(t.COLOR_BUFFER_BIT),this.useInstancing?this.renderInstanced(e):this.renderDirectBuffers(e)}renderInstanced(e){let t=this.gl,r=this.instancedExtension;if(!this.instanceData||this.instanceData.length===0){console.warn("[TerminalGL] \u26A0\uFE0F Instance data not initialized, falling back to standard rendering"),this.useInstancing=!1,this.renderDirectBuffers(e);return}let i=e.width*e.height;if(this.useUint16Indices&&i>8191){console.warn(`[TerminalGL] \u26A0\uFE0F Terminal too large for instanced rendering with Uint16 (${i} cells > 8191). Falling back to standard rendering.`),this.useInstancing=!1,this.renderDirectBuffers(e);return}let s=0,a=this.instanceData.length/8;for(let f=0;f<e.height;f++)for(let u=0;u<e.width;u++){let m=e.cells[f*e.width+u],p=m.bgColorIndex,g=m.fgColorIndex,A=this.canvasBgColor!==null&&p===255,R=m.char===" "||g===255;if(!A){if(s>=a){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${s}, max=${a}`);break}let v=s*8;this.instanceData[v]=u,this.instanceData[v+1]=f,this.instanceData[v+2]=0,this.instanceData[v+3]=0,this.instanceData[v+4]=0,this.instanceData[v+5]=0,this.instanceData[v+6]=p,this.instanceData[v+7]=0,s++}if(!R){let v=m.char.charCodeAt(0),E=this.charCodeToAtlasIndex[v];if(E!==65535){if(s>=a){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${s}, max=${a}`);break}let w=E*4,x=s*8;this.instanceData[x]=u,this.instanceData[x+1]=f,this.instanceData[x+2]=this.atlasUVs[w],this.instanceData[x+3]=this.atlasUVs[w+1],this.instanceData[x+4]=this.atlasUVs[w+2],this.instanceData[x+5]=this.atlasUVs[w+3],this.instanceData[x+6]=0,this.instanceData[x+7]=g,s++}}}if(s===0){console.warn("[TerminalGL] \u26A0\uFE0F No instances to draw (all cells skipped)");return}t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.instanceData.subarray(0,s*8)),t.useProgram(this.program),t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),r.vertexAttribDivisorANGLE(this.aPosition,0),t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer);let l=8*Float32Array.BYTES_PER_ELEMENT,o=t.getAttribLocation(this.program,"aInstanceOffset");t.enableVertexAttribArray(o),t.vertexAttribPointer(o,2,t.FLOAT,!1,l,0),r.vertexAttribDivisorANGLE(o,1);let c=t.getAttribLocation(this.program,"aInstanceUVs");t.enableVertexAttribArray(c),t.vertexAttribPointer(c,4,t.FLOAT,!1,l,2*Float32Array.BYTES_PER_ELEMENT),r.vertexAttribDivisorANGLE(c,1);let d=t.getAttribLocation(this.program,"aInstanceColors");t.enableVertexAttribArray(d),t.vertexAttribPointer(d,2,t.FLOAT,!1,l,6*Float32Array.BYTES_PER_ELEMENT),r.vertexAttribDivisorANGLE(d,1),t.uniform2f(this.uResolution,this.canvas.width,this.canvas.height);let h=t.getUniformLocation(this.program,"uCellSize");t.uniform2f(h,this.cellWidth,this.cellHeight),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),t.uniform1i(this.uTexture,0),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),t.uniform1i(this.uPalette,1),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),r.drawElementsInstancedANGLE(t.TRIANGLES,6,t.UNSIGNED_SHORT,0,s),r.vertexAttribDivisorANGLE(this.aPosition,0),r.vertexAttribDivisorANGLE(o,0),r.vertexAttribDivisorANGLE(c,0),r.vertexAttribDivisorANGLE(d,0)}renderDirectBuffers(e){let t=this.gl,r=e.width*e.height,i=r*2;if(i>this.maxCells){console.error(`[TerminalGL] \u274C Buffer overflow detected! Trying to render ${i} quads but buffer capacity is ${this.maxCells}. This should not happen - resize() should have reallocated.`);return}let s=0,a=0,l=e.cells,o=r;for(let m=0;m<o;m++){let p=l[m],g=p.bgColorIndex,R=this.canvasBgColor!==null&&g===255?255:g,v=0;for(let x=0;x<4;x++)this.renderTexCoords[s++]=v,this.renderTexCoords[s++]=v,this.renderColorIndices[a++]=R;let E=p.fgColorIndex,w=p.char;if(w===" "||E===255)for(let x=0;x<4;x++)this.renderTexCoords[s++]=0,this.renderTexCoords[s++]=0,this.renderColorIndices[a++]=255;else{let x=w.charCodeAt(0),S=this.charCodeToAtlasIndex[x];if(S!==65535){let y=S*4,G=this.atlasUVs[y],W=this.atlasUVs[y+1],O=this.atlasUVs[y+2],H=this.atlasUVs[y+3];this.renderTexCoords[s++]=G,this.renderTexCoords[s++]=W,this.renderColorIndices[a++]=E,this.renderTexCoords[s++]=O,this.renderTexCoords[s++]=W,this.renderColorIndices[a++]=E,this.renderTexCoords[s++]=G,this.renderTexCoords[s++]=H,this.renderColorIndices[a++]=E,this.renderTexCoords[s++]=O,this.renderTexCoords[s++]=H,this.renderColorIndices[a++]=E}else for(let y=0;y<4;y++)this.renderTexCoords[s++]=0,this.renderTexCoords[s++]=0,this.renderColorIndices[a++]=255}}(s!==o*2*4*2||a!==o*2*4)&&console.error("[TerminalGL] \u274C Buffer index mismatch!",{texIdx:s,colorIdx:a,expected:o*2*4}),t.useProgram(this.program),this.vao&&this.vaoExtension?(this.vaoExtension.bindVertexArrayOES(this.vao),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,s)),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a))):(t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,s)),t.enableVertexAttribArray(this.aTexCoord),t.vertexAttribPointer(this.aTexCoord,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a)),t.enableVertexAttribArray(this.aColorIndex),t.vertexAttribPointer(this.aColorIndex,1,t.FLOAT,!1,0,0));let c=this.canvas.width,d=this.canvas.height;(this.cachedResolution[0]!==c||this.cachedResolution[1]!==d)&&(t.uniform2f(this.uResolution,c,d),this.cachedResolution[0]=c,this.cachedResolution[1]=d),this.cachedTextureUnit!==0&&(t.activeTexture(t.TEXTURE0),this.cachedTextureUnit=0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),this.cachedTextureUniform||(t.uniform1i(this.uTexture,0),this.cachedTextureUniform=!0),this.cachedPaletteUnit!==1&&(t.activeTexture(t.TEXTURE1),this.cachedPaletteUnit=1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),this.cachedPaletteUniform||(t.uniform1i(this.uPalette,1),this.cachedPaletteUniform=!0),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer);let f=e.width*e.height*2*6,u=this.useUint16Indices?t.UNSIGNED_SHORT:t.UNSIGNED_INT;t.drawElements(t.TRIANGLES,f,u,0)}resize(e,t){if(!Number.isInteger(e)||e<=0){console.error(`[TerminalGL] \u274C Invalid cols: ${e}. Must be positive integer.`);return}if(!Number.isInteger(t)||t<=0){console.error(`[TerminalGL] \u274C Invalid rows: ${t}. Must be positive integer.`);return}if(e===this.cols&&t===this.rows)return;let r=e*t,i=this.useUint16Indices?8191:262144;if(r>i){let d=Math.floor(Math.sqrt(i));console.error(`[TerminalGL] \u274C Cannot resize to ${e}\xD7${t} (${r} cells). Device limit: ${i} cells (max ~${d}\xD7${d}). ${this.useUint16Indices?"Device lacks OES_element_index_uint extension.":""}`);return}let s=U.checkCompatibility();r>s.recommendedMaxCells&&console.warn(`[TerminalGL] \u26A0\uFE0F Resizing to ${e}\xD7${t} (${r} cells) exceeds recommended limit (${s.recommendedMaxCells} cells). Performance may degrade.`),this.cols=e,this.rows=t,this.staticPositionsInitialized=!1;let a=this.cols*this.rows*2,l=Math.ceil(a*1.5),o=a>this.maxCells,c=this.maxCells>l*4;if(o||c){let d=this.maxCells;this.maxCells=l,this.renderPositions=new Float32Array(this.maxCells*4*2),this.renderTexCoords=new Float32Array(this.maxCells*4*2),this.renderColorIndices=new Float32Array(this.maxCells*4),this.useUint16Indices?this.renderIndices=new Uint16Array(this.maxCells*6):this.renderIndices=new Uint32Array(this.maxCells*6);let h=this.gl;this.useInstancing||(h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderPositions.byteLength,h.DYNAMIC_DRAW)),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderTexCoords.byteLength,h.DYNAMIC_DRAW),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderColorIndices.byteLength,h.DYNAMIC_DRAW),h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),h.bufferData(h.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,h.DYNAMIC_DRAW),this.vaoExtension&&this.vao&&(this.vaoExtension.deleteVertexArrayOES(this.vao),this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.enableVertexAttribArray(this.aPosition),h.vertexAttribPointer(this.aPosition,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.enableVertexAttribArray(this.aTexCoord),h.vertexAttribPointer(this.aTexCoord,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.enableVertexAttribArray(this.aColorIndex),h.vertexAttribPointer(this.aColorIndex,1,h.FLOAT,!1,0,0),h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null)));let f=o?"\u{1F4C8} Growing":"\u{1F4C9} Shrinking",u=d*160/1048576,m=this.maxCells*160/1048576;console.warn(`[TerminalGL] ${f} buffers: ${u.toFixed(2)}MB \u2192 ${m.toFixed(2)}MB (${d} \u2192 ${this.maxCells} quads)`)}this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.ambientEffectEnabled&&this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.width=`${this.canvas.width}px`,this.ambientEffectCanvas.style.height=`${this.canvas.height}px`),this.showGrid&&this.gridOverlay&&this.updateGridOverlay(),this.updateCanvasSize()}getCanvas(){return this.canvas}getGridSize(){return{cols:this.cols,rows:this.rows}}getCellWidth(){return this.cellWidth}getCellHeight(){return this.cellHeight}getCurrentScale(){return this.currentScale}getBaseDimensions(){return{width:this.cols*this.cellWidth,height:this.rows*this.cellHeight}}setOnResizeCallback(e){this.onResizeCallback=e}clearOnResizeCallback(){this.onResizeCallback=void 0}setScalingMode(e){this.scalingMode!==e&&(this.scalingMode=e,this.updateCanvasSize())}getScalingMode(){return this.scalingMode}setGrid(e){e.enabled?(this.gridOverlay?this.gridOverlay.setStyle({strokeColor:e.color,lineWidth:e.lineWidth}):this.gridOverlay=new I(this.containerDiv,{strokeColor:e.color??"rgba(144, 24, 24, 1)",lineWidth:e.lineWidth??1,zIndex:10}),this.showGrid=!0,this.gridOverlay.setVisible(!0),this.updateGridOverlay()):(this.showGrid=!1,this.gridOverlay&&this.gridOverlay.setVisible(!1))}isGridEnabled(){return this.showGrid}setAmbientEffect(e){typeof e=="boolean"?this.ambientEffectEnabled=e:(this.ambientEffectEnabled=!0,e.blur!==void 0&&(this.ambientEffectBlur=e.blur),e.scale!==void 0&&(this.ambientEffectScale=e.scale)),this.ambientEffectEnabled&&!this.ambientEffectCanvas&&this.createAmbientEffectCanvas(),this.ambientEffectCanvas&&(this.ambientEffectEnabled?(this.ambientEffectCanvas.style.display="block",this.ambientEffectCanvas.style.filter=`blur(${this.ambientEffectBlur}px)`,this.ambientEffectCanvas.style.transform=`scale(${this.ambientEffectScale})`,this.updateAmbientEffect()):this.ambientEffectCanvas.style.display="none")}createAmbientEffectCanvas(){this.ambientEffectCanvas||(this.ambientEffectCanvas=document.createElement("canvas"),this.ambientEffectCanvas.className="terminalgl-ambient-effect-canvas",this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.cssText=`
|
|
116
|
+
`,i=this.compileShader(e.VERTEX_SHADER,t),n=this.compileShader(e.FRAGMENT_SHADER,s);if(!i||!n)throw new Error("Shader compilation error");let a=e.createProgram();if(!a)throw new Error("Unable to create WebGL program");if(e.attachShader(a,i),e.attachShader(a,n),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS)){let l=e.getProgramInfoLog(a);throw new Error("Program linking error: "+l)}this.program=a,this.cachedTextureUniform=!1,this.cachedPaletteUniform=!1,this.aPosition=e.getAttribLocation(a,"aPosition"),this.useInstancing?(this.aInstanceOffset=e.getAttribLocation(a,"aInstanceOffset"),this.aInstanceUVs=e.getAttribLocation(a,"aInstanceUVs"),this.aInstanceColors=e.getAttribLocation(a,"aInstanceColors"),this.uCellSize=e.getUniformLocation(a,"uCellSize"),this.instanceDataBuffer=e.createBuffer(),this.aTexCoord=this.aInstanceOffset,this.aColorIndex=this.aInstanceUVs):(this.aTexCoord=e.getAttribLocation(a,"aTexCoord"),this.aColorIndex=e.getAttribLocation(a,"aColorIndex")),this.uResolution=e.getUniformLocation(a,"uResolution"),this.uTexture=e.getUniformLocation(a,"uTexture"),this.uPalette=e.getUniformLocation(a,"uPalette"),this.positionBuffer=e.createBuffer(),this.texCoordBuffer=e.createBuffer(),this.colorIndexBuffer=e.createBuffer(),this.indexBuffer=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderPositions.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderTexCoords.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.bufferData(e.ARRAY_BUFFER,this.renderColorIndices.byteLength,e.DYNAMIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,e.DYNAMIC_DRAW),this.vaoExtension&&(this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),e.bindBuffer(e.ARRAY_BUFFER,this.positionBuffer),e.enableVertexAttribArray(this.aPosition),e.vertexAttribPointer(this.aPosition,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.texCoordBuffer),e.enableVertexAttribArray(this.aTexCoord),e.vertexAttribPointer(this.aTexCoord,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this.colorIndexBuffer),e.enableVertexAttribArray(this.aColorIndex),e.vertexAttribPointer(this.aColorIndex,1,e.FLOAT,!1,0,0),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null))),e.enable(e.BLEND),e.blendFunc(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA),e.viewport(0,0,this.canvas.width,this.canvas.height)}compileShader(e,t){let s=this.gl,i=s.createShader(e);return i?(s.shaderSource(i,t),s.compileShader(i),s.getShaderParameter(i,s.COMPILE_STATUS)?i:(console.error("Shader compilation error:",s.getShaderInfoLog(i)),s.deleteShader(i),null)):null}initGridOverlay(){this.gridOverlay=new I(this.containerDiv,{strokeColor:"rgba(144, 24, 24, 1)",lineWidth:1,zIndex:10}),this.updateGridOverlay()}updateGridOverlay(){if(!this.gridOverlay)return;let e=this.cols*this.cellWidth,t=this.rows*this.cellHeight,s=this.canvas.getBoundingClientRect(),i=this.containerDiv.getBoundingClientRect();this.gridOverlay.setDimensions(this.cols,this.rows,this.cellWidth,this.cellHeight,0,0),this.gridOverlay.setTransform(this.currentScale,e,t,s,i),this.gridOverlay.render()}setBitmapFont(e,t,s,i,n){this.bitmapFont=e,this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(s),this.cellWidth=Math.round(i),this.cellHeight=Math.round(n),this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers..."),this.initInstancedBuffers());try{this.generateAtlas()}catch(a){throw console.error("[TerminalGL] \u274C Failed to generate atlas:",a),a}this.buildCharCodeMap(),this.precomputeAtlasUVs(),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async setImageFont(e,t,s,i,n,a){this.fontLoaded=!0,this.charWidth=Math.round(t),this.charHeight=Math.round(s),this.cellWidth=Math.round(i),this.cellHeight=Math.round(n),this.atlasColumns=F(a);let l=L(a);this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.useInstancing&&(console.warn("[TerminalGL] \u{1F680} Initializing instanced buffers for ImageFont..."),this.initInstancedBuffers()),await this.loadImageFontAtlas(e),this.charCodeToAtlasIndex.fill(65535);for(let o=0;o<=l;o++)this.charCodeToAtlasIndex[o]=o;this.precomputeImageFontUVs(a),this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.useInstancing||this.precomputeStaticPositions(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}async loadImageFontAtlas(e){return new Promise((t,s)=>{let i=new Uint8Array(e),n=new Blob([i],{type:"image/png"}),a=URL.createObjectURL(n),l=new Image;l.onload=()=>{URL.revokeObjectURL(a),this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=l.width,this.atlasCanvas.height=l.height;let o=this.atlasCanvas.getContext("2d");if(!o){s(new Error("Failed to create 2D context for atlas"));return}o.drawImage(l,0,0),this.cachedAtlasWidth=l.width,this.cachedAtlasHeight=l.height,this.createAtlasTexture(),t()},l.onerror=()=>{URL.revokeObjectURL(a),s(new Error("Failed to load PNG image for ImageFont atlas"))},l.src=a})}precomputeImageFontUVs(e){let t=e*256;this.atlasUVs=new Float32Array(t*4);let s=this.cachedAtlasWidth,i=this.cachedAtlasHeight,n=.5/s,a=.5/i;for(let l=0;l<t;l++){let{col:o,row:c}=_(l,e),d=(o*this.charWidth+n)/s,h=(c*this.charHeight+a)/i,u=((o+1)*this.charWidth-n)/s,m=((c+1)*this.charHeight-a)/i,b=l*4;this.atlasUVs[b]=d,this.atlasUVs[b+1]=h,this.atlasUVs[b+2]=u,this.atlasUVs[b+3]=m}}generateAtlas(){if(!this.bitmapFont)return;let e=Array.from(this.bitmapFont.keys()).sort((o,c)=>o-c),t=e.length;this.atlasColumns=Math.ceil(Math.sqrt(t));let s=Math.ceil(t/this.atlasColumns),i=this.atlasColumns*this.charWidth,n=s*this.charHeight;this.atlasCanvas=document.createElement("canvas"),this.atlasCanvas.width=i,this.atlasCanvas.height=n;let a=this.atlasCanvas.getContext("2d");if(!a)throw new Error("Unable to create 2D context for atlas");a.clearRect(0,0,i,n),a.fillStyle="#ffffff";let l=0;for(let o of e){let c=this.bitmapFont.get(o);if(!c)continue;let d=l%this.atlasColumns,h=Math.floor(l/this.atlasColumns),u=d*this.charWidth,m=h*this.charHeight;for(let b=0;b<Math.min(c.length,this.charHeight);b++){let f=c[b];for(let p=0;p<this.charWidth;p++){let g=1<<7-p;f&g&&a.fillRect(u+p,m+b,1,1)}}l++}this.createAtlasTexture()}buildCharCodeMap(){if(!this.bitmapFont)return;this.charCodeToAtlasIndex.fill(65535);let e=Array.from(this.bitmapFont.keys()).sort((t,s)=>t-s);for(let t=0;t<e.length;t++)this.charCodeToAtlasIndex[e[t]]=t}precomputeAtlasUVs(){if(!this.bitmapFont)return;let e=this.bitmapFont.size;this.atlasUVs=new Float32Array(e*4),this.cachedAtlasWidth=this.atlasColumns*this.charWidth,this.cachedAtlasHeight=Math.ceil(e/this.atlasColumns)*this.charHeight;let t=this.cachedAtlasWidth,s=this.cachedAtlasHeight,i=.5/t,n=.5/s;for(let a=0;a<e;a++){let l=a%this.atlasColumns,o=Math.floor(a/this.atlasColumns),c=(l*this.charWidth+i)/t,d=(o*this.charHeight+n)/s,h=((l+1)*this.charWidth-i)/t,u=((o+1)*this.charHeight-n)/s,m=a*4;this.atlasUVs[m]=c,this.atlasUVs[m+1]=d,this.atlasUVs[m+2]=h,this.atlasUVs[m+3]=u}}createAtlasTexture(){if(this.atlasCanvas)try{let e=this.gl,t=e.createTexture();if(!t)throw new Error("Unable to create texture");e.bindTexture(e.TEXTURE_2D,t),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.atlasCanvas),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),this.atlasTexture=t}catch(e){throw console.error("[TerminalGL] \u274C Failed to create atlas texture:",e),e}}clear(){let e=this.gl;e&&e.clear(e.COLOR_BUFFER_BIT)}parseColor(e){if(e.startsWith("#")){let t=e.slice(1),s=0,i=0,n=0;return t.length===3?(s=parseInt(t[0]+t[0],16),i=parseInt(t[1]+t[1],16),n=parseInt(t[2]+t[2],16)):t.length===6&&(s=parseInt(t.slice(0,2),16),i=parseInt(t.slice(2,4),16),n=parseInt(t.slice(4,6),16)),[s/255,i/255,n/255,1]}if(e.startsWith("rgb")){let t=e.match(/rgba?\(([^)]+)\)/);if(t){let s=t[1].split(",").map(i=>parseFloat(i.trim()));return[s[0]/255,s[1]/255,s[2]/255,s[3]!==void 0?s[3]:1]}}return[1,1,1,1]}setupResizeObserver(){if(!(typeof ResizeObserver>"u"))try{this.resizeObserver=new ResizeObserver(()=>{try{this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Error in resize callback:",e)}}),this.resizeObserver.observe(this.parentElement),this.updateCanvasSize()}catch(e){console.error("[TerminalGL] \u274C Failed to setup ResizeObserver:",e)}}updateCanvasSize(){let e=this.parentElement.clientWidth,t=this.parentElement.clientHeight;if(e===0||t===0)return;let s=this.cols*this.cellWidth,i=this.rows*this.cellHeight;if(s===0||i===0)return;let n=e/s,a=t/i,l=Math.min(n,a),o;switch(this.scalingMode){case C.Integer:o=Math.max(1,Math.floor(l));break;case C.Half:o=Math.max(1,Math.floor(l*2)/2);break;case C.Quarter:o=Math.max(1,Math.floor(l*4)/4);break;case C.Eighth:o=Math.max(1,Math.floor(l*8)/8);break;case C.Responsive:o=1;break;case C.None:default:o=Math.max(.1,l);break}if(this.canvas.style.transform=`scale(${o})`,this.ambientEffectEnabled&&this.ambientEffectCanvas){let c=o*this.ambientEffectScale;this.ambientEffectCanvas.style.transform=`scale(${c})`}this.currentScale=o,this.onResizeCallback&&this.onResizeCallback(),this.showGrid&&this.gridOverlay&&this.updateGridOverlay()}updateAmbientEffect(){!this.ambientEffectCanvas||!this.ambientEffectCtx||this.ambientEffectCtx.drawImage(this.canvas,0,0)}setPalette(e){let t=0;for(let s=0;s<Math.min(e.length,256);s++){let i=e[s];t=(t<<5)-t+i.r,t=(t<<5)-t+i.g,t=(t<<5)-t+i.b,t=(t<<5)-t+i.a,t=t|0}if(t!==this.paletteHash){this.paletteHash=t;for(let s=0;s<e.length&&s<256;s++){let i=e[s],n=s*4;this.paletteFloat[n]=i.r/255,this.paletteFloat[n+1]=i.g/255,this.paletteFloat[n+2]=i.b/255,this.paletteFloat[n+3]=i.a/255}this.updatePaletteTexture()}}updatePaletteTexture(){try{let e=this.gl;this.paletteTexture||(this.paletteTexture=e.createTexture()),e.bindTexture(e.TEXTURE_2D,this.paletteTexture);let t=new Uint8Array(256*4);for(let s=0;s<256;s++){let i=s*4;t[i]=this.paletteFloat[i]*255,t[i+1]=this.paletteFloat[i+1]*255,t[i+2]=this.paletteFloat[i+2]*255,t[i+3]=this.paletteFloat[i+3]*255}e.texImage2D(e.TEXTURE_2D,0,e.RGBA,256,1,0,e.RGBA,e.UNSIGNED_BYTE,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.bindTexture(e.TEXTURE_2D,null)}catch(e){throw console.error("[TerminalGL] \u274C Failed to update palette texture:",e),e}}renderDisplayData(e){try{if(!this.isReady()){console.warn("[TerminalGL] \u26A0\uFE0F Not ready: font not loaded yet");return}(e.width!==this.cols||e.height!==this.rows)&&this.resize(e.width,e.height),this.renderDirect(e),this.ambientEffectEnabled&&this.ambientEffectCanvas&&this.ambientEffectCtx&&this.updateAmbientEffect()}catch(t){console.error("[TerminalGL] \u274C Error rendering display data:",t)}}renderDirect(e){let t=this.gl;if(!this.staticPositionsInitialized&&!this.useInstancing&&this.precomputeStaticPositions(),this.canvasBgColor!==null){let s=this.parseColor(this.canvasBgColor);t.clearColor(s[0],s[1],s[2],s[3])}else t.clearColor(0,0,0,0);t.clear(t.COLOR_BUFFER_BIT),this.useInstancing?this.renderInstanced(e):this.renderDirectBuffers(e)}renderInstanced(e){let t=this.gl,s=this.instancedExtension;if(!this.instanceData||this.instanceData.length===0){console.warn("[TerminalGL] \u26A0\uFE0F Instance data not initialized, falling back to standard rendering"),this.renderDirectBuffers(e);return}let i=0,n=this.instanceData.length/8,a=e.width*e.height*2;if(a>n){console.error(`[TerminalGL] \u274C Instance buffer too small! Need ${a}, have ${n}. Display size: ${e.width}\xD7${e.height}, buffer was sized for smaller terminal.`),this.renderDirectBuffers(e);return}for(let o=0;o<e.height;o++)for(let c=0;c<e.width;c++){let d=e.cells[o*e.width+c],h=d.bgColorIndex,u=d.fgColorIndex,m=this.canvasBgColor!==null&&h===255,b=d.char===" "||u===255;if(!m){if(i>=n){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${i}, max=${n}`);break}let f=i*8;this.instanceData[f]=c,this.instanceData[f+1]=o,this.instanceData[f+2]=0,this.instanceData[f+3]=0,this.instanceData[f+4]=0,this.instanceData[f+5]=0,this.instanceData[f+6]=h,this.instanceData[f+7]=0,i++}if(!b){let f=d.char.charCodeAt(0),p=this.charCodeToAtlasIndex[f];if(p!==65535){if(i>=n){console.error(`[TerminalGL] \u274C Instance buffer overflow! instanceIdx=${i}, max=${n}`);break}let g=p*4,x=i*8;this.instanceData[x]=c,this.instanceData[x+1]=o,this.instanceData[x+2]=this.atlasUVs[g],this.instanceData[x+3]=this.atlasUVs[g+1],this.instanceData[x+4]=this.atlasUVs[g+2],this.instanceData[x+5]=this.atlasUVs[g+3],this.instanceData[x+6]=0,this.instanceData[x+7]=u,i++}}}if(i===0){console.warn("[TerminalGL] \u26A0\uFE0F No instances to draw (all cells skipped)");return}t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.instanceData.subarray(0,i*8)),t.useProgram(this.program),t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),s.vertexAttribDivisorANGLE(this.aPosition,0),t.bindBuffer(t.ARRAY_BUFFER,this.instanceDataBuffer);let l=8*Float32Array.BYTES_PER_ELEMENT;t.enableVertexAttribArray(this.aInstanceOffset),t.vertexAttribPointer(this.aInstanceOffset,2,t.FLOAT,!1,l,0),s.vertexAttribDivisorANGLE(this.aInstanceOffset,1),t.enableVertexAttribArray(this.aInstanceUVs),t.vertexAttribPointer(this.aInstanceUVs,4,t.FLOAT,!1,l,2*Float32Array.BYTES_PER_ELEMENT),s.vertexAttribDivisorANGLE(this.aInstanceUVs,1),t.enableVertexAttribArray(this.aInstanceColors),t.vertexAttribPointer(this.aInstanceColors,2,t.FLOAT,!1,l,6*Float32Array.BYTES_PER_ELEMENT),s.vertexAttribDivisorANGLE(this.aInstanceColors,1),t.uniform2f(this.uResolution,this.canvas.width,this.canvas.height),t.uniform2f(this.uCellSize,this.cellWidth,this.cellHeight),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),t.uniform1i(this.uTexture,0),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),t.uniform1i(this.uPalette,1),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),s.drawElementsInstancedANGLE(t.TRIANGLES,6,t.UNSIGNED_SHORT,0,i),s.vertexAttribDivisorANGLE(this.aPosition,0),s.vertexAttribDivisorANGLE(this.aInstanceOffset,0),s.vertexAttribDivisorANGLE(this.aInstanceUVs,0),s.vertexAttribDivisorANGLE(this.aInstanceColors,0)}renderDirectBuffers(e){let t=this.gl,s=e.width*e.height,i=s*2;if(i>this.maxCells){console.error(`[TerminalGL] \u274C Buffer overflow detected! Trying to render ${i} quads but buffer capacity is ${this.maxCells}. This should not happen - resize() should have reallocated.`);return}let n=0,a=0,l=e.cells,o=s;for(let b=0;b<o;b++){let f=l[b],p=f.bgColorIndex,x=this.canvasBgColor!==null&&p===255?255:p,w=0;for(let T=0;T<4;T++)this.renderTexCoords[n++]=w,this.renderTexCoords[n++]=w,this.renderColorIndices[a++]=x;let A=f.fgColorIndex,S=f.char;if(S===" "||A===255)for(let T=0;T<4;T++)this.renderTexCoords[n++]=0,this.renderTexCoords[n++]=0,this.renderColorIndices[a++]=255;else{let T=S.charCodeAt(0),P=this.charCodeToAtlasIndex[T];if(P!==65535){let R=P*4,G=this.atlasUVs[R],W=this.atlasUVs[R+1],O=this.atlasUVs[R+2],H=this.atlasUVs[R+3];this.renderTexCoords[n++]=G,this.renderTexCoords[n++]=W,this.renderColorIndices[a++]=A,this.renderTexCoords[n++]=O,this.renderTexCoords[n++]=W,this.renderColorIndices[a++]=A,this.renderTexCoords[n++]=G,this.renderTexCoords[n++]=H,this.renderColorIndices[a++]=A,this.renderTexCoords[n++]=O,this.renderTexCoords[n++]=H,this.renderColorIndices[a++]=A}else for(let R=0;R<4;R++)this.renderTexCoords[n++]=0,this.renderTexCoords[n++]=0,this.renderColorIndices[a++]=255}}(n!==o*2*4*2||a!==o*2*4)&&console.error("[TerminalGL] \u274C Buffer index mismatch!",{texIdx:n,colorIdx:a,expected:o*2*4}),t.useProgram(this.program),this.vao&&this.vaoExtension?(this.vaoExtension.bindVertexArrayOES(this.vao),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,n)),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a))):(t.bindBuffer(t.ARRAY_BUFFER,this.positionBuffer),t.enableVertexAttribArray(this.aPosition),t.vertexAttribPointer(this.aPosition,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.texCoordBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderTexCoords.subarray(0,n)),t.enableVertexAttribArray(this.aTexCoord),t.vertexAttribPointer(this.aTexCoord,2,t.FLOAT,!1,0,0),t.bindBuffer(t.ARRAY_BUFFER,this.colorIndexBuffer),t.bufferSubData(t.ARRAY_BUFFER,0,this.renderColorIndices.subarray(0,a)),t.enableVertexAttribArray(this.aColorIndex),t.vertexAttribPointer(this.aColorIndex,1,t.FLOAT,!1,0,0));let c=this.canvas.width,d=this.canvas.height;(this.cachedResolution[0]!==c||this.cachedResolution[1]!==d)&&(t.uniform2f(this.uResolution,c,d),this.cachedResolution[0]=c,this.cachedResolution[1]=d),this.cachedTextureUnit!==0&&(t.activeTexture(t.TEXTURE0),this.cachedTextureUnit=0),t.bindTexture(t.TEXTURE_2D,this.atlasTexture),this.cachedTextureUniform||(t.uniform1i(this.uTexture,0),this.cachedTextureUniform=!0),this.cachedPaletteUnit!==1&&(t.activeTexture(t.TEXTURE1),this.cachedPaletteUnit=1),t.bindTexture(t.TEXTURE_2D,this.paletteTexture),this.cachedPaletteUniform||(t.uniform1i(this.uPalette,1),this.cachedPaletteUniform=!0),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer);let u=e.width*e.height*2*6,m=this.useUint16Indices?t.UNSIGNED_SHORT:t.UNSIGNED_INT;t.drawElements(t.TRIANGLES,u,m,0)}resize(e,t){if(!Number.isInteger(e)||e<=0){console.error(`[TerminalGL] \u274C Invalid cols: ${e}. Must be positive integer.`);return}if(!Number.isInteger(t)||t<=0){console.error(`[TerminalGL] \u274C Invalid rows: ${t}. Must be positive integer.`);return}if(e===this.cols&&t===this.rows)return;let s=e*t,i=this.useInstancing?262144:this.useUint16Indices?8191:262144;if(s>i){let d=Math.floor(Math.sqrt(i));console.error(`[TerminalGL] \u274C Cannot resize to ${e}\xD7${t} (${s} cells). Device limit: ${i} cells (max ~${d}\xD7${d}). ${!this.useInstancing&&this.useUint16Indices?"Device lacks OES_element_index_uint extension.":""}`);return}let n=y.checkCompatibility();s>n.recommendedMaxCells&&console.warn(`[TerminalGL] \u26A0\uFE0F Resizing to ${e}\xD7${t} (${s} cells) exceeds recommended limit (${n.recommendedMaxCells} cells). Performance may degrade.`),this.cols=e,this.rows=t,this.staticPositionsInitialized=!1;let a=this.cols*this.rows*2,l=Math.ceil(a*1.5),o=a>this.maxCells,c=this.maxCells>l*4;if(console.warn(`[TerminalGL] \u{1F4D0} resize check: cols=${e}, rows=${t}, newMaxCells=${a}, this.maxCells=${this.maxCells}, needGrow=${o}, needShrink=${c}`),o||c){let d=this.maxCells;if(this.maxCells=l,console.warn(`[TerminalGL] \u{1F4D0} resize realloc: ${d} \u2192 ${this.maxCells} (needGrow=${o}, needShrink=${c})`),this.renderPositions=new Float32Array(this.maxCells*4*2),this.renderTexCoords=new Float32Array(this.maxCells*4*2),this.renderColorIndices=new Float32Array(this.maxCells*4),this.useUint16Indices?this.renderIndices=new Uint16Array(this.maxCells*6):this.renderIndices=new Uint32Array(this.maxCells*6),this.useInstancing&&this.instanceDataBuffer){this.instanceData=new Float32Array(this.maxCells*8);let f=this.gl;f.bindBuffer(f.ARRAY_BUFFER,this.instanceDataBuffer),f.bufferData(f.ARRAY_BUFFER,this.instanceData.byteLength,f.DYNAMIC_DRAW)}let h=this.gl;this.useInstancing||(h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderPositions.byteLength,h.DYNAMIC_DRAW)),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderTexCoords.byteLength,h.DYNAMIC_DRAW),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.bufferData(h.ARRAY_BUFFER,this.renderColorIndices.byteLength,h.DYNAMIC_DRAW),this.useInstancing||(h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),h.bufferData(h.ELEMENT_ARRAY_BUFFER,this.renderIndices.byteLength,h.DYNAMIC_DRAW)),this.vaoExtension&&this.vao&&(this.vaoExtension.deleteVertexArrayOES(this.vao),this.vao=this.vaoExtension.createVertexArrayOES(),this.vao&&(this.vaoExtension.bindVertexArrayOES(this.vao),h.bindBuffer(h.ARRAY_BUFFER,this.positionBuffer),h.enableVertexAttribArray(this.aPosition),h.vertexAttribPointer(this.aPosition,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.texCoordBuffer),h.enableVertexAttribArray(this.aTexCoord),h.vertexAttribPointer(this.aTexCoord,2,h.FLOAT,!1,0,0),h.bindBuffer(h.ARRAY_BUFFER,this.colorIndexBuffer),h.enableVertexAttribArray(this.aColorIndex),h.vertexAttribPointer(this.aColorIndex,1,h.FLOAT,!1,0,0),h.bindBuffer(h.ELEMENT_ARRAY_BUFFER,this.indexBuffer),this.vaoExtension.bindVertexArrayOES(null)));let u=o?"\u{1F4C8} Growing":"\u{1F4C9} Shrinking",m=d*160/1048576,b=this.maxCells*160/1048576;console.warn(`[TerminalGL] ${u} buffers: ${m.toFixed(2)}MB \u2192 ${b.toFixed(2)}MB (${d} \u2192 ${this.maxCells} quads)`)}this.canvas.width=this.cols*this.cellWidth,this.canvas.height=this.rows*this.cellHeight,this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.canvas.style.width=`${this.canvas.width}px`,this.canvas.style.height=`${this.canvas.height}px`,this.ambientEffectEnabled&&this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.width=`${this.canvas.width}px`,this.ambientEffectCanvas.style.height=`${this.canvas.height}px`),this.showGrid&&this.gridOverlay&&this.updateGridOverlay(),this.updateCanvasSize()}getCanvas(){return this.canvas}getGridSize(){return{cols:this.cols,rows:this.rows}}getCellWidth(){return this.cellWidth}getCellHeight(){return this.cellHeight}getCurrentScale(){return this.currentScale}getBaseDimensions(){return{width:this.cols*this.cellWidth,height:this.rows*this.cellHeight}}setOnResizeCallback(e){this.onResizeCallback=e}clearOnResizeCallback(){this.onResizeCallback=void 0}getAvailableSize(){return{width:this.parentElement.clientWidth,height:this.parentElement.clientHeight}}setScalingMode(e){this.scalingMode!==e&&(this.scalingMode=e,this.updateCanvasSize())}getScalingMode(){return this.scalingMode}setCellSize(e,t){let s=Math.max(1,Math.min(255,Math.round(e))),i=Math.max(1,Math.min(255,Math.round(t)));this.cellWidth===s&&this.cellHeight===i||(this.cellWidth=s,this.cellHeight=i,this.charWidth=s,this.charHeight=i,this.glyphOffsetX=Math.round((this.cellWidth-this.charWidth)/2),this.glyphOffsetY=Math.round((this.cellHeight-this.charHeight)/2),this.fontLoaded&&this.generateAtlas(),this.useInstancing&&this.initInstancedBuffers(),this.updateCanvasSize())}getCellSize(){return{cellWidth:this.cellWidth,cellHeight:this.cellHeight}}getMaxCells(){return this.useInstancing?262144:this.useUint16Indices?8191:262144}setGrid(e){e.enabled?(this.gridOverlay?this.gridOverlay.setStyle({strokeColor:e.color,lineWidth:e.lineWidth}):this.gridOverlay=new I(this.containerDiv,{strokeColor:e.color??"rgba(144, 24, 24, 1)",lineWidth:e.lineWidth??1,zIndex:10}),this.showGrid=!0,this.gridOverlay.setVisible(!0),this.updateGridOverlay()):(this.showGrid=!1,this.gridOverlay&&this.gridOverlay.setVisible(!1))}isGridEnabled(){return this.showGrid}setAmbientEffect(e){typeof e=="boolean"?this.ambientEffectEnabled=e:(this.ambientEffectEnabled=!0,e.blur!==void 0&&(this.ambientEffectBlur=e.blur),e.scale!==void 0&&(this.ambientEffectScale=e.scale)),this.ambientEffectEnabled&&!this.ambientEffectCanvas&&this.createAmbientEffectCanvas(),this.ambientEffectCanvas&&(this.ambientEffectEnabled?(this.ambientEffectCanvas.style.display="block",this.ambientEffectCanvas.style.filter=`blur(${this.ambientEffectBlur}px)`,this.ambientEffectCanvas.style.transform=`scale(${this.ambientEffectScale})`,this.updateAmbientEffect()):this.ambientEffectCanvas.style.display="none")}createAmbientEffectCanvas(){this.ambientEffectCanvas||(this.ambientEffectCanvas=document.createElement("canvas"),this.ambientEffectCanvas.className="terminalgl-ambient-effect-canvas",this.ambientEffectCanvas.width=this.canvas.width,this.ambientEffectCanvas.height=this.canvas.height,this.ambientEffectCanvas.style.cssText=`
|
|
117
117
|
display: block !important;
|
|
118
118
|
position: absolute !important;
|
|
119
119
|
width: ${this.canvas.width}px !important;
|
|
@@ -124,4 +124,4 @@ var k=Object.defineProperty;var V=(b,e,t)=>e in b?k(b,e,{enumerable:!0,configura
|
|
|
124
124
|
transform: scale(${this.ambientEffectScale}) !important;
|
|
125
125
|
pointer-events: none !important;
|
|
126
126
|
z-index: 0 !important;
|
|
127
|
-
`,this.ambientEffectCtx=this.ambientEffectCanvas.getContext("2d",{alpha:!0}),this.containerDiv.insertBefore(this.ambientEffectCanvas,this.canvas),console.warn("[TerminalGL] \u{1F308} ambient effect canvas created dynamically"))}isAmbientEffectEnabled(){return this.ambientEffectEnabled}getAmbientEffectConfig(){return{enabled:this.ambientEffectEnabled,blur:this.ambientEffectBlur,scale:this.ambientEffectScale}}getCols(){return this.cols}getRows(){return this.rows}isReady(){return!!(this.fontLoaded&&this.atlasTexture&&this.program)}destroy(){this.dispose()}dispose(){this.resizeObserver&&this.resizeObserver.disconnect();let e=this.gl;this.program&&e.deleteProgram(this.program),this.positionBuffer&&e.deleteBuffer(this.positionBuffer),this.texCoordBuffer&&e.deleteBuffer(this.texCoordBuffer),this.colorIndexBuffer&&e.deleteBuffer(this.colorIndexBuffer),this.indexBuffer&&e.deleteBuffer(this.indexBuffer),this.instanceDataBuffer&&e.deleteBuffer(this.instanceDataBuffer),this.atlasTexture&&e.deleteTexture(this.atlasTexture),this.paletteTexture&&e.deleteTexture(this.paletteTexture),this.vao&&this.vaoExtension&&this.vaoExtension.deleteVertexArrayOES(this.vao);let t=e.getExtension("WEBGL_lose_context");t&&t.loseContext(),this.atlasCanvas&&(this.atlasCanvas.width=0,this.atlasCanvas.height=0,this.atlasCanvas=void 0),this.containerDiv.parentElement&&this.containerDiv.parentElement.removeChild(this.containerDiv),this.canvas.width=0,this.canvas.height=0,this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=0,this.ambientEffectCanvas.height=0,this.ambientEffectCanvas=null),this.gridOverlay&&(this.gridOverlay.destroy(),this.gridOverlay=void 0),this.renderPositions=new Float32Array(0),this.renderTexCoords=new Float32Array(0),this.renderColorIndices=new Float32Array(0),this.renderIndices=new Uint32Array(0),this.paletteFloat=new Float32Array(0),this.atlasUVs=new Float32Array(0),this.instanceData=new Float32Array(0),this.templateQuadPositions=new Float32Array(0),this.templateQuadIndices=new Uint16Array(0)}};
|
|
127
|
+
`,this.ambientEffectCtx=this.ambientEffectCanvas.getContext("2d",{alpha:!0}),this.containerDiv.insertBefore(this.ambientEffectCanvas,this.canvas),console.warn("[TerminalGL] \u{1F308} ambient effect canvas created dynamically"))}isAmbientEffectEnabled(){return this.ambientEffectEnabled}getAmbientEffectConfig(){return{enabled:this.ambientEffectEnabled,blur:this.ambientEffectBlur,scale:this.ambientEffectScale}}getCols(){return this.cols}getRows(){return this.rows}isReady(){return!!(this.fontLoaded&&this.atlasTexture&&this.program)}destroy(){this.dispose()}dispose(){this.resizeObserver&&this.resizeObserver.disconnect();let e=this.gl;this.program&&e.deleteProgram(this.program),this.positionBuffer&&e.deleteBuffer(this.positionBuffer),this.texCoordBuffer&&e.deleteBuffer(this.texCoordBuffer),this.colorIndexBuffer&&e.deleteBuffer(this.colorIndexBuffer),this.indexBuffer&&e.deleteBuffer(this.indexBuffer),this.instanceDataBuffer&&e.deleteBuffer(this.instanceDataBuffer),this.atlasTexture&&e.deleteTexture(this.atlasTexture),this.paletteTexture&&e.deleteTexture(this.paletteTexture),this.vao&&this.vaoExtension&&this.vaoExtension.deleteVertexArrayOES(this.vao);let t=e.getExtension("WEBGL_lose_context");t&&t.loseContext(),this.atlasCanvas&&(this.atlasCanvas.width=0,this.atlasCanvas.height=0,this.atlasCanvas=void 0),this.containerDiv.parentElement&&this.containerDiv.parentElement.removeChild(this.containerDiv),this.canvas.width=0,this.canvas.height=0,this.ambientEffectCanvas&&(this.ambientEffectCanvas.width=0,this.ambientEffectCanvas.height=0,this.ambientEffectCanvas=null),this.gridOverlay&&(this.gridOverlay.destroy(),this.gridOverlay=void 0),this.renderPositions=new Float32Array(0),this.renderTexCoords=new Float32Array(0),this.renderColorIndices=new Float32Array(0),this.renderIndices=new Uint32Array(0),this.paletteFloat=new Float32Array(0),this.atlasUVs=new Float32Array(0),this.instanceData=new Float32Array(0),this.templateQuadPositions=new Float32Array(0),this.templateQuadIndices=new Uint16Array(0)}};E(y,"TerminalGL");var D=y;var M=["#000000","#800000","#008000","#808000","#000080","#800080","#008080","#c0c0c0","#808080","#ff0000","#00ff00","#ffff00","#0000ff","#ff00ff","#00ffff","#ffffff","#080808","#121212","#1c1c1c","#262626","#303030","#3a3a3a","#444444","#4e4e4e","#585858","#626262","#6c6c6c","#767676","#808080","#8a8a8a","#949494","#9e9e9e","#a80000","#00a800","#a8a800","#0000a8","#a800a8","#00a8a8","#a8a8a8","#545454","#fc5454","#54fc54","#fcfc54","#5454fc","#fc54fc","#54fcfc","#fcfcfc","#000000",...Array(192).fill("#808080")];function Y(v,e=M){return v<0||v>=e.length?"#ff00ff":e[v]}E(Y,"paletteIndexToColor");function k(v,e=M){let t=e.indexOf(v.toLowerCase());return t>=0?t:0}E(k,"colorToPaletteIndex");export{M as DEFAULT_PALETTE,I as GridOverlay,C as ScalingMode,D as TerminalGL,k as colorToPaletteIndex,F as getAtlasColumns,_ as getCharGridPosition,L as getMaxCharCode,Y as paletteIndexToColor};
|