{"version":3,"file":"BaseFilter.min.mjs","names":[],"sources":["../../../src/filters/BaseFilter.ts"],"sourcesContent":["import { getEnv } from '../env';\nimport type {\n  T2DPipelineState,\n  TWebGLAttributeLocationMap,\n  TWebGLPipelineState,\n  TWebGLProgramCacheItem,\n  TWebGLUniformLocationMap,\n} from './typedefs';\nimport { isWebGLPipelineState } from './utils';\nimport {\n  highPsourceCode,\n  identityFragmentShader,\n  vertexSource,\n} from './shaders/baseFilter';\nimport type { Abortable } from '../typedefs';\nimport { FabricError } from '../util/internals/console';\nimport { createCanvasElementFor } from '../util/misc/dom';\n\nconst regex = new RegExp(highPsourceCode, 'g');\n\nexport class BaseFilter<\n  Name extends string,\n  OwnProps extends Record<string, any> = object,\n  SerializedProps extends Record<string, any> = OwnProps,\n> {\n  /**\n   * Filter type\n   */\n  get type(): Name {\n    return (this.constructor as typeof BaseFilter).type as Name;\n  }\n\n  /**\n   * The class type. Used to identify which class this is.\n   * This is used for serialization purposes and internally it can be used\n   * to identify classes. As a developer you could use `instance of Class`\n   * but to avoid importing all the code and blocking tree shaking we try\n   * to avoid doing that.\n   */\n  static type = 'BaseFilter';\n\n  /**\n   * Contains the uniform locations for the fragment shader.\n   * uStepW and uStepH are handled by the BaseFilter, each filter class\n   * needs to specify all the one that are needed\n   */\n  static uniformLocations: string[] = [];\n\n  declare static defaults: Record<string, unknown>;\n\n  /**\n   * Constructor\n   * @param {Object} [options] Options object\n   */\n  constructor({\n    type,\n    ...options\n  }: { type?: never } & Partial<OwnProps> & Record<string, any> = {}) {\n    Object.assign(\n      this,\n      (this.constructor as typeof BaseFilter).defaults,\n      options,\n    );\n  }\n\n  protected getFragmentSource(): string {\n    return identityFragmentShader;\n  }\n\n  getVertexSource(): string {\n    return vertexSource;\n  }\n\n  /**\n   * Compile this filter's shader program.\n   *\n   * @param {WebGLRenderingContext} gl The GL canvas context to use for shader compilation.\n   * @param {String} fragmentSource fragmentShader source for compilation\n   * @param {String} vertexSource vertexShader source for compilation\n   */\n  createProgram(\n    gl: WebGLRenderingContext,\n    fragmentSource: string = this.getFragmentSource(),\n    vertexSource: string = this.getVertexSource(),\n  ) {\n    const {\n      WebGLProbe: { GLPrecision = 'highp' },\n    } = getEnv();\n    if (GLPrecision !== 'highp') {\n      fragmentSource = fragmentSource.replace(\n        regex,\n        highPsourceCode.replace('highp', GLPrecision),\n      );\n    }\n    const vertexShader = gl.createShader(gl.VERTEX_SHADER);\n    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n    const program = gl.createProgram();\n\n    if (!vertexShader || !fragmentShader || !program) {\n      throw new FabricError(\n        'Vertex, fragment shader or program creation error',\n      );\n    }\n    gl.shaderSource(vertexShader, vertexSource);\n    gl.compileShader(vertexShader);\n    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {\n      throw new FabricError(\n        `Vertex shader compile error for ${this.type}: ${gl.getShaderInfoLog(\n          vertexShader,\n        )}`,\n      );\n    }\n\n    gl.shaderSource(fragmentShader, fragmentSource);\n    gl.compileShader(fragmentShader);\n    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {\n      throw new FabricError(\n        `Fragment shader compile error for ${this.type}: ${gl.getShaderInfoLog(\n          fragmentShader,\n        )}`,\n      );\n    }\n\n    gl.attachShader(program, vertexShader);\n    gl.attachShader(program, fragmentShader);\n    gl.linkProgram(program);\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n      throw new FabricError(\n        `Shader link error for \"${this.type}\" ${gl.getProgramInfoLog(program)}`,\n      );\n    }\n\n    const uniformLocations = this.getUniformLocations(gl, program) || {};\n    uniformLocations.uStepW = gl.getUniformLocation(program, 'uStepW');\n    uniformLocations.uStepH = gl.getUniformLocation(program, 'uStepH');\n\n    return {\n      program,\n      attributeLocations: this.getAttributeLocations(gl, program),\n      uniformLocations,\n    };\n  }\n\n  /**\n   * Return a map of attribute names to WebGLAttributeLocation objects.\n   *\n   * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n   * @param {WebGLShaderProgram} program The shader program from which to take attribute locations.\n   * @returns {Object} A map of attribute names to attribute locations.\n   */\n  getAttributeLocations(\n    gl: WebGLRenderingContext,\n    program: WebGLProgram,\n  ): TWebGLAttributeLocationMap {\n    return {\n      aPosition: gl.getAttribLocation(program, 'aPosition'),\n    };\n  }\n\n  /**\n   * Return a map of uniform names to WebGLUniformLocation objects.\n   *\n   * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n   * @param {WebGLShaderProgram} program The shader program from which to take uniform locations.\n   * @returns {Object} A map of uniform names to uniform locations.\n   */\n  getUniformLocations(\n    gl: WebGLRenderingContext,\n    program: WebGLProgram,\n  ): TWebGLUniformLocationMap {\n    const locations = (this.constructor as unknown as typeof BaseFilter<string>)\n      .uniformLocations;\n\n    const uniformLocations: Record<string, WebGLUniformLocation | null> = {};\n    for (let i = 0; i < locations.length; i++) {\n      uniformLocations[locations[i]] = gl.getUniformLocation(\n        program,\n        locations[i],\n      );\n    }\n    return uniformLocations;\n  }\n\n  /**\n   * Send attribute data from this filter to its shader program on the GPU.\n   *\n   * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n   * @param {Object} attributeLocations A map of shader attribute names to their locations.\n   */\n  sendAttributeData(\n    gl: WebGLRenderingContext,\n    attributeLocations: Record<string, number>,\n    aPositionData: Float32Array,\n  ) {\n    const attributeLocation = attributeLocations.aPosition;\n    const buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.enableVertexAttribArray(attributeLocation);\n    gl.vertexAttribPointer(attributeLocation, 2, gl.FLOAT, false, 0, 0);\n    gl.bufferData(gl.ARRAY_BUFFER, aPositionData, gl.STATIC_DRAW);\n  }\n\n  _setupFrameBuffer(options: TWebGLPipelineState) {\n    const gl = options.context;\n    if (options.passes > 1) {\n      const width = options.destinationWidth;\n      const height = options.destinationHeight;\n      if (options.sourceWidth !== width || options.sourceHeight !== height) {\n        gl.deleteTexture(options.targetTexture);\n        options.targetTexture = options.filterBackend.createTexture(\n          gl,\n          width,\n          height,\n        );\n      }\n      gl.framebufferTexture2D(\n        gl.FRAMEBUFFER,\n        gl.COLOR_ATTACHMENT0,\n        gl.TEXTURE_2D,\n        options.targetTexture,\n        0,\n      );\n    } else {\n      // draw last filter on canvas and not to framebuffer.\n      gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n      gl.finish();\n    }\n  }\n\n  _swapTextures(options: TWebGLPipelineState) {\n    options.passes--;\n    options.pass++;\n    const temp = options.targetTexture;\n    options.targetTexture = options.sourceTexture;\n    options.sourceTexture = temp;\n  }\n\n  /**\n   * Generic isNeutral implementation for one parameter based filters.\n   * Used only in image applyFilters to discard filters that will not have an effect\n   * on the image\n   * Other filters may need their own version ( ColorMatrix, HueRotation, gamma, ComposedFilter )\n   * @param {Object} options\n   **/\n  // eslint-disable-next-line @typescript-eslint/no-unused-vars\n  isNeutralState(options?: any): boolean {\n    return false;\n  }\n\n  /**\n   * Apply this filter to the input image data provided.\n   *\n   * Determines whether to use WebGL or Canvas2D based on the options.webgl flag.\n   *\n   * @param {Object} options\n   * @param {Number} options.passes The number of filters remaining to be executed\n   * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n   * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n   * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n   * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n   * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n   */\n  applyTo(options: TWebGLPipelineState | T2DPipelineState) {\n    if (isWebGLPipelineState(options)) {\n      this._setupFrameBuffer(options);\n      this.applyToWebGL(options);\n      this._swapTextures(options);\n    } else {\n      this.applyTo2d(options);\n    }\n  }\n\n  applyTo2d(_options: T2DPipelineState): void {\n    // override by subclass\n  }\n\n  /**\n   * Returns a string that represent the current selected shader code for the filter.\n   * Used to force recompilation when parameters change or to retrieve the shader from cache\n   * @type string\n   **/\n  getCacheKey(): string {\n    return this.type;\n  }\n\n  /**\n   * Retrieves the cached shader.\n   * @param {Object} options\n   * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n   * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n   * @return {WebGLProgram} the compiled program shader\n   */\n  retrieveShader(options: TWebGLPipelineState): TWebGLProgramCacheItem {\n    const key = this.getCacheKey();\n    if (!options.programCache[key]) {\n      options.programCache[key] = this.createProgram(options.context);\n    }\n    return options.programCache[key];\n  }\n\n  /**\n   * Apply this filter using webgl.\n   *\n   * @param {Object} options\n   * @param {Number} options.passes The number of filters remaining to be executed\n   * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n   * @param {WebGLTexture} options.originalTexture The texture of the original input image.\n   * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n   * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n   * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n   * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n   */\n  applyToWebGL(options: TWebGLPipelineState) {\n    const gl = options.context;\n    const shader = this.retrieveShader(options);\n    if (options.pass === 0 && options.originalTexture) {\n      gl.bindTexture(gl.TEXTURE_2D, options.originalTexture);\n    } else {\n      gl.bindTexture(gl.TEXTURE_2D, options.sourceTexture);\n    }\n    gl.useProgram(shader.program);\n    this.sendAttributeData(gl, shader.attributeLocations, options.aPosition);\n\n    gl.uniform1f(shader.uniformLocations.uStepW, 1 / options.sourceWidth);\n    gl.uniform1f(shader.uniformLocations.uStepH, 1 / options.sourceHeight);\n\n    this.sendUniformData(gl, shader.uniformLocations);\n    gl.viewport(0, 0, options.destinationWidth, options.destinationHeight);\n    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n  }\n\n  bindAdditionalTexture(\n    gl: WebGLRenderingContext,\n    texture: WebGLTexture,\n    textureUnit: number,\n  ) {\n    gl.activeTexture(textureUnit);\n    gl.bindTexture(gl.TEXTURE_2D, texture);\n    // reset active texture to 0 as usual\n    gl.activeTexture(gl.TEXTURE0);\n  }\n\n  unbindAdditionalTexture(gl: WebGLRenderingContext, textureUnit: number) {\n    gl.activeTexture(textureUnit);\n    gl.bindTexture(gl.TEXTURE_2D, null);\n    gl.activeTexture(gl.TEXTURE0);\n  }\n\n  /**\n   * Send uniform data from this filter to its shader program on the GPU.\n   *\n   * Intended to be overridden by subclasses.\n   *\n   * @param {WebGLRenderingContext} _gl The canvas context used to compile the shader program.\n   * @param {Object} _uniformLocations A map of shader uniform names to their locations.\n   */\n  sendUniformData(\n    _gl: WebGLRenderingContext,\n    _uniformLocations: TWebGLUniformLocationMap,\n  ): void {\n    // override by subclass\n  }\n\n  /**\n   * If needed by a 2d filter, this functions can create an helper canvas to be used\n   * remember that options.targetCanvas is available for use till end of chain.\n   */\n  createHelpLayer(options: T2DPipelineState) {\n    if (!options.helpLayer) {\n      const { sourceWidth, sourceHeight } = options;\n      const helpLayer = createCanvasElementFor({\n        width: sourceWidth,\n        height: sourceHeight,\n      });\n      options.helpLayer = helpLayer;\n    }\n  }\n\n  /**\n   * Returns object representation of an instance\n   * It will automatically export the default values of a filter,\n   * stored in the static defaults property.\n   * @return {Object} Object representation of an instance\n   */\n  toObject(): { type: Name } & SerializedProps {\n    const defaultKeys = Object.keys(\n      (this.constructor as typeof BaseFilter).defaults || {},\n    ) as (keyof SerializedProps)[];\n\n    return {\n      type: this.type,\n      ...defaultKeys.reduce((acc, key) => {\n        acc[key] = this[\n          key as keyof this\n        ] as unknown as (typeof acc)[typeof key];\n        return acc;\n      }, {} as SerializedProps),\n    };\n  }\n\n  /**\n   * Returns a JSON representation of an instance\n   * @return {Object} JSON\n   */\n  toJSON() {\n    // delegate, not alias\n    return this.toObject();\n  }\n\n  static async fromObject(\n    { type, ...filterOptions }: Record<string, any>,\n    _options?: Abortable,\n  ): Promise<BaseFilter<string>> {\n    return new this(filterOptions);\n  }\n}\n"],"mappings":"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"}