shaderpad 1.0.0-beta.61 → 1.0.0-beta.62

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/README.md CHANGED
@@ -303,7 +303,6 @@ Remove a previously registered callback.
303
303
 
304
304
  | Event | Callback Arguments | Description |
305
305
  | ------------------- | ------------------------------------------------------ | ------------------------------------------------ |
306
- | `resize` | `(width: number, height: number)` | Fired when the canvas element is resized |
307
306
  | `updateResolution` | `(width: number, height: number)` | Fired when the drawing buffer resolution changes |
308
307
  | `play` | none | Fired when the render loop starts |
309
308
  | `pause` | none | Fired when the render loop is paused |
@@ -318,12 +317,16 @@ Remove a previously registered callback.
318
317
  | `updateTextures` | `(updates, options?)` | Fired after textures are updated |
319
318
  | `updateUniforms` | `(updates, options?)` | Fired after uniforms are updated |
320
319
 
321
- Plugins may emit additional namespaced events (e.g., `face:ready`, `pose:results`).
320
+ Plugins may emit additional namespaced events (e.g., `face:ready`, `pose:result`).
322
321
 
323
322
  ## Options
324
323
 
325
324
  ShaderPad’s constructor accepts an optional `options` object.
326
325
 
326
+ In addition to the fields below, constructor options also accept texture storage/filter/wrap settings such as
327
+ `internalFormat`, `format`, `type`, `minFilter`, `magFilter`, `wrapS`, and `wrapT`. These configure ShaderPad’s
328
+ internal render targets and history buffers, which is mainly useful for float/integer pipelines and chained shaders.
329
+
327
330
  ### canvas
328
331
 
329
332
  The `canvas` option allows you to pass in an existing canvas element, dimensions object, or `null` for headless mode.
@@ -432,6 +435,8 @@ shader.save('filename', 'Optional mobile share text', { preventShare: true });
432
435
 
433
436
  **Function parameters:**
434
437
 
438
+ - `filename?` (string) - Output filename. Defaults to `export.png`
439
+ - `text?` (string) - Optional share text for platforms that support the Web Share API
435
440
  - `options.preventShare?: boolean` - If `true`, the Web Share API is not used and the file is always downloaded. Default: `false`.
436
441
 
437
442
  #### face
