shaderpad 1.0.0-beta.40 → 1.0.0-beta.42
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 +323 -41
- package/dist/chunk-5CBGNOA3.mjs +10 -0
- package/dist/chunk-5CBGNOA3.mjs.map +1 -0
- package/dist/chunk-JRSBIGBN.mjs +7 -0
- package/dist/chunk-JRSBIGBN.mjs.map +1 -0
- package/dist/index.d.mts +7 -30
- package/dist/index.d.ts +7 -30
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/plugins/face.d.mts +1 -3
- package/dist/plugins/face.d.ts +1 -3
- package/dist/plugins/face.js +53 -76
- package/dist/plugins/face.js.map +1 -1
- package/dist/plugins/face.mjs +51 -79
- package/dist/plugins/face.mjs.map +1 -1
- package/dist/plugins/hands.d.mts +1 -3
- package/dist/plugins/hands.d.ts +1 -3
- package/dist/plugins/hands.js +20 -16
- package/dist/plugins/hands.js.map +1 -1
- package/dist/plugins/hands.mjs +14 -15
- package/dist/plugins/hands.mjs.map +1 -1
- package/dist/plugins/helpers.js +1 -1
- package/dist/plugins/helpers.js.map +1 -1
- package/dist/plugins/helpers.mjs +1 -1
- package/dist/plugins/helpers.mjs.map +1 -1
- package/dist/plugins/mediapipe-common.d.mts +18 -0
- package/dist/plugins/mediapipe-common.d.ts +18 -0
- package/dist/plugins/mediapipe-common.js +7 -0
- package/dist/plugins/mediapipe-common.js.map +1 -0
- package/dist/plugins/mediapipe-common.mjs +2 -0
- package/dist/plugins/mediapipe-common.mjs.map +1 -0
- package/dist/plugins/pose.d.mts +1 -3
- package/dist/plugins/pose.d.ts +1 -3
- package/dist/plugins/pose.js +53 -49
- package/dist/plugins/pose.js.map +1 -1
- package/dist/plugins/pose.mjs +30 -30
- package/dist/plugins/pose.mjs.map +1 -1
- package/dist/plugins/save.d.mts +1 -1
- package/dist/plugins/save.d.ts +1 -1
- package/dist/plugins/save.js +1 -1
- package/dist/plugins/save.js.map +1 -1
- package/dist/plugins/save.mjs.map +1 -1
- package/dist/plugins/segmenter.d.mts +1 -3
- package/dist/plugins/segmenter.d.ts +1 -3
- package/dist/plugins/segmenter.js +17 -13
- package/dist/plugins/segmenter.js.map +1 -1
- package/dist/plugins/segmenter.mjs +11 -11
- package/dist/plugins/segmenter.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-6C6DVCZI.mjs +0 -11
- package/dist/chunk-6C6DVCZI.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/segmenter.ts","../../src/index.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '../index';\nimport type { ImageSegmenter, ImageSegmenterResult, MPMask } from '@mediapipe/tasks-vision';\n\nexport interface SegmenterPluginOptions {\n\tmodelPath?: string;\n\toutputCategoryMask?: boolean;\n\tonReady?: () => void;\n\tonResults?: (results: ImageSegmenterResult) => void;\n}\n\nconst dummyTexture = { data: new Uint8Array(4), width: 1, height: 1 };\n\nfunction createMaskShaderSource(numMasks: number): string {\n\tconst uniforms = Array.from({ length: numMasks }, (_, i) => `uniform sampler2D u_confidenceMask${i};`).join('\\n');\n\n\t// GLSL doesn't allow dynamic indexing of samplers, so we need a switch-like construct.\n\tconst sampleByIndex = Array.from(\n\t\t{ length: numMasks },\n\t\t(_, i) => `\\t\\t${i > 0 ? 'else ' : ''}if (i == ${i}) c = texelFetch(u_confidenceMask${i}, texCoord, 0).r;`\n\t).join('\\n');\n\n\treturn `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nout vec4 outColor;\n${uniforms}\n\nvoid main() {\n\tivec2 texCoord = ivec2(v_uv * vec2(textureSize(u_confidenceMask0, 0)));\n\tfloat maxConfidence = 0.0;\n\tint maxIndex = 0;\n\n\tfor (int i = 0; i < ${numMasks}; i++) {\n\t\tfloat c = 0.0;\n${sampleByIndex}\n\t\tif (c > maxConfidence) {\n\t\t\tmaxConfidence = c;\n\t\t\tmaxIndex = i;\n\t\t}\n\t}\n\n\t// Normalize index: 0 = background, 1/(n-1) to 1 for foreground categories.\n\tfloat normalizedIndex = float(maxIndex) / float(max(1, ${numMasks - 1}));\n\toutColor = vec4(normalizedIndex, maxConfidence, 0.0, 1.0);\n}`;\n}\n\nfunction segmenter(config: { textureName: string; options?: SegmenterPluginOptions }) {\n\tconst { textureName, options } = config;\n\tconst defaultModelPath =\n\t\t'https://storage.googleapis.com/mediapipe-models/image_segmenter/hair_segmenter/float32/latest/hair_segmenter.tflite';\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, gl } = context;\n\n\t\tlet imageSegmenter: ImageSegmenter | null = null;\n\t\tlet vision: any = null;\n\t\tlet lastVideoTime = -1;\n\t\tlet runningMode: 'IMAGE' | 'VIDEO' = 'VIDEO';\n\t\tconst textureSources = new Map<string, TextureSource>();\n\t\tlet numCategories = 1;\n\n\t\t// Shared canvas for MediaPipe and maskShader (same WebGL context).\n\t\tconst sharedCanvas = new OffscreenCanvas(1, 1);\n\t\tlet maskShader: ShaderPad | null = null;\n\t\tasync function initializeImageSegmenter() {\n\t\t\ttry {\n\t\t\t\tconst { FilesetResolver, ImageSegmenter } = await import('@mediapipe/tasks-vision');\n\t\t\t\tvision = await FilesetResolver.forVisionTasks(\n\t\t\t\t\t'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm'\n\t\t\t\t);\n\n\t\t\t\timageSegmenter = await ImageSegmenter.createFromOptions(vision, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options?.modelPath || defaultModelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\tcanvas: sharedCanvas,\n\t\t\t\t\trunningMode: runningMode,\n\t\t\t\t\toutputCategoryMask: options?.outputCategoryMask ?? false, // Better for perf, and category can be inferred from confidence mask index.\n\t\t\t\t\toutputConfidenceMasks: true,\n\t\t\t\t});\n\n\t\t\t\tconst labels = imageSegmenter.getLabels();\n\t\t\t\tif (labels.length) numCategories = labels.length;\n\t\t\t\tshaderPad.updateUniforms({ u_numCategories: numCategories });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Segmenter Plugin] Failed to initialize:', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tfunction updateMaskTexture(confidenceMasks: MPMask[]) {\n\t\t\tif (!maskShader) return;\n\n\t\t\tconst textures: Record<string, WebGLTexture> = {};\n\t\t\tfor (let i = 0; i < confidenceMasks.length; i++) {\n\t\t\t\ttextures[`u_confidenceMask${i}`] = confidenceMasks[i].getAsWebGLTexture();\n\t\t\t}\n\t\t\tmaskShader.updateTextures(textures);\n\t\t\tmaskShader.draw();\n\t\t\tshaderPad.updateTextures({ u_segmentMask: sharedCanvas });\n\t\t\tconfidenceMasks.forEach(mask => mask.close());\n\t\t}\n\n\t\tfunction processSegmenterResults(result: ImageSegmenterResult) {\n\t\t\tconst { confidenceMasks } = result;\n\t\t\tif (!confidenceMasks || confidenceMasks.length === 0) return;\n\n\t\t\t// IMPORTANT: maskShader and MediaPipe share a WebGL context. MediaPipe needs to run at least once before\n\t\t\t// ShaderPad is created on the same canvas, otherwise MediaPipe's WebGL state gets corrupted.\n\t\t\tif (!maskShader) {\n\t\t\t\tconst shaderSource = createMaskShaderSource(confidenceMasks.length);\n\t\t\t\tmaskShader = new ShaderPad(shaderSource, { canvas: sharedCanvas });\n\t\t\t\tfor (let i = 0; i < confidenceMasks.length; i++) {\n\t\t\t\t\tmaskShader.initializeTexture(`u_confidenceMask${i}`, dummyTexture);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateMaskTexture(confidenceMasks);\n\t\t\toptions?.onResults?.(result);\n\t\t}\n\n\t\tshaderPad.registerHook('init', async () => {\n\t\t\tshaderPad.initializeTexture('u_segmentMask', dummyTexture, {\n\t\t\t\tpreserveY: true,\n\t\t\t\tminFilter: gl.NEAREST,\n\t\t\t\tmagFilter: gl.NEAREST,\n\t\t\t});\n\t\t\tshaderPad.initializeUniform('u_numCategories', 'int', numCategories);\n\t\t\tawait initializeImageSegmenter();\n\t\t\toptions?.onReady?.();\n\t\t});\n\n\t\tshaderPad.registerHook('updateTextures', async (updates: Record<string, TextureSource>) => {\n\t\t\tconst source = updates[textureName];\n\t\t\tif (!source) return;\n\n\t\t\tconst previousSource = textureSources.get(textureName);\n\t\t\tif (previousSource !== source) {\n\t\t\t\tlastVideoTime = -1;\n\t\t\t}\n\n\t\t\ttextureSources.set(textureName, source);\n\t\t\tif (!imageSegmenter) return;\n\n\t\t\ttry {\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (runningMode !== requiredMode) {\n\t\t\t\t\trunningMode = requiredMode;\n\t\t\t\t\tawait imageSegmenter.setOptions({ runningMode: runningMode });\n\t\t\t\t}\n\n\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (source.currentTime !== lastVideoTime) {\n\t\t\t\t\t\tlastVideoTime = source.currentTime;\n\t\t\t\t\t\t// TODO: I think segmentForVideo runs its own animation loop maybe? args are (source, startTime, callbackForVideo).\n\t\t\t\t\t\tconst result = imageSegmenter.segmentForVideo(source, performance.now());\n\t\t\t\t\t\tprocessSegmenterResults(result);\n\t\t\t\t\t}\n\t\t\t\t} else if (source instanceof HTMLImageElement || source instanceof HTMLCanvasElement) {\n\t\t\t\t\tif (source.width === 0 || source.height === 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst result = imageSegmenter.segment(source);\n\t\t\t\t\tprocessSegmenterResults(result);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Segmenter Plugin] Segmentation error:', error);\n\t\t\t}\n\t\t});\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (imageSegmenter) {\n\t\t\t\timageSegmenter.close();\n\t\t\t\timageSegmenter = null;\n\t\t\t}\n\t\t\tif (maskShader) {\n\t\t\t\tmaskShader.destroy();\n\t\t\t\tmaskShader = null;\n\t\t\t}\n\t\t\tvision = null;\n\t\t\ttextureSources.clear();\n\t\t});\n\n\t\tinjectGLSL(`\nuniform sampler2D u_segmentMask;\nuniform int u_numCategories;\n\nvec2 segmentAt(vec2 pos) {\n\tvec4 mask = texture(u_segmentMask, pos);\n\treturn vec2(mask.r, mask.g);\n}`);\n\t};\n}\n\nexport default segmenter;\n","const DEFAULT_VERTEX_SHADER_SRC = `#version 300 es\nin vec2 aPosition;\nout vec2 v_uv;\nvoid main() {\n v_uv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\nconst RESIZE_THROTTLE_INTERVAL = 1000 / 30;\n\ninterface Uniform {\n\ttype: 'float' | 'int';\n\tlength: 1 | 2 | 3 | 4;\n\tlocation: WebGLUniformLocation;\n\tarrayLength?: number;\n}\n\nexport interface TextureOptions {\n\tinternalFormat?: number;\n\tformat?: number;\n\ttype?: number;\n\tminFilter?: number;\n\tmagFilter?: number;\n\twrapS?: number;\n\twrapT?: number;\n\tpreserveY?: boolean;\n}\ntype ResolvedTextureOptions = Required<Omit<TextureOptions, 'preserveY'>> & Pick<TextureOptions, 'preserveY'>;\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\n// Custom textures allow partial updates starting from (x, y).\ntype UpdateTextureSource = Exclude<TextureSource, CustomTexture> | PartialCustomTexture;\n\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tuniforms: Map<string, Uniform>;\n\ttextures: Map<string | symbol, Texture>;\n\tget program(): WebGLProgram | null;\n\tcanvas: HTMLCanvasElement | OffscreenCanvas;\n\treserveTextureUnit: (name: string | symbol) => number;\n\treleaseTextureUnit: (name: string | symbol) => void;\n\tinjectGLSL: (code: string) => void;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod =\n\t| 'init'\n\t| 'step'\n\t| 'afterStep'\n\t| 'destroy'\n\t| 'updateResolution'\n\t| 'reset'\n\t| 'initializeTexture'\n\t| 'updateTextures'\n\t| 'initializeUniform'\n\t| 'updateUniforms';\n\nexport interface Options extends Exclude<TextureOptions, 'preserveY'> {\n\tcanvas?: HTMLCanvasElement | OffscreenCanvas | null;\n\tplugins?: Plugin[];\n\thistory?: number;\n\tdebug?: boolean;\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\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 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 isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate fragmentShaderSrc: string;\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 program: WebGLProgram | null = null;\n\tprivate aPositionLocation = 0;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: ReturnType<typeof setTimeout> = null as unknown as ReturnType<typeof setTimeout>;\n\tprivate lastResizeTime = -Infinity;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\tprivate frame = 0;\n\tprivate startTime = 0;\n\tprivate cursorPosition = [0.5, 0.5];\n\tprivate clickPosition = [0.5, 0.5];\n\tprivate isMouseDown = false;\n\tpublic canvas: HTMLCanvasElement | OffscreenCanvas;\n\tpublic onResize?: (width: number, height: number) => void;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\tprivate historyDepth = 0;\n\tprivate textureOptions: TextureOptions;\n\tprivate debug: boolean;\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(fragmentShaderSrc: string, { canvas, plugins, history, debug, ...textureOptions }: Options = {}) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\t\thtmlCanvas.style.position = 'fixed';\n\t\t\thtmlCanvas.style.inset = '0';\n\t\t\thtmlCanvas.style.height = '100dvh';\n\t\t\thtmlCanvas.style.width = '100dvw';\n\t\t\tdocument.body.appendChild(htmlCanvas);\n\t\t}\n\n\t\tthis.gl = this.canvas.getContext('webgl2', { antialias: false }) as WebGL2RenderingContext;\n\t\tif (!this.gl) {\n\t\t\tthrow new Error('WebGL2 not supported. Please use a browser that supports WebGL2.');\n\t\t}\n\n\t\tthis.textureUnitPool = {\n\t\t\tfree: [],\n\t\t\tnext: 0,\n\t\t\tmax: this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),\n\t\t};\n\t\tthis.textureOptions = textureOptions;\n\n\t\tconst { internalFormat, type } = textureOptions;\n\t\tconst isFloatFormat =\n\t\t\ttype === this.gl.FLOAT ||\n\t\t\ttype === this.gl.HALF_FLOAT ||\n\t\t\tinternalFormat === this.gl.RGBA16F ||\n\t\t\tinternalFormat === this.gl.RGBA32F ||\n\t\t\tinternalFormat === this.gl.R16F ||\n\t\t\tinternalFormat === this.gl.R32F ||\n\t\t\tinternalFormat === this.gl.RG16F ||\n\t\t\tinternalFormat === this.gl.RG32F;\n\t\tif (isFloatFormat && !this.gl.getExtension('EXT_color_buffer_float')) {\n\t\t\tconsole.warn('EXT_color_buffer_float not supported, falling back to RGBA8');\n\t\t\tdelete this.textureOptions?.internalFormat;\n\t\t\tdelete this.textureOptions?.format;\n\t\t\tdelete this.textureOptions?.type;\n\t\t}\n\n\t\tif (history) this.historyDepth = history;\n\t\tthis.debug = debug ?? (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production');\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\n\t\tconst glslInjections: string[] = [];\n\t\tif (plugins) {\n\t\t\tconst context: PluginContext = {\n\t\t\t\tgl: this.gl,\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\ttextures: this.textures,\n\t\t\t\tcanvas: this.canvas,\n\t\t\t\treserveTextureUnit: this.reserveTextureUnit.bind(this),\n\t\t\t\treleaseTextureUnit: this.releaseTextureUnit.bind(this),\n\t\t\t\tinjectGLSL: (code: string) => {\n\t\t\t\t\tglslInjections.push(code);\n\t\t\t\t},\n\t\t\t} as PluginContext;\n\t\t\t// Define program as a getter so it always returns the current program.\n\t\t\tObject.defineProperty(context, 'program', {\n\t\t\t\tget: () => this.program,\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t\tplugins.forEach(plugin => plugin(this, context));\n\t\t}\n\n\t\tthis.fragmentShaderSrc = combineShaderCode(fragmentShaderSrc, glslInjections);\n\t\tthis.init();\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.addEventListeners();\n\t\t}\n\t}\n\n\tregisterHook(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\tprivate init() {\n\t\tconst vertexShaderSrc = DEFAULT_VERTEX_SHADER_SRC;\n\n\t\tthis.program = this.gl.createProgram();\n\t\tif (!this.program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSrc);\n\t\tconst fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, this.fragmentShaderSrc);\n\n\t\tthis.gl.attachShader(this.program, vertexShader);\n\t\tthis.gl.attachShader(this.program, fragmentShader);\n\t\tthis.gl.linkProgram(this.program);\n\t\tthis.gl.deleteShader(vertexShader);\n\t\tthis.gl.deleteShader(fragmentShader);\n\n\t\tif (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', this.gl.getProgramInfoLog(this.program));\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\tthis.aPositionLocation = this.gl.getAttribLocation(this.program, 'aPosition');\n\t\tthis.setupBuffer();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\t\tthis.resizeObserver.observe(this.canvas);\n\t\t}\n\n\t\tif (!this.isInternalCanvas) {\n\t\t\tthis.updateResolution();\n\t\t}\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\tif (this.historyDepth > 0) {\n\t\t\tthis._initializeTexture(INTERMEDIATE_TEXTURE_KEY, this.canvas, {\n\t\t\t\t...this.textureOptions,\n\t\t\t});\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\tthis.intermediateFbo = this.gl.createFramebuffer();\n\t\t}\n\n\t\tthis.hooks.get('init')?.forEach(hook => hook.call(this));\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 setupBuffer() {\n\t\tconst quadVertices = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);\n\n\t\tthis.buffer = this.gl.createBuffer();\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\t\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\tthis.gl.enableVertexAttribArray(this.aPositionLocation);\n\t\tthis.gl.vertexAttribPointer(this.aPositionLocation, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\tprivate throttledHandleResize() {\n\t\tclearTimeout(this.resizeTimeout);\n\t\tconst now = performance.now();\n\t\tconst timeUntilNextResize = this.lastResizeTime + RESIZE_THROTTLE_INTERVAL - now;\n\t\tif (timeUntilNextResize <= 0) {\n\t\t\tthis.lastResizeTime = now;\n\t\t\tthis.handleResize();\n\t\t} else {\n\t\t\tthis.resizeTimeout = setTimeout(() => this.throttledHandleResize(), timeUntilNextResize);\n\t\t}\n\t}\n\n\tprivate handleResize() {\n\t\tif (!(this.canvas instanceof HTMLCanvasElement)) return;\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\t\tif (this.isInternalCanvas && (this.canvas.width !== width || this.canvas.height !== height)) {\n\t\t\tthis.canvas.width = width;\n\t\t\tthis.canvas.height = height;\n\t\t}\n\t\tthis.onResize?.(width, height);\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = htmlCanvas.getBoundingClientRect();\n\t\t\tthis.cursorPosition[0] = (x - rect.left) / rect.width;\n\t\t\tthis.cursorPosition[1] = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\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 = htmlCanvas.getBoundingClientRect();\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] = (xVal - rect.left) / rect.width;\n\t\t\t\tthis.clickPosition[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\thtmlCanvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\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\tif (this.historyDepth > 0) {\n\t\t\tthis.resizeTexture(HISTORY_TEXTURE_KEY, ...resolution);\n\t\t\tthis.resizeTexture(INTERMEDIATE_TEXTURE_KEY, ...resolution);\n\t\t}\n\t\tthis.hooks.get('updateResolution')?.forEach(hook => hook.call(this));\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 releaseTextureUnit(name: string | symbol) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) {\n\t\t\tthis.textureUnitPool.free.push(existing.unitIndex);\n\t\t}\n\t}\n\n\tprivate resolveTextureOptions(options?: TextureOptions): ResolvedTextureOptions {\n\t\tconst { gl } = this;\n\t\tconst type = options?.type ?? gl.UNSIGNED_BYTE;\n\t\treturn {\n\t\t\ttype,\n\t\t\tformat: options?.format ?? gl.RGBA,\n\t\t\tinternalFormat:\n\t\t\t\toptions?.internalFormat ??\n\t\t\t\t(type === gl.FLOAT ? gl.RGBA32F : type === gl.HALF_FLOAT ? gl.RGBA16F : gl.RGBA8),\n\t\t\tminFilter: options?.minFilter ?? gl.LINEAR,\n\t\t\tmagFilter: options?.magFilter ?? gl.LINEAR,\n\t\t\twrapS: options?.wrapS ?? gl.CLAMP_TO_EDGE,\n\t\t\twrapT: options?.wrapT ?? gl.CLAMP_TO_EDGE,\n\t\t\tpreserveY: options?.preserveY,\n\t\t};\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 size = textureInfo.width * textureInfo.height * 4;\n\t\tconst transparent =\n\t\t\ttype === gl.FLOAT\n\t\t\t\t? new Float32Array(size)\n\t\t\t\t: type === gl.HALF_FLOAT\n\t\t\t\t? new Uint16Array(size)\n\t\t\t\t: new Uint8Array(size);\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 found in fragment 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.hooks.get('initializeUniform')?.forEach(hook => hook.call(this, ...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, value]) => {\n\t\t\tconst uniform = this.uniforms.get(name);\n\t\t\tif (!uniform) {\n\t\t\t\tthis.log(`${name} not found in fragment 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(value)) {\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 = value.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 (value.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)(value.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 found in fragment 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(value)) value = [value];\n\t\t\t\tif (value.length !== uniform.length) {\n\t\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t\t}\n\t\t\t\t(this.gl as any)[glFunctionName](uniform.location, ...value);\n\t\t\t}\n\t\t});\n\t\tthis.hooks.get('updateUniforms')?.forEach(hook => hook.call(this, ...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: 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\tthis.updateTexture(name, source);\n\n\t\t// Set a uniform to access the texture in the fragment shader.\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\tthis._initializeTexture(name, source, options);\n\t\tthis.hooks.get('initializeTexture')?.forEach(hook => hook.call(this, ...arguments));\n\t}\n\n\tupdateTextures(updates: Record<string, UpdateTextureSource>, options?: { skipHistoryWrite?: boolean }) {\n\t\tthis.hooks.get('updateTextures')?.forEach(hook => hook.call(this, ...arguments));\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tthis.updateTexture(name, source, options);\n\t\t});\n\t}\n\n\tprivate updateTexture(\n\t\tname: string | symbol,\n\t\tsource: UpdateTextureSource,\n\t\toptions?: { skipHistoryWrite?: boolean }\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\t// If dimensions changed, recreate the texture with new dimensions.\n\t\tconst { width, height } = getSourceDimensions(source);\n\t\tif (!width || !height) return;\n\n\t\tconst isPartial = 'isPartial' in source && source.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 source && source.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\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\t\t\t\tthis.gl.texSubImage3D(\n\t\t\t\t\tthis.gl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.history.writeIndex,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t1,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\t((source as PartialCustomTexture).data ?? (source as Exclude<TextureSource, CustomTexture>)) as any\n\t\t\t\t);\n\t\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\t\t\t\tconst frameOffsetUniformName = `${stringFrom(name)}FrameOffset`;\n\t\t\t\tthis.updateUniforms({ [frameOffsetUniformName]: info.history.writeIndex });\n\t\t\t\tinfo.history.writeIndex = (info.history.writeIndex + 1) % info.history.depth;\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\tthis.gl.texSubImage2D(\n\t\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t\t0,\n\t\t\t\t\tsource.x ?? 0,\n\t\t\t\t\tsource.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\tsource.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((source as PartialCustomTexture).data ?? (source as Exclude<TextureSource, CustomTexture>)) 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\tdraw(options?: StepOptions) {\n\t\tconst gl = this.gl;\n\t\tconst w = gl.drawingBufferWidth;\n\t\tconst h = gl.drawingBufferHeight;\n\t\tconst historyInfo = this.textures.get(HISTORY_TEXTURE_KEY);\n\t\tconst intermediateInfo = this.textures.get(INTERMEDIATE_TEXTURE_KEY);\n\t\tconst shouldStoreHistory = historyInfo && !options?.skipHistoryWrite;\n\n\t\tif (shouldStoreHistory) {\n\t\t\t// Render to intermediate texture to avoid feedback loop with history texture\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.intermediateFbo);\n\t\t\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, intermediateInfo!.texture, 0);\n\t\t}\n\n\t\tgl.useProgram(this.program);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n\t\tgl.vertexAttribPointer(this.aPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\t\tgl.enableVertexAttribArray(this.aPositionLocation);\n\t\tgl.viewport(0, 0, w, h);\n\t\tif (!options?.skipClear) gl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tif (shouldStoreHistory) {\n\t\t\t// Copy to history layer\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyInfo.texture);\n\t\t\tgl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, historyInfo.history!.writeIndex, 0, 0, w, h);\n\n\t\t\t// Blit to screen\n\t\t\tgl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.intermediateFbo);\n\t\t\tgl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n\t\t\tgl.blitFramebuffer(0, 0, w, h, 0, 0, w, h, gl.COLOR_BUFFER_BIT, gl.NEAREST);\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t}\n\t}\n\n\tstep(time: number, options?: StepOptions) {\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.hooks.get('step')?.forEach(hook => hook.call(this, time, this.frame));\n\n\t\tthis.draw(options);\n\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\tthis.updateUniforms({ [`${stringFrom(HISTORY_TEXTURE_KEY)}FrameOffset`]: writeIndex });\n\t\t\thistoryInfo.history!.writeIndex = (writeIndex + 1) % depth;\n\t\t}\n\n\t\tthis.hooks.get('afterStep')?.forEach(hook => hook.call(this, time, this.frame));\n\t\t++this.frame;\n\t}\n\n\tplay(\n\t\tonStepComplete?: (time: number, frame: number) => void,\n\t\tsetStepOptions?: (time: number, frame: number) => StepOptions | void\n\t) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tconst options = setStepOptions?.(time, this.frame) ?? undefined;\n\t\t\tthis.step(time, options);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tonStepComplete?.(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\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.hooks.get('reset')?.forEach(hook => hook.call(this));\n\t}\n\n\tdestroy() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\n\t\tthis.resolutionObserver.disconnect();\n\t\tthis.resizeObserver.disconnect();\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t\t});\n\t\t}\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\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.gl.deleteTexture(texture.texture);\n\t\t});\n\t\tthis.textureUnitPool.free = [];\n\t\tthis.textureUnitPool.next = 0;\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.hooks.get('destroy')?.forEach(hook => hook.call(this));\n\n\t\tif (this.isInternalCanvas && this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"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","names":["segmenter_exports","__export","segmenter_default","__toCommonJS","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","HISTORY_TEXTURE_KEY","INTERMEDIATE_TEXTURE_KEY","combineShaderCode","shader","injections","lines","insertAt","line","trimmed","getSourceDimensions","source","stringFrom","name","ShaderPad","fragmentShaderSrc","canvas","plugins","history","debug","textureOptions","htmlCanvas","internalFormat","type","glslInjections","context","code","plugin","fn","vertexShaderSrc","vertexShader","fragmentShader","hook","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","resolution","info","texture","existing","options","gl","textureInfo","format","size","transparent","layer","value","arrayLength","location","probeValue","length","error","args","updates","uniform","glFunctionName","nValues","item","typedArray","newLocation","historyDepth","unitIndex","hasHistory","textureTarget","completeTextureInfo","uSampler","isPartial","shouldFlipY","previousFlipY","frameOffsetUniformName","w","h","historyInfo","intermediateInfo","shouldStoreHistory","time","writeIndex","depth","onStepComplete","setStepOptions","loop","index_default","dummyTexture","createMaskShaderSource","numMasks","uniforms","_","sampleByIndex","segmenter","config","textureName","options","defaultModelPath","shaderPad","context","injectGLSL","gl","imageSegmenter","vision","lastVideoTime","runningMode","textureSources","numCategories","sharedCanvas","maskShader","initializeImageSegmenter","FilesetResolver","ImageSegmenter","labels","error","updateMaskTexture","confidenceMasks","textures","i","mask","processSegmenterResults","result","shaderSource","index_default","updates","source","requiredMode","segmenter_default"]}
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/segmenter.ts","../../src/index.ts","../../src/plugins/mediapipe-common.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '..';\nimport {\n\tgenerateGLSLFn,\n\tdummyTexture,\n\tgetSharedFileset,\n\thashOptions,\n\tisMediaPipeSource,\n\tMediaPipeSource,\n} from './mediapipe-common';\nimport type { ImageSegmenter, ImageSegmenterResult, MPMask } from '@mediapipe/tasks-vision';\n\nexport interface SegmenterPluginOptions {\n\tmodelPath?: string;\n\toutputCategoryMask?: boolean;\n\thistory?: number;\n}\n\nconst DEFAULT_SEGMENTER_OPTIONS: Required<Omit<SegmenterPluginOptions, 'history'>> = {\n\tmodelPath:\n\t\t'https://storage.googleapis.com/mediapipe-models/image_segmenter/hair_segmenter/float32/latest/hair_segmenter.tflite',\n\toutputCategoryMask: false,\n};\n\nfunction createMaskShaderSource(numMasks: number): string {\n\tconst uniforms = Array.from({ length: numMasks }, (_, i) => `uniform sampler2D u_confidenceMask${i};`).join('\\n');\n\n\tconst sampleByIndex = Array.from(\n\t\t{ length: numMasks },\n\t\t(_, i) => `\\t\\t${i > 0 ? 'else ' : ''}if (i == ${i}) c = texelFetch(u_confidenceMask${i}, texCoord, 0).r;`\n\t).join('\\n');\n\n\treturn `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nout vec4 outColor;\n${uniforms}\n\nvoid main() {\n\tivec2 texCoord = ivec2(v_uv * vec2(textureSize(u_confidenceMask0, 0)));\n\tfloat maxConfidence = 0.0;\n\tint maxIndex = 0;\n\n\tfor (int i = 0; i < ${numMasks}; ++i) {\n\t\tfloat c = 0.0;\n${sampleByIndex}\n\t\tif (c > maxConfidence) {\n\t\t\tmaxConfidence = c;\n\t\t\tmaxIndex = i;\n\t\t}\n\t}\n\n\t// Normalize index: 0 = background, 1/(n-1) to 1 for foreground categories.\n\tfloat normalizedIndex = float(maxIndex) / float(max(1, ${numMasks - 1}));\n\toutColor = vec4(normalizedIndex, maxConfidence, 0.0, 1.0);\n}`;\n}\n\ninterface SharedDetector {\n\tsegmenter: ImageSegmenter;\n\tcanvas: OffscreenCanvas;\n\tsubscribers: Map<() => void, boolean>;\n\tstate: {\n\t\trunningMode: 'IMAGE' | 'VIDEO';\n\t\tsource: MediaPipeSource | null;\n\t\tvideoTime: number;\n\t\tresultTimestamp: number;\n\t\tresult: ImageSegmenterResult | null;\n\t\tpending: Promise<void>;\n\t};\n\tlabels: string[];\n\tnumCategories: number;\n\tmask: {\n\t\tshader: ShaderPad;\n\t};\n}\nconst sharedDetectors = new Map<string, SharedDetector>();\n\nfunction updateMaskCanvas(detector: SharedDetector, confidenceMasks: MPMask[]) {\n\tconst {\n\t\tmask: { shader },\n\t} = detector;\n\n\tconst textures: Record<string, WebGLTexture> = {};\n\tfor (let i = 0; i < confidenceMasks.length; ++i) {\n\t\ttextures[`u_confidenceMask${i}`] = confidenceMasks[i].getAsWebGLTexture();\n\t}\n\tshader.updateTextures(textures);\n\tshader.draw();\n\tconfidenceMasks.forEach(m => m.close());\n}\n\nfunction segmenter(config: { textureName: string; options?: SegmenterPluginOptions }) {\n\tconst { textureName, options: { history, ...mediapipeOptions } = {} } = config;\n\tconst options = { ...DEFAULT_SEGMENTER_OPTIONS, ...mediapipeOptions };\n\tconst optionsKey = hashOptions({ ...options, textureName });\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, gl, emitHook } = context;\n\n\t\tconst existingDetector = sharedDetectors.get(optionsKey);\n\t\tconst sharedCanvas = existingDetector?.canvas ?? new OffscreenCanvas(1, 1);\n\t\tlet detector: SharedDetector | null = null;\n\t\tlet skipHistoryWrite = false;\n\n\t\tfunction onResult() {\n\t\t\tif (!detector) return;\n\t\t\tshaderPad.updateTextures({ u_segmentMask: detector.canvas }, { skipHistoryWrite });\n\t\t\temitHook('segmenter:result', detector.state.result);\n\t\t}\n\n\t\tasync function initializeDetector() {\n\t\t\tif (sharedDetectors.has(optionsKey)) {\n\t\t\t\tdetector = sharedDetectors.get(optionsKey)!;\n\t\t\t} else {\n\t\t\t\tconst [mediaPipe, { ImageSegmenter }] = await Promise.all([\n\t\t\t\t\tgetSharedFileset(),\n\t\t\t\t\timport('@mediapipe/tasks-vision'),\n\t\t\t\t]);\n\t\t\t\t// Single shared canvas for MediaPipe and maskShader (same WebGL context required\n\t\t\t\t// because maskShader uses textures from MediaPipe via getAsWebGLTexture).\n\t\t\t\tconst imageSegmenter = await ImageSegmenter.createFromOptions(mediaPipe, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options.modelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\tcanvas: sharedCanvas,\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\toutputCategoryMask: options.outputCategoryMask,\n\t\t\t\t\toutputConfidenceMasks: true,\n\t\t\t\t});\n\n\t\t\t\tconst labels = imageSegmenter.getLabels();\n\t\t\t\tconst numCategories = labels.length || 1;\n\n\t\t\t\tconst maskShader = new ShaderPad(createMaskShaderSource(numCategories), { canvas: sharedCanvas });\n\t\t\t\tfor (let i = 0; i < numCategories; ++i) {\n\t\t\t\t\tmaskShader.initializeTexture(`u_confidenceMask${i}`, dummyTexture);\n\t\t\t\t}\n\n\t\t\t\tdetector = {\n\t\t\t\t\tsegmenter: imageSegmenter,\n\t\t\t\t\tcanvas: sharedCanvas,\n\t\t\t\t\tsubscribers: new Map(),\n\t\t\t\t\tstate: {\n\t\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\t\tsource: null,\n\t\t\t\t\t\tvideoTime: -1,\n\t\t\t\t\t\tresultTimestamp: 0,\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\tpending: Promise.resolve(),\n\t\t\t\t\t},\n\t\t\t\t\tlabels,\n\t\t\t\t\tnumCategories,\n\t\t\t\t\tmask: {\n\t\t\t\t\t\tshader: maskShader,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tsharedDetectors.set(optionsKey, detector);\n\t\t\t}\n\n\t\t\tdetector!.subscribers.set(onResult, false);\n\t\t}\n\t\tconst initPromise = initializeDetector();\n\n\t\tshaderPad.on('init', () => {\n\t\t\tshaderPad.initializeUniform('u_numCategories', 'int', 1);\n\t\t\tshaderPad.initializeTexture('u_segmentMask', sharedCanvas, {\n\t\t\t\tpreserveY: true,\n\t\t\t\tminFilter: gl.NEAREST,\n\t\t\t\tmagFilter: gl.NEAREST,\n\t\t\t\thistory,\n\t\t\t});\n\t\t\tinitPromise.then(() => {\n\t\t\t\tshaderPad.updateUniforms({ u_numCategories: detector!.numCategories });\n\t\t\t\temitHook('segmenter:ready');\n\t\t\t});\n\t\t});\n\n\t\tshaderPad.on('initializeTexture', (name: string, source: TextureSource) => {\n\t\t\tif (name === textureName && isMediaPipeSource(source)) detectSegments(source);\n\t\t});\n\n\t\tshaderPad.on(\n\t\t\t'updateTextures',\n\t\t\t(updates: Record<string, TextureSource>, options?: { skipHistoryWrite?: boolean }) => {\n\t\t\t\tconst source = updates[textureName];\n\t\t\t\tif (isMediaPipeSource(source)) {\n\t\t\t\t\tskipHistoryWrite = options?.skipHistoryWrite ?? false;\n\t\t\t\t\tdetectSegments(source);\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tlet nDetectionCalls = 0;\n\t\tasync function detectSegments(source: MediaPipeSource) {\n\t\t\tconst now = performance.now();\n\t\t\tconst callOrder = ++nDetectionCalls;\n\t\t\tawait initPromise;\n\t\t\tif (!detector) return;\n\n\t\t\tdetector.state.pending = detector.state.pending.then(async () => {\n\t\t\t\tif (callOrder !== nDetectionCalls || !detector) return;\n\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (detector.state.runningMode !== requiredMode) {\n\t\t\t\t\tdetector.state.runningMode = requiredMode;\n\t\t\t\t\tawait detector.segmenter.setOptions({ runningMode: requiredMode });\n\t\t\t\t}\n\n\t\t\t\tlet shouldDetect = false;\n\n\t\t\t\tif (source !== detector.state.source) {\n\t\t\t\t\tdetector.state.source = source;\n\t\t\t\t\tdetector.state.videoTime = -1;\n\t\t\t\t\tshouldDetect = true;\n\t\t\t\t} else if (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.currentTime !== detector.state.videoTime) {\n\t\t\t\t\t\tdetector.state.videoTime = source.currentTime;\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (!(source instanceof HTMLImageElement)) {\n\t\t\t\t\tif (now - detector.state.resultTimestamp > 2) {\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shouldDetect) {\n\t\t\t\t\tlet result: ImageSegmenterResult | undefined;\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) return;\n\t\t\t\t\t\tresult = detector.segmenter.segmentForVideo(source, now);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (source.width === 0 || source.height === 0) return;\n\t\t\t\t\t\tresult = detector.segmenter.segment(source);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result?.confidenceMasks && result.confidenceMasks.length > 0) {\n\t\t\t\t\t\tdetector.state.resultTimestamp = now;\n\t\t\t\t\t\tdetector.state.result = result;\n\t\t\t\t\t\tupdateMaskCanvas(detector, result.confidenceMasks);\n\t\t\t\t\t\tfor (const cb of detector.subscribers.keys()) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (detector.state.result && !detector.subscribers.get(onResult)) {\n\t\t\t\t\tonResult();\n\t\t\t\t\tdetector.subscribers.set(onResult, true);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait detector.state.pending;\n\t\t}\n\n\t\tshaderPad.on('destroy', () => {\n\t\t\tif (detector) {\n\t\t\t\tdetector.subscribers.delete(onResult);\n\t\t\t\tif (detector.subscribers.size === 0) {\n\t\t\t\t\tdetector.segmenter.close();\n\t\t\t\t\tdetector.mask.shader?.destroy();\n\t\t\t\t\tsharedDetectors.delete(optionsKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdetector = null;\n\t\t});\n\n\t\tconst { fn } = generateGLSLFn(history);\n\t\tconst sampleMask = history\n\t\t\t? `int layer = (u_segmentMaskFrameOffset - framesAgo + ${history}) % ${history};\n\tvec4 mask = texture(u_segmentMask, vec3(pos, float(layer)));`\n\t\t\t: `vec4 mask = texture(u_segmentMask, pos);`;\n\n\t\tinjectGLSL(`\nuniform sampler2D${history ? 'Array' : ''} u_segmentMask;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_segmentMaskFrameOffset;`\n\t\t\t\t: ''\n\t\t}\nuniform int u_numCategories;\n\n${fn(\n\t'vec2',\n\t'segmentAt',\n\t'vec2 pos',\n\t`${sampleMask}\n\treturn vec2(mask.r, mask.g);`\n)}`);\n\t};\n}\n\nexport default segmenter;\n","const DEFAULT_VERTEX_SHADER_SRC = `#version 300 es\nin vec2 aPosition;\nout vec2 v_uv;\nvoid main() {\n v_uv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}`;\nconst RESIZE_THROTTLE_INTERVAL = 1000 / 30;\nconst QUAD_VERTICES = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);\n\ninterface Uniform {\n\ttype: 'float' | 'int';\n\tlength: 1 | 2 | 3 | 4;\n\tlocation: WebGLUniformLocation;\n\tarrayLength?: number;\n}\n\nexport interface TextureOptions {\n\tinternalFormat?: number;\n\tformat?: number;\n\ttype?: number;\n\tminFilter?: number;\n\tmagFilter?: number;\n\twrapS?: number;\n\twrapT?: number;\n\tpreserveY?: boolean;\n}\ntype ResolvedTextureOptions = Required<Omit<TextureOptions, 'preserveY'>> & Pick<TextureOptions, 'preserveY'>;\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| 'resize'\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 | null;\n\tplugins?: Plugin[];\n\thistory?: number;\n\tdebug?: boolean;\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\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 isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate gl: WebGL2RenderingContext;\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 program: WebGLProgram | null = null;\n\tprivate aPositionLocation = 0;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: ReturnType<typeof setTimeout> = null as unknown as ReturnType<typeof setTimeout>;\n\tprivate lastResizeTime = -Infinity;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\tprivate frame = 0;\n\tprivate startTime = 0;\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 hooks: Map<LifecycleMethod, Function[]> = new Map();\n\tprivate historyDepth = 0;\n\tprivate textureOptions: TextureOptions;\n\tprivate debug: boolean;\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(fragmentShaderSrc: string, { canvas, plugins, history, debug, ...textureOptions }: Options = {}) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\t\thtmlCanvas.style.position = 'fixed';\n\t\t\thtmlCanvas.style.inset = '0';\n\t\t\thtmlCanvas.style.height = '100dvh';\n\t\t\thtmlCanvas.style.width = '100dvw';\n\t\t\tdocument.body.appendChild(htmlCanvas);\n\t\t}\n\t\tif (this.canvas instanceof OffscreenCanvas) {\n\t\t\tconst wrapDimension = (dimension: 'width' | 'height') => {\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype, dimension)!;\n\t\t\t\tObject.defineProperty(this.canvas, dimension, {\n\t\t\t\t\tget: () => descriptor.get!.call(this.canvas),\n\t\t\t\t\tset: v => {\n\t\t\t\t\t\tdescriptor.set!.call(this.canvas, v);\n\t\t\t\t\t\tthis.updateResolution();\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\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\n\t\tthis.textureUnitPool = {\n\t\t\tfree: [],\n\t\t\tnext: 0,\n\t\t\tmax: gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),\n\t\t};\n\t\tthis.textureOptions = textureOptions;\n\n\t\tconst { internalFormat, type } = textureOptions;\n\t\tconst isFloatFormat =\n\t\t\ttype === gl.FLOAT ||\n\t\t\ttype === gl.HALF_FLOAT ||\n\t\t\tinternalFormat === gl.RGBA16F ||\n\t\t\tinternalFormat === gl.RGBA32F ||\n\t\t\tinternalFormat === gl.R16F ||\n\t\t\tinternalFormat === gl.R32F ||\n\t\t\tinternalFormat === gl.RG16F ||\n\t\t\tinternalFormat === gl.RG32F;\n\t\tif (isFloatFormat && !gl.getExtension('EXT_color_buffer_float')) {\n\t\t\tconsole.warn('EXT_color_buffer_float not supported, falling back to RGBA8');\n\t\t\tdelete this.textureOptions?.internalFormat;\n\t\t\tdelete this.textureOptions?.format;\n\t\t\tdelete this.textureOptions?.type;\n\t\t}\n\n\t\tif (history) this.historyDepth = history;\n\t\tthis.debug = debug ?? (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production');\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\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.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.aPositionLocation = gl.getAttribLocation(program, 'aPosition');\n\t\tthis.buffer = gl.createBuffer();\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, QUAD_VERTICES, gl.STATIC_DRAW);\n\t\tgl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n\t\tgl.enableVertexAttribArray(this.aPositionLocation);\n\t\tgl.vertexAttribPointer(this.aPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\n\t\tgl.useProgram(program);\n\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\t\tthis.resizeObserver.observe(this.canvas);\n\t\t}\n\t\tif (!this.isInternalCanvas) {\n\t\t\tthis.updateResolution();\n\t\t}\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\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.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.addEventListeners();\n\t\t}\n\t\tthis.emitHook('init');\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 throttledHandleResize() {\n\t\tclearTimeout(this.resizeTimeout);\n\t\tconst now = performance.now();\n\t\tconst timeUntilNextResize = this.lastResizeTime + RESIZE_THROTTLE_INTERVAL - now;\n\t\tif (timeUntilNextResize <= 0) {\n\t\t\tthis.lastResizeTime = now;\n\t\t\tthis.handleResize();\n\t\t} else {\n\t\t\tthis.resizeTimeout = setTimeout(() => this.throttledHandleResize(), timeUntilNextResize);\n\t\t}\n\t}\n\n\tprivate handleResize() {\n\t\tif (!(this.canvas instanceof HTMLCanvasElement)) return;\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\t\tif (this.isInternalCanvas && (this.canvas.width !== width || this.canvas.height !== height)) {\n\t\t\tthis.canvas.width = width;\n\t\t\tthis.canvas.height = height;\n\t\t}\n\t\tthis.emitHook('resize', width, height);\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = htmlCanvas.getBoundingClientRect();\n\t\t\tthis.cursorPosition[0] = (x - rect.left) / rect.width;\n\t\t\tthis.cursorPosition[1] = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\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 = htmlCanvas.getBoundingClientRect();\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] = (xVal - rect.left) / rect.width;\n\t\t\t\tthis.clickPosition[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\thtmlCanvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\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 releaseTextureUnit(name: string | symbol) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) {\n\t\t\tthis.textureUnitPool.free.push(existing.unitIndex);\n\t\t}\n\t}\n\n\tprivate resolveTextureOptions(options?: TextureOptions): ResolvedTextureOptions {\n\t\tconst { gl } = this;\n\t\tconst type = options?.type ?? gl.UNSIGNED_BYTE;\n\t\treturn {\n\t\t\ttype,\n\t\t\tformat: options?.format ?? gl.RGBA,\n\t\t\tinternalFormat:\n\t\t\t\toptions?.internalFormat ??\n\t\t\t\t(type === gl.FLOAT ? gl.RGBA32F : type === gl.HALF_FLOAT ? gl.RGBA16F : gl.RGBA8),\n\t\t\tminFilter: options?.minFilter ?? gl.LINEAR,\n\t\t\tmagFilter: options?.magFilter ?? gl.LINEAR,\n\t\t\twrapS: options?.wrapS ?? gl.CLAMP_TO_EDGE,\n\t\t\twrapT: options?.wrapT ?? gl.CLAMP_TO_EDGE,\n\t\t\tpreserveY: options?.preserveY,\n\t\t};\n\t}\n\n\tprivate getPixelArray(type: number, size: number): ArrayBufferView {\n\t\treturn type === this.gl.FLOAT\n\t\t\t? new Float32Array(size)\n\t\t\t: type === this.gl.HALF_FLOAT\n\t\t\t? new Uint16Array(size)\n\t\t\t: new Uint8Array(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: 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\tthis.updateTexture(name, source);\n\n\t\t// Set a uniform to access the texture in the fragment shader.\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\tthis._initializeTexture(name, source, options);\n\t\tthis.emitHook('initializeTexture', ...arguments);\n\t}\n\n\tupdateTextures(updates: Record<string, UpdateTextureSource>, options?: { skipHistoryWrite?: boolean }) {\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 }\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\n\t\t\tif (source.gl === this.gl) {\n\t\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, sourceIntermediateInfo.texture);\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\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\t\t\t\tthis.gl.texSubImage3D(\n\t\t\t\t\tthis.gl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.history.writeIndex,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t1,\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\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\t\t\t\tconst frameOffsetUniformName = `${stringFrom(name)}FrameOffset`;\n\t\t\t\tthis.updateUniforms({ [frameOffsetUniformName]: info.history.writeIndex });\n\t\t\t\tinfo.history.writeIndex = (info.history.writeIndex + 1) % info.history.depth;\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\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\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\n\t\tgl.useProgram(this.program);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n\t\tgl.vertexAttribPointer(this.aPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\t\tgl.enableVertexAttribArray(this.aPositionLocation);\n\t\tgl.viewport(0, 0, w, h);\n\t\tif (!options?.skipClear) gl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tconst historyInfo = this.textures.get(HISTORY_TEXTURE_KEY);\n\t\tif (historyInfo && !options?.skipHistoryWrite) {\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyInfo.texture);\n\t\t\tgl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, historyInfo.history!.writeIndex, 0, 0, w, h);\n\t\t}\n\n\t\tgl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.intermediateFbo);\n\t\tgl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n\t\tgl.blitFramebuffer(0, 0, w, h, 0, 0, w, h, gl.COLOR_BUFFER_BIT, gl.NEAREST);\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\tthis.emitHook('afterDraw', ...arguments);\n\t}\n\n\tstep(time: number, options?: StepOptions) {\n\t\tthis.emitHook('beforeStep', ...arguments);\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\tthis.updateUniforms({ [`${stringFrom(HISTORY_TEXTURE_KEY)}FrameOffset`]: writeIndex });\n\t\t\thistoryInfo.history!.writeIndex = (writeIndex + 1) % depth;\n\t\t}\n\t\t++this.frame;\n\t\tthis.emitHook('afterStep', ...arguments);\n\t}\n\n\tplay(\n\t\tonStepComplete?: (time: number, frame: number) => void,\n\t\tsetStepOptions?: (time: number, frame: number) => StepOptions | void\n\t) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tconst options = setStepOptions?.(time, this.frame) ?? undefined;\n\t\t\tthis.step(time, options);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tonStepComplete?.(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\tthis.emitHook('play');\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t\tthis.emitHook('pause');\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\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.emitHook('reset');\n\t}\n\n\tdestroy() {\n\t\tthis.emitHook('destroy');\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\n\t\tthis.resolutionObserver.disconnect();\n\t\tthis.resizeObserver.disconnect();\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t\t});\n\t\t}\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\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.gl.deleteTexture(texture.texture);\n\t\t});\n\t\tthis.textureUnitPool.free = [];\n\t\tthis.textureUnitPool.next = 0;\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\tif (this.isInternalCanvas && this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n","import { TextureSource } from '..';\n\nexport const dummyTexture = { data: new Uint8Array(4), width: 1, height: 1 };\n\nexport type MediaPipeSource = HTMLVideoElement | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas;\n\nexport function isMediaPipeSource(source: TextureSource): source is MediaPipeSource {\n\treturn (\n\t\tsource instanceof HTMLVideoElement ||\n\t\tsource instanceof HTMLImageElement ||\n\t\tsource instanceof HTMLCanvasElement ||\n\t\tsource instanceof OffscreenCanvas\n\t);\n}\n\nexport function hashOptions(options: object): string {\n\treturn JSON.stringify(options, Object.keys(options).sort());\n}\n\nexport function calculateBoundingBoxCenter(\n\tdata: Float32Array,\n\tentityIdx: number,\n\tlandmarkIndices: readonly number[] | number[],\n\tlandmarkCount: number,\n\toffset: number = 0\n): [number, number, number, number] {\n\tlet minX = Infinity,\n\t\tmaxX = -Infinity,\n\t\tminY = Infinity,\n\t\tmaxY = -Infinity,\n\t\tavgZ = 0,\n\t\tavgVisibility = 0;\n\n\tfor (const idx of landmarkIndices) {\n\t\tconst dataIdx = (offset + entityIdx * landmarkCount + idx) * 4;\n\t\tconst x = data[dataIdx];\n\t\tconst y = data[dataIdx + 1];\n\t\tminX = Math.min(minX, x);\n\t\tmaxX = Math.max(maxX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxY = Math.max(maxY, y);\n\t\tavgZ += data[dataIdx + 2];\n\t\tavgVisibility += data[dataIdx + 3];\n\t}\n\n\treturn [\n\t\t(minX + maxX) / 2,\n\t\t(minY + maxY) / 2,\n\t\tavgZ / landmarkIndices.length,\n\t\tavgVisibility / landmarkIndices.length,\n\t];\n}\n\nlet filesetPromise: Promise<any> | null = null;\nexport function getSharedFileset(): Promise<any> {\n\tif (!filesetPromise) {\n\t\tfilesetPromise = import('@mediapipe/tasks-vision').then(({ FilesetResolver }) =>\n\t\t\tFilesetResolver.forVisionTasks(\n\t\t\t\t`https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${__MEDIAPIPE_TASKS_VISION_VERSION__}/wasm`\n\t\t\t)\n\t\t);\n\t}\n\treturn filesetPromise;\n}\n\nexport function generateGLSLFn(history: number | undefined) {\n\tconst historyParams = history ? ', framesAgo' : '';\n\tconst fn = history\n\t\t? (returnType: string, name: string, args: string, body: string) => {\n\t\t\t\tconst argsOnly = args.replace(/\\w+ /g, '');\n\t\t\t\tconst historyArgs = args ? `${args}, int framesAgo` : 'int framesAgo';\n\t\t\t\tconst callArgs = argsOnly ? `${argsOnly}, 0` : '0';\n\t\t\t\treturn `${returnType} ${name}(${historyArgs}) {\\n${body}\\n}\n${returnType} ${name}(${args}) { return ${name}(${callArgs}); }`;\n\t\t }\n\t\t: (returnType: string, name: string, args: string, body: string) =>\n\t\t\t\t`${returnType} ${name}(${args}) {\\n${body}\\n}`;\n\treturn { historyParams, fn };\n}\n"],"mappings":"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","names":["segmenter_exports","__export","segmenter_default","__toCommonJS","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","QUAD_VERTICES","HISTORY_TEXTURE_KEY","INTERMEDIATE_TEXTURE_KEY","combineShaderCode","shader","injections","lines","insertAt","line","trimmed","getSourceDimensions","source","ShaderPad","stringFrom","name","_ShaderPad","fragmentShaderSrc","canvas","plugins","history","debug","textureOptions","htmlCanvas","wrapDimension","dimension","descriptor","v","gl","internalFormat","type","glslInjections","plugin","code","program","vertexShader","fragmentShader","args","hook","fn","hooks","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","resolution","info","texture","existing","options","size","textureInfo","format","transparent","layer","value","arrayLength","location","probeValue","length","error","updates","newValue","uniform","glFunctionName","nValues","item","typedArray","newLocation","historyDepth","unitIndex","hasHistory","textureTarget","completeTextureInfo","uSampler","nonShaderPadSource","sourceIntermediateInfo","pixels","isPartial","shouldFlipY","previousFlipY","frameOffsetUniformName","partialSource","w","h","intermediateInfo","historyInfo","time","writeIndex","depth","onStepComplete","setStepOptions","loop","index_default","dummyTexture","isMediaPipeSource","source","hashOptions","options","filesetPromise","getSharedFileset","FilesetResolver","generateGLSLFn","history","returnType","name","args","body","argsOnly","historyArgs","callArgs","DEFAULT_SEGMENTER_OPTIONS","createMaskShaderSource","numMasks","uniforms","_","sampleByIndex","sharedDetectors","updateMaskCanvas","detector","confidenceMasks","shader","textures","m","segmenter","config","textureName","history","mediapipeOptions","options","optionsKey","hashOptions","shaderPad","context","injectGLSL","gl","emitHook","sharedCanvas","skipHistoryWrite","onResult","initializeDetector","mediaPipe","ImageSegmenter","getSharedFileset","imageSegmenter","labels","numCategories","maskShader","index_default","i","dummyTexture","initPromise","name","source","isMediaPipeSource","detectSegments","updates","nDetectionCalls","now","callOrder","requiredMode","shouldDetect","result","cb","fn","generateGLSLFn","sampleMask","segmenter_default"]}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import{a as
|
|
2
|
-
`),
|
|
1
|
+
import{a as C}from"../chunk-5CBGNOA3.mjs";import{a as _,b as v,c as I,e as O,f as E}from"../chunk-JRSBIGBN.mjs";var L={modelPath:"https://storage.googleapis.com/mediapipe-models/image_segmenter/hair_segmenter/float32/latest/hair_segmenter.tflite",outputCategoryMask:!1};function z(a){let r=Array.from({length:a},(c,n)=>`uniform sampler2D u_confidenceMask${n};`).join(`
|
|
2
|
+
`),s=Array.from({length:a},(c,n)=>` ${n>0?"else ":""}if (i == ${n}) c = texelFetch(u_confidenceMask${n}, texCoord, 0).r;`).join(`
|
|
3
3
|
`);return`#version 300 es
|
|
4
4
|
precision mediump float;
|
|
5
5
|
in vec2 v_uv;
|
|
6
6
|
out vec4 outColor;
|
|
7
|
-
${
|
|
7
|
+
${r}
|
|
8
8
|
|
|
9
9
|
void main() {
|
|
10
10
|
ivec2 texCoord = ivec2(v_uv * vec2(textureSize(u_confidenceMask0, 0)));
|
|
11
11
|
float maxConfidence = 0.0;
|
|
12
12
|
int maxIndex = 0;
|
|
13
13
|
|
|
14
|
-
for (int i = 0; i < ${a}; i
|
|
14
|
+
for (int i = 0; i < ${a}; ++i) {
|
|
15
15
|
float c = 0.0;
|
|
16
|
-
${
|
|
16
|
+
${s}
|
|
17
17
|
if (c > maxConfidence) {
|
|
18
18
|
maxConfidence = c;
|
|
19
19
|
maxIndex = i;
|
|
@@ -23,12 +23,12 @@ ${u}
|
|
|
23
23
|
// Normalize index: 0 = background, 1/(n-1) to 1 for foreground categories.
|
|
24
24
|
float normalizedIndex = float(maxIndex) / float(max(1, ${a-1}));
|
|
25
25
|
outColor = vec4(normalizedIndex, maxConfidence, 0.0, 1.0);
|
|
26
|
-
}`}function
|
|
27
|
-
|
|
26
|
+
}`}var M=new Map;function F(a,r){let{mask:{shader:s}}=a,c={};for(let n=0;n<r.length;++n)c[`u_confidenceMask${n}`]=r[n].getAsWebGLTexture();s.updateTextures(c),s.draw(),r.forEach(n=>n.close())}function R(a){let{textureName:r,options:{history:s,...c}={}}=a,n={...L,...c},f=I({...n,textureName:r});return function(m,P){let{injectGLSL:D,gl:h,emitHook:S}=P,x=M.get(f)?.canvas??new OffscreenCanvas(1,1),e=null,k=!1;function p(){e&&(m.updateTextures({u_segmentMask:e.canvas},{skipHistoryWrite:k}),S("segmenter:result",e.state.result))}async function $(){if(M.has(f))e=M.get(f);else{let[t,{ImageSegmenter:i}]=await Promise.all([O(),import("@mediapipe/tasks-vision")]),l=await i.createFromOptions(t,{baseOptions:{modelAssetPath:n.modelPath,delegate:"GPU"},canvas:x,runningMode:"VIDEO",outputCategoryMask:n.outputCategoryMask,outputConfidenceMasks:!0}),g=l.getLabels(),u=g.length||1,o=new C(z(u),{canvas:x});for(let d=0;d<u;++d)o.initializeTexture(`u_confidenceMask${d}`,_);e={segmenter:l,canvas:x,subscribers:new Map,state:{runningMode:"VIDEO",source:null,videoTime:-1,resultTimestamp:0,result:null,pending:Promise.resolve()},labels:g,numCategories:u,mask:{shader:o}},M.set(f,e)}e.subscribers.set(p,!1)}let b=$();m.on("init",()=>{m.initializeUniform("u_numCategories","int",1),m.initializeTexture("u_segmentMask",x,{preserveY:!0,minFilter:h.NEAREST,magFilter:h.NEAREST,history:s}),b.then(()=>{m.updateUniforms({u_numCategories:e.numCategories}),S("segmenter:ready")})}),m.on("initializeTexture",(t,i)=>{t===r&&v(i)&&y(i)}),m.on("updateTextures",(t,i)=>{let l=t[r];v(l)&&(k=i?.skipHistoryWrite??!1,y(l))});let T=0;async function y(t){let i=performance.now(),l=++T;await b,e&&(e.state.pending=e.state.pending.then(async()=>{if(l!==T||!e)return;let g=t instanceof HTMLVideoElement?"VIDEO":"IMAGE";e.state.runningMode!==g&&(e.state.runningMode=g,await e.segmenter.setOptions({runningMode:g}));let u=!1;if(t!==e.state.source?(e.state.source=t,e.state.videoTime=-1,u=!0):t instanceof HTMLVideoElement?t.currentTime!==e.state.videoTime&&(e.state.videoTime=t.currentTime,u=!0):t instanceof HTMLImageElement||i-e.state.resultTimestamp>2&&(u=!0),u){let o;if(t instanceof HTMLVideoElement){if(t.videoWidth===0||t.videoHeight===0||t.readyState<2)return;o=e.segmenter.segmentForVideo(t,i)}else{if(t.width===0||t.height===0)return;o=e.segmenter.segment(t)}if(o?.confidenceMasks&&o.confidenceMasks.length>0){e.state.resultTimestamp=i,e.state.result=o,F(e,o.confidenceMasks);for(let d of e.subscribers.keys())d(),e.subscribers.set(d,!0)}}else e.state.result&&!e.subscribers.get(p)&&(p(),e.subscribers.set(p,!0))}),await e.state.pending)}m.on("destroy",()=>{e&&(e.subscribers.delete(p),e.subscribers.size===0&&(e.segmenter.close(),e.mask.shader?.destroy(),M.delete(f))),e=null});let{fn:w}=E(s),A=s?`int layer = (u_segmentMaskFrameOffset - framesAgo + ${s}) % ${s};
|
|
27
|
+
vec4 mask = texture(u_segmentMask, vec3(pos, float(layer)));`:"vec4 mask = texture(u_segmentMask, pos);";D(`
|
|
28
|
+
uniform sampler2D${s?"Array":""} u_segmentMask;${s?`
|
|
29
|
+
uniform int u_segmentMaskFrameOffset;`:""}
|
|
28
30
|
uniform int u_numCategories;
|
|
29
31
|
|
|
30
|
-
vec2
|
|
31
|
-
|
|
32
|
-
return vec2(mask.r, mask.g);
|
|
33
|
-
}`)}}var P=w;export{P as default};
|
|
32
|
+
${w("vec2","segmentAt","vec2 pos",`${A}
|
|
33
|
+
return vec2(mask.r, mask.g);`)}`)}}var j=R;export{j as default};
|
|
34
34
|
//# sourceMappingURL=segmenter.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/segmenter.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '../index';\nimport type { ImageSegmenter, ImageSegmenterResult, MPMask } from '@mediapipe/tasks-vision';\n\nexport interface SegmenterPluginOptions {\n\tmodelPath?: string;\n\toutputCategoryMask?: boolean;\n\tonReady?: () => void;\n\tonResults?: (results: ImageSegmenterResult) => void;\n}\n\nconst dummyTexture = { data: new Uint8Array(4), width: 1, height: 1 };\n\nfunction createMaskShaderSource(numMasks: number): string {\n\tconst uniforms = Array.from({ length: numMasks }, (_, i) => `uniform sampler2D u_confidenceMask${i};`).join('\\n');\n\n\t// GLSL doesn't allow dynamic indexing of samplers, so we need a switch-like construct.\n\tconst sampleByIndex = Array.from(\n\t\t{ length: numMasks },\n\t\t(_, i) => `\\t\\t${i > 0 ? 'else ' : ''}if (i == ${i}) c = texelFetch(u_confidenceMask${i}, texCoord, 0).r;`\n\t).join('\\n');\n\n\treturn `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nout vec4 outColor;\n${uniforms}\n\nvoid main() {\n\tivec2 texCoord = ivec2(v_uv * vec2(textureSize(u_confidenceMask0, 0)));\n\tfloat maxConfidence = 0.0;\n\tint maxIndex = 0;\n\n\tfor (int i = 0; i < ${numMasks}; i++) {\n\t\tfloat c = 0.0;\n${sampleByIndex}\n\t\tif (c > maxConfidence) {\n\t\t\tmaxConfidence = c;\n\t\t\tmaxIndex = i;\n\t\t}\n\t}\n\n\t// Normalize index: 0 = background, 1/(n-1) to 1 for foreground categories.\n\tfloat normalizedIndex = float(maxIndex) / float(max(1, ${numMasks - 1}));\n\toutColor = vec4(normalizedIndex, maxConfidence, 0.0, 1.0);\n}`;\n}\n\nfunction segmenter(config: { textureName: string; options?: SegmenterPluginOptions }) {\n\tconst { textureName, options } = config;\n\tconst defaultModelPath =\n\t\t'https://storage.googleapis.com/mediapipe-models/image_segmenter/hair_segmenter/float32/latest/hair_segmenter.tflite';\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, gl } = context;\n\n\t\tlet imageSegmenter: ImageSegmenter | null = null;\n\t\tlet vision: any = null;\n\t\tlet lastVideoTime = -1;\n\t\tlet runningMode: 'IMAGE' | 'VIDEO' = 'VIDEO';\n\t\tconst textureSources = new Map<string, TextureSource>();\n\t\tlet numCategories = 1;\n\n\t\t// Shared canvas for MediaPipe and maskShader (same WebGL context).\n\t\tconst sharedCanvas = new OffscreenCanvas(1, 1);\n\t\tlet maskShader: ShaderPad | null = null;\n\t\tasync function initializeImageSegmenter() {\n\t\t\ttry {\n\t\t\t\tconst { FilesetResolver, ImageSegmenter } = await import('@mediapipe/tasks-vision');\n\t\t\t\tvision = await FilesetResolver.forVisionTasks(\n\t\t\t\t\t'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm'\n\t\t\t\t);\n\n\t\t\t\timageSegmenter = await ImageSegmenter.createFromOptions(vision, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options?.modelPath || defaultModelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\tcanvas: sharedCanvas,\n\t\t\t\t\trunningMode: runningMode,\n\t\t\t\t\toutputCategoryMask: options?.outputCategoryMask ?? false, // Better for perf, and category can be inferred from confidence mask index.\n\t\t\t\t\toutputConfidenceMasks: true,\n\t\t\t\t});\n\n\t\t\t\tconst labels = imageSegmenter.getLabels();\n\t\t\t\tif (labels.length) numCategories = labels.length;\n\t\t\t\tshaderPad.updateUniforms({ u_numCategories: numCategories });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Segmenter Plugin] Failed to initialize:', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tfunction updateMaskTexture(confidenceMasks: MPMask[]) {\n\t\t\tif (!maskShader) return;\n\n\t\t\tconst textures: Record<string, WebGLTexture> = {};\n\t\t\tfor (let i = 0; i < confidenceMasks.length; i++) {\n\t\t\t\ttextures[`u_confidenceMask${i}`] = confidenceMasks[i].getAsWebGLTexture();\n\t\t\t}\n\t\t\tmaskShader.updateTextures(textures);\n\t\t\tmaskShader.draw();\n\t\t\tshaderPad.updateTextures({ u_segmentMask: sharedCanvas });\n\t\t\tconfidenceMasks.forEach(mask => mask.close());\n\t\t}\n\n\t\tfunction processSegmenterResults(result: ImageSegmenterResult) {\n\t\t\tconst { confidenceMasks } = result;\n\t\t\tif (!confidenceMasks || confidenceMasks.length === 0) return;\n\n\t\t\t// IMPORTANT: maskShader and MediaPipe share a WebGL context. MediaPipe needs to run at least once before\n\t\t\t// ShaderPad is created on the same canvas, otherwise MediaPipe's WebGL state gets corrupted.\n\t\t\tif (!maskShader) {\n\t\t\t\tconst shaderSource = createMaskShaderSource(confidenceMasks.length);\n\t\t\t\tmaskShader = new ShaderPad(shaderSource, { canvas: sharedCanvas });\n\t\t\t\tfor (let i = 0; i < confidenceMasks.length; i++) {\n\t\t\t\t\tmaskShader.initializeTexture(`u_confidenceMask${i}`, dummyTexture);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateMaskTexture(confidenceMasks);\n\t\t\toptions?.onResults?.(result);\n\t\t}\n\n\t\tshaderPad.registerHook('init', async () => {\n\t\t\tshaderPad.initializeTexture('u_segmentMask', dummyTexture, {\n\t\t\t\tpreserveY: true,\n\t\t\t\tminFilter: gl.NEAREST,\n\t\t\t\tmagFilter: gl.NEAREST,\n\t\t\t});\n\t\t\tshaderPad.initializeUniform('u_numCategories', 'int', numCategories);\n\t\t\tawait initializeImageSegmenter();\n\t\t\toptions?.onReady?.();\n\t\t});\n\n\t\tshaderPad.registerHook('updateTextures', async (updates: Record<string, TextureSource>) => {\n\t\t\tconst source = updates[textureName];\n\t\t\tif (!source) return;\n\n\t\t\tconst previousSource = textureSources.get(textureName);\n\t\t\tif (previousSource !== source) {\n\t\t\t\tlastVideoTime = -1;\n\t\t\t}\n\n\t\t\ttextureSources.set(textureName, source);\n\t\t\tif (!imageSegmenter) return;\n\n\t\t\ttry {\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (runningMode !== requiredMode) {\n\t\t\t\t\trunningMode = requiredMode;\n\t\t\t\t\tawait imageSegmenter.setOptions({ runningMode: runningMode });\n\t\t\t\t}\n\n\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (source.currentTime !== lastVideoTime) {\n\t\t\t\t\t\tlastVideoTime = source.currentTime;\n\t\t\t\t\t\t// TODO: I think segmentForVideo runs its own animation loop maybe? args are (source, startTime, callbackForVideo).\n\t\t\t\t\t\tconst result = imageSegmenter.segmentForVideo(source, performance.now());\n\t\t\t\t\t\tprocessSegmenterResults(result);\n\t\t\t\t\t}\n\t\t\t\t} else if (source instanceof HTMLImageElement || source instanceof HTMLCanvasElement) {\n\t\t\t\t\tif (source.width === 0 || source.height === 0) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst result = imageSegmenter.segment(source);\n\t\t\t\t\tprocessSegmenterResults(result);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Segmenter Plugin] Segmentation error:', error);\n\t\t\t}\n\t\t});\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (imageSegmenter) {\n\t\t\t\timageSegmenter.close();\n\t\t\t\timageSegmenter = null;\n\t\t\t}\n\t\t\tif (maskShader) {\n\t\t\t\tmaskShader.destroy();\n\t\t\t\tmaskShader = null;\n\t\t\t}\n\t\t\tvision = null;\n\t\t\ttextureSources.clear();\n\t\t});\n\n\t\tinjectGLSL(`\nuniform sampler2D u_segmentMask;\nuniform int u_numCategories;\n\nvec2 segmentAt(vec2 pos) {\n\tvec4 mask = texture(u_segmentMask, pos);\n\treturn vec2(mask.r, mask.g);\n}`);\n\t};\n}\n\nexport default segmenter;\n"],"mappings":"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","names":["dummyTexture","createMaskShaderSource","numMasks","uniforms","_","i","sampleByIndex","segmenter","config","textureName","options","defaultModelPath","shaderPad","context","injectGLSL","gl","imageSegmenter","vision","lastVideoTime","runningMode","textureSources","numCategories","sharedCanvas","maskShader","initializeImageSegmenter","FilesetResolver","ImageSegmenter","labels","error","updateMaskTexture","confidenceMasks","textures","mask","processSegmenterResults","result","shaderSource","index_default","updates","source","requiredMode","segmenter_default"]}
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/segmenter.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '..';\nimport {\n\tgenerateGLSLFn,\n\tdummyTexture,\n\tgetSharedFileset,\n\thashOptions,\n\tisMediaPipeSource,\n\tMediaPipeSource,\n} from './mediapipe-common';\nimport type { ImageSegmenter, ImageSegmenterResult, MPMask } from '@mediapipe/tasks-vision';\n\nexport interface SegmenterPluginOptions {\n\tmodelPath?: string;\n\toutputCategoryMask?: boolean;\n\thistory?: number;\n}\n\nconst DEFAULT_SEGMENTER_OPTIONS: Required<Omit<SegmenterPluginOptions, 'history'>> = {\n\tmodelPath:\n\t\t'https://storage.googleapis.com/mediapipe-models/image_segmenter/hair_segmenter/float32/latest/hair_segmenter.tflite',\n\toutputCategoryMask: false,\n};\n\nfunction createMaskShaderSource(numMasks: number): string {\n\tconst uniforms = Array.from({ length: numMasks }, (_, i) => `uniform sampler2D u_confidenceMask${i};`).join('\\n');\n\n\tconst sampleByIndex = Array.from(\n\t\t{ length: numMasks },\n\t\t(_, i) => `\\t\\t${i > 0 ? 'else ' : ''}if (i == ${i}) c = texelFetch(u_confidenceMask${i}, texCoord, 0).r;`\n\t).join('\\n');\n\n\treturn `#version 300 es\nprecision mediump float;\nin vec2 v_uv;\nout vec4 outColor;\n${uniforms}\n\nvoid main() {\n\tivec2 texCoord = ivec2(v_uv * vec2(textureSize(u_confidenceMask0, 0)));\n\tfloat maxConfidence = 0.0;\n\tint maxIndex = 0;\n\n\tfor (int i = 0; i < ${numMasks}; ++i) {\n\t\tfloat c = 0.0;\n${sampleByIndex}\n\t\tif (c > maxConfidence) {\n\t\t\tmaxConfidence = c;\n\t\t\tmaxIndex = i;\n\t\t}\n\t}\n\n\t// Normalize index: 0 = background, 1/(n-1) to 1 for foreground categories.\n\tfloat normalizedIndex = float(maxIndex) / float(max(1, ${numMasks - 1}));\n\toutColor = vec4(normalizedIndex, maxConfidence, 0.0, 1.0);\n}`;\n}\n\ninterface SharedDetector {\n\tsegmenter: ImageSegmenter;\n\tcanvas: OffscreenCanvas;\n\tsubscribers: Map<() => void, boolean>;\n\tstate: {\n\t\trunningMode: 'IMAGE' | 'VIDEO';\n\t\tsource: MediaPipeSource | null;\n\t\tvideoTime: number;\n\t\tresultTimestamp: number;\n\t\tresult: ImageSegmenterResult | null;\n\t\tpending: Promise<void>;\n\t};\n\tlabels: string[];\n\tnumCategories: number;\n\tmask: {\n\t\tshader: ShaderPad;\n\t};\n}\nconst sharedDetectors = new Map<string, SharedDetector>();\n\nfunction updateMaskCanvas(detector: SharedDetector, confidenceMasks: MPMask[]) {\n\tconst {\n\t\tmask: { shader },\n\t} = detector;\n\n\tconst textures: Record<string, WebGLTexture> = {};\n\tfor (let i = 0; i < confidenceMasks.length; ++i) {\n\t\ttextures[`u_confidenceMask${i}`] = confidenceMasks[i].getAsWebGLTexture();\n\t}\n\tshader.updateTextures(textures);\n\tshader.draw();\n\tconfidenceMasks.forEach(m => m.close());\n}\n\nfunction segmenter(config: { textureName: string; options?: SegmenterPluginOptions }) {\n\tconst { textureName, options: { history, ...mediapipeOptions } = {} } = config;\n\tconst options = { ...DEFAULT_SEGMENTER_OPTIONS, ...mediapipeOptions };\n\tconst optionsKey = hashOptions({ ...options, textureName });\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL, gl, emitHook } = context;\n\n\t\tconst existingDetector = sharedDetectors.get(optionsKey);\n\t\tconst sharedCanvas = existingDetector?.canvas ?? new OffscreenCanvas(1, 1);\n\t\tlet detector: SharedDetector | null = null;\n\t\tlet skipHistoryWrite = false;\n\n\t\tfunction onResult() {\n\t\t\tif (!detector) return;\n\t\t\tshaderPad.updateTextures({ u_segmentMask: detector.canvas }, { skipHistoryWrite });\n\t\t\temitHook('segmenter:result', detector.state.result);\n\t\t}\n\n\t\tasync function initializeDetector() {\n\t\t\tif (sharedDetectors.has(optionsKey)) {\n\t\t\t\tdetector = sharedDetectors.get(optionsKey)!;\n\t\t\t} else {\n\t\t\t\tconst [mediaPipe, { ImageSegmenter }] = await Promise.all([\n\t\t\t\t\tgetSharedFileset(),\n\t\t\t\t\timport('@mediapipe/tasks-vision'),\n\t\t\t\t]);\n\t\t\t\t// Single shared canvas for MediaPipe and maskShader (same WebGL context required\n\t\t\t\t// because maskShader uses textures from MediaPipe via getAsWebGLTexture).\n\t\t\t\tconst imageSegmenter = await ImageSegmenter.createFromOptions(mediaPipe, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options.modelPath,\n\t\t\t\t\t\tdelegate: 'GPU',\n\t\t\t\t\t},\n\t\t\t\t\tcanvas: sharedCanvas,\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\toutputCategoryMask: options.outputCategoryMask,\n\t\t\t\t\toutputConfidenceMasks: true,\n\t\t\t\t});\n\n\t\t\t\tconst labels = imageSegmenter.getLabels();\n\t\t\t\tconst numCategories = labels.length || 1;\n\n\t\t\t\tconst maskShader = new ShaderPad(createMaskShaderSource(numCategories), { canvas: sharedCanvas });\n\t\t\t\tfor (let i = 0; i < numCategories; ++i) {\n\t\t\t\t\tmaskShader.initializeTexture(`u_confidenceMask${i}`, dummyTexture);\n\t\t\t\t}\n\n\t\t\t\tdetector = {\n\t\t\t\t\tsegmenter: imageSegmenter,\n\t\t\t\t\tcanvas: sharedCanvas,\n\t\t\t\t\tsubscribers: new Map(),\n\t\t\t\t\tstate: {\n\t\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\t\tsource: null,\n\t\t\t\t\t\tvideoTime: -1,\n\t\t\t\t\t\tresultTimestamp: 0,\n\t\t\t\t\t\tresult: null,\n\t\t\t\t\t\tpending: Promise.resolve(),\n\t\t\t\t\t},\n\t\t\t\t\tlabels,\n\t\t\t\t\tnumCategories,\n\t\t\t\t\tmask: {\n\t\t\t\t\t\tshader: maskShader,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tsharedDetectors.set(optionsKey, detector);\n\t\t\t}\n\n\t\t\tdetector!.subscribers.set(onResult, false);\n\t\t}\n\t\tconst initPromise = initializeDetector();\n\n\t\tshaderPad.on('init', () => {\n\t\t\tshaderPad.initializeUniform('u_numCategories', 'int', 1);\n\t\t\tshaderPad.initializeTexture('u_segmentMask', sharedCanvas, {\n\t\t\t\tpreserveY: true,\n\t\t\t\tminFilter: gl.NEAREST,\n\t\t\t\tmagFilter: gl.NEAREST,\n\t\t\t\thistory,\n\t\t\t});\n\t\t\tinitPromise.then(() => {\n\t\t\t\tshaderPad.updateUniforms({ u_numCategories: detector!.numCategories });\n\t\t\t\temitHook('segmenter:ready');\n\t\t\t});\n\t\t});\n\n\t\tshaderPad.on('initializeTexture', (name: string, source: TextureSource) => {\n\t\t\tif (name === textureName && isMediaPipeSource(source)) detectSegments(source);\n\t\t});\n\n\t\tshaderPad.on(\n\t\t\t'updateTextures',\n\t\t\t(updates: Record<string, TextureSource>, options?: { skipHistoryWrite?: boolean }) => {\n\t\t\t\tconst source = updates[textureName];\n\t\t\t\tif (isMediaPipeSource(source)) {\n\t\t\t\t\tskipHistoryWrite = options?.skipHistoryWrite ?? false;\n\t\t\t\t\tdetectSegments(source);\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tlet nDetectionCalls = 0;\n\t\tasync function detectSegments(source: MediaPipeSource) {\n\t\t\tconst now = performance.now();\n\t\t\tconst callOrder = ++nDetectionCalls;\n\t\t\tawait initPromise;\n\t\t\tif (!detector) return;\n\n\t\t\tdetector.state.pending = detector.state.pending.then(async () => {\n\t\t\t\tif (callOrder !== nDetectionCalls || !detector) return;\n\n\t\t\t\tconst requiredMode = source instanceof HTMLVideoElement ? 'VIDEO' : 'IMAGE';\n\t\t\t\tif (detector.state.runningMode !== requiredMode) {\n\t\t\t\t\tdetector.state.runningMode = requiredMode;\n\t\t\t\t\tawait detector.segmenter.setOptions({ runningMode: requiredMode });\n\t\t\t\t}\n\n\t\t\t\tlet shouldDetect = false;\n\n\t\t\t\tif (source !== detector.state.source) {\n\t\t\t\t\tdetector.state.source = source;\n\t\t\t\t\tdetector.state.videoTime = -1;\n\t\t\t\t\tshouldDetect = true;\n\t\t\t\t} else if (source instanceof HTMLVideoElement) {\n\t\t\t\t\tif (source.currentTime !== detector.state.videoTime) {\n\t\t\t\t\t\tdetector.state.videoTime = source.currentTime;\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (!(source instanceof HTMLImageElement)) {\n\t\t\t\t\tif (now - detector.state.resultTimestamp > 2) {\n\t\t\t\t\t\tshouldDetect = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (shouldDetect) {\n\t\t\t\t\tlet result: ImageSegmenterResult | undefined;\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.videoWidth === 0 || source.videoHeight === 0 || source.readyState < 2) return;\n\t\t\t\t\t\tresult = detector.segmenter.segmentForVideo(source, now);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (source.width === 0 || source.height === 0) return;\n\t\t\t\t\t\tresult = detector.segmenter.segment(source);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result?.confidenceMasks && result.confidenceMasks.length > 0) {\n\t\t\t\t\t\tdetector.state.resultTimestamp = now;\n\t\t\t\t\t\tdetector.state.result = result;\n\t\t\t\t\t\tupdateMaskCanvas(detector, result.confidenceMasks);\n\t\t\t\t\t\tfor (const cb of detector.subscribers.keys()) {\n\t\t\t\t\t\t\tcb();\n\t\t\t\t\t\t\tdetector.subscribers.set(cb, true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (detector.state.result && !detector.subscribers.get(onResult)) {\n\t\t\t\t\tonResult();\n\t\t\t\t\tdetector.subscribers.set(onResult, true);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tawait detector.state.pending;\n\t\t}\n\n\t\tshaderPad.on('destroy', () => {\n\t\t\tif (detector) {\n\t\t\t\tdetector.subscribers.delete(onResult);\n\t\t\t\tif (detector.subscribers.size === 0) {\n\t\t\t\t\tdetector.segmenter.close();\n\t\t\t\t\tdetector.mask.shader?.destroy();\n\t\t\t\t\tsharedDetectors.delete(optionsKey);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdetector = null;\n\t\t});\n\n\t\tconst { fn } = generateGLSLFn(history);\n\t\tconst sampleMask = history\n\t\t\t? `int layer = (u_segmentMaskFrameOffset - framesAgo + ${history}) % ${history};\n\tvec4 mask = texture(u_segmentMask, vec3(pos, float(layer)));`\n\t\t\t: `vec4 mask = texture(u_segmentMask, pos);`;\n\n\t\tinjectGLSL(`\nuniform sampler2D${history ? 'Array' : ''} u_segmentMask;${\n\t\t\thistory\n\t\t\t\t? `\nuniform int u_segmentMaskFrameOffset;`\n\t\t\t\t: ''\n\t\t}\nuniform int u_numCategories;\n\n${fn(\n\t'vec2',\n\t'segmentAt',\n\t'vec2 pos',\n\t`${sampleMask}\n\treturn vec2(mask.r, mask.g);`\n)}`);\n\t};\n}\n\nexport default segmenter;\n"],"mappings":"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","names":["DEFAULT_SEGMENTER_OPTIONS","createMaskShaderSource","numMasks","uniforms","_","i","sampleByIndex","sharedDetectors","updateMaskCanvas","detector","confidenceMasks","shader","textures","m","segmenter","config","textureName","history","mediapipeOptions","options","optionsKey","hashOptions","shaderPad","context","injectGLSL","gl","emitHook","sharedCanvas","skipHistoryWrite","onResult","initializeDetector","mediaPipe","ImageSegmenter","getSharedFileset","imageSegmenter","labels","numCategories","maskShader","index_default","dummyTexture","initPromise","name","source","isMediaPipeSource","detectSegments","updates","nDetectionCalls","now","callOrder","requiredMode","shouldDetect","result","cb","fn","generateGLSLFn","sampleMask","segmenter_default"]}
|
package/package.json
CHANGED
package/dist/chunk-6C6DVCZI.mjs
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
var x=`#version 300 es
|
|
2
|
-
in vec2 aPosition;
|
|
3
|
-
out vec2 v_uv;
|
|
4
|
-
void main() {
|
|
5
|
-
v_uv = aPosition * 0.5 + 0.5;
|
|
6
|
-
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
7
|
-
}
|
|
8
|
-
`,b=33.333333333333336,m=Symbol("u_history"),d=Symbol("__SHADERPAD_BUFFER");function v(l,e){if(!e?.length)return l;let t=l.split(`
|
|
9
|
-
`),s=t.findLastIndex(i=>{let r=i.trimStart();return r.startsWith("precision ")||r.startsWith("#version ")})+1;return t.splice(s,0,...e),t.join(`
|
|
10
|
-
`)}function T(l){return l instanceof WebGLTexture?{width:0,height:0}:l instanceof HTMLVideoElement?{width:l.videoWidth,height:l.videoHeight}:l instanceof HTMLImageElement?{width:l.naturalWidth??l.width,height:l.naturalHeight??l.height}:{width:l.width,height:l.height}}function f(l){return typeof l=="symbol"?l.description??"":l}var p=class{isInternalCanvas=!1;isTouchDevice=!1;gl;fragmentShaderSrc;uniforms=new Map;textures=new Map;textureUnitPool;buffer=null;program=null;aPositionLocation=0;animationFrameId;resolutionObserver;resizeObserver;resizeTimeout=null;lastResizeTime=-1/0;eventListeners=new Map;frame=0;startTime=0;cursorPosition=[.5,.5];clickPosition=[.5,.5];isMouseDown=!1;canvas;onResize;hooks=new Map;historyDepth=0;textureOptions;debug;intermediateFbo=null;constructor(e,{canvas:t,plugins:s,history:i,debug:r,...n}={}){if(this.canvas=t||document.createElement("canvas"),!t){this.isInternalCanvas=!0;let c=this.canvas;c.style.position="fixed",c.style.inset="0",c.style.height="100dvh",c.style.width="100dvw",document.body.appendChild(c)}if(this.gl=this.canvas.getContext("webgl2",{antialias:!1}),!this.gl)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.textureUnitPool={free:[],next:0,max:this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},this.textureOptions=n;let{internalFormat:o,type:u}=n;(u===this.gl.FLOAT||u===this.gl.HALF_FLOAT||o===this.gl.RGBA16F||o===this.gl.RGBA32F||o===this.gl.R16F||o===this.gl.R32F||o===this.gl.RG16F||o===this.gl.RG32F)&&!this.gl.getExtension("EXT_color_buffer_float")&&(console.warn("EXT_color_buffer_float not supported, falling back to RGBA8"),delete this.textureOptions?.internalFormat,delete this.textureOptions?.format,delete this.textureOptions?.type),i&&(this.historyDepth=i),this.debug=r??(typeof process<"u"&&!1),this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize());let a=[];if(s){let c={gl:this.gl,uniforms:this.uniforms,textures:this.textures,canvas:this.canvas,reserveTextureUnit:this.reserveTextureUnit.bind(this),releaseTextureUnit:this.releaseTextureUnit.bind(this),injectGLSL:g=>{a.push(g)}};Object.defineProperty(c,"program",{get:()=>this.program,enumerable:!0,configurable:!0}),s.forEach(g=>g(this,c))}this.fragmentShaderSrc=v(e,a),this.init(),this.canvas instanceof HTMLCanvasElement&&this.addEventListeners()}registerHook(e,t){this.hooks.has(e)||this.hooks.set(e,[]),this.hooks.get(e).push(t)}init(){let e=x;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let t=this.createShader(this.gl.VERTEX_SHADER,e),s=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,t),this.gl.attachShader(this.program,s),this.gl.linkProgram(this.program),this.gl.deleteShader(t),this.gl.deleteShader(s),!this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS))throw console.error("Program link error:",this.gl.getProgramInfoLog(this.program)),this.gl.deleteProgram(this.program),new Error("Failed to link WebGL program");this.aPositionLocation=this.gl.getAttribLocation(this.program,"aPosition"),this.setupBuffer(),this.gl.useProgram(this.program),this.canvas instanceof HTMLCanvasElement&&(this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]}),this.resizeObserver.observe(this.canvas)),this.isInternalCanvas||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.historyDepth>0&&(this._initializeTexture(d,this.canvas,{...this.textureOptions}),this._initializeTexture(m,this.canvas,{history:this.historyDepth,...this.textureOptions}),this.intermediateFbo=this.gl.createFramebuffer()),this.hooks.get("init")?.forEach(i=>i.call(this))}createShader(e,t){let s=this.gl.createShader(e);if(this.gl.shaderSource(s,t),this.gl.compileShader(s),!this.gl.getShaderParameter(s,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",t),console.error(this.gl.getShaderInfoLog(s)),this.gl.deleteShader(s),new Error("Shader compilation failed");return s}setupBuffer(){let e=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]);this.buffer=this.gl.createBuffer(),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.buffer),this.gl.bufferData(this.gl.ARRAY_BUFFER,e,this.gl.STATIC_DRAW),this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.gl.enableVertexAttribArray(this.aPositionLocation),this.gl.vertexAttribPointer(this.aPositionLocation,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let e=performance.now(),t=this.lastResizeTime+b-e;t<=0?(this.lastResizeTime=e,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),t)}handleResize(){if(!(this.canvas instanceof HTMLCanvasElement))return;let e=window.devicePixelRatio||1,t=this.canvas.clientWidth*e,s=this.canvas.clientHeight*e;this.isInternalCanvas&&(this.canvas.width!==t||this.canvas.height!==s)&&(this.canvas.width=t,this.canvas.height=s),this.onResize?.(t,s)}addEventListeners(){let e=this.canvas,t=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let n=e.getBoundingClientRect();this.cursorPosition[0]=(i-n.left)/n.width,this.cursorPosition[1]=1-(r-n.top)/n.height,this.updateUniforms({u_cursor:this.cursorPosition})},s=(i,r,n)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let o=e.getBoundingClientRect(),u=r,h=n;this.clickPosition[0]=(u-o.left)/o.width,this.clickPosition[1]=1-(h-o.top)/o.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,s(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&s(!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),s(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&s(!1)}),this.eventListeners.forEach((i,r)=>{e.addEventListener(r,i)})}updateResolution(){let e=[this.gl.drawingBufferWidth,this.gl.drawingBufferHeight];this.gl.viewport(0,0,...e),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:e}):this.initializeUniform("u_resolution","float",e),this.historyDepth>0&&(this.resizeTexture(m,...e),this.resizeTexture(d,...e)),this.hooks.get("updateResolution")?.forEach(t=>t.call(this))}resizeTexture(e,t,s){let i=this.textures.get(e);if(!i||i.width===t&&i.height===s)return;this.gl.deleteTexture(i.texture),i.width=t,i.height=s;let{texture:r}=this.createTexture(e,i);i.texture=r,i.history&&(i.history.writeIndex=0,this.clearHistoryTextureLayers(i))}reserveTextureUnit(e){let t=this.textures.get(e);if(t)return t.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++}releaseTextureUnit(e){let t=this.textures.get(e);t&&this.textureUnitPool.free.push(t.unitIndex)}resolveTextureOptions(e){let{gl:t}=this,s=e?.type??t.UNSIGNED_BYTE;return{type:s,format:e?.format??t.RGBA,internalFormat:e?.internalFormat??(s===t.FLOAT?t.RGBA32F:s===t.HALF_FLOAT?t.RGBA16F:t.RGBA8),minFilter:e?.minFilter??t.LINEAR,magFilter:e?.magFilter??t.LINEAR,wrapS:e?.wrapS??t.CLAMP_TO_EDGE,wrapT:e?.wrapT??t.CLAMP_TO_EDGE,preserveY:e?.preserveY}}clearHistoryTextureLayers(e){if(!e.history)return;let t=this.gl,{type:s,format:i}=e.options,r=e.width*e.height*4,n=s===t.FLOAT?new Float32Array(r):s===t.HALF_FLOAT?new Uint16Array(r):new Uint8Array(r);t.activeTexture(t.TEXTURE0+e.unitIndex),t.bindTexture(t.TEXTURE_2D_ARRAY,e.texture);for(let o=0;o<e.history.depth;++o)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,o,e.width,e.height,1,i,s,n)}initializeUniform(e,t,s,i){let r=i?.arrayLength;if(this.uniforms.has(e))throw new Error(`${e} is already initialized.`);if(t!=="float"&&t!=="int")throw new Error(`Invalid uniform type: ${t}. Expected 'float' or 'int'.`);if(r&&!(Array.isArray(s)&&s.length===r))throw new Error(`${e} array length mismatch: must initialize with ${r} elements.`);let n=this.gl.getUniformLocation(this.program,e);if(!n&&r&&(n=this.gl.getUniformLocation(this.program,`${e}[0]`)),!n){this.log(`${e} not found in fragment shader. Skipping initialization.`);return}let o=r?s[0]:s,u=Array.isArray(o)?o.length:1;this.uniforms.set(e,{type:t,length:u,location:n,arrayLength:r});try{this.updateUniforms({[e]:s})}catch(h){throw this.uniforms.delete(e),h}this.hooks.get("initializeUniform")?.forEach(h=>h.call(this,...arguments))}log(...e){this.debug&&console.debug(...e)}updateUniforms(e,t){this.gl.useProgram(this.program),Object.entries(e).forEach(([s,i])=>{let r=this.uniforms.get(s);if(!r){this.log(`${s} not found in fragment shader. Skipping update.`);return}let n=`uniform${r.length}${r.type.charAt(0)}`;if(r.arrayLength){if(!Array.isArray(i))throw new Error(`${s} is an array, but the value passed to updateUniforms is not an array.`);let o=i.length;if(!o)return;if(o>r.arrayLength)throw new Error(`${s} received ${o} values, but maximum length is ${r.arrayLength}.`);if(i.some(a=>(Array.isArray(a)?a.length:1)!==r.length))throw new Error(`Tried to update ${s} with some elements that are not length ${r.length}.`);let u=new(r.type==="float"?Float32Array:Int32Array)(i.flat()),h=r.location;if(t?.startIndex){let a=this.gl.getUniformLocation(this.program,`${s}[${t.startIndex}]`);if(!a)throw new Error(`${s}[${t.startIndex}] not found in fragment shader. Did you pass an invalid startIndex?`);h=a}this.gl[n+"v"](h,u)}else{if(Array.isArray(i)||(i=[i]),i.length!==r.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${r.length}.`);this.gl[n](r.location,...i)}}),this.hooks.get("updateUniforms")?.forEach(s=>s.call(this,...arguments))}createTexture(e,t){let{width:s,height:i}=t,r=t.history?.depth??0,n=this.gl.createTexture();if(!n)throw new Error("Failed to create texture");let o=t.unitIndex;if(typeof o!="number")try{o=this.reserveTextureUnit(e)}catch(c){throw this.gl.deleteTexture(n),c}let u=r>0,h=u?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:a}=t;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(h,n),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_S,a.wrapS),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_T,a.wrapT),this.gl.texParameteri(h,this.gl.TEXTURE_MIN_FILTER,a.minFilter),this.gl.texParameteri(h,this.gl.TEXTURE_MAG_FILTER,a.magFilter),u?this.gl.texStorage3D(h,1,a.internalFormat,s,i,r):e===d&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,a.internalFormat,s,i,0,a.format,a.type,null),{texture:n,unitIndex:o}}_initializeTexture(e,t,s){if(this.textures.has(e))throw new Error(`Texture '${f(e)}' is already initialized.`);let{history:i=0,...r}=s??{},{width:n,height:o}=T(t);if(!n||!o)throw new Error("Texture source must have valid dimensions");let u={width:n,height:o,options:this.resolveTextureOptions(r)};i>0&&(u.history={depth:i,writeIndex:0});let{texture:h,unitIndex:a}=this.createTexture(e,u),c={texture:h,unitIndex:a,...u};i>0&&(this.initializeUniform(`${f(e)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(c)),this.textures.set(e,c),this.updateTexture(e,t);let g=this.gl.getUniformLocation(this.program,f(e));g&&this.gl.uniform1i(g,a)}initializeTexture(e,t,s){this._initializeTexture(e,t,s),this.hooks.get("initializeTexture")?.forEach(i=>i.call(this,...arguments))}updateTextures(e,t){this.hooks.get("updateTextures")?.forEach(s=>s.call(this,...arguments)),Object.entries(e).forEach(([s,i])=>{this.updateTexture(s,i,t)})}updateTexture(e,t,s){let i=this.textures.get(e);if(!i)throw new Error(`Texture '${f(e)}' is not initialized.`);if(t instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,t);return}let{width:r,height:n}=T(t);if(!r||!n)return;let o="isPartial"in t&&t.isPartial;o||this.resizeTexture(e,r,n);let h=!("data"in t&&t.data)&&!i.options?.preserveY,a=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(i.history){if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture),!s?.skipHistoryWrite){this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,h),this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,i.history.writeIndex,r,n,1,i.options.format,i.options.type,t.data??t),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,a);let c=`${f(e)}FrameOffset`;this.updateUniforms({[c]:i.history.writeIndex}),i.history.writeIndex=(i.history.writeIndex+1)%i.history.depth}}else this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,i.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,h),o?this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,t.x??0,t.y??0,r,n,i.options.format,i.options.type,t.data):this.gl.texImage2D(this.gl.TEXTURE_2D,0,i.options.internalFormat,r,n,0,i.options.format,i.options.type,t.data??t),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,a)}draw(e){let t=this.gl,s=t.drawingBufferWidth,i=t.drawingBufferHeight,r=this.textures.get(m),n=this.textures.get(d),o=r&&!e?.skipHistoryWrite;o&&(t.bindFramebuffer(t.FRAMEBUFFER,this.intermediateFbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,n.texture,0)),t.useProgram(this.program),t.bindBuffer(t.ARRAY_BUFFER,this.buffer),t.vertexAttribPointer(this.aPositionLocation,2,t.FLOAT,!1,0,0),t.enableVertexAttribArray(this.aPositionLocation),t.viewport(0,0,s,i),e?.skipClear||t.clear(t.COLOR_BUFFER_BIT),t.drawArrays(t.TRIANGLES,0,6),o&&(t.bindTexture(t.TEXTURE_2D_ARRAY,r.texture),t.copyTexSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,r.history.writeIndex,0,0,s,i),t.bindFramebuffer(t.READ_FRAMEBUFFER,this.intermediateFbo),t.bindFramebuffer(t.DRAW_FRAMEBUFFER,null),t.blitFramebuffer(0,0,s,i,0,0,s,i,t.COLOR_BUFFER_BIT,t.NEAREST),t.bindFramebuffer(t.FRAMEBUFFER,null))}step(e,t){let s={};this.uniforms.has("u_time")&&(s.u_time=e),this.uniforms.has("u_frame")&&(s.u_frame=this.frame),this.updateUniforms(s),this.hooks.get("step")?.forEach(r=>r.call(this,e,this.frame)),this.draw(t);let i=this.textures.get(m);if(i&&!t?.skipHistoryWrite){let{writeIndex:r,depth:n}=i.history;this.updateUniforms({[`${f(m)}FrameOffset`]:r}),i.history.writeIndex=(r+1)%n}this.hooks.get("afterStep")?.forEach(r=>r.call(this,e,this.frame)),++this.frame}play(e,t){this.pause();let s=i=>{i=(i-this.startTime)/1e3;let r=t?.(i,this.frame)??void 0;this.step(i,r),this.animationFrameId=requestAnimationFrame(s),e?.(i,this.frame)};this.animationFrameId=requestAnimationFrame(s)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.textures.forEach(e=>{e.history&&(e.history.writeIndex=0,this.clearHistoryTextureLayers(e))}),this.hooks.get("reset")?.forEach(e=>e.call(this))}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),this.canvas instanceof HTMLCanvasElement&&this.eventListeners.forEach((e,t)=>{this.canvas.removeEventListener(t,e)}),this.program&&this.gl.deleteProgram(this.program),this.intermediateFbo&&(this.gl.deleteFramebuffer(this.intermediateFbo),this.intermediateFbo=null),this.textures.forEach(e=>{this.gl.deleteTexture(e.texture)}),this.textureUnitPool.free=[],this.textureUnitPool.next=0,this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.hooks.get("destroy")?.forEach(e=>e.call(this)),this.isInternalCanvas&&this.canvas instanceof HTMLCanvasElement&&this.canvas.remove()}},E=p;export{E as a};
|
|
11
|
-
//# sourceMappingURL=chunk-6C6DVCZI.mjs.map
|