shaderpad 1.0.0-beta.56 → 1.0.0-beta.57
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 +2 -1
- package/dist/{chunk-WRFTQKNK.mjs → chunk-ZDI2D5RQ.mjs} +3 -3
- package/dist/chunk-ZDI2D5RQ.mjs.map +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/plugins/autosize.js +1 -1
- package/dist/plugins/autosize.js.map +1 -1
- package/dist/plugins/autosize.mjs +1 -1
- package/dist/plugins/autosize.mjs.map +1 -1
- package/dist/plugins/pose.js +5 -5
- package/dist/plugins/pose.js.map +1 -1
- package/dist/plugins/pose.mjs +1 -1
- package/dist/plugins/segmenter.js +3 -3
- package/dist/plugins/segmenter.js.map +1 -1
- package/dist/plugins/segmenter.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-WRFTQKNK.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -264,7 +264,8 @@ interface StepOptions {
|
|
|
264
264
|
|
|
265
265
|
```typescript
|
|
266
266
|
shader.pause(); // Pause the render loop.
|
|
267
|
-
shader.reset(); // Reset frame counter and clear history buffers.
|
|
267
|
+
shader.reset(); // Reset frame counter, clock, and clear history buffers.
|
|
268
|
+
shader.resetFrame(); // Reset frame counter and clock only.
|
|
268
269
|
shader.destroy(); // Clean up resources.
|
|
269
270
|
```
|
|
270
271
|
|
|
@@ -4,7 +4,7 @@ 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
|
-
}`,G=[["8UI","UNSIGNED_BYTE"],["8I","BYTE"],["16UI","UNSIGNED_SHORT"],["16I","SHORT"],["16F","HALF_FLOAT"],["32UI","UNSIGNED_INT"],["32I","INT"],["32F","FLOAT"],["8","UNSIGNED_BYTE"]];function P(h){return h&&G.find(([t])=>h.endsWith(t))?.[1]}var R=Symbol("u_history"),
|
|
7
|
+
}`,G=[["8UI","UNSIGNED_BYTE"],["8I","BYTE"],["16UI","UNSIGNED_SHORT"],["16I","SHORT"],["16F","HALF_FLOAT"],["32UI","UNSIGNED_INT"],["32I","INT"],["32F","FLOAT"],["8","UNSIGNED_BYTE"]];function P(h){return h&&G.find(([t])=>h.endsWith(t))?.[1]}var R=Symbol("u_history"),p=Symbol("__SHADERPAD_BUFFER"),F=new WeakMap;function D(h,t){if(!t?.length)return h;let e=h.split(`
|
|
8
8
|
`),i=e.findLastIndex(r=>{let s=r.trimStart();return s.startsWith("precision ")||s.startsWith("#version ")})+1;return e.splice(i,0,...t),e.join(`
|
|
9
|
-
`)}function S(h){return h instanceof WebGLTexture?{width:0,height:0}:h instanceof A?{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 x(h){return typeof h=="symbol"?h.description??"":h}var A=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:i,history:r,debug:s,cursorTarget:a,...o}={}){if(e&&"getContext"in e)this.canvas=e;else{let{width:d=1,height:c=1}=e||{};this.canvas=new OffscreenCanvas(d,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 l=F.get(this.canvas);l||(l={textureUnitPool:{free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},instances:new Set([this])},F.set(this.canvas,l)),this.textureUnitPool=l.textureUnitPool,l.instances.add(this),this.textureOptions=o,r&&(this.historyDepth=r),this.debug=s??(typeof process<"u"&&!1),this.cursorTarget=a??(this.canvas instanceof HTMLCanvasElement?this.canvas:void 0),this.animationFrameId=null;let u=[];i&&i.forEach(d=>d(this,{gl:n,canvas:this.canvas,injectGLSL:c=>{u.push(c)},emitHook:this.emitHook.bind(this)}));let g=this.gl.createProgram();if(!g)throw new Error("Failed to create WebGL program");this.program=g;let f=this.createShader(this.gl.VERTEX_SHADER,U),p=this.createShader(n.FRAGMENT_SHADER,D(t,u));if(n.attachShader(g,f),n.attachShader(g,p),n.bindAttribLocation(g,0,"a_position"),n.linkProgram(g),n.deleteShader(f),n.deleteShader(p),!n.getProgramParameter(g,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(g)),n.deleteProgram(g),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(g),this.canvas instanceof HTMLCanvasElement)this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]});else{let d=c=>{let m=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,c),E=this.canvas;Object.defineProperty(E,c,{get:()=>m.get.call(E),set:I=>{m.set.call(E,I);let b=F.get(E);if(b)for(let y of b.instances)y.updateResolution()},configurable:m.configurable,enumerable:m.enumerable})};d("width"),d("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(T,this.canvas,{...this.textureOptions}),this.intermediateFbo=n.createFramebuffer(),this.bindIntermediate(),n.bindFramebuffer(n.FRAMEBUFFER,null),this.historyDepth>0&&this._initializeTexture(R,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(i=>i.call(this,...e))}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}off(t,e){let i=this.hooks.get(t);i&&i.splice(i.indexOf(e),1)}createShader(t,e){let i=this.gl.createShader(t);if(this.gl.shaderSource(i,e),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(i)),this.gl.deleteShader(i),new Error("Shader compilation failed");return i}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=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.getCursorTargetRect(),a=(i-s.left)/s.width,o=1-(r-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=(i,r,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let a=this.getCursorTargetRect(),o=r,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",i=>{let r=i;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",i=>{let r=i;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,e(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&e(!1)}),this.eventListeners.set("touchmove",i=>{let r=i;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let r=i;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),e(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,r)=>{this.cursorTarget.addEventListener(r,i)})}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(T,...t),this.historyDepth>0&&this.resizeTexture(R,...t),this.emitHook("updateResolution",...t)}resizeTexture(t,e,i){let r=this.textures.get(t);if(!r||r.width===e&&r.height===i)return;this.gl.deleteTexture(r.texture),r.width=e,r.height=i;let{texture:s}=this.createTexture(t,r);r.texture=s,r.history&&(r.history.writeIndex=0,this.clearHistoryTextureLayers(r))}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,i=t?.internalFormat,r=t?.type??P(i)??"UNSIGNED_BYTE",s=this.resolveGLConstant(r),a=i??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 i=this.glHelpers.typeToArray.get(t)??Uint8Array;return new i(e)}clearHistoryTextureLayers(t){if(!t.history)return;let e=this.gl,{type:i,format:r}=t.options,s=this.getPixelArray(i,t.width*t.height*4);e.activeTexture(e.TEXTURE0+t.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,t.texture);for(let a=0;a<t.history.depth;++a)e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,a,t.width,t.height,1,r,i,s)}initializeUniform(t,e,i,r){let s=r?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);if(s&&!(Array.isArray(i)&&i.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?i[0]:i,n=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:n,location:a,arrayLength:s});try{this.updateUniforms({[t]:i})}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(([i,r])=>{let s=this.uniforms.get(i);if(!s){this.log(`${i} not in shader. Skipping update.`);return}let a=`uniform${s.length}${s.type.charAt(0)}`;if(s.arrayLength){if(!Array.isArray(r))throw new Error(`${i} is an array, but the value passed to updateUniforms is not an array.`);let o=r.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${i} received ${o} values, but maximum length is ${s.arrayLength}.`);if(r.some(u=>(Array.isArray(u)?u.length:1)!==s.length))throw new Error(`Tried to update ${i} with some elements that are not length ${s.length}.`);let n=new(s.type==="float"?Float32Array:Int32Array)(r.flat()),l=s.location;if(e?.startIndex){let u=this.gl.getUniformLocation(this.program,`${i}[${e.startIndex}]`);if(!u)throw new Error(`${i}[${e.startIndex}] not in shader. Did you pass an invalid startIndex?`);l=u}this.gl[a+"v"](l,n)}else{if(Array.isArray(r)||(r=[r]),r.length!==s.length)throw new Error(`Invalid uniform value length: ${r.length}. Expected ${s.length}.`);this.gl[a](s.location,...r)}}),this.emitHook("updateUniforms",...arguments)}createTexture(t,e){let{width:i,height:r}=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(g){throw this.gl.deleteTexture(a),g}let n=s>0,l=n?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:u}=e;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(l,a),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_S,u.wrapS),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_T,u.wrapT),this.gl.texParameteri(l,this.gl.TEXTURE_MIN_FILTER,u.minFilter),this.gl.texParameteri(l,this.gl.TEXTURE_MAG_FILTER,u.magFilter),n?this.gl.texStorage3D(l,1,u.internalFormat,i,r,s):t===T&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,u.internalFormat,i,r,0,u.format,u.type,null),{texture:a,unitIndex:o}}_initializeTexture(t,e,i){if(this.textures.has(t))throw new Error(`Texture '${x(t)}' is already initialized.`);let{history:r=0,...s}=i??{},{width:a,height:o}=S(e);if(!a||!o)throw new Error("Texture source must have valid dimensions");let n={width:a,height:o,options:this.resolveTextureOptions(s)};r>0&&(n.history={depth:r,writeIndex:0});let{texture:l,unitIndex:u}=this.createTexture(t,n),g={texture:l,unitIndex:u,...n};r>0&&(this.initializeUniform(`${x(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(g)),this.textures.set(t,g),t!==T&&t!==R&&this.updateTexture(t,e),this.gl.useProgram(this.program);let f=this.gl.getUniformLocation(this.program,x(t));f&&this.gl.uniform1i(f,u)}initializeTexture(t,e,i){let r=i?.history!=null&&i.history>0?{...i,history:i.history+1}:i;this._initializeTexture(t,e,r),this.emitHook("initializeTexture",...arguments)}updateTextures(t,e){Object.entries(t).forEach(([i,r])=>{this.updateTexture(i,r,e)}),this.emitHook("updateTextures",...arguments)}updateTexture(t,e,i){let r=this.textures.get(t);if(!r)throw new Error(`Texture '${x(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let s=e;if(e instanceof h){let f=e.textures.get(T),p=f.width,d=f.height;if(e.gl===this.gl){if(!r.history){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,f.texture);return}let{depth:y}=r.history,_=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i?.historyWriteIndex)?i.historyWriteIndex.map(L=>v(L,y)):[v(i.historyWriteIndex,y)];this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,e.intermediateFbo),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);for(let L of _)this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,L,0,0,p,d);this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,null),this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);let w=`${x(t)}FrameOffset`;this.updateUniforms({[w]:_[_.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%y);return}let{width:c,height:m,options:{format:E,type:I}}=f,b=this.getPixelArray(I,c*m*4);e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,e.intermediateFbo),e.gl.readPixels(0,0,c,m,E,I,b),e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,null),s={data:b,width:c,height:m}}let{width:a,height:o}=S(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)&&!r.options?.preserveY,g=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(r.history){if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture),!i?.skipHistoryWrite){let{depth:f}=r.history,p=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i.historyWriteIndex)?i.historyWriteIndex.map(m=>v(m,f)):[v(i.historyWriteIndex,f)];this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u);let d=s.data??s;for(let m of p)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,m,a,o,1,r.options.format,r.options.type,d);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g);let c=`${x(t)}FrameOffset`;this.updateUniforms({[c]:p[p.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%f)}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,r.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u),n){let f=s;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,f.x??0,f.y??0,a,o,r.options.format,r.options.type,f.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,r.options.internalFormat,a,o,0,r.options.format,r.options.type,s.data??s);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g)}}bindIntermediate(){let t=this.gl,e=this.textures.get(T);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(T);if(e.options.isIntegerColorFormat){let i=e.options.type;this.glHelpers.unsignedIntTypes.has(i)?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,i=e.drawingBufferWidth,r=e.drawingBufferHeight;t?.skipClear?this.bindIntermediate():this.clear(),e.useProgram(this.program),e.bindVertexArray(this.vao),e.viewport(0,0,i,r),e.drawArrays(e.TRIANGLES,0,3),this.isHeadless||this.textures.get(T).options.isIntegerColorFormat||(e.bindFramebuffer(e.READ_FRAMEBUFFER,this.intermediateFbo),e.bindFramebuffer(e.DRAW_FRAMEBUFFER,null),e.blitFramebuffer(0,0,i,r,0,0,i,r,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 i={};this.uniforms.has("u_time")&&(i.u_time=t),this.uniforms.has("u_frame")&&(i.u_frame=this.frame),this.updateUniforms(i),this.draw(e);let r=this.textures.get(R);if(r&&!e?.skipHistoryWrite){let{writeIndex:s,depth:a}=r.history,o=this.gl;o.bindFramebuffer(o.READ_FRAMEBUFFER,this.intermediateFbo),o.bindTexture(o.TEXTURE_2D_ARRAY,r.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({[`${x(R)}FrameOffset`]:n}),r.history.writeIndex=n}++this.frame,this.emitHook("afterStep",t,this.frame,e)}play(t){this.pause(),this.isPlaying=!0;let e=i=>{i=(i-this.startTime)/1e3;let r=t?.(i,this.frame)??void 0;this._step(i,r),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")}reset(){this.frame=0,this.startTime=performance.now(),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,i)=>{this.cursorTarget.removeEventListener(i,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=F.get(this.canvas);t&&(t.instances.delete(this),t.instances.size===0&&F.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()}},C=A;export{C as a};
|
|
10
|
-
//# sourceMappingURL=chunk-
|
|
9
|
+
`)}function S(h){return h instanceof WebGLTexture?{width:0,height:0}:h instanceof A?{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 x(h){return typeof h=="symbol"?h.description??"":h}var A=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:i,history:r,debug:s,cursorTarget:a,...o}={}){if(e&&"getContext"in e)this.canvas=e;else{let{width:d=1,height:m=1}=e||{};this.canvas=new OffscreenCanvas(d,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=F.get(this.canvas);l||(l={textureUnitPool:{free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},instances:new Set([this])},F.set(this.canvas,l)),this.textureUnitPool=l.textureUnitPool,l.instances.add(this),this.textureOptions=o,r&&(this.historyDepth=r),this.debug=s??(typeof process<"u"&&!1),this.cursorTarget=a??(this.canvas instanceof HTMLCanvasElement?this.canvas:void 0),this.animationFrameId=null;let u=[];i&&i.forEach(d=>d(this,{gl:n,canvas:this.canvas,injectGLSL:m=>{u.push(m)},emitHook:this.emitHook.bind(this)}));let g=this.gl.createProgram();if(!g)throw new Error("Failed to create WebGL program");this.program=g;let f=this.createShader(this.gl.VERTEX_SHADER,U),T=this.createShader(n.FRAGMENT_SHADER,D(t,u));if(n.attachShader(g,f),n.attachShader(g,T),n.bindAttribLocation(g,0,"a_position"),n.linkProgram(g),n.deleteShader(f),n.deleteShader(T),!n.getProgramParameter(g,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(g)),n.deleteProgram(g),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(g),this.canvas instanceof HTMLCanvasElement)this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]});else{let d=m=>{let c=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,m),E=this.canvas;Object.defineProperty(E,m,{get:()=>c.get.call(E),set:I=>{c.set.call(E,I);let b=F.get(E);if(b)for(let y of b.instances)y.updateResolution()},configurable:c.configurable,enumerable:c.enumerable})};d("width"),d("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(R,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(i=>i.call(this,...e))}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}off(t,e){let i=this.hooks.get(t);i&&i.splice(i.indexOf(e),1)}createShader(t,e){let i=this.gl.createShader(t);if(this.gl.shaderSource(i,e),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(i)),this.gl.deleteShader(i),new Error("Shader compilation failed");return i}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=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.getCursorTargetRect(),a=(i-s.left)/s.width,o=1-(r-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=(i,r,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let a=this.getCursorTargetRect(),o=r,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",i=>{let r=i;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",i=>{let r=i;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,e(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&e(!1)}),this.eventListeners.set("touchmove",i=>{let r=i;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let r=i;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),e(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,r)=>{this.cursorTarget.addEventListener(r,i)})}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(R,...t),this.emitHook("updateResolution",...t)}resizeTexture(t,e,i){let r=this.textures.get(t);if(!r||r.width===e&&r.height===i)return;this.gl.deleteTexture(r.texture),r.width=e,r.height=i;let{texture:s}=this.createTexture(t,r);r.texture=s,r.history&&(r.history.writeIndex=0,this.clearHistoryTextureLayers(r))}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,i=t?.internalFormat,r=t?.type??P(i)??"UNSIGNED_BYTE",s=this.resolveGLConstant(r),a=i??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 i=this.glHelpers.typeToArray.get(t)??Uint8Array;return new i(e)}clearHistoryTextureLayers(t){if(!t.history)return;let e=this.gl,{type:i,format:r}=t.options,s=this.getPixelArray(i,t.width*t.height*4);e.activeTexture(e.TEXTURE0+t.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,t.texture);for(let a=0;a<t.history.depth;++a)e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,a,t.width,t.height,1,r,i,s)}initializeUniform(t,e,i,r){let s=r?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);if(s&&!(Array.isArray(i)&&i.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?i[0]:i,n=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:n,location:a,arrayLength:s});try{this.updateUniforms({[t]:i})}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(([i,r])=>{let s=this.uniforms.get(i);if(!s){this.log(`${i} not in shader. Skipping update.`);return}let a=`uniform${s.length}${s.type.charAt(0)}`;if(s.arrayLength){if(!Array.isArray(r))throw new Error(`${i} is an array, but the value passed to updateUniforms is not an array.`);let o=r.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${i} received ${o} values, but maximum length is ${s.arrayLength}.`);if(r.some(u=>(Array.isArray(u)?u.length:1)!==s.length))throw new Error(`Tried to update ${i} with some elements that are not length ${s.length}.`);let n=new(s.type==="float"?Float32Array:Int32Array)(r.flat()),l=s.location;if(e?.startIndex){let u=this.gl.getUniformLocation(this.program,`${i}[${e.startIndex}]`);if(!u)throw new Error(`${i}[${e.startIndex}] not in shader. Did you pass an invalid startIndex?`);l=u}this.gl[a+"v"](l,n)}else{if(Array.isArray(r)||(r=[r]),r.length!==s.length)throw new Error(`Invalid uniform value length: ${r.length}. Expected ${s.length}.`);this.gl[a](s.location,...r)}}),this.emitHook("updateUniforms",...arguments)}createTexture(t,e){let{width:i,height:r}=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(g){throw this.gl.deleteTexture(a),g}let n=s>0,l=n?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:u}=e;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(l,a),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_S,u.wrapS),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_T,u.wrapT),this.gl.texParameteri(l,this.gl.TEXTURE_MIN_FILTER,u.minFilter),this.gl.texParameteri(l,this.gl.TEXTURE_MAG_FILTER,u.magFilter),n?this.gl.texStorage3D(l,1,u.internalFormat,i,r,s):t===p&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,u.internalFormat,i,r,0,u.format,u.type,null),{texture:a,unitIndex:o}}_initializeTexture(t,e,i){if(this.textures.has(t))throw new Error(`Texture '${x(t)}' is already initialized.`);let{history:r=0,...s}=i??{},{width:a,height:o}=S(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)};r>0&&(n.history={depth:r,writeIndex:0});let{texture:l,unitIndex:u}=this.createTexture(t,n),g={texture:l,unitIndex:u,...n};r>0&&(this.initializeUniform(`${x(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(g)),this.textures.set(t,g),t!==p&&t!==R&&this.updateTexture(t,e),this.gl.useProgram(this.program);let f=this.gl.getUniformLocation(this.program,x(t));f&&this.gl.uniform1i(f,u)}initializeTexture(t,e,i){let r=i?.history!=null&&i.history>0?{...i,history:i.history+1}:i;this._initializeTexture(t,e,r),this.emitHook("initializeTexture",...arguments)}updateTextures(t,e){Object.entries(t).forEach(([i,r])=>{this.updateTexture(i,r,e)}),this.emitHook("updateTextures",...arguments)}updateTexture(t,e,i){let r=this.textures.get(t);if(!r)throw new Error(`Texture '${x(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let s=e;if(e instanceof h){let f=e.textures.get(p),T=f.width,d=f.height;if(e.gl===this.gl){if(!r.history){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,f.texture);return}let{depth:y}=r.history,_=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i?.historyWriteIndex)?i.historyWriteIndex.map(L=>v(L,y)):[v(i.historyWriteIndex,y)];this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,e.intermediateFbo),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);for(let L of _)this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,L,0,0,T,d);this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,null),this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);let w=`${x(t)}FrameOffset`;this.updateUniforms({[w]:_[_.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%y);return}let{width:m,height:c,options:{format:E,type:I}}=f,b=this.getPixelArray(I,m*c*4);e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,e.intermediateFbo),e.gl.readPixels(0,0,m,c,E,I,b),e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,null),s={data:b,width:m,height:c}}let{width:a,height:o}=S(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)&&!r.options?.preserveY,g=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(r.history){if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture),!i?.skipHistoryWrite){let{depth:f}=r.history,T=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i.historyWriteIndex)?i.historyWriteIndex.map(c=>v(c,f)):[v(i.historyWriteIndex,f)];this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u);let d=s.data??s;for(let c of T)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,c,a,o,1,r.options.format,r.options.type,d);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g);let m=`${x(t)}FrameOffset`;this.updateUniforms({[m]:T[T.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%f)}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,r.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u),n){let f=s;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,f.x??0,f.y??0,a,o,r.options.format,r.options.type,f.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,r.options.internalFormat,a,o,0,r.options.format,r.options.type,s.data??s);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g)}}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 i=e.options.type;this.glHelpers.unsignedIntTypes.has(i)?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,i=e.drawingBufferWidth,r=e.drawingBufferHeight;t?.skipClear?this.bindIntermediate():this.clear(),e.useProgram(this.program),e.bindVertexArray(this.vao),e.viewport(0,0,i,r),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,i,r,0,0,i,r,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 i={};this.uniforms.has("u_time")&&(i.u_time=t),this.uniforms.has("u_frame")&&(i.u_frame=this.frame),this.updateUniforms(i),this.draw(e);let r=this.textures.get(R);if(r&&!e?.skipHistoryWrite){let{writeIndex:s,depth:a}=r.history,o=this.gl;o.bindFramebuffer(o.READ_FRAMEBUFFER,this.intermediateFbo),o.bindTexture(o.TEXTURE_2D_ARRAY,r.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({[`${x(R)}FrameOffset`]:n}),r.history.writeIndex=n}++this.frame,this.emitHook("afterStep",t,this.frame,e)}play(t){this.pause(),this.isPlaying=!0;let e=i=>{i=(i-this.startTime)/1e3;let r=t?.(i,this.frame)??void 0;this._step(i,r),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,i)=>{this.cursorTarget.removeEventListener(i,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=F.get(this.canvas);t&&(t.instances.delete(this),t.instances.size===0&&F.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()}},C=A;export{C as a};
|
|
10
|
+
//# sourceMappingURL=chunk-ZDI2D5RQ.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';\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\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}\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 interface Options extends Exclude<TextureOptions, 'preserveY'> {\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\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): { width: number; height: number } {\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 { width: source.naturalWidth ?? source.width, height: source.naturalHeight ?? source.height };\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 = 0;\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', { antialias: false }) 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})\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, { attributes: true, attributeFilter: ['width', 'height'] });\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\thooks.splice(hooks.indexOf(fn), 1);\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(): { left: number; top: number; width: number; height: number } {\n\t\tconst target = this.cursorTarget!;\n\t\tif (target === window) {\n\t\t\treturn { left: 0, top: 0, width: window.innerWidth, height: window.innerHeight };\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({ u_click: [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0] });\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 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\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}\n\n\tinitializeUniform(\n\t\tname: string,\n\t\ttype: 'float' | 'int',\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 (type !== 'float' && type !== 'int') {\n\t\t\tthrow new Error(`Invalid uniform type: ${type}. Expected 'float' or 'int'.`);\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\n\t\t\tlet glFunctionName = `uniform${uniform.length}${uniform.type.charAt(0)}`; // e.g. uniform1f, uniform3i…\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 typedArray = new (uniform.type === 'float' ? Float32Array : Int32Array)(newValue.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 = { texture, unitIndex, ...textureInfo };\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(\n\t\tupdates: Record<string, UpdateTextureSource>,\n\t\toptions?: { skipHistoryWrite?: boolean; historyWriteIndex?: number | number[] }\n\t) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tthis.updateTexture(name, source, options);\n\t\t});\n\t\tthis.emitHook('updateTextures', ...arguments);\n\t}\n\n\tprivate updateTexture(\n\t\tname: string | symbol,\n\t\tsource: UpdateTextureSource,\n\t\toptions?: { skipHistoryWrite?: boolean; historyWriteIndex?: number | number[] }\n\t) {\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? options.historyWriteIndex.map(i => safeMod(i, depth))\n\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({ [frameOffsetUniformName]: targetSlots[targetSlots.length - 1] });\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\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? options.historyWriteIndex.map(i => safeMod(i, depth))\n\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 sourceData =\n\t\t\t\t\t(nonShaderPadSource as PartialCustomTexture).data ??\n\t\t\t\t\t(nonShaderPadSource as Exclude<TextureSource, CustomTexture | ShaderPad>);\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\t0,\n\t\t\t\t\t\t0,\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({ [frameOffsetUniformName]: targetSlots[targetSlots.length - 1] });\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}\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\tthis._step(performance.now() - this.startTime, 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({ [`${stringFrom(HISTORY_TEXTURE_KEY)}FrameOffset`]: nextWriteIndex });\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(); // Prevent double play.\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\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}\n\n\tpause() {\n\t\tthis._pause();\n\t\tthis.emitHook('pause');\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":"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","names":["DEFAULT_VERTEX_SHADER_SRC","FORMAT_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","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","textureInfo","format","transparent","layer","arrayLength","location","probeValue","length","error","updates","newValue","uniform","glFunctionName","nValues","item","typedArray","newLocation","historyDepth","unitIndex","hasHistory","textureTarget","completeTextureInfo","uSampler","opts","nonShaderPadSource","sourceIntermediateInfo","srcW","srcH","depth","targetSlots","i","safeMod","slot","frameOffsetUniformName","pixels","isPartial","shouldFlipY","previousFlipY","sourceData","partialSource","intermediateInfo","t","w","h","time","historyInfo","writeIndex","nextWriteIndex","onBeforeStep","loop","index_default"]}
|
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ 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
|
-
}`,B=[["8UI","UNSIGNED_BYTE"],["8I","BYTE"],["16UI","UNSIGNED_SHORT"],["16I","SHORT"],["16F","HALF_FLOAT"],["32UI","UNSIGNED_INT"],["32I","INT"],["32F","FLOAT"],["8","UNSIGNED_BYTE"]];function N(h){return h&&B.find(([t])=>h.endsWith(t))?.[1]}var R=Symbol("u_history"),
|
|
7
|
+
}`,B=[["8UI","UNSIGNED_BYTE"],["8I","BYTE"],["16UI","UNSIGNED_SHORT"],["16I","SHORT"],["16F","HALF_FLOAT"],["32UI","UNSIGNED_INT"],["32I","INT"],["32F","FLOAT"],["8","UNSIGNED_BYTE"]];function N(h){return h&&B.find(([t])=>h.endsWith(t))?.[1]}var R=Symbol("u_history"),p=Symbol("__SHADERPAD_BUFFER"),F=new WeakMap;function W(h,t){if(!t?.length)return h;let e=h.split(`
|
|
8
8
|
`),i=e.findLastIndex(r=>{let s=r.trimStart();return s.startsWith("precision ")||s.startsWith("#version ")})+1;return e.splice(i,0,...t),e.join(`
|
|
9
|
-
`)}function S(h){return h instanceof WebGLTexture?{width:0,height:0}:h instanceof A?{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 x(h){return typeof h=="symbol"?h.description??"":h}var A=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:i,history:r,debug:s,cursorTarget:a,...o}={}){if(e&&"getContext"in e)this.canvas=e;else{let{width:d=1,height:c=1}=e||{};this.canvas=new OffscreenCanvas(d,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 l=F.get(this.canvas);l||(l={textureUnitPool:{free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},instances:new Set([this])},F.set(this.canvas,l)),this.textureUnitPool=l.textureUnitPool,l.instances.add(this),this.textureOptions=o,r&&(this.historyDepth=r),this.debug=s??(typeof process<"u"&&!1),this.cursorTarget=a??(this.canvas instanceof HTMLCanvasElement?this.canvas:void 0),this.animationFrameId=null;let u=[];i&&i.forEach(d=>d(this,{gl:n,canvas:this.canvas,injectGLSL:c=>{u.push(c)},emitHook:this.emitHook.bind(this)}));let g=this.gl.createProgram();if(!g)throw new Error("Failed to create WebGL program");this.program=g;let f=this.createShader(this.gl.VERTEX_SHADER,H),p=this.createShader(n.FRAGMENT_SHADER,W(t,u));if(n.attachShader(g,f),n.attachShader(g,p),n.bindAttribLocation(g,0,"a_position"),n.linkProgram(g),n.deleteShader(f),n.deleteShader(p),!n.getProgramParameter(g,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(g)),n.deleteProgram(g),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(g),this.canvas instanceof HTMLCanvasElement)this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]});else{let d=c=>{let m=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,c),E=this.canvas;Object.defineProperty(E,c,{get:()=>m.get.call(E),set:I=>{m.set.call(E,I);let b=F.get(E);if(b)for(let y of b.instances)y.updateResolution()},configurable:m.configurable,enumerable:m.enumerable})};d("width"),d("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(T,this.canvas,{...this.textureOptions}),this.intermediateFbo=n.createFramebuffer(),this.bindIntermediate(),n.bindFramebuffer(n.FRAMEBUFFER,null),this.historyDepth>0&&this._initializeTexture(R,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(i=>i.call(this,...e))}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}off(t,e){let i=this.hooks.get(t);i&&i.splice(i.indexOf(e),1)}createShader(t,e){let i=this.gl.createShader(t);if(this.gl.shaderSource(i,e),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(i)),this.gl.deleteShader(i),new Error("Shader compilation failed");return i}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=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.getCursorTargetRect(),a=(i-s.left)/s.width,o=1-(r-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=(i,r,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let a=this.getCursorTargetRect(),o=r,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",i=>{let r=i;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",i=>{let r=i;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,e(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&e(!1)}),this.eventListeners.set("touchmove",i=>{let r=i;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let r=i;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),e(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,r)=>{this.cursorTarget.addEventListener(r,i)})}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(T,...t),this.historyDepth>0&&this.resizeTexture(R,...t),this.emitHook("updateResolution",...t)}resizeTexture(t,e,i){let r=this.textures.get(t);if(!r||r.width===e&&r.height===i)return;this.gl.deleteTexture(r.texture),r.width=e,r.height=i;let{texture:s}=this.createTexture(t,r);r.texture=s,r.history&&(r.history.writeIndex=0,this.clearHistoryTextureLayers(r))}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,i=t?.internalFormat,r=t?.type??N(i)??"UNSIGNED_BYTE",s=this.resolveGLConstant(r),a=i??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 i=this.glHelpers.typeToArray.get(t)??Uint8Array;return new i(e)}clearHistoryTextureLayers(t){if(!t.history)return;let e=this.gl,{type:i,format:r}=t.options,s=this.getPixelArray(i,t.width*t.height*4);e.activeTexture(e.TEXTURE0+t.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,t.texture);for(let a=0;a<t.history.depth;++a)e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,a,t.width,t.height,1,r,i,s)}initializeUniform(t,e,i,r){let s=r?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);if(s&&!(Array.isArray(i)&&i.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?i[0]:i,n=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:n,location:a,arrayLength:s});try{this.updateUniforms({[t]:i})}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(([i,r])=>{let s=this.uniforms.get(i);if(!s){this.log(`${i} not in shader. Skipping update.`);return}let a=`uniform${s.length}${s.type.charAt(0)}`;if(s.arrayLength){if(!Array.isArray(r))throw new Error(`${i} is an array, but the value passed to updateUniforms is not an array.`);let o=r.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${i} received ${o} values, but maximum length is ${s.arrayLength}.`);if(r.some(u=>(Array.isArray(u)?u.length:1)!==s.length))throw new Error(`Tried to update ${i} with some elements that are not length ${s.length}.`);let n=new(s.type==="float"?Float32Array:Int32Array)(r.flat()),l=s.location;if(e?.startIndex){let u=this.gl.getUniformLocation(this.program,`${i}[${e.startIndex}]`);if(!u)throw new Error(`${i}[${e.startIndex}] not in shader. Did you pass an invalid startIndex?`);l=u}this.gl[a+"v"](l,n)}else{if(Array.isArray(r)||(r=[r]),r.length!==s.length)throw new Error(`Invalid uniform value length: ${r.length}. Expected ${s.length}.`);this.gl[a](s.location,...r)}}),this.emitHook("updateUniforms",...arguments)}createTexture(t,e){let{width:i,height:r}=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(g){throw this.gl.deleteTexture(a),g}let n=s>0,l=n?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:u}=e;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(l,a),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_S,u.wrapS),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_T,u.wrapT),this.gl.texParameteri(l,this.gl.TEXTURE_MIN_FILTER,u.minFilter),this.gl.texParameteri(l,this.gl.TEXTURE_MAG_FILTER,u.magFilter),n?this.gl.texStorage3D(l,1,u.internalFormat,i,r,s):t===T&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,u.internalFormat,i,r,0,u.format,u.type,null),{texture:a,unitIndex:o}}_initializeTexture(t,e,i){if(this.textures.has(t))throw new Error(`Texture '${x(t)}' is already initialized.`);let{history:r=0,...s}=i??{},{width:a,height:o}=S(e);if(!a||!o)throw new Error("Texture source must have valid dimensions");let n={width:a,height:o,options:this.resolveTextureOptions(s)};r>0&&(n.history={depth:r,writeIndex:0});let{texture:l,unitIndex:u}=this.createTexture(t,n),g={texture:l,unitIndex:u,...n};r>0&&(this.initializeUniform(`${x(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(g)),this.textures.set(t,g),t!==T&&t!==R&&this.updateTexture(t,e),this.gl.useProgram(this.program);let f=this.gl.getUniformLocation(this.program,x(t));f&&this.gl.uniform1i(f,u)}initializeTexture(t,e,i){let r=i?.history!=null&&i.history>0?{...i,history:i.history+1}:i;this._initializeTexture(t,e,r),this.emitHook("initializeTexture",...arguments)}updateTextures(t,e){Object.entries(t).forEach(([i,r])=>{this.updateTexture(i,r,e)}),this.emitHook("updateTextures",...arguments)}updateTexture(t,e,i){let r=this.textures.get(t);if(!r)throw new Error(`Texture '${x(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let s=e;if(e instanceof h){let f=e.textures.get(T),p=f.width,d=f.height;if(e.gl===this.gl){if(!r.history){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,f.texture);return}let{depth:y}=r.history,_=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i?.historyWriteIndex)?i.historyWriteIndex.map(L=>v(L,y)):[v(i.historyWriteIndex,y)];this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,e.intermediateFbo),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);for(let L of _)this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,L,0,0,p,d);this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,null),this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);let U=`${x(t)}FrameOffset`;this.updateUniforms({[U]:_[_.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%y);return}let{width:c,height:m,options:{format:E,type:I}}=f,b=this.getPixelArray(I,c*m*4);e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,e.intermediateFbo),e.gl.readPixels(0,0,c,m,E,I,b),e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,null),s={data:b,width:c,height:m}}let{width:a,height:o}=S(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)&&!r.options?.preserveY,g=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(r.history){if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture),!i?.skipHistoryWrite){let{depth:f}=r.history,p=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i.historyWriteIndex)?i.historyWriteIndex.map(m=>v(m,f)):[v(i.historyWriteIndex,f)];this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u);let d=s.data??s;for(let m of p)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,m,a,o,1,r.options.format,r.options.type,d);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g);let c=`${x(t)}FrameOffset`;this.updateUniforms({[c]:p[p.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%f)}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,r.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u),n){let f=s;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,f.x??0,f.y??0,a,o,r.options.format,r.options.type,f.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,r.options.internalFormat,a,o,0,r.options.format,r.options.type,s.data??s);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g)}}bindIntermediate(){let t=this.gl,e=this.textures.get(T);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(T);if(e.options.isIntegerColorFormat){let i=e.options.type;this.glHelpers.unsignedIntTypes.has(i)?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,i=e.drawingBufferWidth,r=e.drawingBufferHeight;t?.skipClear?this.bindIntermediate():this.clear(),e.useProgram(this.program),e.bindVertexArray(this.vao),e.viewport(0,0,i,r),e.drawArrays(e.TRIANGLES,0,3),this.isHeadless||this.textures.get(T).options.isIntegerColorFormat||(e.bindFramebuffer(e.READ_FRAMEBUFFER,this.intermediateFbo),e.bindFramebuffer(e.DRAW_FRAMEBUFFER,null),e.blitFramebuffer(0,0,i,r,0,0,i,r,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 i={};this.uniforms.has("u_time")&&(i.u_time=t),this.uniforms.has("u_frame")&&(i.u_frame=this.frame),this.updateUniforms(i),this.draw(e);let r=this.textures.get(R);if(r&&!e?.skipHistoryWrite){let{writeIndex:s,depth:a}=r.history,o=this.gl;o.bindFramebuffer(o.READ_FRAMEBUFFER,this.intermediateFbo),o.bindTexture(o.TEXTURE_2D_ARRAY,r.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({[`${x(R)}FrameOffset`]:n}),r.history.writeIndex=n}++this.frame,this.emitHook("afterStep",t,this.frame,e)}play(t){this.pause(),this.isPlaying=!0;let e=i=>{i=(i-this.startTime)/1e3;let r=t?.(i,this.frame)??void 0;this._step(i,r),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")}reset(){this.frame=0,this.startTime=performance.now(),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,i)=>{this.cursorTarget.removeEventListener(i,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=F.get(this.canvas);t&&(t.instances.delete(this),t.instances.size===0&&F.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()}},k=A;
|
|
9
|
+
`)}function S(h){return h instanceof WebGLTexture?{width:0,height:0}:h instanceof A?{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 x(h){return typeof h=="symbol"?h.description??"":h}var A=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:i,history:r,debug:s,cursorTarget:a,...o}={}){if(e&&"getContext"in e)this.canvas=e;else{let{width:d=1,height:c=1}=e||{};this.canvas=new OffscreenCanvas(d,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 l=F.get(this.canvas);l||(l={textureUnitPool:{free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},instances:new Set([this])},F.set(this.canvas,l)),this.textureUnitPool=l.textureUnitPool,l.instances.add(this),this.textureOptions=o,r&&(this.historyDepth=r),this.debug=s??(typeof process<"u"&&!1),this.cursorTarget=a??(this.canvas instanceof HTMLCanvasElement?this.canvas:void 0),this.animationFrameId=null;let u=[];i&&i.forEach(d=>d(this,{gl:n,canvas:this.canvas,injectGLSL:c=>{u.push(c)},emitHook:this.emitHook.bind(this)}));let g=this.gl.createProgram();if(!g)throw new Error("Failed to create WebGL program");this.program=g;let f=this.createShader(this.gl.VERTEX_SHADER,H),T=this.createShader(n.FRAGMENT_SHADER,W(t,u));if(n.attachShader(g,f),n.attachShader(g,T),n.bindAttribLocation(g,0,"a_position"),n.linkProgram(g),n.deleteShader(f),n.deleteShader(T),!n.getProgramParameter(g,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(g)),n.deleteProgram(g),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(g),this.canvas instanceof HTMLCanvasElement)this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]});else{let d=c=>{let m=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,c),E=this.canvas;Object.defineProperty(E,c,{get:()=>m.get.call(E),set:I=>{m.set.call(E,I);let b=F.get(E);if(b)for(let y of b.instances)y.updateResolution()},configurable:m.configurable,enumerable:m.enumerable})};d("width"),d("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(R,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(i=>i.call(this,...e))}on(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}off(t,e){let i=this.hooks.get(t);i&&i.splice(i.indexOf(e),1)}createShader(t,e){let i=this.gl.createShader(t);if(this.gl.shaderSource(i,e),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(i)),this.gl.deleteShader(i),new Error("Shader compilation failed");return i}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=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.getCursorTargetRect(),a=(i-s.left)/s.width,o=1-(r-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=(i,r,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let a=this.getCursorTargetRect(),o=r,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",i=>{let r=i;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",i=>{let r=i;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,e(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&e(!1)}),this.eventListeners.set("touchmove",i=>{let r=i;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let r=i;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),e(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,r)=>{this.cursorTarget.addEventListener(r,i)})}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(R,...t),this.emitHook("updateResolution",...t)}resizeTexture(t,e,i){let r=this.textures.get(t);if(!r||r.width===e&&r.height===i)return;this.gl.deleteTexture(r.texture),r.width=e,r.height=i;let{texture:s}=this.createTexture(t,r);r.texture=s,r.history&&(r.history.writeIndex=0,this.clearHistoryTextureLayers(r))}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,i=t?.internalFormat,r=t?.type??N(i)??"UNSIGNED_BYTE",s=this.resolveGLConstant(r),a=i??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 i=this.glHelpers.typeToArray.get(t)??Uint8Array;return new i(e)}clearHistoryTextureLayers(t){if(!t.history)return;let e=this.gl,{type:i,format:r}=t.options,s=this.getPixelArray(i,t.width*t.height*4);e.activeTexture(e.TEXTURE0+t.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,t.texture);for(let a=0;a<t.history.depth;++a)e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,a,t.width,t.height,1,r,i,s)}initializeUniform(t,e,i,r){let s=r?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);if(s&&!(Array.isArray(i)&&i.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?i[0]:i,n=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:n,location:a,arrayLength:s});try{this.updateUniforms({[t]:i})}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(([i,r])=>{let s=this.uniforms.get(i);if(!s){this.log(`${i} not in shader. Skipping update.`);return}let a=`uniform${s.length}${s.type.charAt(0)}`;if(s.arrayLength){if(!Array.isArray(r))throw new Error(`${i} is an array, but the value passed to updateUniforms is not an array.`);let o=r.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${i} received ${o} values, but maximum length is ${s.arrayLength}.`);if(r.some(u=>(Array.isArray(u)?u.length:1)!==s.length))throw new Error(`Tried to update ${i} with some elements that are not length ${s.length}.`);let n=new(s.type==="float"?Float32Array:Int32Array)(r.flat()),l=s.location;if(e?.startIndex){let u=this.gl.getUniformLocation(this.program,`${i}[${e.startIndex}]`);if(!u)throw new Error(`${i}[${e.startIndex}] not in shader. Did you pass an invalid startIndex?`);l=u}this.gl[a+"v"](l,n)}else{if(Array.isArray(r)||(r=[r]),r.length!==s.length)throw new Error(`Invalid uniform value length: ${r.length}. Expected ${s.length}.`);this.gl[a](s.location,...r)}}),this.emitHook("updateUniforms",...arguments)}createTexture(t,e){let{width:i,height:r}=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(g){throw this.gl.deleteTexture(a),g}let n=s>0,l=n?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:u}=e;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(l,a),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_S,u.wrapS),this.gl.texParameteri(l,this.gl.TEXTURE_WRAP_T,u.wrapT),this.gl.texParameteri(l,this.gl.TEXTURE_MIN_FILTER,u.minFilter),this.gl.texParameteri(l,this.gl.TEXTURE_MAG_FILTER,u.magFilter),n?this.gl.texStorage3D(l,1,u.internalFormat,i,r,s):t===p&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,u.internalFormat,i,r,0,u.format,u.type,null),{texture:a,unitIndex:o}}_initializeTexture(t,e,i){if(this.textures.has(t))throw new Error(`Texture '${x(t)}' is already initialized.`);let{history:r=0,...s}=i??{},{width:a,height:o}=S(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)};r>0&&(n.history={depth:r,writeIndex:0});let{texture:l,unitIndex:u}=this.createTexture(t,n),g={texture:l,unitIndex:u,...n};r>0&&(this.initializeUniform(`${x(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(g)),this.textures.set(t,g),t!==p&&t!==R&&this.updateTexture(t,e),this.gl.useProgram(this.program);let f=this.gl.getUniformLocation(this.program,x(t));f&&this.gl.uniform1i(f,u)}initializeTexture(t,e,i){let r=i?.history!=null&&i.history>0?{...i,history:i.history+1}:i;this._initializeTexture(t,e,r),this.emitHook("initializeTexture",...arguments)}updateTextures(t,e){Object.entries(t).forEach(([i,r])=>{this.updateTexture(i,r,e)}),this.emitHook("updateTextures",...arguments)}updateTexture(t,e,i){let r=this.textures.get(t);if(!r)throw new Error(`Texture '${x(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let s=e;if(e instanceof h){let f=e.textures.get(p),T=f.width,d=f.height;if(e.gl===this.gl){if(!r.history){this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,f.texture);return}let{depth:y}=r.history,_=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i?.historyWriteIndex)?i.historyWriteIndex.map(L=>v(L,y)):[v(i.historyWriteIndex,y)];this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,e.intermediateFbo),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);for(let L of _)this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,L,0,0,T,d);this.gl.bindFramebuffer(this.gl.READ_FRAMEBUFFER,null),this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture);let U=`${x(t)}FrameOffset`;this.updateUniforms({[U]:_[_.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%y);return}let{width:c,height:m,options:{format:E,type:I}}=f,b=this.getPixelArray(I,c*m*4);e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,e.intermediateFbo),e.gl.readPixels(0,0,c,m,E,I,b),e.gl.bindFramebuffer(e.gl.FRAMEBUFFER,null),s={data:b,width:c,height:m}}let{width:a,height:o}=S(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)&&!r.options?.preserveY,g=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(r.history){if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,r.texture),!i?.skipHistoryWrite){let{depth:f}=r.history,T=i?.historyWriteIndex===void 0?[r.history.writeIndex]:Array.isArray(i.historyWriteIndex)?i.historyWriteIndex.map(m=>v(m,f)):[v(i.historyWriteIndex,f)];this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u);let d=s.data??s;for(let m of T)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,m,a,o,1,r.options.format,r.options.type,d);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g);let c=`${x(t)}FrameOffset`;this.updateUniforms({[c]:T[T.length-1]}),i?.historyWriteIndex===void 0&&(r.history.writeIndex=(r.history.writeIndex+1)%f)}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,r.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u),n){let f=s;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,f.x??0,f.y??0,a,o,r.options.format,r.options.type,f.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,r.options.internalFormat,a,o,0,r.options.format,r.options.type,s.data??s);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,g)}}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 i=e.options.type;this.glHelpers.unsignedIntTypes.has(i)?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,i=e.drawingBufferWidth,r=e.drawingBufferHeight;t?.skipClear?this.bindIntermediate():this.clear(),e.useProgram(this.program),e.bindVertexArray(this.vao),e.viewport(0,0,i,r),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,i,r,0,0,i,r,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 i={};this.uniforms.has("u_time")&&(i.u_time=t),this.uniforms.has("u_frame")&&(i.u_frame=this.frame),this.updateUniforms(i),this.draw(e);let r=this.textures.get(R);if(r&&!e?.skipHistoryWrite){let{writeIndex:s,depth:a}=r.history,o=this.gl;o.bindFramebuffer(o.READ_FRAMEBUFFER,this.intermediateFbo),o.bindTexture(o.TEXTURE_2D_ARRAY,r.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({[`${x(R)}FrameOffset`]:n}),r.history.writeIndex=n}++this.frame,this.emitHook("afterStep",t,this.frame,e)}play(t){this.pause(),this.isPlaying=!0;let e=i=>{i=(i-this.startTime)/1e3;let r=t?.(i,this.frame)??void 0;this._step(i,r),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,i)=>{this.cursorTarget.removeEventListener(i,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=F.get(this.canvas);t&&(t.instances.delete(this),t.instances.size===0&&F.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()}},k=A;
|
|
10
10
|
//# sourceMappingURL=index.js.map
|