@@ -710,7 +715,7 @@ for (int i = 0; i < u_maxHands; ++i) {
710
715
 
711
716
  #### segmenter
712
717
 
713
- The `segmenter` plugin uses [MediaPipe Image Segmenter](https://ai.google.dev/edge/mediapipe/solutions/vision/image_segmenter) to segment objects in video or image textures. It supports models with multiple categories (e.g., background, hair, chair, dog…). By default, it uses the [hair segmentation model](https://ai.google.dev/edge/mediapipe/solutions/vision/image_segmenter#hair-model).
718
+ The `segmenter` plugin uses [MediaPipe Image Segmenter](https://ai.google.dev/edge/mediapipe/solutions/vision/image_segmenter) to segment objects in video or image textures. It supports models with multiple categories (e.g., background, hair, chair, dog…). By default, it uses MediaPipe's selfie segmenter model.
714
719
 
715
720
  ```typescript
716
721
  import ShaderPad from 'shaderpad';
@@ -731,7 +736,7 @@ const shader = new ShaderPad(fragmentShaderSrc, {
731
736
 
732
737
  **Options:**
733
738
 
734
- - `modelPath?: string` - Path to the segmentation model (default: DeepLab v3)
739
+ - `modelPath?: string` - Path to the segmentation model (default: MediaPipe selfie segmenter)
735
740
  - `outputConfidenceMasks?: boolean` - Whether to output per-category confidence masks (default: `false`). If `false`, confidence is always 1.
736
741
  - `history?: number` - Frames of history to store for mask texture
737
742
 
@@ -746,7 +751,7 @@ const shader = new ShaderPad(fragmentShaderSrc, {
746
751
 
747
752
  | Uniform | Type | Description |
748
753
  | ----------------- | ----------------------------- | ----------------------------------------------------------------------- |
749
- | `u_segmentMask` | sampler2D (or sampler2DArray) | Segment mask texture (R: normalized category, G: confidence, B: unused) |
754
+ | `u_segmentMask` | sampler2D (or sampler2DArray) | Segment mask texture (R: confidence, G: normalized category, B: unused) |
750
755
  | `u_numCategories` | int | Number of segmentation categories (including background) |
751
756
 
752
757
  **Helper functions:**
@@ -777,6 +782,12 @@ The `autosize` plugin handles automatic canvas resolution updates with ResizeObs
777
782
  - `target?: Element | Window` - What to observe for resize (default: canvas itself for HTMLCanvasElement, window for OffscreenCanvas)
778
783
  - `throttle?: number` - Throttle interval in milliseconds (default: 33ms)
779
784
 
785
+ **Events:**
786
+
787
+ | Event | Callback Arguments | Description |
788
+ | ----------------- | --------------------------------- | ---------------------------------------------------- |
789
+ | `autosize:resize` | `(width: number, height: number)` | Fired when the canvas drawing buffer size is updated |
790
+
780
791
  ## Contributing
781
792
 
782
793
  ### Running an example
@@ -0,0 +1,10 @@
1
+ import{a as F}from"./chunk-LXQJ4NRK.mjs";var O=`#version 300 es
2
+ in vec2 a_position;
3
+ out vec2 v_uv;
4
+ void main() {
5
+ gl_Position = vec4(a_position, 0.0, 1.0);
6
+ v_uv = a_position * 0.5 + 0.5;
7
+ }`,N=[["8UI","UNSIGNED_BYTE"],["8I","BYTE"],["16UI","UNSIGNED_SHORT"],["16I","SHORT"],["16F","HALF_FLOAT"],["32UI","UNSIGNED_INT"],["32I","INT"],["32F","FLOAT"],["8","UNSIGNED_BYTE"]],w={float:"f",int:"i",uint:"ui"};function D(h){return h&&N.find(([t])=>h.endsWith(t))?.[1]}var I=Symbol("u_history"),p=Symbol("__SHADERPAD_BUFFER"),A=new WeakMap;function C(h,t){if(!t?.length)return h;let e=h.split(`
8
+ `),r=e.findLastIndex(i=>{let s=i.trimStart();return s.startsWith("precision ")||s.startsWith("#version ")})+1;return e.splice(r,0,...t),e.join(`
9
+ `)}function G(h){return h instanceof WebGLTexture?{width:0,height:0}:h instanceof _?{width:h.canvas.width,height:h.canvas.height}:h instanceof HTMLVideoElement?{width:h.videoWidth,height:h.videoHeight}:h instanceof HTMLImageElement?{width:h.naturalWidth??h.width,height:h.naturalHeight??h.height}:{width:h.width,height:h.height}}function E(h){return typeof h=="symbol"?h.description??"":h}var _=class h{isHeadless=!1;isTouchDevice=!1;gl;glHelpers;uniforms=new Map;textures=new Map;textureUnitPool;buffer=null;vao=null;program=null;animationFrameId;eventListeners=new Map;frame=0;startTime=Number.NaN;isPlaying=!1;cursorPosition=[.5,.5];clickPosition=[.5,.5];isMouseDown=!1;canvas;resolutionObserver=null;hooks=new Map;historyDepth=0;textureOptions;debug;cursorTarget;intermediateFbo=null;constructor(t,{canvas:e,plugins:r,history:i,debug:s,cursorTarget:a,...o}={}){if(e&&"getContext"in e)this.canvas=e;else{let{width:f=1,height:m=1}=e||{};this.canvas=new OffscreenCanvas(f,m),this.isHeadless=!0}let n=this.canvas.getContext("webgl2",{antialias:!1});if(!n)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.gl=n,this.glHelpers={typeToArray:new Map([[n.FLOAT,Float32Array],[n.HALF_FLOAT,Uint16Array],[n.UNSIGNED_SHORT,Uint16Array],[n.SHORT,Int16Array],[n.BYTE,Int8Array],[n.UNSIGNED_INT,Uint32Array],[n.INT,Int32Array]]),typeToInternalFormatString:new Map([[n.FLOAT,"RGBA32F"],[n.HALF_FLOAT,"RGBA16F"],[n.UNSIGNED_SHORT,"RGBA32UI"],[n.SHORT,"RGBA32I"],[n.BYTE,"RGBA32I"],[n.UNSIGNED_INT,"RGBA32UI"],[n.INT,"RGBA32I"]]),unsignedIntTypes:new Set([n.UNSIGNED_BYTE,n.UNSIGNED_SHORT,n.UNSIGNED_INT])};let u=A.get(this.canvas);u||(u={textureUnitPool:{free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},instances:new Set([this])},A.set(this.canvas,u)),this.textureUnitPool=u.textureUnitPool,u.instances.add(this),this.textureOptions=o,i&&(this.historyDepth=i),this.debug=s??(typeof process<"u"&&!1),this.cursorTarget=a??(this.canvas instanceof HTMLCanvasElement?this.canvas:void 0),this.animationFrameId=null;let g=[];r&&r.forEach(f=>f(this,{gl:n,canvas:this.canvas,injectGLSL:m=>{g.push(m)},emitHook:this.emitHook.bind(this),updateTexturesInternal:this.updateTexturesInternal.bind(this)}));let l=this.gl.createProgram();if(!l)throw new Error("Failed to create WebGL program");this.program=l;let T=this.createShader(this.gl.VERTEX_SHADER,O),v=this.createShader(n.FRAGMENT_SHADER,C(t,g));if(n.attachShader(l,T),n.attachShader(l,v),n.bindAttribLocation(l,0,"a_position"),n.linkProgram(l),n.deleteShader(T),n.deleteShader(v),!n.getProgramParameter(l,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(l)),n.deleteProgram(l),new Error("Failed to link WebGL program");if(this.vao=n.createVertexArray(),n.bindVertexArray(this.vao),this.buffer=n.createBuffer(),n.bindBuffer(n.ARRAY_BUFFER,this.buffer),n.bufferData(n.ARRAY_BUFFER,new Float32Array([-1,-1,3,-1,-1,3]),n.STATIC_DRAW),n.enableVertexAttribArray(0),n.vertexAttribPointer(0,2,n.FLOAT,!1,0,0),n.viewport(0,0,n.drawingBufferWidth,n.drawingBufferHeight),n.useProgram(l),this.canvas instanceof HTMLCanvasElement)this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]});else{let f=m=>{let c=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,m),d=this.canvas;Object.defineProperty(d,m,{get:()=>c.get.call(d),set:x=>{c.set.call(d,x);let b=A.get(d);if(b)for(let y of b.instances)y.updateResolution()},configurable:c.configurable,enumerable:c.enumerable})};f("width"),f("height")}this.updateResolution(),this.initializeUniform("u_cursor","float",this.cursorPosition),this.initializeUniform("u_click","float",[...this.clickPosition,this.isMouseDown?1:0]),this.initializeUniform("u_time","float",0),this.initializeUniform("u_frame","int",0),this._initializeTexture(p,this.canvas,{...this.textureOptions}),this.intermediateFbo=n.createFramebuffer(),this.bindIntermediate(),n.bindFramebuffer(n.FRAMEBUFFER,null),this.historyDepth>0&&this._initializeTexture(I,this.canvas,{history:this.historyDepth,...this.textureOptions}),this.cursorTarget&&this.addEventListeners(),this.emitHook("_init")}resolveGLConstant(t){let e=this.gl[t];if(e===void 0)throw new Error(`Unknown GL constant: ${t}`);return e}emitHook(t,...e){this.hooks.get(t)?.forEach(r=>r.call(this,...e))}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}off(t,e){let r=this.hooks.get(t);if(r){let i=r.indexOf(e);i>=0&&r.splice(i,1)}}createShader(t,e){let r=this.gl.createShader(t);if(this.gl.shaderSource(r,e),this.gl.compileShader(r),!this.gl.getShaderParameter(r,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(r)),this.gl.deleteShader(r),new Error("Shader compilation failed");return r}getCursorTargetRect(){let t=this.cursorTarget;return t===window?{left:0,top:0,width:window.innerWidth,height:window.innerHeight}:t.getBoundingClientRect()}addEventListeners(){if(!this.cursorTarget)return;let t=(r,i)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.getCursorTargetRect(),a=(r-s.left)/s.width,o=1-(i-s.top)/s.height;this.cursorPosition[0]=Math.max(0,Math.min(1,a)),this.cursorPosition[1]=Math.max(0,Math.min(1,o)),this.updateUniforms({u_cursor:this.cursorPosition})},e=(r,i,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=r,r){let a=this.getCursorTargetRect(),o=i,n=s;this.clickPosition[0]=Math.max(0,Math.min(1,(o-a.left)/a.width)),this.clickPosition[1]=Math.max(0,Math.min(1,1-(n-a.top)/a.height))}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",r=>{let i=r;this.isTouchDevice||t(i.clientX,i.clientY)}),this.eventListeners.set("mousedown",r=>{let i=r;this.isTouchDevice||i.button===0&&(this.isMouseDown=!0,e(!0,i.clientX,i.clientY))}),this.eventListeners.set("mouseup",r=>{let i=r;this.isTouchDevice||i.button===0&&e(!1)}),this.eventListeners.set("touchmove",r=>{let i=r;i.touches.length>0&&t(i.touches[0].clientX,i.touches[0].clientY)}),this.eventListeners.set("touchstart",r=>{let i=r;this.isTouchDevice=!0,i.touches.length>0&&(t(i.touches[0].clientX,i.touches[0].clientY),e(!0,i.touches[0].clientX,i.touches[0].clientY))}),this.eventListeners.set("touchend",r=>{r.touches.length===0&&e(!1)}),this.eventListeners.forEach((r,i)=>{this.cursorTarget.addEventListener(i,r)})}updateResolution(){let t=[this.gl.drawingBufferWidth,this.gl.drawingBufferHeight];this.gl.viewport(0,0,...t),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:t}):this.initializeUniform("u_resolution","float",t),this.resizeTexture(p,...t),this.historyDepth>0&&this.resizeTexture(I,...t),this.emitHook("updateResolution",...t)}resizeTexture(t,e,r){let i=this.textures.get(t);if(!i||i.width===e&&i.height===r)return;this.gl.deleteTexture(i.texture),i.width=e,i.height=r;let{texture:s}=this.createTexture(t,i);i.texture=s,i.history&&(i.history.writeIndex=0,this.clearHistoryTextureLayers(i))}reserveTextureUnit(t){let e=this.textures.get(t);if(e)return e.unitIndex;if(this.textureUnitPool.free.length>0)return this.textureUnitPool.free.pop();if(this.textureUnitPool.next>=this.textureUnitPool.max)throw new Error("Exceeded the available texture units for this device.");return this.textureUnitPool.next++}resolveTextureOptions(t){let{gl:e}=this,r=t?.internalFormat,i=t?.type??D(r)??"UNSIGNED_BYTE",s=this.resolveGLConstant(i),a=r??this.glHelpers.typeToInternalFormatString.get(s)??"RGBA8",o=/^(R|RG|RGB|RGBA)(8|16|32)(UI|I)$/.test(a),n=t?.format??(o?"RGBA_INTEGER":"RGBA"),u={type:s,format:this.resolveGLConstant(n),internalFormat:this.resolveGLConstant(a),minFilter:this.resolveGLConstant(t?.minFilter??"LINEAR"),magFilter:this.resolveGLConstant(t?.magFilter??"LINEAR"),wrapS:this.resolveGLConstant(t?.wrapS??"CLAMP_TO_EDGE"),wrapT:this.resolveGLConstant(t?.wrapT??"CLAMP_TO_EDGE"),preserveY:t?.preserveY,isIntegerColorFormat:o};if((u.internalFormat===e.RGBA16F||u.internalFormat===e.RGBA32F)&&!e.getExtension("EXT_color_buffer_float"))throw new Error("Missing EXT_color_buffer_float.");return u}getPixelArray(t,e){let r=this.glHelpers.typeToArray.get(t)??Uint8Array;return new r(e)}isNotRgba(t){return t!==this.gl.RGBA&&t!==this.gl.RGBA_INTEGER}clearHistoryTextureLayers(t){if(!t.history)return;let e=this.gl,{type:r,format:i}=t.options,s=this.getPixelArray(r,t.width*t.height*4);e.activeTexture(e.TEXTURE0+t.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,t.texture);let a=this.isNotRgba(i),o;a&&(o=e.getParameter(e.UNPACK_ALIGNMENT),e.pixelStorei(e.UNPACK_ALIGNMENT,1));for(let n=0;n<t.history.depth;++n)e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,n,t.width,t.height,1,i,r,s);a&&e.pixelStorei(e.UNPACK_ALIGNMENT,o)}initializeUniform(t,e,r,i){let s=i?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(!w[e])throw new Error(`Invalid uniform type: ${e}. Expected one of: ${Object.keys(w).join(", ")}.`);if(s&&!(Array.isArray(r)&&r.length===s))throw new Error(`${t} array length mismatch: must initialize with ${s} elements.`);let a=this.gl.getUniformLocation(this.program,t);if(!a&&s&&(a=this.gl.getUniformLocation(this.program,`${t}[0]`)),!a){this.log(`${t} not in shader. Skipping initialization.`);return}let o=s?r[0]:r,n=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:n,location:a,arrayLength:s});try{this.updateUniforms({[t]:r})}catch(u){throw this.uniforms.delete(t),u}this.emitHook("initializeUniform",...arguments)}log(...t){this.debug&&console.debug(...t)}updateUniforms(t,e){this.gl.useProgram(this.program),Object.entries(t).forEach(([r,i])=>{let s=this.uniforms.get(r);if(!s){this.log(`${r} not in shader. Skipping update.`);return}let a=`uniform${s.length}${w[s.type]}`;if(s.arrayLength){if(!Array.isArray(i))throw new Error(`${r} is an array, but the value passed to updateUniforms is not an array.`);let o=i.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${r} received ${o} values, but maximum length is ${s.arrayLength}.`);if(i.some(l=>(Array.isArray(l)?l.length:1)!==s.length))throw new Error(`Tried to update ${r} with some elements that are not length ${s.length}.`);let n=i.flat(),u=s.type==="float"?new Float32Array(n):s.type==="uint"?new Uint32Array(n):new Int32Array(n),g=s.location;if(e?.startIndex){let l=this.gl.getUniformLocation(this.program,`${r}[${e.startIndex}]`);if(!l)throw new Error(`${r}[${e.startIndex}] not in shader. Did you pass an invalid startIndex?`);g=l}this.gl[a+"v"](g,u)}else{if(Array.isArray(i)||(i=[i]),i.length!==s.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${s.length}.`);this.gl[a](s.location,...i)}}),this.emitHook("updateUniforms",...arguments)}createTexture(t,e){let{width:r,height:i}=e,s=e.history?.depth??0,a=this.gl.createTexture();if(!a)throw new Error("Failed to create texture");let o=e.unitIndex;if(typeof o!="number")try{o=this.reserveTextureUnit(t)}catch(l){throw this.gl.deleteTexture(a),l}let n=s>0,u=n?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:g}=e;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(u,a),this.gl.texParameteri(u,this.gl.TEXTURE_WRAP_S,g.wrapS),this.gl.texParameteri(u,this.gl.TEXTURE_WRAP_T,g.wrapT),this.gl.texParameteri(u,this.gl.TEXTURE_MIN_FILTER,g.minFilter),this.gl.texParameteri(u,this.gl.TEXTURE_MAG_FILTER,g.magFilter),n?this.gl.texStorage3D(u,1,g.internalFormat,r,i,s):t===p&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,g.internalFormat,r,i,0,g.format,g.type,null),{texture:a,unitIndex:o}}_initializeTexture(t,e,r){if(this.textures.has(t))throw new Error(`Texture '${E(t)}' is already initialized.`);let{history:i=0,...s}=r??{},{width:a,height:o}=G(e);if(!a||!o)throw new Error("Texture source must have valid dimensions");let n={width:a,height:o,options:e instanceof h&&Object.keys(s).length===0&&e.textures.has(p)?e.textures.get(p).options:this.resolveTextureOptions(s)};i>0&&(n.history={depth:i,writeIndex:0});let{texture:u,unitIndex:g}=this.createTexture(t,n),l={texture:u,unitIndex:g,...n};i>0&&(this.initializeUniform(`${E(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(l)),this.textures.set(t,l),t!==p&&t!==I&&this.updateTexture(t,e),this.gl.useProgram(this.program);let T=this.gl.getUniformLocation(this.program,E(t));T&&this.gl.uniform1i(T,g)}initializeTexture(t,e,r){let i=r?.history!=null&&r.history>0?{...r,history:r.history+1}:r;this._initializeTexture(t,e,i),this.emitHook("initializeTexture",...arguments)}updateTextures(t,e){this.updateTexturesInternal(t,e),this.emitHook("updateTextures",...arguments)}updateTexturesInternal(t,e){Object.entries(t).forEach(([r,i])=>{this.updateTexture(r,i,e)})}updateTexture(t,e,r){let i=this.textures.get(t);if(!i)throw new Error(`Texture '${E(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let s=e;if(e instanceof h){let f=e.textures.get(p),m=f.width,c=f.height;if(e.gl===this.gl){if(!i.history){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,f.texture);return}let{depth:U}=i.history,S=r?.historyWriteIndex===void 0?[i.history.writeIndex]:Array.isArray(r?.historyWriteIndex)?r.historyWriteIndex.map(L=>F(L,U)):[F(r.historyWriteIndex,U)];this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,e.intermediateFbo),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture);for(let L of S)this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,L,0,0,m,c);this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,null),this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture);let P=`${E(t)}FrameOffset`;this.updateUniforms({[P]:S[S.length-1]}),r?.historyWriteIndex===void 0&&(i.history.writeIndex=(i.history.writeIndex+1)%U);return}let{width:d,height:x,options:{format:b,type:y}}=f,R=this.getPixelArray(y,d*x*4);e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,e.intermediateFbo),e.gl.readPixels(0,0,d,x,b,y,R),e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,null),s={data:R,width:d,height:x}}let{width:a,height:o}=G(s);if(!a||!o)return;let n="isPartial"in s&&s.isPartial;n||this.resizeTexture(t,a,o);let u="data"in s&&s.data,g=!u&&!i.options?.preserveY,l=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL),T=u&&this.isNotRgba(i.options.format),v;if(T&&(v=this.gl.getParameter(this.gl.UNPACK_ALIGNMENT),this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,1)),i.history){if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture),!r?.skipHistoryWrite){let{depth:f}=i.history,m=r?.historyWriteIndex===void 0?[i.history.writeIndex]:Array.isArray(r.historyWriteIndex)?r.historyWriteIndex.map(R=>F(R,f)):[F(r.historyWriteIndex,f)];this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g);let c=s,d=c.data??s,x=n?c.x??0:0,b=n?c.y??0:0;for(let R of m)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,x,b,R,a,o,1,i.options.format,i.options.type,d);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l);let y=`${E(t)}FrameOffset`;this.updateUniforms({[y]:m[m.length-1]}),r?.historyWriteIndex===void 0&&(i.history.writeIndex=(i.history.writeIndex+1)%f)}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,i.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g),n){let f=s;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,f.x??0,f.y??0,a,o,i.options.format,i.options.type,f.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,i.options.internalFormat,a,o,0,i.options.format,i.options.type,s.data??s);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l)}T&&this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,v)}bindIntermediate(){let t=this.gl,e=this.textures.get(p);t.bindFramebuffer(t.FRAMEBUFFER,this.intermediateFbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,e.texture,0)}clear(){this.bindIntermediate();let t=this.gl,e=this.textures.get(p);if(e.options.isIntegerColorFormat){let r=e.options.type;this.glHelpers.unsignedIntTypes.has(r)?t.clearBufferuiv(t.COLOR,0,new Uint32Array(4)):t.clearBufferiv(t.COLOR,0,new Int32Array(4))}else t.clear(t.COLOR_BUFFER_BIT)}draw(t){this.emitHook("beforeDraw",...arguments);let e=this.gl,r=e.drawingBufferWidth,i=e.drawingBufferHeight;t?.skipClear?this.bindIntermediate():this.clear(),e.useProgram(this.program),e.bindVertexArray(this.vao),e.viewport(0,0,r,i),e.drawArrays(e.TRIANGLES,0,3),this.isHeadless||this.textures.get(p).options.isIntegerColorFormat||(e.bindFramebuffer(e.READ_FRAMEBUFFER,this.intermediateFbo),e.bindFramebuffer(e.DRAW_FRAMEBUFFER,null),e.blitFramebuffer(0,0,r,i,0,0,r,i,e.COLOR_BUFFER_BIT,e.NEAREST),e.bindFramebuffer(e.FRAMEBUFFER,null)),this.emitHook("afterDraw",...arguments)}step(t){Number.isFinite(this.startTime)||(this.startTime=performance.now()),this._step((performance.now()-this.startTime)/1e3,t)}_step(t,e){this.emitHook("beforeStep",t,this.frame,e);let r={};this.uniforms.has("u_time")&&(r.u_time=t),this.uniforms.has("u_frame")&&(r.u_frame=this.frame),this.updateUniforms(r),this.draw(e);let i=this.textures.get(I);if(i&&!e?.skipHistoryWrite){let{writeIndex:s,depth:a}=i.history,o=this.gl;o.bindFramebuffer(o.READ_FRAMEBUFFER,this.intermediateFbo),o.bindTexture(o.TEXTURE_2D_ARRAY,i.texture),o.copyTexSubImage3D(o.TEXTURE_2D_ARRAY,0,0,0,s,0,0,o.drawingBufferWidth,o.drawingBufferHeight),o.bindFramebuffer(o.READ_FRAMEBUFFER,null);let n=(s+1)%a;this.updateUniforms({[`${E(I)}FrameOffset`]:n}),i.history.writeIndex=n}++this.frame,this.emitHook("afterStep",t,this.frame,e)}play(t){this._pause(),Number.isFinite(this.startTime)||(this.startTime=performance.now()),this.isPlaying=!0;let e=r=>{r=(r-this.startTime)/1e3;let i=t?.(r,this.frame)??void 0;this._step(r,i),this.isPlaying&&(this.animationFrameId=requestAnimationFrame(e))};this.animationFrameId=requestAnimationFrame(e),this.emitHook("play")}_pause(){let t=this.isPlaying;return this.isPlaying=!1,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),t}pause(){this._pause()&&this.emitHook("pause")}resetFrame(){this.frame=0,this.startTime=performance.now()}reset(){this.resetFrame(),this.textures.forEach(t=>{t.history&&(t.history.writeIndex=0,this.clearHistoryTextureLayers(t))}),this.clear(),this.emitHook("reset")}destroy(){this.emitHook("destroy"),this._pause(),this.cursorTarget&&(this.eventListeners.forEach((e,r)=>{this.cursorTarget.removeEventListener(r,e)}),this.eventListeners.clear()),this.resolutionObserver&&(this.resolutionObserver.disconnect(),this.resolutionObserver=null),this.program&&(this.gl.deleteProgram(this.program),this.program=null),this.intermediateFbo&&(this.gl.deleteFramebuffer(this.intermediateFbo),this.intermediateFbo=null),this.textures.forEach(e=>{this.textureUnitPool.free.push(e.unitIndex),this.gl.deleteTexture(e.texture)}),this.textures.clear();let t=A.get(this.canvas);t&&(t.instances.delete(this),t.instances.size===0&&A.delete(this.canvas)),this.vao&&(this.gl.deleteVertexArray(this.vao),this.vao=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.uniforms.clear(),this.hooks.clear()}},B=_;export{B as a};
10
+ //# sourceMappingURL=chunk-BWFX3DVI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { safeMod } from './util.js';\n\nconst DEFAULT_VERTEX_SHADER_SRC = `#version 300 es\nin vec2 a_position;\nout vec2 v_uv;\nvoid main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n v_uv = a_position * 0.5 + 0.5;\n}`;\n\ninterface Uniform {\n\ttype: 'float' | 'int' | 'uint';\n\tlength: 1 | 2 | 3 | 4;\n\tlocation: WebGLUniformLocation;\n\tarrayLength?: number;\n}\n\ntype GLInternalFormatChannels = 'R' | 'RG' | 'RGB' | 'RGBA';\ntype GLInternalFormatDepth = '8' | '16F' | '32F' | '8UI' | '8I' | '16UI' | '16I' | '32UI' | '32I';\nexport type GLInternalFormatString = `${GLInternalFormatChannels}${GLInternalFormatDepth}`;\n\nexport type GLFormatString =\n\t| 'RED'\n\t| 'RG'\n\t| 'RGB'\n\t| 'RGBA'\n\t| 'RED_INTEGER'\n\t| 'RG_INTEGER'\n\t| 'RGB_INTEGER'\n\t| 'RGBA_INTEGER';\nexport type GLTypeString =\n\t| 'UNSIGNED_BYTE'\n\t| 'BYTE'\n\t| 'FLOAT'\n\t| 'HALF_FLOAT'\n\t| 'UNSIGNED_SHORT'\n\t| 'SHORT'\n\t| 'UNSIGNED_INT'\n\t| 'INT';\nexport type GLFilterString = 'LINEAR' | 'NEAREST';\nexport type GLWrapString = 'CLAMP_TO_EDGE' | 'REPEAT' | 'MIRRORED_REPEAT';\n\nconst FORMAT_TYPE_SUFFIXES: [string, GLTypeString][] = [\n\t['8UI', 'UNSIGNED_BYTE'],\n\t['8I', 'BYTE'],\n\t['16UI', 'UNSIGNED_SHORT'],\n\t['16I', 'SHORT'],\n\t['16F', 'HALF_FLOAT'],\n\t['32UI', 'UNSIGNED_INT'],\n\t['32I', 'INT'],\n\t['32F', 'FLOAT'],\n\t['8', 'UNSIGNED_BYTE'],\n];\n\nconst UNIFORM_TYPE_SUFFIXES: Record<Uniform['type'], string> = {\n\tfloat: 'f',\n\tint: 'i',\n\tuint: 'ui',\n};\n\nfunction typeFromInternalFormatString(internalFormatString?: GLInternalFormatString): GLTypeString | undefined {\n\treturn internalFormatString && FORMAT_TYPE_SUFFIXES.find(([suffix]) => internalFormatString.endsWith(suffix))?.[1];\n}\n\ntype GLConstantString = GLInternalFormatString | GLFormatString | GLTypeString | GLFilterString | GLWrapString;\n\nexport interface TextureOptions {\n\tinternalFormat?: GLInternalFormatString;\n\tformat?: GLFormatString;\n\ttype?: GLTypeString;\n\tminFilter?: GLFilterString;\n\tmagFilter?: GLFilterString;\n\twrapS?: GLWrapString;\n\twrapT?: GLWrapString;\n\tpreserveY?: boolean;\n}\ntype ResolvedTextureOptions = {\n\ttype: number;\n\tformat: number;\n\tinternalFormat: number;\n\tminFilter: number;\n\tmagFilter: number;\n\twrapS: number;\n\twrapT: number;\n\tpreserveY?: boolean;\n\tisIntegerColorFormat: boolean;\n};\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n\twidth: number;\n\theight: number;\n\thistory?: {\n\t\tdepth: number;\n\t\twriteIndex: number;\n\t};\n\toptions: ResolvedTextureOptions;\n}\n\nexport interface CustomTexture {\n\tdata: ArrayBufferView | null;\n\twidth: number;\n\theight: number;\n}\n\nexport interface PartialCustomTexture extends CustomTexture {\n\tisPartial?: boolean;\n\tx?: number;\n\ty?: number;\n}\n\nexport type TextureSource =\n\t| HTMLImageElement\n\t| HTMLVideoElement\n\t| HTMLCanvasElement\n\t| OffscreenCanvas\n\t| ImageBitmap\n\t| WebGLTexture\n\t| CustomTexture\n\t| ShaderPad;\n\n// Custom textures allow partial updates starting from (x, y).\ntype UpdateTextureSource = Exclude<TextureSource, CustomTexture> | PartialCustomTexture;\n\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tcanvas: HTMLCanvasElement | OffscreenCanvas;\n\tinjectGLSL: (code: string) => void;\n\temitHook: (name: LifecycleMethod, ...args: any[]) => void;\n\tupdateTexturesInternal: (\n\t\tupdates: Record<string, UpdateTextureSource>,\n\t\toptions?: InternalUpdateTexturesOptions,\n\t) => void;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod =\n\t| '_init'\n\t| 'initializeTexture'\n\t| 'initializeUniform'\n\t| 'updateTextures'\n\t| 'updateUniforms'\n\t| 'beforeStep'\n\t| 'afterStep'\n\t| 'beforeDraw'\n\t| 'afterDraw'\n\t| 'updateResolution'\n\t| 'play'\n\t| 'pause'\n\t| 'reset'\n\t| 'destroy'\n\t| `${string}:${string}`;\n\nexport type RenderTextureOptions = Omit<TextureOptions, 'preserveY'>;\n\nexport interface Options extends RenderTextureOptions {\n\tcanvas?: HTMLCanvasElement | OffscreenCanvas | { width: number; height: number } | null;\n\tplugins?: Plugin[];\n\thistory?: number;\n\tdebug?: boolean;\n\tcursorTarget?: Window | Element;\n}\n\nexport interface StepOptions {\n\tskipClear?: boolean;\n\tskipHistoryWrite?: boolean;\n}\n\nexport interface UpdateTexturesOptions {\n\tskipHistoryWrite?: boolean;\n}\n\ntype InternalUpdateTexturesOptions = UpdateTexturesOptions & {\n\thistoryWriteIndex?: number | number[];\n};\n\ntype TextureUnitPool = {\n\tfree: number[];\n\tnext: number;\n\tmax: number;\n};\n\nconst HISTORY_TEXTURE_KEY = Symbol('u_history');\nconst INTERMEDIATE_TEXTURE_KEY = Symbol('__SHADERPAD_BUFFER');\n\nconst canvasRegistry = new WeakMap<\n\tHTMLCanvasElement | OffscreenCanvas,\n\t{ textureUnitPool: TextureUnitPool; instances: Set<ShaderPad> }\n>();\n\nfunction combineShaderCode(shader: string, injections: string[]): string {\n\tif (!injections?.length) return shader;\n\tconst lines = shader.split('\\n');\n\tconst insertAt =\n\t\tlines.findLastIndex(line => {\n\t\t\tconst trimmed = line.trimStart();\n\t\t\treturn trimmed.startsWith('precision ') || trimmed.startsWith('#version ');\n\t\t}) + 1;\n\tlines.splice(insertAt, 0, ...injections);\n\treturn lines.join('\\n');\n}\n\nfunction getSourceDimensions(source: TextureSource): {\n\twidth: number;\n\theight: number;\n} {\n\tif (source instanceof WebGLTexture) {\n\t\treturn { width: 0, height: 0 }; // Invalid - dimensions not readable.\n\t}\n\tif (source instanceof ShaderPad) {\n\t\treturn { width: source.canvas.width, height: source.canvas.height };\n\t}\n\tif (source instanceof HTMLVideoElement) {\n\t\treturn { width: source.videoWidth, height: source.videoHeight };\n\t}\n\tif (source instanceof HTMLImageElement) {\n\t\treturn {\n\t\t\twidth: source.naturalWidth ?? source.width,\n\t\t\theight: source.naturalHeight ?? source.height,\n\t\t};\n\t}\n\t// CustomTexture, HTMLCanvasElement, OffscreenCanvas, ImageBitmap.\n\treturn { width: source.width, height: source.height };\n}\n\nfunction stringFrom(name: string | symbol) {\n\treturn typeof name === 'symbol' ? (name.description ?? '') : name;\n}\n\nclass ShaderPad {\n\tprivate isHeadless = false;\n\tprivate isTouchDevice = false;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate glHelpers!: {\n\t\ttypeToArray: Map<number, new (length: number) => ArrayBufferView>;\n\t\ttypeToInternalFormatString: Map<number, GLInternalFormatString>;\n\t\tunsignedIntTypes: Set<number>;\n\t};\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string | symbol, Texture> = new Map();\n\tprivate textureUnitPool: TextureUnitPool;\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate vao: WebGLVertexArrayObject | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate animationFrameId: number | null;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\tprivate frame = 0;\n\tprivate startTime = Number.NaN;\n\tprivate isPlaying = false;\n\tprivate cursorPosition = [0.5, 0.5];\n\tprivate clickPosition = [0.5, 0.5];\n\tprivate isMouseDown = false;\n\tpublic canvas: HTMLCanvasElement | OffscreenCanvas;\n\tprivate resolutionObserver: MutationObserver | null = null;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\tprivate historyDepth = 0;\n\tprivate textureOptions: TextureOptions;\n\tprivate debug: boolean;\n\tprivate cursorTarget: Window | Element | undefined;\n\t// WebGL can’t read from and write to the history texture at the same time.\n\t// We write to an intermediate texture then blit to the history texture.\n\tprivate intermediateFbo: WebGLFramebuffer | null = null;\n\n\tconstructor(\n\t\tfragmentShaderSrc: string,\n\t\t{ canvas, plugins, history, debug, cursorTarget, ...textureOptions }: Options = {},\n\t) {\n\t\tif (canvas && 'getContext' in canvas) {\n\t\t\tthis.canvas = canvas;\n\t\t} else {\n\t\t\tconst { width = 1, height = 1 } = canvas || {};\n\t\t\tthis.canvas = new OffscreenCanvas(width, height);\n\t\t\tthis.isHeadless = true;\n\t\t}\n\n\t\tconst gl = this.canvas.getContext('webgl2', {\n\t\t\tantialias: false,\n\t\t}) as WebGL2RenderingContext;\n\t\tif (!gl) {\n\t\t\tthrow new Error('WebGL2 not supported. Please use a browser that supports WebGL2.');\n\t\t}\n\t\tthis.gl = gl;\n\t\tthis.glHelpers = {\n\t\t\ttypeToArray: new Map<number, new (length: number) => ArrayBufferView>([\n\t\t\t\t[gl.FLOAT, Float32Array],\n\t\t\t\t[gl.HALF_FLOAT, Uint16Array],\n\t\t\t\t[gl.UNSIGNED_SHORT, Uint16Array],\n\t\t\t\t[gl.SHORT, Int16Array],\n\t\t\t\t[gl.BYTE, Int8Array],\n\t\t\t\t[gl.UNSIGNED_INT, Uint32Array],\n\t\t\t\t[gl.INT, Int32Array],\n\t\t\t]),\n\t\t\ttypeToInternalFormatString: new Map<number, GLInternalFormatString>([\n\t\t\t\t[gl.FLOAT, 'RGBA32F'],\n\t\t\t\t[gl.HALF_FLOAT, 'RGBA16F'],\n\t\t\t\t[gl.UNSIGNED_SHORT, 'RGBA32UI'],\n\t\t\t\t[gl.SHORT, 'RGBA32I'],\n\t\t\t\t[gl.BYTE, 'RGBA32I'],\n\t\t\t\t[gl.UNSIGNED_INT, 'RGBA32UI'],\n\t\t\t\t[gl.INT, 'RGBA32I'],\n\t\t\t]),\n\t\t\tunsignedIntTypes: new Set([gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT, gl.UNSIGNED_INT]),\n\t\t};\n\n\t\tlet registryEntry = canvasRegistry.get(this.canvas);\n\t\tif (!registryEntry) {\n\t\t\tregistryEntry = {\n\t\t\t\ttextureUnitPool: {\n\t\t\t\t\tfree: [],\n\t\t\t\t\tnext: 0,\n\t\t\t\t\tmax: gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),\n\t\t\t\t},\n\t\t\t\tinstances: new Set([this]),\n\t\t\t};\n\t\t\tcanvasRegistry.set(this.canvas, registryEntry);\n\t\t}\n\t\tthis.textureUnitPool = registryEntry.textureUnitPool;\n\t\tregistryEntry.instances.add(this);\n\n\t\tthis.textureOptions = textureOptions;\n\n\t\tif (history) this.historyDepth = history;\n\t\tthis.debug = debug ?? (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production');\n\t\tthis.cursorTarget = cursorTarget ?? (this.canvas instanceof HTMLCanvasElement ? this.canvas : undefined);\n\t\tthis.animationFrameId = null;\n\n\t\tconst glslInjections: string[] = [];\n\t\tif (plugins) {\n\t\t\tplugins.forEach(plugin =>\n\t\t\t\tplugin(this, {\n\t\t\t\t\tgl,\n\t\t\t\t\tcanvas: this.canvas,\n\t\t\t\t\tinjectGLSL: (code: string) => {\n\t\t\t\t\t\tglslInjections.push(code);\n\t\t\t\t\t},\n\t\t\t\t\temitHook: this.emitHook.bind(this),\n\t\t\t\t\tupdateTexturesInternal: this.updateTexturesInternal.bind(this),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst program = this.gl.createProgram();\n\t\tif (!program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tthis.program = program;\n\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, DEFAULT_VERTEX_SHADER_SRC);\n\t\tconst fragmentShader = this.createShader(\n\t\t\tgl.FRAGMENT_SHADER,\n\t\t\tcombineShaderCode(fragmentShaderSrc, glslInjections),\n\t\t);\n\t\tgl.attachShader(program, vertexShader);\n\t\tgl.attachShader(program, fragmentShader);\n\t\tgl.bindAttribLocation(program, 0, 'a_position');\n\t\tgl.linkProgram(program);\n\t\tgl.deleteShader(vertexShader);\n\t\tgl.deleteShader(fragmentShader);\n\n\t\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', gl.getProgramInfoLog(program));\n\t\t\tgl.deleteProgram(program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\tthis.vao = gl.createVertexArray();\n\t\tgl.bindVertexArray(this.vao);\n\t\tthis.buffer = gl.createBuffer();\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);\n\t\tgl.enableVertexAttribArray(0);\n\t\tgl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n\t\tgl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n\n\t\tgl.useProgram(program);\n\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\t\tthis.resolutionObserver.observe(this.canvas, {\n\t\t\t\tattributes: true,\n\t\t\t\tattributeFilter: ['width', 'height'],\n\t\t\t});\n\t\t} else {\n\t\t\tconst wrapDimension = (dimension: 'width' | 'height') => {\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype, dimension)!;\n\t\t\t\tconst canvas = this.canvas;\n\t\t\t\tObject.defineProperty(canvas, dimension, {\n\t\t\t\t\tget: () => descriptor.get!.call(canvas),\n\t\t\t\t\tset: v => {\n\t\t\t\t\t\tdescriptor.set!.call(canvas, v);\n\t\t\t\t\t\tconst entry = canvasRegistry.get(canvas);\n\t\t\t\t\t\tif (entry) {\n\t\t\t\t\t\t\tfor (const instance of entry.instances) {\n\t\t\t\t\t\t\t\tinstance.updateResolution();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tconfigurable: descriptor.configurable,\n\t\t\t\t\tenumerable: descriptor.enumerable,\n\t\t\t\t});\n\t\t\t};\n\t\t\twrapDimension('width');\n\t\t\twrapDimension('height');\n\t\t}\n\t\tthis.updateResolution();\n\n\t\tthis.initializeUniform('u_cursor', 'float', this.cursorPosition);\n\t\tthis.initializeUniform('u_click', 'float', [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0]);\n\t\tthis.initializeUniform('u_time', 'float', 0);\n\t\tthis.initializeUniform('u_frame', 'int', 0);\n\n\t\tthis._initializeTexture(INTERMEDIATE_TEXTURE_KEY, this.canvas, {\n\t\t\t...this.textureOptions,\n\t\t});\n\t\tthis.intermediateFbo = gl.createFramebuffer();\n\t\tthis.bindIntermediate();\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\n\t\tif (this.historyDepth > 0) {\n\t\t\tthis._initializeTexture(HISTORY_TEXTURE_KEY, this.canvas, {\n\t\t\t\thistory: this.historyDepth,\n\t\t\t\t...this.textureOptions,\n\t\t\t});\n\t\t}\n\t\tif (this.cursorTarget) {\n\t\t\tthis.addEventListeners();\n\t\t}\n\t\tthis.emitHook('_init');\n\t}\n\n\tprivate resolveGLConstant(value: GLConstantString): number {\n\t\tconst resolved = this.gl[value];\n\t\tif (resolved === undefined) {\n\t\t\tthrow new Error(`Unknown GL constant: ${value}`);\n\t\t}\n\t\treturn resolved;\n\t}\n\n\tprivate emitHook(name: LifecycleMethod, ...args: any[]) {\n\t\tthis.hooks.get(name)?.forEach(hook => hook.call(this, ...args));\n\t}\n\n\ton(name: LifecycleMethod, fn: Function) {\n\t\tif (!this.hooks.has(name)) {\n\t\t\tthis.hooks.set(name, []);\n\t\t}\n\t\tthis.hooks.get(name)!.push(fn);\n\t}\n\n\toff(name: LifecycleMethod, fn: Function) {\n\t\tconst hooks = this.hooks.get(name);\n\t\tif (hooks) {\n\t\t\tconst index = hooks.indexOf(fn);\n\t\t\tif (index >= 0) {\n\t\t\t\thooks.splice(index, 1);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate getCursorTargetRect(): {\n\t\tleft: number;\n\t\ttop: number;\n\t\twidth: number;\n\t\theight: number;\n\t} {\n\t\tconst target = this.cursorTarget!;\n\t\tif (target === window) {\n\t\t\treturn {\n\t\t\t\tleft: 0,\n\t\t\t\ttop: 0,\n\t\t\t\twidth: window.innerWidth,\n\t\t\t\theight: window.innerHeight,\n\t\t\t};\n\t\t}\n\t\treturn (target as Element).getBoundingClientRect();\n\t}\n\n\tprivate addEventListeners() {\n\t\tif (!this.cursorTarget) return;\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = this.getCursorTargetRect();\n\t\t\tconst u = (x - rect.left) / rect.width;\n\t\t\tconst v = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\tthis.cursorPosition[0] = Math.max(0, Math.min(1, u));\n\t\t\tthis.cursorPosition[1] = Math.max(0, Math.min(1, v));\n\t\t\tthis.updateUniforms({ u_cursor: this.cursorPosition });\n\t\t};\n\n\t\tconst updateClick = (isMouseDown: boolean, x?: number, y?: number) => {\n\t\t\tif (!this.uniforms.has('u_click')) return;\n\t\t\tthis.isMouseDown = isMouseDown;\n\t\t\tif (isMouseDown) {\n\t\t\t\tconst rect = this.getCursorTargetRect();\n\t\t\t\tconst xVal = x as number;\n\t\t\t\tconst yVal = y as number;\n\t\t\t\tthis.clickPosition[0] = Math.max(0, Math.min(1, (xVal - rect.left) / rect.width));\n\t\t\t\tthis.clickPosition[1] = Math.max(0, Math.min(1, 1 - (yVal - rect.top) / rect.height)); // Flip Y for WebGL\n\t\t\t}\n\t\t\tthis.updateUniforms({\n\t\t\t\tu_click: [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0],\n\t\t\t});\n\t\t};\n\n\t\tthis.eventListeners.set('mousemove', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tupdateCursor(mouseEvent.clientX, mouseEvent.clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('mousedown', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tif (mouseEvent.button === 0) {\n\t\t\t\t\tthis.isMouseDown = true;\n\t\t\t\t\tupdateClick(true, mouseEvent.clientX, mouseEvent.clientY);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('mouseup', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tif (mouseEvent.button === 0) {\n\t\t\t\t\tupdateClick(false);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchmove', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tif (touchEvent.touches.length > 0) {\n\t\t\t\tupdateCursor(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchstart', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tthis.isTouchDevice = true;\n\t\t\tif (touchEvent.touches.length > 0) {\n\t\t\t\tupdateCursor(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t\tupdateClick(true, touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchend', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tif (touchEvent.touches.length === 0) {\n\t\t\t\tupdateClick(false);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\tthis.cursorTarget!.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tupdateResolution() {\n\t\tconst resolution: [number, number] = [this.gl.drawingBufferWidth, this.gl.drawingBufferHeight];\n\t\tthis.gl.viewport(0, 0, ...resolution);\n\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\tthis.updateUniforms({ u_resolution: resolution });\n\t\t} else {\n\t\t\tthis.initializeUniform('u_resolution', 'float', resolution);\n\t\t}\n\t\tthis.resizeTexture(INTERMEDIATE_TEXTURE_KEY, ...resolution);\n\t\tif (this.historyDepth > 0) {\n\t\t\tthis.resizeTexture(HISTORY_TEXTURE_KEY, ...resolution);\n\t\t}\n\t\tthis.emitHook('updateResolution', ...resolution);\n\t}\n\n\tprivate resizeTexture(name: string | symbol, width: number, height: number) {\n\t\tconst info = this.textures.get(name);\n\t\tif (!info || (info.width === width && info.height === height)) return;\n\n\t\tthis.gl.deleteTexture(info.texture);\n\t\tinfo.width = width;\n\t\tinfo.height = height;\n\t\tconst { texture } = this.createTexture(name, info);\n\t\tinfo.texture = texture;\n\t\tif (info.history) {\n\t\t\tinfo.history.writeIndex = 0;\n\t\t\tthis.clearHistoryTextureLayers(info);\n\t\t}\n\t}\n\n\tprivate reserveTextureUnit(name: string | symbol) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) return existing.unitIndex;\n\t\tif (this.textureUnitPool.free.length > 0) return this.textureUnitPool.free.pop()!;\n\t\tif (this.textureUnitPool.next >= this.textureUnitPool.max) {\n\t\t\tthrow new Error('Exceeded the available texture units for this device.');\n\t\t}\n\t\treturn this.textureUnitPool.next++;\n\t}\n\n\tprivate resolveTextureOptions(options?: TextureOptions): ResolvedTextureOptions {\n\t\tconst { gl } = this;\n\t\tconst internalFormatOption = options?.internalFormat;\n\t\tconst typeString = options?.type ?? typeFromInternalFormatString(internalFormatOption) ?? 'UNSIGNED_BYTE';\n\t\tconst type = this.resolveGLConstant(typeString);\n\t\tconst internalFormatString =\n\t\t\tinternalFormatOption ?? this.glHelpers.typeToInternalFormatString.get(type) ?? 'RGBA8';\n\t\tconst isIntegerColorFormat = /^(R|RG|RGB|RGBA)(8|16|32)(UI|I)$/.test(internalFormatString);\n\t\tconst formatString = options?.format ?? (isIntegerColorFormat ? 'RGBA_INTEGER' : 'RGBA');\n\t\tconst result: ResolvedTextureOptions = {\n\t\t\ttype,\n\t\t\tformat: this.resolveGLConstant(formatString),\n\t\t\tinternalFormat: this.resolveGLConstant(internalFormatString),\n\t\t\tminFilter: this.resolveGLConstant(options?.minFilter ?? 'LINEAR'),\n\t\t\tmagFilter: this.resolveGLConstant(options?.magFilter ?? 'LINEAR'),\n\t\t\twrapS: this.resolveGLConstant(options?.wrapS ?? 'CLAMP_TO_EDGE'),\n\t\t\twrapT: this.resolveGLConstant(options?.wrapT ?? 'CLAMP_TO_EDGE'),\n\t\t\tpreserveY: options?.preserveY,\n\t\t\tisIntegerColorFormat,\n\t\t};\n\t\tconst isFloatColorFormat = result.internalFormat === gl.RGBA16F || result.internalFormat === gl.RGBA32F;\n\t\t// gl.getExtension isn’t just a check, it’s a required side-effect to enable floats.\n\t\tif (isFloatColorFormat && !gl.getExtension('EXT_color_buffer_float')) {\n\t\t\tthrow new Error('Missing EXT_color_buffer_float.');\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate getPixelArray(type: number, size: number): ArrayBufferView {\n\t\tconst ArrayType = this.glHelpers.typeToArray.get(type) ?? Uint8Array;\n\t\treturn new ArrayType(size);\n\t}\n\n\tprivate isNotRgba(format: number): boolean {\n\t\treturn format !== this.gl.RGBA && format !== this.gl.RGBA_INTEGER;\n\t}\n\n\tprivate clearHistoryTextureLayers(textureInfo: Texture): void {\n\t\tif (!textureInfo.history) return;\n\n\t\tconst gl = this.gl;\n\t\tconst { type, format } = textureInfo.options;\n\t\tconst transparent = this.getPixelArray(type, textureInfo.width * textureInfo.height * 4);\n\t\tgl.activeTexture(gl.TEXTURE0 + textureInfo.unitIndex);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, textureInfo.texture);\n\t\tconst needsAlignmentFix = this.isNotRgba(format);\n\t\tlet previousAlignment;\n\t\tif (needsAlignmentFix) {\n\t\t\tpreviousAlignment = gl.getParameter(gl.UNPACK_ALIGNMENT);\n\t\t\tgl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);\n\t\t}\n\t\tfor (let layer = 0; layer < textureInfo.history.depth; ++layer) {\n\t\t\tgl.texSubImage3D(\n\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tlayer,\n\t\t\t\ttextureInfo.width,\n\t\t\t\ttextureInfo.height,\n\t\t\t\t1,\n\t\t\t\tformat,\n\t\t\t\ttype,\n\t\t\t\ttransparent,\n\t\t\t);\n\t\t}\n\t\tif (needsAlignmentFix) gl.pixelStorei(gl.UNPACK_ALIGNMENT, previousAlignment);\n\t}\n\n\tinitializeUniform(\n\t\tname: string,\n\t\ttype: Uniform['type'],\n\t\tvalue: number | number[] | (number | number[])[],\n\t\toptions?: { arrayLength?: number },\n\t) {\n\t\tconst arrayLength = options?.arrayLength;\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`${name} is already initialized.`);\n\t\t}\n\t\tif (!UNIFORM_TYPE_SUFFIXES[type]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid uniform type: ${type}. Expected one of: ${Object.keys(UNIFORM_TYPE_SUFFIXES).join(', ')}.`,\n\t\t\t);\n\t\t}\n\t\tif (arrayLength && !(Array.isArray(value) && value.length === arrayLength)) {\n\t\t\tthrow new Error(`${name} array length mismatch: must initialize with ${arrayLength} elements.`);\n\t\t}\n\n\t\tlet location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location && arrayLength) {\n\t\t\tlocation = this.gl.getUniformLocation(this.program!, `${name}[0]`);\n\t\t}\n\t\tif (!location) {\n\t\t\tthis.log(`${name} not in shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst probeValue = arrayLength ? (value as number[] | number[][])[0] : value;\n\t\tconst length = Array.isArray(probeValue) ? (probeValue.length as 1 | 2 | 3 | 4) : 1;\n\t\tthis.uniforms.set(name, { type, length, location, arrayLength });\n\n\t\ttry {\n\t\t\tthis.updateUniforms({ [name]: value });\n\t\t} catch (error) {\n\t\t\tthis.uniforms.delete(name);\n\t\t\tthrow error;\n\t\t}\n\t\tthis.emitHook('initializeUniform', ...arguments);\n\t}\n\n\tprivate log(...args: any[]) {\n\t\tif (this.debug) console.debug(...args);\n\t}\n\n\tupdateUniforms(\n\t\tupdates: Record<string, number | number[] | (number | number[])[]>,\n\t\toptions?: { startIndex?: number },\n\t) {\n\t\tthis.gl.useProgram(this.program);\n\t\tObject.entries(updates).forEach(([name, newValue]) => {\n\t\t\tconst uniform = this.uniforms.get(name);\n\t\t\tif (!uniform) {\n\t\t\t\tthis.log(`${name} not in shader. Skipping update.`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet glFunctionName = `uniform${uniform.length}${UNIFORM_TYPE_SUFFIXES[uniform.type]}`;\n\t\t\tif (uniform.arrayLength) {\n\t\t\t\tif (!Array.isArray(newValue)) {\n\t\t\t\t\tthrow new Error(`${name} is an array, but the value passed to updateUniforms is not an array.`);\n\t\t\t\t}\n\t\t\t\tconst nValues = newValue.length;\n\t\t\t\tif (!nValues) return;\n\t\t\t\tif (nValues > uniform.arrayLength) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${name} received ${nValues} values, but maximum length is ${uniform.arrayLength}.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (newValue.some(item => (Array.isArray(item) ? item.length : 1) !== uniform.length)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Tried to update ${name} with some elements that are not length ${uniform.length}.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst flat = newValue.flat();\n\t\t\t\tconst typedArray =\n\t\t\t\t\tuniform.type === 'float'\n\t\t\t\t\t\t? new Float32Array(flat)\n\t\t\t\t\t\t: uniform.type === 'uint'\n\t\t\t\t\t\t\t? new Uint32Array(flat)\n\t\t\t\t\t\t\t: new Int32Array(flat);\n\t\t\t\tlet location = uniform.location;\n\t\t\t\tif (options?.startIndex) {\n\t\t\t\t\tconst newLocation = this.gl.getUniformLocation(this.program!, `${name}[${options.startIndex}]`);\n\t\t\t\t\tif (!newLocation) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`${name}[${options.startIndex}] not in shader. Did you pass an invalid startIndex?`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tlocation = newLocation;\n\t\t\t\t}\n\t\t\t\t(this.gl as any)[glFunctionName + 'v'](location, typedArray);\n\t\t\t} else {\n\t\t\t\tif (!Array.isArray(newValue)) newValue = [newValue];\n\t\t\t\tif (newValue.length !== uniform.length) {\n\t\t\t\t\tthrow new Error(`Invalid uniform value length: ${newValue.length}. Expected ${uniform.length}.`);\n\t\t\t\t}\n\t\t\t\t(this.gl as any)[glFunctionName](uniform.location, ...newValue);\n\t\t\t}\n\t\t});\n\t\tthis.emitHook('updateUniforms', ...arguments);\n\t}\n\n\tprivate createTexture(\n\t\tname: string | symbol,\n\t\ttextureInfo: Pick<Texture, 'width' | 'height' | 'history' | 'options'> & { unitIndex?: number },\n\t) {\n\t\tconst { width, height } = textureInfo;\n\t\tconst historyDepth = textureInfo.history?.depth ?? 0;\n\n\t\tconst texture = this.gl.createTexture();\n\t\tif (!texture) {\n\t\t\tthrow new Error('Failed to create texture');\n\t\t}\n\n\t\tlet unitIndex = textureInfo.unitIndex;\n\t\tif (typeof unitIndex !== 'number') {\n\t\t\ttry {\n\t\t\t\tunitIndex = this.reserveTextureUnit(name);\n\t\t\t} catch (error) {\n\t\t\t\tthis.gl.deleteTexture(texture);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst hasHistory = historyDepth > 0;\n\t\tconst textureTarget = hasHistory ? this.gl.TEXTURE_2D_ARRAY : this.gl.TEXTURE_2D;\n\t\tconst { options } = textureInfo;\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(textureTarget, texture);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_WRAP_S, options.wrapS);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_WRAP_T, options.wrapT);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MIN_FILTER, options.minFilter);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MAG_FILTER, options.magFilter);\n\t\tif (hasHistory) {\n\t\t\tthis.gl.texStorage3D(textureTarget, 1, options.internalFormat, width, height, historyDepth);\n\t\t} else if (name === INTERMEDIATE_TEXTURE_KEY) {\n\t\t\tthis.gl.texImage2D(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t0,\n\t\t\t\toptions.internalFormat,\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\t0,\n\t\t\t\toptions.format,\n\t\t\t\toptions.type,\n\t\t\t\tnull,\n\t\t\t);\n\t\t}\n\t\treturn { texture, unitIndex };\n\t}\n\n\tprivate _initializeTexture(\n\t\tname: string | symbol,\n\t\tsource: TextureSource,\n\t\toptions?: TextureOptions & { history?: number },\n\t) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${stringFrom(name)}' is already initialized.`);\n\t\t}\n\n\t\tconst { history: historyDepth = 0, ...textureOptions } = options ?? {};\n\t\tconst { width, height } = getSourceDimensions(source);\n\t\tif (!width || !height) {\n\t\t\tthrow new Error(`Texture source must have valid dimensions`);\n\t\t}\n\t\tconst textureInfo: Pick<Texture, 'width' | 'height' | 'history' | 'options'> = {\n\t\t\twidth,\n\t\t\theight,\n\t\t\toptions:\n\t\t\t\tsource instanceof ShaderPad &&\n\t\t\t\tObject.keys(textureOptions).length === 0 &&\n\t\t\t\tsource.textures.has(INTERMEDIATE_TEXTURE_KEY)\n\t\t\t\t\t? source.textures.get(INTERMEDIATE_TEXTURE_KEY)!.options\n\t\t\t\t\t: this.resolveTextureOptions(textureOptions),\n\t\t};\n\t\tif (historyDepth > 0) {\n\t\t\ttextureInfo.history = { depth: historyDepth, writeIndex: 0 };\n\t\t}\n\t\tconst { texture, unitIndex } = this.createTexture(name, textureInfo);\n\t\tconst completeTextureInfo: Texture = {\n\t\t\ttexture,\n\t\t\tunitIndex,\n\t\t\t...textureInfo,\n\t\t};\n\t\tif (historyDepth > 0) {\n\t\t\tthis.initializeUniform(`${stringFrom(name)}FrameOffset`, 'int', 0);\n\t\t\tthis.clearHistoryTextureLayers(completeTextureInfo);\n\t\t}\n\t\tthis.textures.set(name, completeTextureInfo);\n\t\tif (name !== INTERMEDIATE_TEXTURE_KEY && name !== HISTORY_TEXTURE_KEY) {\n\t\t\tthis.updateTexture(name, source);\n\t\t}\n\n\t\t// Set a uniform to access the texture in the fragment shader.\n\t\tthis.gl.useProgram(this.program!);\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, stringFrom(name));\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tinitializeTexture(name: string, source: TextureSource, options?: TextureOptions & { history?: number }) {\n\t\t// Since history[0] is the current frame, add 1 to history depth to allow history[maxHistory].\n\t\tconst opts =\n\t\t\toptions?.history != null && options.history > 0 ? { ...options, history: options.history + 1 } : options;\n\t\tthis._initializeTexture(name, source, opts);\n\t\tthis.emitHook('initializeTexture', ...arguments);\n\t}\n\n\tupdateTextures(updates: Record<string, UpdateTextureSource>, options?: UpdateTexturesOptions) {\n\t\tthis.updateTexturesInternal(updates, options);\n\t\tthis.emitHook('updateTextures', ...arguments);\n\t}\n\n\tprivate updateTexturesInternal(\n\t\tupdates: Record<string, UpdateTextureSource>,\n\t\toptions?: InternalUpdateTexturesOptions,\n\t) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tthis.updateTexture(name, source, options);\n\t\t});\n\t}\n\n\tprivate updateTexture(name: string | symbol, source: UpdateTextureSource, options?: InternalUpdateTexturesOptions) {\n\t\tconst info = this.textures.get(name);\n\t\tif (!info) throw new Error(`Texture '${stringFrom(name)}' is not initialized.`);\n\n\t\tif (source instanceof WebGLTexture) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, source);\n\t\t\treturn;\n\t\t}\n\n\t\tlet nonShaderPadSource = source as Exclude<UpdateTextureSource, ShaderPad>;\n\t\tif (source instanceof ShaderPad) {\n\t\t\tconst sourceIntermediateInfo = source.textures.get(INTERMEDIATE_TEXTURE_KEY)!;\n\t\t\tconst srcW = sourceIntermediateInfo.width;\n\t\t\tconst srcH = sourceIntermediateInfo.height;\n\n\t\t\tif (source.gl === this.gl) {\n\t\t\t\tif (!info.history) {\n\t\t\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, sourceIntermediateInfo.texture);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst { depth } = info.history;\n\t\t\t\tconst targetSlots =\n\t\t\t\t\toptions?.historyWriteIndex === undefined\n\t\t\t\t\t\t? [info.history.writeIndex]\n\t\t\t\t\t\t: Array.isArray(options?.historyWriteIndex)\n\t\t\t\t\t\t\t? options.historyWriteIndex.map(i => safeMod(i, depth))\n\t\t\t\t\t\t\t: [safeMod(options.historyWriteIndex, depth)];\n\t\t\t\tthis.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER, source.intermediateFbo);\n\t\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY, info.texture);\n\t\t\t\tfor (const slot of targetSlots) {\n\t\t\t\t\tthis.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY, 0, 0, 0, slot, 0, 0, srcW, srcH);\n\t\t\t\t}\n\t\t\t\tthis.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER, null);\n\t\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY, info.texture);\n\t\t\t\tconst frameOffsetUniformName = `${stringFrom(name)}FrameOffset`;\n\t\t\t\tthis.updateUniforms({\n\t\t\t\t\t[frameOffsetUniformName]: targetSlots[targetSlots.length - 1],\n\t\t\t\t});\n\t\t\t\tif (options?.historyWriteIndex === undefined) {\n\t\t\t\t\tinfo.history.writeIndex = (info.history.writeIndex + 1) % depth;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Different contexts - transfer via readPixels to preserve precision.\n\t\t\tconst {\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\toptions: { format, type },\n\t\t\t} = sourceIntermediateInfo;\n\t\t\tconst pixels = this.getPixelArray(type, width * height * 4);\n\t\t\tsource.gl.bindFramebuffer(source.gl.FRAMEBUFFER, source.intermediateFbo);\n\t\t\tsource.gl.readPixels(0, 0, width, height, format, type, pixels);\n\t\t\tsource.gl.bindFramebuffer(source.gl.FRAMEBUFFER, null);\n\t\t\tnonShaderPadSource = { data: pixels, width, height };\n\t\t}\n\n\t\t// If dimensions changed, recreate the texture with new dimensions.\n\t\tconst { width, height } = getSourceDimensions(nonShaderPadSource);\n\t\tif (!width || !height) return;\n\n\t\tconst isPartial = 'isPartial' in nonShaderPadSource && nonShaderPadSource.isPartial;\n\t\tif (!isPartial) {\n\t\t\tthis.resizeTexture(name, width, height);\n\t\t}\n\n\t\t// UNPACK_FLIP_Y_WEBGL only works for DOM element sources, not typed arrays.\n\t\tconst isTypedArray = 'data' in nonShaderPadSource && nonShaderPadSource.data;\n\t\tconst shouldFlipY = !isTypedArray && !info.options?.preserveY;\n\t\tconst previousFlipY = this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);\n\t\tconst needsAlignmentFix = isTypedArray && this.isNotRgba(info.options.format);\n\t\tlet previousAlignment;\n\t\tif (needsAlignmentFix) {\n\t\t\tpreviousAlignment = this.gl.getParameter(this.gl.UNPACK_ALIGNMENT);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1);\n\t\t}\n\n\t\tif (info.history) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY, info.texture);\n\t\t\tif (!options?.skipHistoryWrite) {\n\t\t\t\tconst { depth } = info.history;\n\t\t\t\tconst targetSlots =\n\t\t\t\t\toptions?.historyWriteIndex === undefined\n\t\t\t\t\t\t? [info.history.writeIndex]\n\t\t\t\t\t\t: Array.isArray(options.historyWriteIndex)\n\t\t\t\t\t\t\t? options.historyWriteIndex.map(i => safeMod(i, depth))\n\t\t\t\t\t\t\t: [safeMod(options.historyWriteIndex, depth)];\n\n\t\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\t\t\t\tconst partialSource = nonShaderPadSource as PartialCustomTexture;\n\t\t\t\tconst sourceData =\n\t\t\t\t\tpartialSource.data ??\n\t\t\t\t\t(nonShaderPadSource as Exclude<TextureSource, CustomTexture | ShaderPad>);\n\t\t\t\tconst xOffset = isPartial ? (partialSource.x ?? 0) : 0;\n\t\t\t\tconst yOffset = isPartial ? (partialSource.y ?? 0) : 0;\n\n\t\t\t\tfor (const slot of targetSlots) {\n\t\t\t\t\tthis.gl.texSubImage3D(\n\t\t\t\t\t\tthis.gl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\txOffset,\n\t\t\t\t\t\tyOffset,\n\t\t\t\t\t\tslot,\n\t\t\t\t\t\twidth,\n\t\t\t\t\t\theight,\n\t\t\t\t\t\t1,\n\t\t\t\t\t\tinfo.options.format,\n\t\t\t\t\t\tinfo.options.type,\n\t\t\t\t\t\tsourceData as any,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\n\t\t\t\tconst frameOffsetUniformName = `${stringFrom(name)}FrameOffset`;\n\t\t\t\tthis.updateUniforms({\n\t\t\t\t\t[frameOffsetUniformName]: targetSlots[targetSlots.length - 1],\n\t\t\t\t});\n\n\t\t\t\tif (options?.historyWriteIndex === undefined) {\n\t\t\t\t\tinfo.history.writeIndex = (info.history.writeIndex + 1) % depth;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, info.texture);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\n\t\t\tif (isPartial) {\n\t\t\t\tconst partialSource = nonShaderPadSource as PartialCustomTexture;\n\t\t\t\tthis.gl.texSubImage2D(\n\t\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t\t0,\n\t\t\t\t\tpartialSource.x ?? 0,\n\t\t\t\t\tpartialSource.y ?? 0,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\tpartialSource.data,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.gl.texImage2D(\n\t\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.options.internalFormat,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\t((nonShaderPadSource as PartialCustomTexture).data ??\n\t\t\t\t\t\t(nonShaderPadSource as Exclude<TextureSource, CustomTexture | ShaderPad>)) as any,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\t\t}\n\t\tif (needsAlignmentFix) this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, previousAlignment);\n\t}\n\n\tprivate bindIntermediate() {\n\t\tconst gl = this.gl;\n\t\tconst intermediateInfo = this.textures.get(INTERMEDIATE_TEXTURE_KEY)!;\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.intermediateFbo);\n\t\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, intermediateInfo.texture, 0);\n\t}\n\n\tclear() {\n\t\tthis.bindIntermediate();\n\t\tconst gl = this.gl;\n\t\tconst intermediateInfo = this.textures.get(INTERMEDIATE_TEXTURE_KEY)!;\n\t\tif (intermediateInfo.options.isIntegerColorFormat) {\n\t\t\tconst t = intermediateInfo.options.type;\n\t\t\tif (this.glHelpers.unsignedIntTypes.has(t)) {\n\t\t\t\tgl.clearBufferuiv(gl.COLOR, 0, new Uint32Array(4));\n\t\t\t} else {\n\t\t\t\tgl.clearBufferiv(gl.COLOR, 0, new Int32Array(4));\n\t\t\t}\n\t\t} else {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t}\n\t}\n\n\tdraw(options?: StepOptions) {\n\t\tthis.emitHook('beforeDraw', ...arguments);\n\t\tconst gl = this.gl;\n\t\tconst w = gl.drawingBufferWidth;\n\t\tconst h = gl.drawingBufferHeight;\n\n\t\tif (options?.skipClear) {\n\t\t\tthis.bindIntermediate();\n\t\t} else {\n\t\t\tthis.clear();\n\t\t}\n\n\t\tgl.useProgram(this.program);\n\t\tgl.bindVertexArray(this.vao);\n\t\tgl.viewport(0, 0, w, h);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 3);\n\n\t\tif (!this.isHeadless) {\n\t\t\tconst intermediateInfo = this.textures.get(INTERMEDIATE_TEXTURE_KEY)!;\n\t\t\tif (!intermediateInfo.options.isIntegerColorFormat) {\n\t\t\t\tgl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.intermediateFbo);\n\t\t\t\tgl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n\t\t\t\tgl.blitFramebuffer(0, 0, w, h, 0, 0, w, h, gl.COLOR_BUFFER_BIT, gl.NEAREST);\n\t\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\t}\n\t\t}\n\t\tthis.emitHook('afterDraw', ...arguments);\n\t}\n\n\tstep(options?: StepOptions) {\n\t\tif (!Number.isFinite(this.startTime)) {\n\t\t\tthis.startTime = performance.now();\n\t\t}\n\t\tthis._step((performance.now() - this.startTime) / 1000, options);\n\t}\n\n\tprivate _step(time: number, options?: StepOptions) {\n\t\tthis.emitHook('beforeStep', time, this.frame, options);\n\t\tconst updates: Record<string, number> = {};\n\t\tif (this.uniforms.has('u_time')) updates.u_time = time;\n\t\tif (this.uniforms.has('u_frame')) updates.u_frame = this.frame;\n\t\tthis.updateUniforms(updates);\n\t\tthis.draw(options);\n\t\tconst historyInfo = this.textures.get(HISTORY_TEXTURE_KEY);\n\t\tif (historyInfo && !options?.skipHistoryWrite) {\n\t\t\tconst { writeIndex, depth } = historyInfo.history!;\n\t\t\tconst gl = this.gl;\n\t\t\tgl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.intermediateFbo);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyInfo.texture);\n\t\t\tgl.copyTexSubImage3D(\n\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\twriteIndex,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tgl.drawingBufferWidth,\n\t\t\t\tgl.drawingBufferHeight,\n\t\t\t);\n\t\t\tgl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);\n\t\t\tconst nextWriteIndex = (writeIndex + 1) % depth;\n\t\t\tthis.updateUniforms({\n\t\t\t\t[`${stringFrom(HISTORY_TEXTURE_KEY)}FrameOffset`]: nextWriteIndex,\n\t\t\t});\n\t\t\thistoryInfo.history!.writeIndex = nextWriteIndex;\n\t\t}\n\t\t++this.frame;\n\t\tthis.emitHook('afterStep', time, this.frame, options);\n\t}\n\n\tplay(onBeforeStep?: (time: number, frame: number) => StepOptions | void) {\n\t\tthis._pause();\n\t\tif (!Number.isFinite(this.startTime)) {\n\t\t\tthis.startTime = performance.now();\n\t\t}\n\t\tthis.isPlaying = true;\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tconst options = onBeforeStep?.(time, this.frame) ?? undefined;\n\t\t\tthis._step(time, options);\n\t\t\tif (this.isPlaying) this.animationFrameId = requestAnimationFrame(loop);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\tthis.emitHook('play');\n\t}\n\n\tprivate _pause() {\n\t\tconst wasPlaying = this.isPlaying;\n\t\tthis.isPlaying = false;\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t\treturn wasPlaying;\n\t}\n\n\tpause() {\n\t\tif (this._pause()) {\n\t\t\tthis.emitHook('pause');\n\t\t}\n\t}\n\n\tresetFrame() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\n\t}\n\n\treset() {\n\t\tthis.resetFrame();\n\t\tthis.textures.forEach(texture => {\n\t\t\tif (texture.history) {\n\t\t\t\ttexture.history.writeIndex = 0;\n\t\t\t\tthis.clearHistoryTextureLayers(texture);\n\t\t\t}\n\t\t});\n\t\tthis.clear();\n\t\tthis.emitHook('reset');\n\t}\n\n\tdestroy() {\n\t\tthis.emitHook('destroy');\n\n\t\tthis._pause();\n\n\t\tif (this.cursorTarget) {\n\t\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\t\tthis.cursorTarget!.removeEventListener(event, listener);\n\t\t\t});\n\t\t\tthis.eventListeners.clear();\n\t\t}\n\n\t\tif (this.resolutionObserver) {\n\t\t\tthis.resolutionObserver.disconnect();\n\t\t\tthis.resolutionObserver = null;\n\t\t}\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t\tthis.program = null;\n\t\t}\n\n\t\tif (this.intermediateFbo) {\n\t\t\tthis.gl.deleteFramebuffer(this.intermediateFbo);\n\t\t\tthis.intermediateFbo = null;\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.textureUnitPool.free.push(texture.unitIndex);\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\t\tthis.textures.clear();\n\t\tconst entry = canvasRegistry.get(this.canvas);\n\t\tif (entry) {\n\t\t\tentry.instances.delete(this);\n\t\t\tif (entry.instances.size === 0) {\n\t\t\t\tcanvasRegistry.delete(this.canvas);\n\t\t\t}\n\t\t}\n\n\t\tif (this.vao) {\n\t\t\tthis.gl.deleteVertexArray(this.vao);\n\t\t\tthis.vao = null;\n\t\t}\n\n\t\tif (this.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tthis.uniforms.clear();\n\t\tthis.hooks.clear();\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"yCAEA,IAAMA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAwC5BC,EAAiD,CACtD,CAAC,MAAO,eAAe,EACvB,CAAC,KAAM,MAAM,EACb,CAAC,OAAQ,gBAAgB,EACzB,CAAC,MAAO,OAAO,EACf,CAAC,MAAO,YAAY,EACpB,CAAC,OAAQ,cAAc,EACvB,CAAC,MAAO,KAAK,EACb,CAAC,MAAO,OAAO,EACf,CAAC,IAAK,eAAe,CACtB,EAEMC,EAAyD,CAC9D,MAAO,IACP,IAAK,IACL,KAAM,IACP,EAEA,SAASC,EAA6BC,EAAyE,CAC9G,OAAOA,GAAwBH,EAAqB,KAAK,CAAC,CAACI,CAAM,IAAMD,EAAqB,SAASC,CAAM,CAAC,IAAI,CAAC,CAClH,CA0HA,IAAMC,EAAsB,OAAO,WAAW,EACxCC,EAA2B,OAAO,oBAAoB,EAEtDC,EAAiB,IAAI,QAK3B,SAASC,EAAkBC,EAAgBC,EAA8B,CACxE,GAAI,CAACA,GAAY,OAAQ,OAAOD,EAChC,IAAME,EAAQF,EAAO,MAAM;AAAA,CAAI,EACzBG,EACLD,EAAM,cAAcE,GAAQ,CAC3B,IAAMC,EAAUD,EAAK,UAAU,EAC/B,OAAOC,EAAQ,WAAW,YAAY,GAAKA,EAAQ,WAAW,WAAW,CAC1E,CAAC,EAAI,EACN,OAAAH,EAAM,OAAOC,EAAU,EAAG,GAAGF,CAAU,EAChCC,EAAM,KAAK;AAAA,CAAI,CACvB,CAEA,SAASI,EAAoBC,EAG3B,CACD,OAAIA,aAAkB,aACd,CAAE,MAAO,EAAG,OAAQ,CAAE,EAE1BA,aAAkBC,EACd,CAAE,MAAOD,EAAO,OAAO,MAAO,OAAQA,EAAO,OAAO,MAAO,EAE/DA,aAAkB,iBACd,CAAE,MAAOA,EAAO,WAAY,OAAQA,EAAO,WAAY,EAE3DA,aAAkB,iBACd,CACN,MAAOA,EAAO,cAAgBA,EAAO,MACrC,OAAQA,EAAO,eAAiBA,EAAO,MACxC,EAGM,CAAE,MAAOA,EAAO,MAAO,OAAQA,EAAO,MAAO,CACrD,CAEA,SAASE,EAAWC,EAAuB,CAC1C,OAAO,OAAOA,GAAS,SAAYA,EAAK,aAAe,GAAMA,CAC9D,CAEA,IAAMF,EAAN,MAAMG,CAAU,CACP,WAAa,GACb,cAAgB,GAChB,GACA,UAKA,SAAiC,IAAI,IACrC,SAA0C,IAAI,IAC9C,gBACA,OAA6B,KAC7B,IAAqC,KACrC,QAA+B,KAC/B,iBACA,eAA6C,IAAI,IACjD,MAAQ,EACR,UAAY,OAAO,IACnB,UAAY,GACZ,eAAiB,CAAC,GAAK,EAAG,EAC1B,cAAgB,CAAC,GAAK,EAAG,EACzB,YAAc,GACf,OACC,mBAA8C,KAC9C,MAA0C,IAAI,IAC9C,aAAe,EACf,eACA,MACA,aAGA,gBAA2C,KAEnD,YACCC,EACA,CAAE,OAAAC,EAAQ,QAAAC,EAAS,QAAAC,EAAS,MAAAC,EAAO,aAAAC,EAAc,GAAGC,CAAe,EAAa,CAAC,EAChF,CACD,GAAIL,GAAU,eAAgBA,EAC7B,KAAK,OAASA,MACR,CACN,GAAM,CAAE,MAAAM,EAAQ,EAAG,OAAAC,EAAS,CAAE,EAAIP,GAAU,CAAC,EAC7C,KAAK,OAAS,IAAI,gBAAgBM,EAAOC,CAAM,EAC/C,KAAK,WAAa,EACnB,CAEA,IAAMC,EAAK,KAAK,OAAO,WAAW,SAAU,CAC3C,UAAW,EACZ,CAAC,EACD,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,kEAAkE,EAEnF,KAAK,GAAKA,EACV,KAAK,UAAY,CAChB,YAAa,IAAI,IAAqD,CACrE,CAACA,EAAG,MAAO,YAAY,EACvB,CAACA,EAAG,WAAY,WAAW,EAC3B,CAACA,EAAG,eAAgB,WAAW,EAC/B,CAACA,EAAG,MAAO,UAAU,EACrB,CAACA,EAAG,KAAM,SAAS,EACnB,CAACA,EAAG,aAAc,WAAW,EAC7B,CAACA,EAAG,IAAK,UAAU,CACpB,CAAC,EACD,2BAA4B,IAAI,IAAoC,CACnE,CAACA,EAAG,MAAO,SAAS,EACpB,CAACA,EAAG,WAAY,SAAS,EACzB,CAACA,EAAG,eAAgB,UAAU,EAC9B,CAACA,EAAG,MAAO,SAAS,EACpB,CAACA,EAAG,KAAM,SAAS,EACnB,CAACA,EAAG,aAAc,UAAU,EAC5B,CAACA,EAAG,IAAK,SAAS,CACnB,CAAC,EACD,iBAAkB,IAAI,IAAI,CAACA,EAAG,cAAeA,EAAG,eAAgBA,EAAG,YAAY,CAAC,CACjF,EAEA,IAAIC,EAAgBxB,EAAe,IAAI,KAAK,MAAM,EAC7CwB,IACJA,EAAgB,CACf,gBAAiB,CAChB,KAAM,CAAC,EACP,KAAM,EACN,IAAKD,EAAG,aAAaA,EAAG,gCAAgC,CACzD,EACA,UAAW,IAAI,IAAI,CAAC,IAAI,CAAC,CAC1B,EACAvB,EAAe,IAAI,KAAK,OAAQwB,CAAa,GAE9C,KAAK,gBAAkBA,EAAc,gBACrCA,EAAc,UAAU,IAAI,IAAI,EAEhC,KAAK,eAAiBJ,EAElBH,IAAS,KAAK,aAAeA,GACjC,KAAK,MAAQC,IAAU,OAAO,QAAY,KAAe,IACzD,KAAK,aAAeC,IAAiB,KAAK,kBAAkB,kBAAoB,KAAK,OAAS,QAC9F,KAAK,iBAAmB,KAExB,IAAMM,EAA2B,CAAC,EAC9BT,GACHA,EAAQ,QAAQU,GACfA,EAAO,KAAM,CACZ,GAAAH,EACA,OAAQ,KAAK,OACb,WAAaI,GAAiB,CAC7BF,EAAe,KAAKE,CAAI,CACzB,EACA,SAAU,KAAK,SAAS,KAAK,IAAI,EACjC,uBAAwB,KAAK,uBAAuB,KAAK,IAAI,CAC9D,CAAC,CACF,EAGD,IAAMC,EAAU,KAAK,GAAG,cAAc,EACtC,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,gCAAgC,EAEjD,KAAK,QAAUA,EAEf,IAAMC,EAAe,KAAK,aAAa,KAAK,GAAG,cAAerC,CAAyB,EACjFsC,EAAiB,KAAK,aAC3BP,EAAG,gBACHtB,EAAkBa,EAAmBW,CAAc,CACpD,EAQA,GAPAF,EAAG,aAAaK,EAASC,CAAY,EACrCN,EAAG,aAAaK,EAASE,CAAc,EACvCP,EAAG,mBAAmBK,EAAS,EAAG,YAAY,EAC9CL,EAAG,YAAYK,CAAO,EACtBL,EAAG,aAAaM,CAAY,EAC5BN,EAAG,aAAaO,CAAc,EAE1B,CAACP,EAAG,oBAAoBK,EAASL,EAAG,WAAW,EAClD,cAAQ,MAAM,sBAAuBA,EAAG,kBAAkBK,CAAO,CAAC,EAClEL,EAAG,cAAcK,CAAO,EAClB,IAAI,MAAM,8BAA8B,EAe/C,GAZA,KAAK,IAAML,EAAG,kBAAkB,EAChCA,EAAG,gBAAgB,KAAK,GAAG,EAC3B,KAAK,OAASA,EAAG,aAAa,EAC9BA,EAAG,WAAWA,EAAG,aAAc,KAAK,MAAM,EAC1CA,EAAG,WAAWA,EAAG,aAAc,IAAI,aAAa,CAAC,GAAI,GAAI,EAAG,GAAI,GAAI,CAAC,CAAC,EAAGA,EAAG,WAAW,EACvFA,EAAG,wBAAwB,CAAC,EAC5BA,EAAG,oBAAoB,EAAG,EAAGA,EAAG,MAAO,GAAO,EAAG,CAAC,EAElDA,EAAG,SAAS,EAAG,EAAGA,EAAG,mBAAoBA,EAAG,mBAAmB,EAE/DA,EAAG,WAAWK,CAAO,EAEjB,KAAK,kBAAkB,kBAC1B,KAAK,mBAAqB,IAAI,iBAAiB,IAAM,KAAK,iBAAiB,CAAC,EAC5E,KAAK,mBAAmB,QAAQ,KAAK,OAAQ,CAC5C,WAAY,GACZ,gBAAiB,CAAC,QAAS,QAAQ,CACpC,CAAC,MACK,CACN,IAAMG,EAAiBC,GAAkC,CACxD,IAAMC,EAAa,OAAO,yBAAyB,gBAAgB,UAAWD,CAAS,EACjFjB,EAAS,KAAK,OACpB,OAAO,eAAeA,EAAQiB,EAAW,CACxC,IAAK,IAAMC,EAAW,IAAK,KAAKlB,CAAM,EACtC,IAAKmB,GAAK,CACTD,EAAW,IAAK,KAAKlB,EAAQmB,CAAC,EAC9B,IAAMC,EAAQnC,EAAe,IAAIe,CAAM,EACvC,GAAIoB,EACH,QAAWC,KAAYD,EAAM,UAC5BC,EAAS,iBAAiB,CAG7B,EACA,aAAcH,EAAW,aACzB,WAAYA,EAAW,UACxB,CAAC,CACF,EACAF,EAAc,OAAO,EACrBA,EAAc,QAAQ,CACvB,CACA,KAAK,iBAAiB,EAEtB,KAAK,kBAAkB,WAAY,QAAS,KAAK,cAAc,EAC/D,KAAK,kBAAkB,UAAW,QAAS,CAAC,GAAG,KAAK,cAAe,KAAK,YAAc,EAAM,CAAG,CAAC,EAChG,KAAK,kBAAkB,SAAU,QAAS,CAAC,EAC3C,KAAK,kBAAkB,UAAW,MAAO,CAAC,EAE1C,KAAK,mBAAmBhC,EAA0B,KAAK,OAAQ,CAC9D,GAAG,KAAK,cACT,CAAC,EACD,KAAK,gBAAkBwB,EAAG,kBAAkB,EAC5C,KAAK,iBAAiB,EACtBA,EAAG,gBAAgBA,EAAG,YAAa,IAAI,EAEnC,KAAK,aAAe,GACvB,KAAK,mBAAmBzB,EAAqB,KAAK,OAAQ,CACzD,QAAS,KAAK,aACd,GAAG,KAAK,cACT,CAAC,EAEE,KAAK,cACR,KAAK,kBAAkB,EAExB,KAAK,SAAS,OAAO,CACtB,CAEQ,kBAAkBuC,EAAiC,CAC1D,IAAMC,EAAW,KAAK,GAAGD,CAAK,EAC9B,GAAIC,IAAa,OAChB,MAAM,IAAI,MAAM,wBAAwBD,CAAK,EAAE,EAEhD,OAAOC,CACR,CAEQ,SAAS1B,KAA0B2B,EAAa,CACvD,KAAK,MAAM,IAAI3B,CAAI,GAAG,QAAQ4B,GAAQA,EAAK,KAAK,KAAM,GAAGD,CAAI,CAAC,CAC/D,CAEA,GAAG3B,EAAuB6B,EAAc,CAClC,KAAK,MAAM,IAAI7B,CAAI,GACvB,KAAK,MAAM,IAAIA,EAAM,CAAC,CAAC,EAExB,KAAK,MAAM,IAAIA,CAAI,EAAG,KAAK6B,CAAE,CAC9B,CAEA,IAAI7B,EAAuB6B,EAAc,CACxC,IAAMC,EAAQ,KAAK,MAAM,IAAI9B,CAAI,EACjC,GAAI8B,EAAO,CACV,IAAMC,EAAQD,EAAM,QAAQD,CAAE,EAC1BE,GAAS,GACZD,EAAM,OAAOC,EAAO,CAAC,CAEvB,CACD,CAEQ,aAAaC,EAAcnC,EAA6B,CAC/D,IAAMP,EAAS,KAAK,GAAG,aAAa0C,CAAI,EAGxC,GAFA,KAAK,GAAG,aAAa1C,EAAQO,CAAM,EACnC,KAAK,GAAG,cAAcP,CAAM,EACxB,CAAC,KAAK,GAAG,mBAAmBA,EAAQ,KAAK,GAAG,cAAc,EAC7D,cAAQ,MAAM,6BAA8BO,CAAM,EAClD,QAAQ,MAAM,KAAK,GAAG,iBAAiBP,CAAM,CAAC,EAC9C,KAAK,GAAG,aAAaA,CAAM,EACrB,IAAI,MAAM,2BAA2B,EAE5C,OAAOA,CACR,CAEQ,qBAKN,CACD,IAAM2C,EAAS,KAAK,aACpB,OAAIA,IAAW,OACP,CACN,KAAM,EACN,IAAK,EACL,MAAO,OAAO,WACd,OAAQ,OAAO,WAChB,EAEOA,EAAmB,sBAAsB,CAClD,CAEQ,mBAAoB,CAC3B,GAAI,CAAC,KAAK,aAAc,OACxB,IAAMC,EAAe,CAACC,EAAWC,IAAc,CAC9C,GAAI,CAAC,KAAK,SAAS,IAAI,UAAU,EAAG,OACpC,IAAMC,EAAO,KAAK,oBAAoB,EAChCC,GAAKH,EAAIE,EAAK,MAAQA,EAAK,MAC3Bf,EAAI,GAAKc,EAAIC,EAAK,KAAOA,EAAK,OACpC,KAAK,eAAe,CAAC,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGC,CAAC,CAAC,EACnD,KAAK,eAAe,CAAC,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGhB,CAAC,CAAC,EACnD,KAAK,eAAe,CAAE,SAAU,KAAK,cAAe,CAAC,CACtD,EAEMiB,EAAc,CAACC,EAAsBL,EAAYC,IAAe,CACrE,GAAK,KAAK,SAAS,IAAI,SAAS,EAEhC,IADA,KAAK,YAAcI,EACfA,EAAa,CAChB,IAAMH,EAAO,KAAK,oBAAoB,EAChCI,EAAON,EACPO,EAAON,EACb,KAAK,cAAc,CAAC,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,GAAIK,EAAOJ,EAAK,MAAQA,EAAK,KAAK,CAAC,EAChF,KAAK,cAAc,CAAC,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,GAAKK,EAAOL,EAAK,KAAOA,EAAK,MAAM,CAAC,CACrF,CACA,KAAK,eAAe,CACnB,QAAS,CAAC,GAAG,KAAK,cAAe,KAAK,YAAc,EAAM,CAAG,CAC9D,CAAC,EACF,EAEA,KAAK,eAAe,IAAI,YAAaM,GAAS,CAC7C,IAAMC,EAAaD,EACd,KAAK,eACTT,EAAaU,EAAW,QAASA,EAAW,OAAO,CAErD,CAAC,EAED,KAAK,eAAe,IAAI,YAAaD,GAAS,CAC7C,IAAMC,EAAaD,EACd,KAAK,eACLC,EAAW,SAAW,IACzB,KAAK,YAAc,GACnBL,EAAY,GAAMK,EAAW,QAASA,EAAW,OAAO,EAG3D,CAAC,EAED,KAAK,eAAe,IAAI,UAAWD,GAAS,CAC3C,IAAMC,EAAaD,EACd,KAAK,eACLC,EAAW,SAAW,GACzBL,EAAY,EAAK,CAGpB,CAAC,EAED,KAAK,eAAe,IAAI,YAAaI,GAAS,CAC7C,IAAME,EAAaF,EACfE,EAAW,QAAQ,OAAS,GAC/BX,EAAaW,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,CAE3E,CAAC,EAED,KAAK,eAAe,IAAI,aAAcF,GAAS,CAC9C,IAAME,EAAaF,EACnB,KAAK,cAAgB,GACjBE,EAAW,QAAQ,OAAS,IAC/BX,EAAaW,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,EACzEN,EAAY,GAAMM,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,EAEhF,CAAC,EAED,KAAK,eAAe,IAAI,WAAYF,GAAS,CACzBA,EACJ,QAAQ,SAAW,GACjCJ,EAAY,EAAK,CAEnB,CAAC,EAED,KAAK,eAAe,QAAQ,CAACO,EAAUH,IAAU,CAChD,KAAK,aAAc,iBAAiBA,EAAOG,CAAQ,CACpD,CAAC,CACF,CAEA,kBAAmB,CAClB,IAAMC,EAA+B,CAAC,KAAK,GAAG,mBAAoB,KAAK,GAAG,mBAAmB,EAC7F,KAAK,GAAG,SAAS,EAAG,EAAG,GAAGA,CAAU,EAChC,KAAK,SAAS,IAAI,cAAc,EACnC,KAAK,eAAe,CAAE,aAAcA,CAAW,CAAC,EAEhD,KAAK,kBAAkB,eAAgB,QAASA,CAAU,EAE3D,KAAK,cAAc5D,EAA0B,GAAG4D,CAAU,EACtD,KAAK,aAAe,GACvB,KAAK,cAAc7D,EAAqB,GAAG6D,CAAU,EAEtD,KAAK,SAAS,mBAAoB,GAAGA,CAAU,CAChD,CAEQ,cAAc/C,EAAuBS,EAAeC,EAAgB,CAC3E,IAAMsC,EAAO,KAAK,SAAS,IAAIhD,CAAI,EACnC,GAAI,CAACgD,GAASA,EAAK,QAAUvC,GAASuC,EAAK,SAAWtC,EAAS,OAE/D,KAAK,GAAG,cAAcsC,EAAK,OAAO,EAClCA,EAAK,MAAQvC,EACbuC,EAAK,OAAStC,EACd,GAAM,CAAE,QAAAuC,CAAQ,EAAI,KAAK,cAAcjD,EAAMgD,CAAI,EACjDA,EAAK,QAAUC,EACXD,EAAK,UACRA,EAAK,QAAQ,WAAa,EAC1B,KAAK,0BAA0BA,CAAI,EAErC,CAEQ,mBAAmBhD,EAAuB,CACjD,IAAMkD,EAAW,KAAK,SAAS,IAAIlD,CAAI,EACvC,GAAIkD,EAAU,OAAOA,EAAS,UAC9B,GAAI,KAAK,gBAAgB,KAAK,OAAS,EAAG,OAAO,KAAK,gBAAgB,KAAK,IAAI,EAC/E,GAAI,KAAK,gBAAgB,MAAQ,KAAK,gBAAgB,IACrD,MAAM,IAAI,MAAM,uDAAuD,EAExE,OAAO,KAAK,gBAAgB,MAC7B,CAEQ,sBAAsBC,EAAkD,CAC/E,GAAM,CAAE,GAAAxC,CAAG,EAAI,KACTyC,EAAuBD,GAAS,eAChCE,EAAaF,GAAS,MAAQpE,EAA6BqE,CAAoB,GAAK,gBACpFpB,EAAO,KAAK,kBAAkBqB,CAAU,EACxCrE,EACLoE,GAAwB,KAAK,UAAU,2BAA2B,IAAIpB,CAAI,GAAK,QAC1EsB,EAAuB,mCAAmC,KAAKtE,CAAoB,EACnFuE,EAAeJ,GAAS,SAAWG,EAAuB,eAAiB,QAC3EE,EAAiC,CACtC,KAAAxB,EACA,OAAQ,KAAK,kBAAkBuB,CAAY,EAC3C,eAAgB,KAAK,kBAAkBvE,CAAoB,EAC3D,UAAW,KAAK,kBAAkBmE,GAAS,WAAa,QAAQ,EAChE,UAAW,KAAK,kBAAkBA,GAAS,WAAa,QAAQ,EAChE,MAAO,KAAK,kBAAkBA,GAAS,OAAS,eAAe,EAC/D,MAAO,KAAK,kBAAkBA,GAAS,OAAS,eAAe,EAC/D,UAAWA,GAAS,UACpB,qBAAAG,CACD,EAGA,IAF2BE,EAAO,iBAAmB7C,EAAG,SAAW6C,EAAO,iBAAmB7C,EAAG,UAEtE,CAACA,EAAG,aAAa,wBAAwB,EAClE,MAAM,IAAI,MAAM,iCAAiC,EAElD,OAAO6C,CACR,CAEQ,cAAcxB,EAAcyB,EAA+B,CAClE,IAAMC,EAAY,KAAK,UAAU,YAAY,IAAI1B,CAAI,GAAK,WAC1D,OAAO,IAAI0B,EAAUD,CAAI,CAC1B,CAEQ,UAAUE,EAAyB,CAC1C,OAAOA,IAAW,KAAK,GAAG,MAAQA,IAAW,KAAK,GAAG,YACtD,CAEQ,0BAA0BC,EAA4B,CAC7D,GAAI,CAACA,EAAY,QAAS,OAE1B,IAAMjD,EAAK,KAAK,GACV,CAAE,KAAAqB,EAAM,OAAA2B,CAAO,EAAIC,EAAY,QAC/BC,EAAc,KAAK,cAAc7B,EAAM4B,EAAY,MAAQA,EAAY,OAAS,CAAC,EACvFjD,EAAG,cAAcA,EAAG,SAAWiD,EAAY,SAAS,EACpDjD,EAAG,YAAYA,EAAG,iBAAkBiD,EAAY,OAAO,EACvD,IAAME,EAAoB,KAAK,UAAUH,CAAM,EAC3CI,EACAD,IACHC,EAAoBpD,EAAG,aAAaA,EAAG,gBAAgB,EACvDA,EAAG,YAAYA,EAAG,iBAAkB,CAAC,GAEtC,QAASqD,EAAQ,EAAGA,EAAQJ,EAAY,QAAQ,MAAO,EAAEI,EACxDrD,EAAG,cACFA,EAAG,iBACH,EACA,EACA,EACAqD,EACAJ,EAAY,MACZA,EAAY,OACZ,EACAD,EACA3B,EACA6B,CACD,EAEGC,GAAmBnD,EAAG,YAAYA,EAAG,iBAAkBoD,CAAiB,CAC7E,CAEA,kBACC/D,EACAgC,EACAP,EACA0B,EACC,CACD,IAAMc,EAAcd,GAAS,YAC7B,GAAI,KAAK,SAAS,IAAInD,CAAI,EACzB,MAAM,IAAI,MAAM,GAAGA,CAAI,0BAA0B,EAElD,GAAI,CAAClB,EAAsBkD,CAAI,EAC9B,MAAM,IAAI,MACT,yBAAyBA,CAAI,sBAAsB,OAAO,KAAKlD,CAAqB,EAAE,KAAK,IAAI,CAAC,GACjG,EAED,GAAImF,GAAe,EAAE,MAAM,QAAQxC,CAAK,GAAKA,EAAM,SAAWwC,GAC7D,MAAM,IAAI,MAAM,GAAGjE,CAAI,gDAAgDiE,CAAW,YAAY,EAG/F,IAAIC,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAUlE,CAAI,EAI7D,GAHI,CAACkE,GAAYD,IAChBC,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAU,GAAGlE,CAAI,KAAK,GAE9D,CAACkE,EAAU,CACd,KAAK,IAAI,GAAGlE,CAAI,0CAA0C,EAC1D,MACD,CAEA,IAAMmE,EAAaF,EAAexC,EAAgC,CAAC,EAAIA,EACjE2C,EAAS,MAAM,QAAQD,CAAU,EAAKA,EAAW,OAA2B,EAClF,KAAK,SAAS,IAAInE,EAAM,CAAE,KAAAgC,EAAM,OAAAoC,EAAQ,SAAAF,EAAU,YAAAD,CAAY,CAAC,EAE/D,GAAI,CACH,KAAK,eAAe,CAAE,CAACjE,CAAI,EAAGyB,CAAM,CAAC,CACtC,OAAS4C,EAAO,CACf,WAAK,SAAS,OAAOrE,CAAI,EACnBqE,CACP,CACA,KAAK,SAAS,oBAAqB,GAAG,SAAS,CAChD,CAEQ,OAAO1C,EAAa,CACvB,KAAK,OAAO,QAAQ,MAAM,GAAGA,CAAI,CACtC,CAEA,eACC2C,EACAnB,EACC,CACD,KAAK,GAAG,WAAW,KAAK,OAAO,EAC/B,OAAO,QAAQmB,CAAO,EAAE,QAAQ,CAAC,CAACtE,EAAMuE,CAAQ,IAAM,CACrD,IAAMC,EAAU,KAAK,SAAS,IAAIxE,CAAI,EACtC,GAAI,CAACwE,EAAS,CACb,KAAK,IAAI,GAAGxE,CAAI,kCAAkC,EAClD,MACD,CACA,IAAIyE,EAAiB,UAAUD,EAAQ,MAAM,GAAG1F,EAAsB0F,EAAQ,IAAI,CAAC,GACnF,GAAIA,EAAQ,YAAa,CACxB,GAAI,CAAC,MAAM,QAAQD,CAAQ,EAC1B,MAAM,IAAI,MAAM,GAAGvE,CAAI,uEAAuE,EAE/F,IAAM0E,EAAUH,EAAS,OACzB,GAAI,CAACG,EAAS,OACd,GAAIA,EAAUF,EAAQ,YACrB,MAAM,IAAI,MACT,GAAGxE,CAAI,aAAa0E,CAAO,kCAAkCF,EAAQ,WAAW,GACjF,EAED,GAAID,EAAS,KAAKI,IAAS,MAAM,QAAQA,CAAI,EAAIA,EAAK,OAAS,KAAOH,EAAQ,MAAM,EACnF,MAAM,IAAI,MACT,mBAAmBxE,CAAI,2CAA2CwE,EAAQ,MAAM,GACjF,EAED,IAAMI,EAAOL,EAAS,KAAK,EACrBM,EACLL,EAAQ,OAAS,QACd,IAAI,aAAaI,CAAI,EACrBJ,EAAQ,OAAS,OAChB,IAAI,YAAYI,CAAI,EACpB,IAAI,WAAWA,CAAI,EACpBV,EAAWM,EAAQ,SACvB,GAAIrB,GAAS,WAAY,CACxB,IAAM2B,EAAc,KAAK,GAAG,mBAAmB,KAAK,QAAU,GAAG9E,CAAI,IAAImD,EAAQ,UAAU,GAAG,EAC9F,GAAI,CAAC2B,EACJ,MAAM,IAAI,MACT,GAAG9E,CAAI,IAAImD,EAAQ,UAAU,sDAC9B,EAEDe,EAAWY,CACZ,CACC,KAAK,GAAWL,EAAiB,GAAG,EAAEP,EAAUW,CAAU,CAC5D,KAAO,CAEN,GADK,MAAM,QAAQN,CAAQ,IAAGA,EAAW,CAACA,CAAQ,GAC9CA,EAAS,SAAWC,EAAQ,OAC/B,MAAM,IAAI,MAAM,iCAAiCD,EAAS,MAAM,cAAcC,EAAQ,MAAM,GAAG,EAE/F,KAAK,GAAWC,CAAc,EAAED,EAAQ,SAAU,GAAGD,CAAQ,CAC/D,CACD,CAAC,EACD,KAAK,SAAS,iBAAkB,GAAG,SAAS,CAC7C,CAEQ,cACPvE,EACA4D,EACC,CACD,GAAM,CAAE,MAAAnD,EAAO,OAAAC,CAAO,EAAIkD,EACpBmB,EAAenB,EAAY,SAAS,OAAS,EAE7CX,EAAU,KAAK,GAAG,cAAc,EACtC,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,0BAA0B,EAG3C,IAAI+B,EAAYpB,EAAY,UAC5B,GAAI,OAAOoB,GAAc,SACxB,GAAI,CACHA,EAAY,KAAK,mBAAmBhF,CAAI,CACzC,OAASqE,EAAO,CACf,WAAK,GAAG,cAAcpB,CAAO,EACvBoB,CACP,CAGD,IAAMY,EAAaF,EAAe,EAC5BG,EAAgBD,EAAa,KAAK,GAAG,iBAAmB,KAAK,GAAG,WAChE,CAAE,QAAA9B,CAAQ,EAAIS,EACpB,YAAK,GAAG,cAAc,KAAK,GAAG,SAAWoB,CAAS,EAClD,KAAK,GAAG,YAAYE,EAAejC,CAAO,EAC1C,KAAK,GAAG,cAAciC,EAAe,KAAK,GAAG,eAAgB/B,EAAQ,KAAK,EAC1E,KAAK,GAAG,cAAc+B,EAAe,KAAK,GAAG,eAAgB/B,EAAQ,KAAK,EAC1E,KAAK,GAAG,cAAc+B,EAAe,KAAK,GAAG,mBAAoB/B,EAAQ,SAAS,EAClF,KAAK,GAAG,cAAc+B,EAAe,KAAK,GAAG,mBAAoB/B,EAAQ,SAAS,EAC9E8B,EACH,KAAK,GAAG,aAAaC,EAAe,EAAG/B,EAAQ,eAAgB1C,EAAOC,EAAQqE,CAAY,EAChF/E,IAASb,GACnB,KAAK,GAAG,WACP,KAAK,GAAG,WACR,EACAgE,EAAQ,eACR1C,EACAC,EACA,EACAyC,EAAQ,OACRA,EAAQ,KACR,IACD,EAEM,CAAE,QAAAF,EAAS,UAAA+B,CAAU,CAC7B,CAEQ,mBACPhF,EACAH,EACAsD,EACC,CACD,GAAI,KAAK,SAAS,IAAInD,CAAI,EACzB,MAAM,IAAI,MAAM,YAAYD,EAAWC,CAAI,CAAC,2BAA2B,EAGxE,GAAM,CAAE,QAAS+E,EAAe,EAAG,GAAGvE,CAAe,EAAI2C,GAAW,CAAC,EAC/D,CAAE,MAAA1C,EAAO,OAAAC,CAAO,EAAId,EAAoBC,CAAM,EACpD,GAAI,CAACY,GAAS,CAACC,EACd,MAAM,IAAI,MAAM,2CAA2C,EAE5D,IAAMkD,EAAyE,CAC9E,MAAAnD,EACA,OAAAC,EACA,QACCb,aAAkBI,GAClB,OAAO,KAAKO,CAAc,EAAE,SAAW,GACvCX,EAAO,SAAS,IAAIV,CAAwB,EACzCU,EAAO,SAAS,IAAIV,CAAwB,EAAG,QAC/C,KAAK,sBAAsBqB,CAAc,CAC9C,EACIuE,EAAe,IAClBnB,EAAY,QAAU,CAAE,MAAOmB,EAAc,WAAY,CAAE,GAE5D,GAAM,CAAE,QAAA9B,EAAS,UAAA+B,CAAU,EAAI,KAAK,cAAchF,EAAM4D,CAAW,EAC7DuB,EAA+B,CACpC,QAAAlC,EACA,UAAA+B,EACA,GAAGpB,CACJ,EACImB,EAAe,IAClB,KAAK,kBAAkB,GAAGhF,EAAWC,CAAI,CAAC,cAAe,MAAO,CAAC,EACjE,KAAK,0BAA0BmF,CAAmB,GAEnD,KAAK,SAAS,IAAInF,EAAMmF,CAAmB,EACvCnF,IAASb,GAA4Ba,IAASd,GACjD,KAAK,cAAcc,EAAMH,CAAM,EAIhC,KAAK,GAAG,WAAW,KAAK,OAAQ,EAChC,IAAMuF,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAUrF,EAAWC,CAAI,CAAC,EACvEoF,GACH,KAAK,GAAG,UAAUA,EAAUJ,CAAS,CAEvC,CAEA,kBAAkBhF,EAAcH,EAAuBsD,EAAiD,CAEvG,IAAMkC,EACLlC,GAAS,SAAW,MAAQA,EAAQ,QAAU,EAAI,CAAE,GAAGA,EAAS,QAASA,EAAQ,QAAU,CAAE,EAAIA,EAClG,KAAK,mBAAmBnD,EAAMH,EAAQwF,CAAI,EAC1C,KAAK,SAAS,oBAAqB,GAAG,SAAS,CAChD,CAEA,eAAef,EAA8CnB,EAAiC,CAC7F,KAAK,uBAAuBmB,EAASnB,CAAO,EAC5C,KAAK,SAAS,iBAAkB,GAAG,SAAS,CAC7C,CAEQ,uBACPmB,EACAnB,EACC,CACD,OAAO,QAAQmB,CAAO,EAAE,QAAQ,CAAC,CAACtE,EAAMH,CAAM,IAAM,CACnD,KAAK,cAAcG,EAAMH,EAAQsD,CAAO,CACzC,CAAC,CACF,CAEQ,cAAcnD,EAAuBH,EAA6BsD,EAAyC,CAClH,IAAMH,EAAO,KAAK,SAAS,IAAIhD,CAAI,EACnC,GAAI,CAACgD,EAAM,MAAM,IAAI,MAAM,YAAYjD,EAAWC,CAAI,CAAC,uBAAuB,EAE9E,GAAIH,aAAkB,aAAc,CACnC,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWmD,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYnD,CAAM,EAC9C,MACD,CAEA,IAAIyF,EAAqBzF,EACzB,GAAIA,aAAkBI,EAAW,CAChC,IAAMsF,EAAyB1F,EAAO,SAAS,IAAIV,CAAwB,EACrEqG,EAAOD,EAAuB,MAC9BE,EAAOF,EAAuB,OAEpC,GAAI1F,EAAO,KAAO,KAAK,GAAI,CAC1B,GAAI,CAACmD,EAAK,QAAS,CAClB,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWA,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYuC,EAAuB,OAAO,EACtE,MACD,CACA,GAAM,CAAE,MAAAG,CAAM,EAAI1C,EAAK,QACjB2C,EACLxC,GAAS,oBAAsB,OAC5B,CAACH,EAAK,QAAQ,UAAU,EACxB,MAAM,QAAQG,GAAS,iBAAiB,EACvCA,EAAQ,kBAAkB,IAAIyC,GAAKC,EAAQD,EAAGF,CAAK,CAAC,EACpD,CAACG,EAAQ1C,EAAQ,kBAAmBuC,CAAK,CAAC,EAC/C,KAAK,GAAG,gBAAgB,KAAK,GAAG,iBAAkB7F,EAAO,eAAe,EACxE,KAAK,GAAG,YAAY,KAAK,GAAG,iBAAkBmD,EAAK,OAAO,EAC1D,QAAW8C,KAAQH,EAClB,KAAK,GAAG,kBAAkB,KAAK,GAAG,iBAAkB,EAAG,EAAG,EAAGG,EAAM,EAAG,EAAGN,EAAMC,CAAI,EAEpF,KAAK,GAAG,gBAAgB,KAAK,GAAG,iBAAkB,IAAI,EACtD,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWzC,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,iBAAkBA,EAAK,OAAO,EAC1D,IAAM+C,EAAyB,GAAGhG,EAAWC,CAAI,CAAC,cAClD,KAAK,eAAe,CACnB,CAAC+F,CAAsB,EAAGJ,EAAYA,EAAY,OAAS,CAAC,CAC7D,CAAC,EACGxC,GAAS,oBAAsB,SAClCH,EAAK,QAAQ,YAAcA,EAAK,QAAQ,WAAa,GAAK0C,GAE3D,MACD,CAGA,GAAM,CACL,MAAAjF,EACA,OAAAC,EACA,QAAS,CAAE,OAAAiD,EAAQ,KAAA3B,CAAK,CACzB,EAAIuD,EACES,EAAS,KAAK,cAAchE,EAAMvB,EAAQC,EAAS,CAAC,EAC1Db,EAAO,GAAG,gBAAgBA,EAAO,GAAG,YAAaA,EAAO,eAAe,EACvEA,EAAO,GAAG,WAAW,EAAG,EAAGY,EAAOC,EAAQiD,EAAQ3B,EAAMgE,CAAM,EAC9DnG,EAAO,GAAG,gBAAgBA,EAAO,GAAG,YAAa,IAAI,EACrDyF,EAAqB,CAAE,KAAMU,EAAQ,MAAAvF,EAAO,OAAAC,CAAO,CACpD,CAGA,GAAM,CAAE,MAAAD,EAAO,OAAAC,CAAO,EAAId,EAAoB0F,CAAkB,EAChE,GAAI,CAAC7E,GAAS,CAACC,EAAQ,OAEvB,IAAMuF,EAAY,cAAeX,GAAsBA,EAAmB,UACrEW,GACJ,KAAK,cAAcjG,EAAMS,EAAOC,CAAM,EAIvC,IAAMwF,EAAe,SAAUZ,GAAsBA,EAAmB,KAClEa,EAAc,CAACD,GAAgB,CAAClD,EAAK,SAAS,UAC9CoD,EAAgB,KAAK,GAAG,aAAa,KAAK,GAAG,mBAAmB,EAChEtC,EAAoBoC,GAAgB,KAAK,UAAUlD,EAAK,QAAQ,MAAM,EACxEe,EAMJ,GALID,IACHC,EAAoB,KAAK,GAAG,aAAa,KAAK,GAAG,gBAAgB,EACjE,KAAK,GAAG,YAAY,KAAK,GAAG,iBAAkB,CAAC,GAG5Cf,EAAK,SAGR,GAFA,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWA,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,iBAAkBA,EAAK,OAAO,EACtD,CAACG,GAAS,iBAAkB,CAC/B,GAAM,CAAE,MAAAuC,CAAM,EAAI1C,EAAK,QACjB2C,EACLxC,GAAS,oBAAsB,OAC5B,CAACH,EAAK,QAAQ,UAAU,EACxB,MAAM,QAAQG,EAAQ,iBAAiB,EACtCA,EAAQ,kBAAkB,IAAIyC,GAAKC,EAAQD,EAAGF,CAAK,CAAC,EACpD,CAACG,EAAQ1C,EAAQ,kBAAmBuC,CAAK,CAAC,EAE/C,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqBS,CAAW,EAC5D,IAAME,EAAgBf,EAChBgB,EACLD,EAAc,MACbf,EACIiB,EAAUN,EAAaI,EAAc,GAAK,EAAK,EAC/CG,EAAUP,EAAaI,EAAc,GAAK,EAAK,EAErD,QAAWP,KAAQH,EAClB,KAAK,GAAG,cACP,KAAK,GAAG,iBACR,EACAY,EACAC,EACAV,EACArF,EACAC,EACA,EACAsC,EAAK,QAAQ,OACbA,EAAK,QAAQ,KACbsD,CACD,EAED,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqBF,CAAa,EAE9D,IAAML,EAAyB,GAAGhG,EAAWC,CAAI,CAAC,cAClD,KAAK,eAAe,CACnB,CAAC+F,CAAsB,EAAGJ,EAAYA,EAAY,OAAS,CAAC,CAC7D,CAAC,EAEGxC,GAAS,oBAAsB,SAClCH,EAAK,QAAQ,YAAcA,EAAK,QAAQ,WAAa,GAAK0C,EAE5D,MACM,CAKN,GAJA,KAAK,GAAG,cAAc,KAAK,GAAG,SAAW1C,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYA,EAAK,OAAO,EACpD,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqBmD,CAAW,EAExDF,EAAW,CACd,IAAMI,EAAgBf,EACtB,KAAK,GAAG,cACP,KAAK,GAAG,WACR,EACAe,EAAc,GAAK,EACnBA,EAAc,GAAK,EACnB5F,EACAC,EACAsC,EAAK,QAAQ,OACbA,EAAK,QAAQ,KACbqD,EAAc,IACf,CACD,MACC,KAAK,GAAG,WACP,KAAK,GAAG,WACR,EACArD,EAAK,QAAQ,eACbvC,EACAC,EACA,EACAsC,EAAK,QAAQ,OACbA,EAAK,QAAQ,KACXsC,EAA4C,MAC5CA,CACH,EAED,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqBc,CAAa,CAC/D,CACItC,GAAmB,KAAK,GAAG,YAAY,KAAK,GAAG,iBAAkBC,CAAiB,CACvF,CAEQ,kBAAmB,CAC1B,IAAMpD,EAAK,KAAK,GACV8F,EAAmB,KAAK,SAAS,IAAItH,CAAwB,EACnEwB,EAAG,gBAAgBA,EAAG,YAAa,KAAK,eAAe,EACvDA,EAAG,qBAAqBA,EAAG,YAAaA,EAAG,kBAAmBA,EAAG,WAAY8F,EAAiB,QAAS,CAAC,CACzG,CAEA,OAAQ,CACP,KAAK,iBAAiB,EACtB,IAAM9F,EAAK,KAAK,GACV8F,EAAmB,KAAK,SAAS,IAAItH,CAAwB,EACnE,GAAIsH,EAAiB,QAAQ,qBAAsB,CAClD,IAAMC,EAAID,EAAiB,QAAQ,KAC/B,KAAK,UAAU,iBAAiB,IAAIC,CAAC,EACxC/F,EAAG,eAAeA,EAAG,MAAO,EAAG,IAAI,YAAY,CAAC,CAAC,EAEjDA,EAAG,cAAcA,EAAG,MAAO,EAAG,IAAI,WAAW,CAAC,CAAC,CAEjD,MACCA,EAAG,MAAMA,EAAG,gBAAgB,CAE9B,CAEA,KAAKwC,EAAuB,CAC3B,KAAK,SAAS,aAAc,GAAG,SAAS,EACxC,IAAMxC,EAAK,KAAK,GACVgG,EAAIhG,EAAG,mBACPiG,EAAIjG,EAAG,oBAETwC,GAAS,UACZ,KAAK,iBAAiB,EAEtB,KAAK,MAAM,EAGZxC,EAAG,WAAW,KAAK,OAAO,EAC1BA,EAAG,gBAAgB,KAAK,GAAG,EAC3BA,EAAG,SAAS,EAAG,EAAGgG,EAAGC,CAAC,EACtBjG,EAAG,WAAWA,EAAG,UAAW,EAAG,CAAC,EAE3B,KAAK,YACgB,KAAK,SAAS,IAAIxB,CAAwB,EAC7C,QAAQ,uBAC7BwB,EAAG,gBAAgBA,EAAG,iBAAkB,KAAK,eAAe,EAC5DA,EAAG,gBAAgBA,EAAG,iBAAkB,IAAI,EAC5CA,EAAG,gBAAgB,EAAG,EAAGgG,EAAGC,EAAG,EAAG,EAAGD,EAAGC,EAAGjG,EAAG,iBAAkBA,EAAG,OAAO,EAC1EA,EAAG,gBAAgBA,EAAG,YAAa,IAAI,GAGzC,KAAK,SAAS,YAAa,GAAG,SAAS,CACxC,CAEA,KAAKwC,EAAuB,CACtB,OAAO,SAAS,KAAK,SAAS,IAClC,KAAK,UAAY,YAAY,IAAI,GAElC,KAAK,OAAO,YAAY,IAAI,EAAI,KAAK,WAAa,IAAMA,CAAO,CAChE,CAEQ,MAAM0D,EAAc1D,EAAuB,CAClD,KAAK,SAAS,aAAc0D,EAAM,KAAK,MAAO1D,CAAO,EACrD,IAAMmB,EAAkC,CAAC,EACrC,KAAK,SAAS,IAAI,QAAQ,IAAGA,EAAQ,OAASuC,GAC9C,KAAK,SAAS,IAAI,SAAS,IAAGvC,EAAQ,QAAU,KAAK,OACzD,KAAK,eAAeA,CAAO,EAC3B,KAAK,KAAKnB,CAAO,EACjB,IAAM2D,EAAc,KAAK,SAAS,IAAI5H,CAAmB,EACzD,GAAI4H,GAAe,CAAC3D,GAAS,iBAAkB,CAC9C,GAAM,CAAE,WAAA4D,EAAY,MAAArB,CAAM,EAAIoB,EAAY,QACpCnG,EAAK,KAAK,GAChBA,EAAG,gBAAgBA,EAAG,iBAAkB,KAAK,eAAe,EAC5DA,EAAG,YAAYA,EAAG,iBAAkBmG,EAAY,OAAO,EACvDnG,EAAG,kBACFA,EAAG,iBACH,EACA,EACA,EACAoG,EACA,EACA,EACApG,EAAG,mBACHA,EAAG,mBACJ,EACAA,EAAG,gBAAgBA,EAAG,iBAAkB,IAAI,EAC5C,IAAMqG,GAAkBD,EAAa,GAAKrB,EAC1C,KAAK,eAAe,CACnB,CAAC,GAAG3F,EAAWb,CAAmB,CAAC,aAAa,EAAG8H,CACpD,CAAC,EACDF,EAAY,QAAS,WAAaE,CACnC,CACA,EAAE,KAAK,MACP,KAAK,SAAS,YAAaH,EAAM,KAAK,MAAO1D,CAAO,CACrD,CAEA,KAAK8D,EAAoE,CACxE,KAAK,OAAO,EACP,OAAO,SAAS,KAAK,SAAS,IAClC,KAAK,UAAY,YAAY,IAAI,GAElC,KAAK,UAAY,GACjB,IAAMC,EAAQL,GAAiB,CAC9BA,GAAQA,EAAO,KAAK,WAAa,IACjC,IAAM1D,EAAU8D,IAAeJ,EAAM,KAAK,KAAK,GAAK,OACpD,KAAK,MAAMA,EAAM1D,CAAO,EACpB,KAAK,YAAW,KAAK,iBAAmB,sBAAsB+D,CAAI,EACvE,EACA,KAAK,iBAAmB,sBAAsBA,CAAI,EAClD,KAAK,SAAS,MAAM,CACrB,CAEQ,QAAS,CAChB,IAAMC,EAAa,KAAK,UACxB,YAAK,UAAY,GACb,KAAK,mBACR,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,MAElBA,CACR,CAEA,OAAQ,CACH,KAAK,OAAO,GACf,KAAK,SAAS,OAAO,CAEvB,CAEA,YAAa,CACZ,KAAK,MAAQ,EACb,KAAK,UAAY,YAAY,IAAI,CAClC,CAEA,OAAQ,CACP,KAAK,WAAW,EAChB,KAAK,SAAS,QAAQlE,GAAW,CAC5BA,EAAQ,UACXA,EAAQ,QAAQ,WAAa,EAC7B,KAAK,0BAA0BA,CAAO,EAExC,CAAC,EACD,KAAK,MAAM,EACX,KAAK,SAAS,OAAO,CACtB,CAEA,SAAU,CACT,KAAK,SAAS,SAAS,EAEvB,KAAK,OAAO,EAER,KAAK,eACR,KAAK,eAAe,QAAQ,CAACH,EAAUH,IAAU,CAChD,KAAK,aAAc,oBAAoBA,EAAOG,CAAQ,CACvD,CAAC,EACD,KAAK,eAAe,MAAM,GAGvB,KAAK,qBACR,KAAK,mBAAmB,WAAW,EACnC,KAAK,mBAAqB,MAGvB,KAAK,UACR,KAAK,GAAG,cAAc,KAAK,OAAO,EAClC,KAAK,QAAU,MAGZ,KAAK,kBACR,KAAK,GAAG,kBAAkB,KAAK,eAAe,EAC9C,KAAK,gBAAkB,MAGxB,KAAK,SAAS,QAAQG,GAAW,CAChC,KAAK,gBAAgB,KAAK,KAAKA,EAAQ,SAAS,EAChD,KAAK,GAAG,cAAcA,EAAQ,OAAO,CACtC,CAAC,EACD,KAAK,SAAS,MAAM,EACpB,IAAM1B,EAAQnC,EAAe,IAAI,KAAK,MAAM,EACxCmC,IACHA,EAAM,UAAU,OAAO,IAAI,EACvBA,EAAM,UAAU,OAAS,GAC5BnC,EAAe,OAAO,KAAK,MAAM,GAI/B,KAAK,MACR,KAAK,GAAG,kBAAkB,KAAK,GAAG,EAClC,KAAK,IAAM,MAGR,KAAK,SACR,KAAK,GAAG,aAAa,KAAK,MAAM,EAChC,KAAK,OAAS,MAGf,KAAK,SAAS,MAAM,EACpB,KAAK,MAAM,MAAM,CAClB,CACD,EAEOgI,EAAQtH","names":["DEFAULT_VERTEX_SHADER_SRC","FORMAT_TYPE_SUFFIXES","UNIFORM_TYPE_SUFFIXES","typeFromInternalFormatString","internalFormatString","suffix","HISTORY_TEXTURE_KEY","INTERMEDIATE_TEXTURE_KEY","canvasRegistry","combineShaderCode","shader","injections","lines","insertAt","line","trimmed","getSourceDimensions","source","ShaderPad","stringFrom","name","_ShaderPad","fragmentShaderSrc","canvas","plugins","history","debug","cursorTarget","textureOptions","width","height","gl","registryEntry","glslInjections","plugin","code","program","vertexShader","fragmentShader","wrapDimension","dimension","descriptor","v","entry","instance","value","resolved","args","hook","fn","hooks","index","type","target","updateCursor","x","y","rect","u","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","resolution","info","texture","existing","options","internalFormatOption","typeString","isIntegerColorFormat","formatString","result","size","ArrayType","format","textureInfo","transparent","needsAlignmentFix","previousAlignment","layer","arrayLength","location","probeValue","length","error","updates","newValue","uniform","glFunctionName","nValues","item","flat","typedArray","newLocation","historyDepth","unitIndex","hasHistory","textureTarget","completeTextureInfo","uSampler","opts","nonShaderPadSource","sourceIntermediateInfo","srcW","srcH","depth","targetSlots","i","safeMod","slot","frameOffsetUniformName","pixels","isPartial","isTypedArray","shouldFlipY","previousFlipY","partialSource","sourceData","xOffset","yOffset","intermediateInfo","t","w","h","time","historyInfo","writeIndex","nextWriteIndex","onBeforeStep","loop","wasPlaying","index_default"]}
@@ -4,4 +4,4 @@ ${r}
4
4
  ${i} ${t}(${e}) { return ${t}(${m}); }`}:(i,t,e,r)=>`${i} ${t}(${e}) {
5
5
  ${r}
6
6
  }`}}export{y as a,h as b,$ as c,M as d,b as e,d as f};
7
- //# sourceMappingURL=chunk-JRSBIGBN.mjs.map
7
+ //# sourceMappingURL=chunk-VMNWRREI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/mediapipe-common.ts"],"sourcesContent":["import { TextureSource } from '..';\n\nexport const dummyTexture = { data: new Uint8Array(4), width: 1, height: 1 };\n\nexport type MediaPipeSource = HTMLVideoElement | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas;\n\nexport function isMediaPipeSource(source: TextureSource): source is MediaPipeSource {\n\treturn (\n\t\tsource instanceof HTMLVideoElement ||\n\t\tsource instanceof HTMLImageElement ||\n\t\tsource instanceof HTMLCanvasElement ||\n\t\tsource instanceof OffscreenCanvas\n\t);\n}\n\nexport function hashOptions(options: object): string {\n\treturn JSON.stringify(options, Object.keys(options).sort());\n}\n\nexport function calculateBoundingBoxCenter(\n\tdata: Float32Array,\n\tentityIdx: number,\n\tlandmarkIndices: readonly number[] | number[],\n\tlandmarkCount: number,\n\toffset: number = 0,\n): [number, number, number, number] {\n\tlet minX = Infinity,\n\t\tmaxX = -Infinity,\n\t\tminY = Infinity,\n\t\tmaxY = -Infinity,\n\t\tavgZ = 0,\n\t\tavgVisibility = 0;\n\n\tfor (const idx of landmarkIndices) {\n\t\tconst dataIdx = (offset + entityIdx * landmarkCount + idx) * 4;\n\t\tconst x = data[dataIdx];\n\t\tconst y = data[dataIdx + 1];\n\t\tminX = Math.min(minX, x);\n\t\tmaxX = Math.max(maxX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxY = Math.max(maxY, y);\n\t\tavgZ += data[dataIdx + 2];\n\t\tavgVisibility += data[dataIdx + 3];\n\t}\n\n\treturn [\n\t\t(minX + maxX) / 2,\n\t\t(minY + maxY) / 2,\n\t\tavgZ / landmarkIndices.length,\n\t\tavgVisibility / landmarkIndices.length,\n\t];\n}\n\nlet filesetPromise: Promise<any> | null = null;\nexport function getSharedFileset(): Promise<any> {\n\tif (!filesetPromise) {\n\t\tfilesetPromise = import('@mediapipe/tasks-vision').then(({ FilesetResolver }) =>\n\t\t\tFilesetResolver.forVisionTasks(\n\t\t\t\t`https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${__MEDIAPIPE_TASKS_VISION_VERSION__}/wasm`,\n\t\t\t),\n\t\t);\n\t}\n\treturn filesetPromise;\n}\n\nexport function generateGLSLFn(history: number | undefined) {\n\tconst historyParams = history ? ', framesAgo' : '';\n\tconst fn = history\n\t\t? (returnType: string, name: string, args: string, body: string) => {\n\t\t\t\tconst argsOnly = args.replace(/\\w+ /g, '');\n\t\t\t\tconst historyArgs = args ? `${args}, int framesAgo` : 'int framesAgo';\n\t\t\t\tconst callArgs = argsOnly ? `${argsOnly}, 0` : '0';\n\t\t\t\treturn `${returnType} ${name}(${historyArgs}) {\\n${body}\\n}\n${returnType} ${name}(${args}) { return ${name}(${callArgs}); }`;\n\t\t\t}\n\t\t: (returnType: string, name: string, args: string, body: string) =>\n\t\t\t\t`${returnType} ${name}(${args}) {\\n${body}\\n}`;\n\treturn { historyParams, fn };\n}\n"],"mappings":"AAEO,IAAMA,EAAe,CAAE,KAAM,IAAI,WAAW,CAAC,EAAG,MAAO,EAAG,OAAQ,CAAE,EAIpE,SAASC,EAAkBC,EAAkD,CACnF,OACCA,aAAkB,kBAClBA,aAAkB,kBAClBA,aAAkB,mBAClBA,aAAkB,eAEpB,CAEO,SAASC,EAAYC,EAAyB,CACpD,OAAO,KAAK,UAAUA,EAAS,OAAO,KAAKA,CAAO,EAAE,KAAK,CAAC,CAC3D,CAEO,SAASC,EACfC,EACAC,EACAC,EACAC,EACAC,EAAiB,EACkB,CACnC,IAAIC,EAAO,IACVC,EAAO,KACPC,EAAO,IACPC,EAAO,KACPC,EAAO,EACPC,EAAgB,EAEjB,QAAWC,KAAOT,EAAiB,CAClC,IAAMU,GAAWR,EAASH,EAAYE,EAAgBQ,GAAO,EACvDE,EAAIb,EAAKY,CAAO,EAChBE,EAAId,EAAKY,EAAU,CAAC,EAC1BP,EAAO,KAAK,IAAIA,EAAMQ,CAAC,EACvBP,EAAO,KAAK,IAAIA,EAAMO,CAAC,EACvBN,EAAO,KAAK,IAAIA,EAAMO,CAAC,EACvBN,EAAO,KAAK,IAAIA,EAAMM,CAAC,EACvBL,GAAQT,EAAKY,EAAU,CAAC,EACxBF,GAAiBV,EAAKY,EAAU,CAAC,CAClC,CAEA,MAAO,EACLP,EAAOC,GAAQ,GACfC,EAAOC,GAAQ,EAChBC,EAAOP,EAAgB,OACvBQ,EAAgBR,EAAgB,MACjC,CACD,CAEA,IAAIa,EAAsC,KACnC,SAASC,GAAiC,CAChD,OAAKD,IACJA,EAAiB,OAAO,yBAAyB,EAAE,KAAK,CAAC,CAAE,gBAAAE,CAAgB,IAC1EA,EAAgB,eACf,+EACD,CACD,GAEMF,CACR,CAEO,SAASG,EAAeC,EAA6B,CAY3D,MAAO,CAAE,cAXaA,EAAU,cAAgB,GAWxB,GAVbA,EACR,CAACC,EAAoBC,EAAcC,EAAcC,IAAiB,CAClE,IAAMC,EAAWF,EAAK,QAAQ,QAAS,EAAE,EACnCG,EAAcH,EAAO,GAAGA,CAAI,kBAAoB,gBAChDI,EAAWF,EAAW,GAAGA,CAAQ,MAAQ,IAC/C,MAAO,GAAGJ,CAAU,IAAIC,CAAI,IAAII,CAAW;AAAA,EAAQF,CAAI;AAAA;AAAA,EACzDH,CAAU,IAAIC,CAAI,IAAIC,CAAI,cAAcD,CAAI,IAAIK,CAAQ,MACvD,EACC,CAACN,EAAoBC,EAAcC,EAAcC,IACjD,GAAGH,CAAU,IAAIC,CAAI,IAAIC,CAAI;AAAA,EAAQC,CAAI;AAAA,EACjB,CAC5B","names":["dummyTexture","isMediaPipeSource","source","hashOptions","options","calculateBoundingBoxCenter","data","entityIdx","landmarkIndices","landmarkCount","offset","minX","maxX","minY","maxY","avgZ","avgVisibility","idx","dataIdx","x","y","filesetPromise","getSharedFileset","FilesetResolver","generateGLSLFn","history","returnType","name","args","body","argsOnly","historyArgs","callArgs"]}
package/dist/index.d.mts CHANGED
@@ -38,10 +38,12 @@ interface PluginContext {
38
38
  canvas: HTMLCanvasElement | OffscreenCanvas;
39
39
  injectGLSL: (code: string) => void;
40
40
  emitHook: (name: LifecycleMethod, ...args: any[]) => void;
41
+ updateTexturesInternal: (updates: Record<string, UpdateTextureSource>, options?: InternalUpdateTexturesOptions) => void;
41
42
  }
42
43
  type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
43
44
  type LifecycleMethod = '_init' | 'initializeTexture' | 'initializeUniform' | 'updateTextures' | 'updateUniforms' | 'beforeStep' | 'afterStep' | 'beforeDraw' | 'afterDraw' | 'updateResolution' | 'play' | 'pause' | 'reset' | 'destroy' | `${string}:${string}`;
44
- interface Options extends Exclude<TextureOptions, 'preserveY'> {
45
+ type RenderTextureOptions = Omit<TextureOptions, 'preserveY'>;
46
+ interface Options extends RenderTextureOptions {
45
47
  canvas?: HTMLCanvasElement | OffscreenCanvas | {
46
48
  width: number;
47
49
  height: number;
@@ -55,6 +57,12 @@ interface StepOptions {
55
57
  skipClear?: boolean;
56
58
  skipHistoryWrite?: boolean;
57
59
  }
60
+ interface UpdateTexturesOptions {
61
+ skipHistoryWrite?: boolean;
62
+ }
63
+ type InternalUpdateTexturesOptions = UpdateTexturesOptions & {
64
+ historyWriteIndex?: number | number[];
65
+ };
58
66
  declare class ShaderPad {
59
67
  private isHeadless;
60
68
  private isTouchDevice;
@@ -109,10 +117,8 @@ declare class ShaderPad {
109
117
  initializeTexture(name: string, source: TextureSource, options?: TextureOptions & {
110
118
  history?: number;
111
119
  }): void;
112
- updateTextures(updates: Record<string, UpdateTextureSource>, options?: {
113
- skipHistoryWrite?: boolean;
114
- historyWriteIndex?: number | number[];
115
- }): void;
120
+ updateTextures(updates: Record<string, UpdateTextureSource>, options?: UpdateTexturesOptions): void;
121
+ private updateTexturesInternal;
116
122
  private updateTexture;
117
123
  private bindIntermediate;
118
124
  clear(): void;
@@ -127,4 +133,4 @@ declare class ShaderPad {
127
133
  destroy(): void;
128
134
  }
129
135
 
130
- export { type CustomTexture, type GLFilterString, type GLFormatString, type GLInternalFormatString, type GLTypeString, type GLWrapString, type Options, type PartialCustomTexture, type PluginContext, type StepOptions, type TextureOptions, type TextureSource, ShaderPad as default };
136
+ export { type CustomTexture, type GLFilterString, type GLFormatString, type GLInternalFormatString, type GLTypeString, type GLWrapString, type Options, type PartialCustomTexture, type PluginContext, type RenderTextureOptions, type StepOptions, type TextureOptions, type TextureSource, type UpdateTexturesOptions, ShaderPad as default };
package/dist/index.d.ts CHANGED
@@ -38,10 +38,12 @@ interface PluginContext {
38
38
  canvas: HTMLCanvasElement | OffscreenCanvas;
39
39
  injectGLSL: (code: string) => void;
40
40
  emitHook: (name: LifecycleMethod, ...args: any[]) => void;
41
+ updateTexturesInternal: (updates: Record<string, UpdateTextureSource>, options?: InternalUpdateTexturesOptions) => void;
41
42
  }
42
43
  type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
43
44
  type LifecycleMethod = '_init' | 'initializeTexture' | 'initializeUniform' | 'updateTextures' | 'updateUniforms' | 'beforeStep' | 'afterStep' | 'beforeDraw' | 'afterDraw' | 'updateResolution' | 'play' | 'pause' | 'reset' | 'destroy' | `${string}:${string}`;
44
- interface Options extends Exclude<TextureOptions, 'preserveY'> {
45
+ type RenderTextureOptions = Omit<TextureOptions, 'preserveY'>;
46
+ interface Options extends RenderTextureOptions {
45
47
  canvas?: HTMLCanvasElement | OffscreenCanvas | {
46
48
  width: number;
47
49
  height: number;
@@ -55,6 +57,12 @@ interface StepOptions {
55
57
  skipClear?: boolean;
56
58
  skipHistoryWrite?: boolean;
57
59
  }
60
+ interface UpdateTexturesOptions {
61
+ skipHistoryWrite?: boolean;
62
+ }
63
+ type InternalUpdateTexturesOptions = UpdateTexturesOptions & {
64
+ historyWriteIndex?: number | number[];
65
+ };
58
66
  declare class ShaderPad {
59
67
  private isHeadless;
60
68
  private isTouchDevice;
@@ -109,10 +117,8 @@ declare class ShaderPad {
109
117
  initializeTexture(name: string, source: TextureSource, options?: TextureOptions & {
110
118
  history?: number;
111
119
  }): void;
112
- updateTextures(updates: Record<string, UpdateTextureSource>, options?: {
113
- skipHistoryWrite?: boolean;
114
- historyWriteIndex?: number | number[];
115
- }): void;
120
+ updateTextures(updates: Record<string, UpdateTextureSource>, options?: UpdateTexturesOptions): void;
121
+ private updateTexturesInternal;
116
122
  private updateTexture;
117
123
  private bindIntermediate;
118
124
  clear(): void;
@@ -127,4 +133,4 @@ declare class ShaderPad {
127
133
  destroy(): void;
128
134
  }
129
135
 
130
- export { type CustomTexture, type GLFilterString, type GLFormatString, type GLInternalFormatString, type GLTypeString, type GLWrapString, type Options, type PartialCustomTexture, type PluginContext, type StepOptions, type TextureOptions, type TextureSource, ShaderPad as default };
136
+ export { type CustomTexture, type GLFilterString, type GLFormatString, type GLInternalFormatString, type GLTypeString, type GLWrapString, type Options, type PartialCustomTexture, type PluginContext, type RenderTextureOptions, type StepOptions, type TextureOptions, type TextureSource, type UpdateTexturesOptions, ShaderPad as default };
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- "use strict";var w=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var M=(h,t)=>{for(var e in t)w(h,e,{get:t[e],enumerable:!0})},B=(h,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of N(t))!C.call(h,i)&&i!==e&&w(h,i,{get:()=>t[i],enumerable:!(r=D(t,i))||r.enumerable});return h};var H=h=>B(w({},"__esModule",{value:!0}),h);var z={};M(z,{default:()=>$});module.exports=H(z);function y(h,t){return(h%t+t)%t}var W=`#version 300 es
1
+ "use strict";var w=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var M=(h,t)=>{for(var e in t)w(h,e,{get:t[e],enumerable:!0})},B=(h,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of D(t))!C.call(h,i)&&i!==e&&w(h,i,{get:()=>t[i],enumerable:!(r=N(t,i))||r.enumerable});return h};var H=h=>B(w({},"__esModule",{value:!0}),h);var z={};M(z,{default:()=>$});module.exports=H(z);function F(h,t){return(h%t+t)%t}var W=`#version 300 es
2
2
  in vec2 a_position;
3
3
  out vec2 v_uv;
4
4
  void main() {
5
5
  gl_Position = vec4(a_position, 0.0, 1.0);
6
6
  v_uv = a_position * 0.5 + 0.5;
7
- }`,k=[["8UI","UNSIGNED_BYTE"],["8I","BYTE"],["16UI","UNSIGNED_SHORT"],["16I","SHORT"],["16F","HALF_FLOAT"],["32UI","UNSIGNED_INT"],["32I","INT"],["32F","FLOAT"],["8","UNSIGNED_BYTE"]],U={float:"f",int:"i",uint:"ui"};function X(h){return h&&k.find(([t])=>h.endsWith(t))?.[1]}var v=Symbol("u_history"),d=Symbol("__SHADERPAD_BUFFER"),R=new WeakMap;function Y(h,t){if(!t?.length)return h;let e=h.split(`
7
+ }`,k=[["8UI","UNSIGNED_BYTE"],["8I","BYTE"],["16UI","UNSIGNED_SHORT"],["16I","SHORT"],["16F","HALF_FLOAT"],["32UI","UNSIGNED_INT"],["32I","INT"],["32F","FLOAT"],["8","UNSIGNED_BYTE"]],G={float:"f",int:"i",uint:"ui"};function X(h){return h&&k.find(([t])=>h.endsWith(t))?.[1]}var I=Symbol("u_history"),p=Symbol("__SHADERPAD_BUFFER"),A=new WeakMap;function Y(h,t){if(!t?.length)return h;let e=h.split(`
8
8
  `),r=e.findLastIndex(i=>{let s=i.trimStart();return s.startsWith("precision ")||s.startsWith("#version ")})+1;return e.splice(r,0,...t),e.join(`
9
- `)}function P(h){return h instanceof WebGLTexture?{width:0,height:0}:h instanceof I?{width:h.canvas.width,height:h.canvas.height}:h instanceof HTMLVideoElement?{width:h.videoWidth,height:h.videoHeight}:h instanceof HTMLImageElement?{width:h.naturalWidth??h.width,height:h.naturalHeight??h.height}:{width:h.width,height:h.height}}function E(h){return typeof h=="symbol"?h.description??"":h}var I=class h{isHeadless=!1;isTouchDevice=!1;gl;glHelpers;uniforms=new Map;textures=new Map;textureUnitPool;buffer=null;vao=null;program=null;animationFrameId;eventListeners=new Map;frame=0;startTime=0;isPlaying=!1;cursorPosition=[.5,.5];clickPosition=[.5,.5];isMouseDown=!1;canvas;resolutionObserver=null;hooks=new Map;historyDepth=0;textureOptions;debug;cursorTarget;intermediateFbo=null;constructor(t,{canvas:e,plugins:r,history:i,debug:s,cursorTarget:a,...o}={}){if(e&&"getContext"in e)this.canvas=e;else{let{width:f=1,height:m=1}=e||{};this.canvas=new OffscreenCanvas(f,m),this.isHeadless=!0}let n=this.canvas.getContext("webgl2",{antialias:!1});if(!n)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.gl=n,this.glHelpers={typeToArray:new Map([[n.FLOAT,Float32Array],[n.HALF_FLOAT,Uint16Array],[n.UNSIGNED_SHORT,Uint16Array],[n.SHORT,Int16Array],[n.BYTE,Int8Array],[n.UNSIGNED_INT,Uint32Array],[n.INT,Int32Array]]),typeToInternalFormatString:new Map([[n.FLOAT,"RGBA32F"],[n.HALF_FLOAT,"RGBA16F"],[n.UNSIGNED_SHORT,"RGBA32UI"],[n.SHORT,"RGBA32I"],[n.BYTE,"RGBA32I"],[n.UNSIGNED_INT,"RGBA32UI"],[n.INT,"RGBA32I"]]),unsignedIntTypes:new Set([n.UNSIGNED_BYTE,n.UNSIGNED_SHORT,n.UNSIGNED_INT])};let l=R.get(this.canvas);l||(l={textureUnitPool:{free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},instances:new Set([this])},R.set(this.canvas,l)),this.textureUnitPool=l.textureUnitPool,l.instances.add(this),this.textureOptions=o,i&&(this.historyDepth=i),this.debug=s??(typeof process<"u"&&!1),this.cursorTarget=a??(this.canvas instanceof HTMLCanvasElement?this.canvas:void 0),this.animationFrameId=null;let g=[];r&&r.forEach(f=>f(this,{gl:n,canvas:this.canvas,injectGLSL:m=>{g.push(m)},emitHook:this.emitHook.bind(this)}));let u=this.gl.createProgram();if(!u)throw new Error("Failed to create WebGL program");this.program=u;let T=this.createShader(this.gl.VERTEX_SHADER,W),b=this.createShader(n.FRAGMENT_SHADER,Y(t,g));if(n.attachShader(u,T),n.attachShader(u,b),n.bindAttribLocation(u,0,"a_position"),n.linkProgram(u),n.deleteShader(T),n.deleteShader(b),!n.getProgramParameter(u,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(u)),n.deleteProgram(u),new Error("Failed to link WebGL program");if(this.vao=n.createVertexArray(),n.bindVertexArray(this.vao),this.buffer=n.createBuffer(),n.bindBuffer(n.ARRAY_BUFFER,this.buffer),n.bufferData(n.ARRAY_BUFFER,new Float32Array([-1,-1,3,-1,-1,3]),n.STATIC_DRAW),n.enableVertexAttribArray(0),n.vertexAttribPointer(0,2,n.FLOAT,!1,0,0),n.viewport(0,0,n.drawingBufferWidth,n.drawingBufferHeight),n.useProgram(u),this.canvas instanceof HTMLCanvasElement)this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]});else{let f=m=>{let x=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,m),c=this.canvas;Object.defineProperty(c,m,{get:()=>x.get.call(c),set:p=>{x.set.call(c,p);let F=R.get(c);if(F)for(let A of F.instances)A.updateResolution()},configurable:x.configurable,enumerable:x.enumerable})};f("width"),f("height")}this.updateResolution(),this.initializeUniform("u_cursor","float",this.cursorPosition),this.initializeUniform("u_click","float",[...this.clickPosition,this.isMouseDown?1:0]),this.initializeUniform("u_time","float",0),this.initializeUniform("u_frame","int",0),this._initializeTexture(d,this.canvas,{...this.textureOptions}),this.intermediateFbo=n.createFramebuffer(),this.bindIntermediate(),n.bindFramebuffer(n.FRAMEBUFFER,null),this.historyDepth>0&&this._initializeTexture(v,this.canvas,{history:this.historyDepth,...this.textureOptions}),this.cursorTarget&&this.addEventListeners(),this.emitHook("_init")}resolveGLConstant(t){let e=this.gl[t];if(e===void 0)throw new Error(`Unknown GL constant: ${t}`);return e}emitHook(t,...e){this.hooks.get(t)?.forEach(r=>r.call(this,...e))}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}off(t,e){let r=this.hooks.get(t);r&&r.splice(r.indexOf(e),1)}createShader(t,e){let r=this.gl.createShader(t);if(this.gl.shaderSource(r,e),this.gl.compileShader(r),!this.gl.getShaderParameter(r,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(r)),this.gl.deleteShader(r),new Error("Shader compilation failed");return r}getCursorTargetRect(){let t=this.cursorTarget;return t===window?{left:0,top:0,width:window.innerWidth,height:window.innerHeight}:t.getBoundingClientRect()}addEventListeners(){if(!this.cursorTarget)return;let t=(r,i)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.getCursorTargetRect(),a=(r-s.left)/s.width,o=1-(i-s.top)/s.height;this.cursorPosition[0]=Math.max(0,Math.min(1,a)),this.cursorPosition[1]=Math.max(0,Math.min(1,o)),this.updateUniforms({u_cursor:this.cursorPosition})},e=(r,i,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=r,r){let a=this.getCursorTargetRect(),o=i,n=s;this.clickPosition[0]=Math.max(0,Math.min(1,(o-a.left)/a.width)),this.clickPosition[1]=Math.max(0,Math.min(1,1-(n-a.top)/a.height))}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",r=>{let i=r;this.isTouchDevice||t(i.clientX,i.clientY)}),this.eventListeners.set("mousedown",r=>{let i=r;this.isTouchDevice||i.button===0&&(this.isMouseDown=!0,e(!0,i.clientX,i.clientY))}),this.eventListeners.set("mouseup",r=>{let i=r;this.isTouchDevice||i.button===0&&e(!1)}),this.eventListeners.set("touchmove",r=>{let i=r;i.touches.length>0&&t(i.touches[0].clientX,i.touches[0].clientY)}),this.eventListeners.set("touchstart",r=>{let i=r;this.isTouchDevice=!0,i.touches.length>0&&(t(i.touches[0].clientX,i.touches[0].clientY),e(!0,i.touches[0].clientX,i.touches[0].clientY))}),this.eventListeners.set("touchend",r=>{r.touches.length===0&&e(!1)}),this.eventListeners.forEach((r,i)=>{this.cursorTarget.addEventListener(i,r)})}updateResolution(){let t=[this.gl.drawingBufferWidth,this.gl.drawingBufferHeight];this.gl.viewport(0,0,...t),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:t}):this.initializeUniform("u_resolution","float",t),this.resizeTexture(d,...t),this.historyDepth>0&&this.resizeTexture(v,...t),this.emitHook("updateResolution",...t)}resizeTexture(t,e,r){let i=this.textures.get(t);if(!i||i.width===e&&i.height===r)return;this.gl.deleteTexture(i.texture),i.width=e,i.height=r;let{texture:s}=this.createTexture(t,i);i.texture=s,i.history&&(i.history.writeIndex=0,this.clearHistoryTextureLayers(i))}reserveTextureUnit(t){let e=this.textures.get(t);if(e)return e.unitIndex;if(this.textureUnitPool.free.length>0)return this.textureUnitPool.free.pop();if(this.textureUnitPool.next>=this.textureUnitPool.max)throw new Error("Exceeded the available texture units for this device.");return this.textureUnitPool.next++}resolveTextureOptions(t){let{gl:e}=this,r=t?.internalFormat,i=t?.type??X(r)??"UNSIGNED_BYTE",s=this.resolveGLConstant(i),a=r??this.glHelpers.typeToInternalFormatString.get(s)??"RGBA8",o=/^(R|RG|RGB|RGBA)(8|16|32)(UI|I)$/.test(a),n=t?.format??(o?"RGBA_INTEGER":"RGBA"),l={type:s,format:this.resolveGLConstant(n),internalFormat:this.resolveGLConstant(a),minFilter:this.resolveGLConstant(t?.minFilter??"LINEAR"),magFilter:this.resolveGLConstant(t?.magFilter??"LINEAR"),wrapS:this.resolveGLConstant(t?.wrapS??"CLAMP_TO_EDGE"),wrapT:this.resolveGLConstant(t?.wrapT??"CLAMP_TO_EDGE"),preserveY:t?.preserveY,isIntegerColorFormat:o};if((l.internalFormat===e.RGBA16F||l.internalFormat===e.RGBA32F)&&!e.getExtension("EXT_color_buffer_float"))throw new Error("Missing EXT_color_buffer_float.");return l}getPixelArray(t,e){let r=this.glHelpers.typeToArray.get(t)??Uint8Array;return new r(e)}isNotRgba(t){return t!==this.gl.RGBA&&t!==this.gl.RGBA_INTEGER}clearHistoryTextureLayers(t){if(!t.history)return;let e=this.gl,{type:r,format:i}=t.options,s=this.getPixelArray(r,t.width*t.height*4);e.activeTexture(e.TEXTURE0+t.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,t.texture);let a=this.isNotRgba(i),o;a&&(o=e.getParameter(e.UNPACK_ALIGNMENT),e.pixelStorei(e.UNPACK_ALIGNMENT,1));for(let n=0;n<t.history.depth;++n)e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,n,t.width,t.height,1,i,r,s);a&&e.pixelStorei(e.UNPACK_ALIGNMENT,o)}initializeUniform(t,e,r,i){let s=i?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(!U[e])throw new Error(`Invalid uniform type: ${e}. Expected one of: ${Object.keys(U).join(", ")}.`);if(s&&!(Array.isArray(r)&&r.length===s))throw new Error(`${t} array length mismatch: must initialize with ${s} elements.`);let a=this.gl.getUniformLocation(this.program,t);if(!a&&s&&(a=this.gl.getUniformLocation(this.program,`${t}[0]`)),!a){this.log(`${t} not in shader. Skipping initialization.`);return}let o=s?r[0]:r,n=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:n,location:a,arrayLength:s});try{this.updateUniforms({[t]:r})}catch(l){throw this.uniforms.delete(t),l}this.emitHook("initializeUniform",...arguments)}log(...t){this.debug&&console.debug(...t)}updateUniforms(t,e){this.gl.useProgram(this.program),Object.entries(t).forEach(([r,i])=>{let s=this.uniforms.get(r);if(!s){this.log(`${r} not in shader. Skipping update.`);return}let a=`uniform${s.length}${U[s.type]}`;if(s.arrayLength){if(!Array.isArray(i))throw new Error(`${r} is an array, but the value passed to updateUniforms is not an array.`);let o=i.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${r} received ${o} values, but maximum length is ${s.arrayLength}.`);if(i.some(u=>(Array.isArray(u)?u.length:1)!==s.length))throw new Error(`Tried to update ${r} with some elements that are not length ${s.length}.`);let n=i.flat(),l=s.type==="float"?new Float32Array(n):s.type==="uint"?new Uint32Array(n):new Int32Array(n),g=s.location;if(e?.startIndex){let u=this.gl.getUniformLocation(this.program,`${r}[${e.startIndex}]`);if(!u)throw new Error(`${r}[${e.startIndex}] not in shader. Did you pass an invalid startIndex?`);g=u}this.gl[a+"v"](g,l)}else{if(Array.isArray(i)||(i=[i]),i.length!==s.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${s.length}.`);this.gl[a](s.location,...i)}}),this.emitHook("updateUniforms",...arguments)}createTexture(t,e){let{width:r,height:i}=e,s=e.history?.depth??0,a=this.gl.createTexture();if(!a)throw new Error("Failed to create texture");let o=e.unitIndex;if(typeof o!="number")try{o=this.reserveTextureUnit(t)}catch(u){throw this.gl.deleteTexture(a),u}let n=s>0,l=n?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:g}=e;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(l,a),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_S,g.wrapS),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_T,g.wrapT),this.gl.texParameteri(l,this.gl.TEXTURE_MIN_FILTER,g.minFilter),this.gl.texParameteri(l,this.gl.TEXTURE_MAG_FILTER,g.magFilter),n?this.gl.texStorage3D(l,1,g.internalFormat,r,i,s):t===d&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,g.internalFormat,r,i,0,g.format,g.type,null),{texture:a,unitIndex:o}}_initializeTexture(t,e,r){if(this.textures.has(t))throw new Error(`Texture '${E(t)}' is already initialized.`);let{history:i=0,...s}=r??{},{width:a,height:o}=P(e);if(!a||!o)throw new Error("Texture source must have valid dimensions");let n={width:a,height:o,options:e instanceof h&&Object.keys(s).length===0&&e.textures.has(d)?e.textures.get(d).options:this.resolveTextureOptions(s)};i>0&&(n.history={depth:i,writeIndex:0});let{texture:l,unitIndex:g}=this.createTexture(t,n),u={texture:l,unitIndex:g,...n};i>0&&(this.initializeUniform(`${E(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(u)),this.textures.set(t,u),t!==d&&t!==v&&this.updateTexture(t,e),this.gl.useProgram(this.program);let T=this.gl.getUniformLocation(this.program,E(t));T&&this.gl.uniform1i(T,g)}initializeTexture(t,e,r){let i=r?.history!=null&&r.history>0?{...r,history:r.history+1}:r;this._initializeTexture(t,e,i),this.emitHook("initializeTexture",...arguments)}updateTextures(t,e){Object.entries(t).forEach(([r,i])=>{this.updateTexture(r,i,e)}),this.emitHook("updateTextures",...arguments)}updateTexture(t,e,r){let i=this.textures.get(t);if(!i)throw new Error(`Texture '${E(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let s=e;if(e instanceof h){let f=e.textures.get(d),m=f.width,x=f.height;if(e.gl===this.gl){if(!i.history){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,f.texture);return}let{depth:_}=i.history,L=r?.historyWriteIndex===void 0?[i.history.writeIndex]:Array.isArray(r?.historyWriteIndex)?r.historyWriteIndex.map(S=>y(S,_)):[y(r.historyWriteIndex,_)];this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,e.intermediateFbo),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture);for(let S of L)this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,S,0,0,m,x);this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,null),this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture);let O=`${E(t)}FrameOffset`;this.updateUniforms({[O]:L[L.length-1]}),r?.historyWriteIndex===void 0&&(i.history.writeIndex=(i.history.writeIndex+1)%_);return}let{width:c,height:p,options:{format:F,type:A}}=f,G=this.getPixelArray(A,c*p*4);e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,e.intermediateFbo),e.gl.readPixels(0,0,c,p,F,A,G),e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,null),s={data:G,width:c,height:p}}let{width:a,height:o}=P(s);if(!a||!o)return;let n="isPartial"in s&&s.isPartial;n||this.resizeTexture(t,a,o);let l="data"in s&&s.data,g=!l&&!i.options?.preserveY,u=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL),T=l&&this.isNotRgba(i.options.format),b;if(T&&(b=this.gl.getParameter(this.gl.UNPACK_ALIGNMENT),this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,1)),i.history){if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture),!r?.skipHistoryWrite){let{depth:f}=i.history,m=r?.historyWriteIndex===void 0?[i.history.writeIndex]:Array.isArray(r.historyWriteIndex)?r.historyWriteIndex.map(p=>y(p,f)):[y(r.historyWriteIndex,f)];this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g);let x=s.data??s;for(let p of m)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,p,a,o,1,i.options.format,i.options.type,x);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u);let c=`${E(t)}FrameOffset`;this.updateUniforms({[c]:m[m.length-1]}),r?.historyWriteIndex===void 0&&(i.history.writeIndex=(i.history.writeIndex+1)%f)}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,i.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g),n){let f=s;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,f.x??0,f.y??0,a,o,i.options.format,i.options.type,f.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,i.options.internalFormat,a,o,0,i.options.format,i.options.type,s.data??s);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u)}T&&this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,b)}bindIntermediate(){let t=this.gl,e=this.textures.get(d);t.bindFramebuffer(t.FRAMEBUFFER,this.intermediateFbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,e.texture,0)}clear(){this.bindIntermediate();let t=this.gl,e=this.textures.get(d);if(e.options.isIntegerColorFormat){let r=e.options.type;this.glHelpers.unsignedIntTypes.has(r)?t.clearBufferuiv(t.COLOR,0,new Uint32Array(4)):t.clearBufferiv(t.COLOR,0,new Int32Array(4))}else t.clear(t.COLOR_BUFFER_BIT)}draw(t){this.emitHook("beforeDraw",...arguments);let e=this.gl,r=e.drawingBufferWidth,i=e.drawingBufferHeight;t?.skipClear?this.bindIntermediate():this.clear(),e.useProgram(this.program),e.bindVertexArray(this.vao),e.viewport(0,0,r,i),e.drawArrays(e.TRIANGLES,0,3),this.isHeadless||this.textures.get(d).options.isIntegerColorFormat||(e.bindFramebuffer(e.READ_FRAMEBUFFER,this.intermediateFbo),e.bindFramebuffer(e.DRAW_FRAMEBUFFER,null),e.blitFramebuffer(0,0,r,i,0,0,r,i,e.COLOR_BUFFER_BIT,e.NEAREST),e.bindFramebuffer(e.FRAMEBUFFER,null)),this.emitHook("afterDraw",...arguments)}step(t){this._step(performance.now()-this.startTime,t)}_step(t,e){this.emitHook("beforeStep",t,this.frame,e);let r={};this.uniforms.has("u_time")&&(r.u_time=t),this.uniforms.has("u_frame")&&(r.u_frame=this.frame),this.updateUniforms(r),this.draw(e);let i=this.textures.get(v);if(i&&!e?.skipHistoryWrite){let{writeIndex:s,depth:a}=i.history,o=this.gl;o.bindFramebuffer(o.READ_FRAMEBUFFER,this.intermediateFbo),o.bindTexture(o.TEXTURE_2D_ARRAY,i.texture),o.copyTexSubImage3D(o.TEXTURE_2D_ARRAY,0,0,0,s,0,0,o.drawingBufferWidth,o.drawingBufferHeight),o.bindFramebuffer(o.READ_FRAMEBUFFER,null);let n=(s+1)%a;this.updateUniforms({[`${E(v)}FrameOffset`]:n}),i.history.writeIndex=n}++this.frame,this.emitHook("afterStep",t,this.frame,e)}play(t){this.pause(),this.isPlaying=!0;let e=r=>{r=(r-this.startTime)/1e3;let i=t?.(r,this.frame)??void 0;this._step(r,i),this.isPlaying&&(this.animationFrameId=requestAnimationFrame(e))};this.animationFrameId=requestAnimationFrame(e),this.emitHook("play")}_pause(){this.isPlaying=!1,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}pause(){this._pause(),this.emitHook("pause")}resetFrame(){this.frame=0,this.startTime=performance.now()}reset(){this.resetFrame(),this.textures.forEach(t=>{t.history&&(t.history.writeIndex=0,this.clearHistoryTextureLayers(t))}),this.clear(),this.emitHook("reset")}destroy(){this.emitHook("destroy"),this._pause(),this.cursorTarget&&(this.eventListeners.forEach((e,r)=>{this.cursorTarget.removeEventListener(r,e)}),this.eventListeners.clear()),this.resolutionObserver&&(this.resolutionObserver.disconnect(),this.resolutionObserver=null),this.program&&(this.gl.deleteProgram(this.program),this.program=null),this.intermediateFbo&&(this.gl.deleteFramebuffer(this.intermediateFbo),this.intermediateFbo=null),this.textures.forEach(e=>{this.textureUnitPool.free.push(e.unitIndex),this.gl.deleteTexture(e.texture)}),this.textures.clear();let t=R.get(this.canvas);t&&(t.instances.delete(this),t.instances.size===0&&R.delete(this.canvas)),this.vao&&(this.gl.deleteVertexArray(this.vao),this.vao=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.uniforms.clear(),this.hooks.clear()}},$=I;
9
+ `)}function P(h){return h instanceof WebGLTexture?{width:0,height:0}:h instanceof _?{width:h.canvas.width,height:h.canvas.height}:h instanceof HTMLVideoElement?{width:h.videoWidth,height:h.videoHeight}:h instanceof HTMLImageElement?{width:h.naturalWidth??h.width,height:h.naturalHeight??h.height}:{width:h.width,height:h.height}}function E(h){return typeof h=="symbol"?h.description??"":h}var _=class h{isHeadless=!1;isTouchDevice=!1;gl;glHelpers;uniforms=new Map;textures=new Map;textureUnitPool;buffer=null;vao=null;program=null;animationFrameId;eventListeners=new Map;frame=0;startTime=Number.NaN;isPlaying=!1;cursorPosition=[.5,.5];clickPosition=[.5,.5];isMouseDown=!1;canvas;resolutionObserver=null;hooks=new Map;historyDepth=0;textureOptions;debug;cursorTarget;intermediateFbo=null;constructor(t,{canvas:e,plugins:r,history:i,debug:s,cursorTarget:a,...o}={}){if(e&&"getContext"in e)this.canvas=e;else{let{width:f=1,height:c=1}=e||{};this.canvas=new OffscreenCanvas(f,c),this.isHeadless=!0}let n=this.canvas.getContext("webgl2",{antialias:!1});if(!n)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.gl=n,this.glHelpers={typeToArray:new Map([[n.FLOAT,Float32Array],[n.HALF_FLOAT,Uint16Array],[n.UNSIGNED_SHORT,Uint16Array],[n.SHORT,Int16Array],[n.BYTE,Int8Array],[n.UNSIGNED_INT,Uint32Array],[n.INT,Int32Array]]),typeToInternalFormatString:new Map([[n.FLOAT,"RGBA32F"],[n.HALF_FLOAT,"RGBA16F"],[n.UNSIGNED_SHORT,"RGBA32UI"],[n.SHORT,"RGBA32I"],[n.BYTE,"RGBA32I"],[n.UNSIGNED_INT,"RGBA32UI"],[n.INT,"RGBA32I"]]),unsignedIntTypes:new Set([n.UNSIGNED_BYTE,n.UNSIGNED_SHORT,n.UNSIGNED_INT])};let u=A.get(this.canvas);u||(u={textureUnitPool:{free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},instances:new Set([this])},A.set(this.canvas,u)),this.textureUnitPool=u.textureUnitPool,u.instances.add(this),this.textureOptions=o,i&&(this.historyDepth=i),this.debug=s??(typeof process<"u"&&!1),this.cursorTarget=a??(this.canvas instanceof HTMLCanvasElement?this.canvas:void 0),this.animationFrameId=null;let g=[];r&&r.forEach(f=>f(this,{gl:n,canvas:this.canvas,injectGLSL:c=>{g.push(c)},emitHook:this.emitHook.bind(this),updateTexturesInternal:this.updateTexturesInternal.bind(this)}));let l=this.gl.createProgram();if(!l)throw new Error("Failed to create WebGL program");this.program=l;let T=this.createShader(this.gl.VERTEX_SHADER,W),R=this.createShader(n.FRAGMENT_SHADER,Y(t,g));if(n.attachShader(l,T),n.attachShader(l,R),n.bindAttribLocation(l,0,"a_position"),n.linkProgram(l),n.deleteShader(T),n.deleteShader(R),!n.getProgramParameter(l,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(l)),n.deleteProgram(l),new Error("Failed to link WebGL program");if(this.vao=n.createVertexArray(),n.bindVertexArray(this.vao),this.buffer=n.createBuffer(),n.bindBuffer(n.ARRAY_BUFFER,this.buffer),n.bufferData(n.ARRAY_BUFFER,new Float32Array([-1,-1,3,-1,-1,3]),n.STATIC_DRAW),n.enableVertexAttribArray(0),n.vertexAttribPointer(0,2,n.FLOAT,!1,0,0),n.viewport(0,0,n.drawingBufferWidth,n.drawingBufferHeight),n.useProgram(l),this.canvas instanceof HTMLCanvasElement)this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]});else{let f=c=>{let m=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,c),d=this.canvas;Object.defineProperty(d,c,{get:()=>m.get.call(d),set:x=>{m.set.call(d,x);let b=A.get(d);if(b)for(let y of b.instances)y.updateResolution()},configurable:m.configurable,enumerable:m.enumerable})};f("width"),f("height")}this.updateResolution(),this.initializeUniform("u_cursor","float",this.cursorPosition),this.initializeUniform("u_click","float",[...this.clickPosition,this.isMouseDown?1:0]),this.initializeUniform("u_time","float",0),this.initializeUniform("u_frame","int",0),this._initializeTexture(p,this.canvas,{...this.textureOptions}),this.intermediateFbo=n.createFramebuffer(),this.bindIntermediate(),n.bindFramebuffer(n.FRAMEBUFFER,null),this.historyDepth>0&&this._initializeTexture(I,this.canvas,{history:this.historyDepth,...this.textureOptions}),this.cursorTarget&&this.addEventListeners(),this.emitHook("_init")}resolveGLConstant(t){let e=this.gl[t];if(e===void 0)throw new Error(`Unknown GL constant: ${t}`);return e}emitHook(t,...e){this.hooks.get(t)?.forEach(r=>r.call(this,...e))}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}off(t,e){let r=this.hooks.get(t);if(r){let i=r.indexOf(e);i>=0&&r.splice(i,1)}}createShader(t,e){let r=this.gl.createShader(t);if(this.gl.shaderSource(r,e),this.gl.compileShader(r),!this.gl.getShaderParameter(r,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(r)),this.gl.deleteShader(r),new Error("Shader compilation failed");return r}getCursorTargetRect(){let t=this.cursorTarget;return t===window?{left:0,top:0,width:window.innerWidth,height:window.innerHeight}:t.getBoundingClientRect()}addEventListeners(){if(!this.cursorTarget)return;let t=(r,i)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.getCursorTargetRect(),a=(r-s.left)/s.width,o=1-(i-s.top)/s.height;this.cursorPosition[0]=Math.max(0,Math.min(1,a)),this.cursorPosition[1]=Math.max(0,Math.min(1,o)),this.updateUniforms({u_cursor:this.cursorPosition})},e=(r,i,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=r,r){let a=this.getCursorTargetRect(),o=i,n=s;this.clickPosition[0]=Math.max(0,Math.min(1,(o-a.left)/a.width)),this.clickPosition[1]=Math.max(0,Math.min(1,1-(n-a.top)/a.height))}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",r=>{let i=r;this.isTouchDevice||t(i.clientX,i.clientY)}),this.eventListeners.set("mousedown",r=>{let i=r;this.isTouchDevice||i.button===0&&(this.isMouseDown=!0,e(!0,i.clientX,i.clientY))}),this.eventListeners.set("mouseup",r=>{let i=r;this.isTouchDevice||i.button===0&&e(!1)}),this.eventListeners.set("touchmove",r=>{let i=r;i.touches.length>0&&t(i.touches[0].clientX,i.touches[0].clientY)}),this.eventListeners.set("touchstart",r=>{let i=r;this.isTouchDevice=!0,i.touches.length>0&&(t(i.touches[0].clientX,i.touches[0].clientY),e(!0,i.touches[0].clientX,i.touches[0].clientY))}),this.eventListeners.set("touchend",r=>{r.touches.length===0&&e(!1)}),this.eventListeners.forEach((r,i)=>{this.cursorTarget.addEventListener(i,r)})}updateResolution(){let t=[this.gl.drawingBufferWidth,this.gl.drawingBufferHeight];this.gl.viewport(0,0,...t),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:t}):this.initializeUniform("u_resolution","float",t),this.resizeTexture(p,...t),this.historyDepth>0&&this.resizeTexture(I,...t),this.emitHook("updateResolution",...t)}resizeTexture(t,e,r){let i=this.textures.get(t);if(!i||i.width===e&&i.height===r)return;this.gl.deleteTexture(i.texture),i.width=e,i.height=r;let{texture:s}=this.createTexture(t,i);i.texture=s,i.history&&(i.history.writeIndex=0,this.clearHistoryTextureLayers(i))}reserveTextureUnit(t){let e=this.textures.get(t);if(e)return e.unitIndex;if(this.textureUnitPool.free.length>0)return this.textureUnitPool.free.pop();if(this.textureUnitPool.next>=this.textureUnitPool.max)throw new Error("Exceeded the available texture units for this device.");return this.textureUnitPool.next++}resolveTextureOptions(t){let{gl:e}=this,r=t?.internalFormat,i=t?.type??X(r)??"UNSIGNED_BYTE",s=this.resolveGLConstant(i),a=r??this.glHelpers.typeToInternalFormatString.get(s)??"RGBA8",o=/^(R|RG|RGB|RGBA)(8|16|32)(UI|I)$/.test(a),n=t?.format??(o?"RGBA_INTEGER":"RGBA"),u={type:s,format:this.resolveGLConstant(n),internalFormat:this.resolveGLConstant(a),minFilter:this.resolveGLConstant(t?.minFilter??"LINEAR"),magFilter:this.resolveGLConstant(t?.magFilter??"LINEAR"),wrapS:this.resolveGLConstant(t?.wrapS??"CLAMP_TO_EDGE"),wrapT:this.resolveGLConstant(t?.wrapT??"CLAMP_TO_EDGE"),preserveY:t?.preserveY,isIntegerColorFormat:o};if((u.internalFormat===e.RGBA16F||u.internalFormat===e.RGBA32F)&&!e.getExtension("EXT_color_buffer_float"))throw new Error("Missing EXT_color_buffer_float.");return u}getPixelArray(t,e){let r=this.glHelpers.typeToArray.get(t)??Uint8Array;return new r(e)}isNotRgba(t){return t!==this.gl.RGBA&&t!==this.gl.RGBA_INTEGER}clearHistoryTextureLayers(t){if(!t.history)return;let e=this.gl,{type:r,format:i}=t.options,s=this.getPixelArray(r,t.width*t.height*4);e.activeTexture(e.TEXTURE0+t.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,t.texture);let a=this.isNotRgba(i),o;a&&(o=e.getParameter(e.UNPACK_ALIGNMENT),e.pixelStorei(e.UNPACK_ALIGNMENT,1));for(let n=0;n<t.history.depth;++n)e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,n,t.width,t.height,1,i,r,s);a&&e.pixelStorei(e.UNPACK_ALIGNMENT,o)}initializeUniform(t,e,r,i){let s=i?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(!G[e])throw new Error(`Invalid uniform type: ${e}. Expected one of: ${Object.keys(G).join(", ")}.`);if(s&&!(Array.isArray(r)&&r.length===s))throw new Error(`${t} array length mismatch: must initialize with ${s} elements.`);let a=this.gl.getUniformLocation(this.program,t);if(!a&&s&&(a=this.gl.getUniformLocation(this.program,`${t}[0]`)),!a){this.log(`${t} not in shader. Skipping initialization.`);return}let o=s?r[0]:r,n=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:n,location:a,arrayLength:s});try{this.updateUniforms({[t]:r})}catch(u){throw this.uniforms.delete(t),u}this.emitHook("initializeUniform",...arguments)}log(...t){this.debug&&console.debug(...t)}updateUniforms(t,e){this.gl.useProgram(this.program),Object.entries(t).forEach(([r,i])=>{let s=this.uniforms.get(r);if(!s){this.log(`${r} not in shader. Skipping update.`);return}let a=`uniform${s.length}${G[s.type]}`;if(s.arrayLength){if(!Array.isArray(i))throw new Error(`${r} is an array, but the value passed to updateUniforms is not an array.`);let o=i.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${r} received ${o} values, but maximum length is ${s.arrayLength}.`);if(i.some(l=>(Array.isArray(l)?l.length:1)!==s.length))throw new Error(`Tried to update ${r} with some elements that are not length ${s.length}.`);let n=i.flat(),u=s.type==="float"?new Float32Array(n):s.type==="uint"?new Uint32Array(n):new Int32Array(n),g=s.location;if(e?.startIndex){let l=this.gl.getUniformLocation(this.program,`${r}[${e.startIndex}]`);if(!l)throw new Error(`${r}[${e.startIndex}] not in shader. Did you pass an invalid startIndex?`);g=l}this.gl[a+"v"](g,u)}else{if(Array.isArray(i)||(i=[i]),i.length!==s.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${s.length}.`);this.gl[a](s.location,...i)}}),this.emitHook("updateUniforms",...arguments)}createTexture(t,e){let{width:r,height:i}=e,s=e.history?.depth??0,a=this.gl.createTexture();if(!a)throw new Error("Failed to create texture");let o=e.unitIndex;if(typeof o!="number")try{o=this.reserveTextureUnit(t)}catch(l){throw this.gl.deleteTexture(a),l}let n=s>0,u=n?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:g}=e;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(u,a),this.gl.texParameteri(u,this.gl.TEXTURE_WRAP_S,g.wrapS),this.gl.texParameteri(u,this.gl.TEXTURE_WRAP_T,g.wrapT),this.gl.texParameteri(u,this.gl.TEXTURE_MIN_FILTER,g.minFilter),this.gl.texParameteri(u,this.gl.TEXTURE_MAG_FILTER,g.magFilter),n?this.gl.texStorage3D(u,1,g.internalFormat,r,i,s):t===p&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,g.internalFormat,r,i,0,g.format,g.type,null),{texture:a,unitIndex:o}}_initializeTexture(t,e,r){if(this.textures.has(t))throw new Error(`Texture '${E(t)}' is already initialized.`);let{history:i=0,...s}=r??{},{width:a,height:o}=P(e);if(!a||!o)throw new Error("Texture source must have valid dimensions");let n={width:a,height:o,options:e instanceof h&&Object.keys(s).length===0&&e.textures.has(p)?e.textures.get(p).options:this.resolveTextureOptions(s)};i>0&&(n.history={depth:i,writeIndex:0});let{texture:u,unitIndex:g}=this.createTexture(t,n),l={texture:u,unitIndex:g,...n};i>0&&(this.initializeUniform(`${E(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(l)),this.textures.set(t,l),t!==p&&t!==I&&this.updateTexture(t,e),this.gl.useProgram(this.program);let T=this.gl.getUniformLocation(this.program,E(t));T&&this.gl.uniform1i(T,g)}initializeTexture(t,e,r){let i=r?.history!=null&&r.history>0?{...r,history:r.history+1}:r;this._initializeTexture(t,e,i),this.emitHook("initializeTexture",...arguments)}updateTextures(t,e){this.updateTexturesInternal(t,e),this.emitHook("updateTextures",...arguments)}updateTexturesInternal(t,e){Object.entries(t).forEach(([r,i])=>{this.updateTexture(r,i,e)})}updateTexture(t,e,r){let i=this.textures.get(t);if(!i)throw new Error(`Texture '${E(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let s=e;if(e instanceof h){let f=e.textures.get(p),c=f.width,m=f.height;if(e.gl===this.gl){if(!i.history){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,f.texture);return}let{depth:L}=i.history,U=r?.historyWriteIndex===void 0?[i.history.writeIndex]:Array.isArray(r?.historyWriteIndex)?r.historyWriteIndex.map(S=>F(S,L)):[F(r.historyWriteIndex,L)];this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,e.intermediateFbo),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture);for(let S of U)this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,S,0,0,c,m);this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,null),this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture);let O=`${E(t)}FrameOffset`;this.updateUniforms({[O]:U[U.length-1]}),r?.historyWriteIndex===void 0&&(i.history.writeIndex=(i.history.writeIndex+1)%L);return}let{width:d,height:x,options:{format:b,type:y}}=f,v=this.getPixelArray(y,d*x*4);e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,e.intermediateFbo),e.gl.readPixels(0,0,d,x,b,y,v),e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,null),s={data:v,width:d,height:x}}let{width:a,height:o}=P(s);if(!a||!o)return;let n="isPartial"in s&&s.isPartial;n||this.resizeTexture(t,a,o);let u="data"in s&&s.data,g=!u&&!i.options?.preserveY,l=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL),T=u&&this.isNotRgba(i.options.format),R;if(T&&(R=this.gl.getParameter(this.gl.UNPACK_ALIGNMENT),this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,1)),i.history){if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture),!r?.skipHistoryWrite){let{depth:f}=i.history,c=r?.historyWriteIndex===void 0?[i.history.writeIndex]:Array.isArray(r.historyWriteIndex)?r.historyWriteIndex.map(v=>F(v,f)):[F(r.historyWriteIndex,f)];this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g);let m=s,d=m.data??s,x=n?m.x??0:0,b=n?m.y??0:0;for(let v of c)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,x,b,v,a,o,1,i.options.format,i.options.type,d);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l);let y=`${E(t)}FrameOffset`;this.updateUniforms({[y]:c[c.length-1]}),r?.historyWriteIndex===void 0&&(i.history.writeIndex=(i.history.writeIndex+1)%f)}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,i.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g),n){let f=s;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,f.x??0,f.y??0,a,o,i.options.format,i.options.type,f.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,i.options.internalFormat,a,o,0,i.options.format,i.options.type,s.data??s);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l)}T&&this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT,R)}bindIntermediate(){let t=this.gl,e=this.textures.get(p);t.bindFramebuffer(t.FRAMEBUFFER,this.intermediateFbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,e.texture,0)}clear(){this.bindIntermediate();let t=this.gl,e=this.textures.get(p);if(e.options.isIntegerColorFormat){let r=e.options.type;this.glHelpers.unsignedIntTypes.has(r)?t.clearBufferuiv(t.COLOR,0,new Uint32Array(4)):t.clearBufferiv(t.COLOR,0,new Int32Array(4))}else t.clear(t.COLOR_BUFFER_BIT)}draw(t){this.emitHook("beforeDraw",...arguments);let e=this.gl,r=e.drawingBufferWidth,i=e.drawingBufferHeight;t?.skipClear?this.bindIntermediate():this.clear(),e.useProgram(this.program),e.bindVertexArray(this.vao),e.viewport(0,0,r,i),e.drawArrays(e.TRIANGLES,0,3),this.isHeadless||this.textures.get(p).options.isIntegerColorFormat||(e.bindFramebuffer(e.READ_FRAMEBUFFER,this.intermediateFbo),e.bindFramebuffer(e.DRAW_FRAMEBUFFER,null),e.blitFramebuffer(0,0,r,i,0,0,r,i,e.COLOR_BUFFER_BIT,e.NEAREST),e.bindFramebuffer(e.FRAMEBUFFER,null)),this.emitHook("afterDraw",...arguments)}step(t){Number.isFinite(this.startTime)||(this.startTime=performance.now()),this._step((performance.now()-this.startTime)/1e3,t)}_step(t,e){this.emitHook("beforeStep",t,this.frame,e);let r={};this.uniforms.has("u_time")&&(r.u_time=t),this.uniforms.has("u_frame")&&(r.u_frame=this.frame),this.updateUniforms(r),this.draw(e);let i=this.textures.get(I);if(i&&!e?.skipHistoryWrite){let{writeIndex:s,depth:a}=i.history,o=this.gl;o.bindFramebuffer(o.READ_FRAMEBUFFER,this.intermediateFbo),o.bindTexture(o.TEXTURE_2D_ARRAY,i.texture),o.copyTexSubImage3D(o.TEXTURE_2D_ARRAY,0,0,0,s,0,0,o.drawingBufferWidth,o.drawingBufferHeight),o.bindFramebuffer(o.READ_FRAMEBUFFER,null);let n=(s+1)%a;this.updateUniforms({[`${E(I)}FrameOffset`]:n}),i.history.writeIndex=n}++this.frame,this.emitHook("afterStep",t,this.frame,e)}play(t){this._pause(),Number.isFinite(this.startTime)||(this.startTime=performance.now()),this.isPlaying=!0;let e=r=>{r=(r-this.startTime)/1e3;let i=t?.(r,this.frame)??void 0;this._step(r,i),this.isPlaying&&(this.animationFrameId=requestAnimationFrame(e))};this.animationFrameId=requestAnimationFrame(e),this.emitHook("play")}_pause(){let t=this.isPlaying;return this.isPlaying=!1,this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),t}pause(){this._pause()&&this.emitHook("pause")}resetFrame(){this.frame=0,this.startTime=performance.now()}reset(){this.resetFrame(),this.textures.forEach(t=>{t.history&&(t.history.writeIndex=0,this.clearHistoryTextureLayers(t))}),this.clear(),this.emitHook("reset")}destroy(){this.emitHook("destroy"),this._pause(),this.cursorTarget&&(this.eventListeners.forEach((e,r)=>{this.cursorTarget.removeEventListener(r,e)}),this.eventListeners.clear()),this.resolutionObserver&&(this.resolutionObserver.disconnect(),this.resolutionObserver=null),this.program&&(this.gl.deleteProgram(this.program),this.program=null),this.intermediateFbo&&(this.gl.deleteFramebuffer(this.intermediateFbo),this.intermediateFbo=null),this.textures.forEach(e=>{this.textureUnitPool.free.push(e.unitIndex),this.gl.deleteTexture(e.texture)}),this.textures.clear();let t=A.get(this.canvas);t&&(t.instances.delete(this),t.instances.size===0&&A.delete(this.canvas)),this.vao&&(this.gl.deleteVertexArray(this.vao),this.vao=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.uniforms.clear(),this.hooks.clear()}},$=_;
10
10
  //# sourceMappingURL=index.js.map