{"version":3,"file":"apply-crt-filter.mjs","names":[],"sources":["../../src/helpers/apply-crt-filter.ts"],"sourcesContent":["import createContext from 'gl';\nimport { createCrtFromContext, type CrtRenderer } from '@4bitlabs/crt-lite';\nimport type { ImageDataLike } from '@4bitlabs/image';\n\nconst DEFAULT_CRT_OPTIONS = {\n  Fx: -0.025,\n  Fy: -0.035,\n  S: 0.995,\n  hBlur: 2.5,\n  grain: 0,\n  vignette: 1.0,\n  scanLines: true,\n};\n\nfunction readPixels(\n  gl: WebGL2RenderingContext,\n  width: number,\n  height: number,\n): ImageDataLike {\n  const stride = width * 4;\n\n  const pixels = new Uint8ClampedArray(stride * height);\n  gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);\n\n  const flippedPixels = new Uint8ClampedArray(width * height * 4);\n  for (\n    let src = 0, dst = (height - 1) * stride;\n    src < stride * height;\n    src += stride, dst -= stride\n  ) {\n    flippedPixels.set(pixels.subarray(src, src + stride), dst);\n  }\n\n  return {\n    width,\n    height,\n    data: flippedPixels,\n  };\n}\n\nexport function optionalDeferredCrtFilter(enabled: boolean) {\n  if (!enabled) return (source: ImageDataLike) => source;\n\n  let gl: WebGL2RenderingContext | null = null;\n  let renderer: CrtRenderer | null = null;\n\n  return (source: ImageDataLike) => {\n    const { width, height } = source;\n\n    /* init */\n    if (gl === null) {\n      gl = createContext(width, height, {\n        preserveDrawingBuffer: false,\n        createWebGL2Context: true,\n      });\n    }\n    if (renderer === null) {\n      renderer = createCrtFromContext(gl, width, height);\n    }\n\n    renderer.update(source, DEFAULT_CRT_OPTIONS);\n    return readPixels(gl, width, height);\n  };\n}\n\nexport function crtFilter(source: ImageDataLike): ImageDataLike {\n  const { width, height } = source;\n\n  const gl = createContext(width, height, {\n    preserveDrawingBuffer: true,\n    createWebGL2Context: true,\n  });\n\n  const { update } = createCrtFromContext(gl, width, height);\n  update(source, DEFAULT_CRT_OPTIONS);\n  return readPixels(gl, width, height);\n}\n"],"mappings":";;;AAIA,MAAM,sBAAsB;CAC1B,IAAI;CACJ,IAAI;CACJ,GAAG;CACH,OAAO;CACP,OAAO;CACP,UAAU;CACV,WAAW;AACb;AAEA,SAAS,WACP,IACA,OACA,QACe;CACf,MAAM,SAAS,QAAQ;CAEvB,MAAM,SAAS,IAAI,kBAAkB,SAAS,MAAM;CACpD,GAAG,WAAW,GAAG,GAAG,OAAO,QAAQ,GAAG,MAAM,GAAG,eAAe,MAAM;CAEpE,MAAM,gBAAgB,IAAI,kBAAkB,QAAQ,SAAS,CAAC;CAC9D,KACE,IAAI,MAAM,GAAG,OAAO,SAAS,KAAK,QAClC,MAAM,SAAS,QACf,OAAO,QAAQ,OAAO,QAEtB,cAAc,IAAI,OAAO,SAAS,KAAK,MAAM,MAAM,GAAG,GAAG;CAG3D,OAAO;EACL;EACA;EACA,MAAM;CACR;AACF;AAEA,SAAgB,0BAA0B,SAAkB;CAC1D,IAAI,CAAC,SAAS,QAAQ,WAA0B;CAEhD,IAAI,KAAoC;CACxC,IAAI,WAA+B;CAEnC,QAAQ,WAA0B;EAChC,MAAM,EAAE,OAAO,WAAW;EAG1B,IAAI,OAAO,MACT,KAAK,cAAc,OAAO,QAAQ;GAChC,uBAAuB;GACvB,qBAAqB;EACvB,CAAC;EAEH,IAAI,aAAa,MACf,WAAW,qBAAqB,IAAI,OAAO,MAAM;EAGnD,SAAS,OAAO,QAAQ,mBAAmB;EAC3C,OAAO,WAAW,IAAI,OAAO,MAAM;CACrC;AACF;AAEA,SAAgB,UAAU,QAAsC;CAC9D,MAAM,EAAE,OAAO,WAAW;CAE1B,MAAM,KAAK,cAAc,OAAO,QAAQ;EACtC,uBAAuB;EACvB,qBAAqB;CACvB,CAAC;CAED,MAAM,EAAE,WAAW,qBAAqB,IAAI,OAAO,MAAM;CACzD,OAAO,QAAQ,mBAAmB;CAClC,OAAO,WAAW,IAAI,OAAO,MAAM;AACrC"}