// Final grade: ACES tonemap, chromatic aberration, vignette, film grain,
// then linear -> sRGB. Runs after bloom so it grades the composited HDR.

export const FINAL_VERT = /* glsl */ `
varying vec2 vUv;
void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;

export const FINAL_FRAG = /* glsl */ `
precision highp float;
uniform sampler2D tDiffuse;
uniform float uTime;
uniform vec2 uRes;
uniform float uAberration;
uniform float uExposure;
varying vec2 vUv;

float hashf(vec2 p) {
  vec3 p3 = fract(vec3(p.xyx) * 0.1031);
  p3 += dot(p3, p3.yzx + 33.33);
  return fract((p3.x + p3.y) * p3.z);
}

vec3 aces(vec3 x) {
  const float a = 2.51, b = 0.03, c = 2.43, d = 0.59, e = 0.14;
  return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0.0, 1.0);
}

void main() {
  vec2 c = vUv - 0.5;
  float r2 = dot(c, c);
  vec2 off = c * r2 * uAberration;
  vec3 col;
  col.r = texture2D(tDiffuse, vUv + off).r;
  col.g = texture2D(tDiffuse, vUv).g;
  col.b = texture2D(tDiffuse, vUv - off).b;

  col = aces(col * uExposure);

  // vignette
  col *= 1.0 - 0.42 * smoothstep(0.08, 0.62, r2);

  // grain (kills gradient banding too)
  float g = hashf(vUv * uRes + fract(uTime) * 113.0);
  col += (g - 0.5) * 0.018;

  // linear -> sRGB
  col = pow(max(col, 0.0), vec3(1.0 / 2.2));
  gl_FragColor = vec4(col, 1.0);
}
`;
