/* Fragment shader for performing corrections for the Oculus VR Rift
 * (w) 2015 by Mario Kleiner. Licensed under MIT license. Derived from
 * sample code in the Oculus 0.5 SDKs developer guide and info from the
 * web and SDK.
 */

#extension GL_ARB_texture_rectangle : enable

uniform sampler2DRect Image;
uniform sampler2DRect PrevImage;
uniform sampler2DRect OverdriveLUT;
uniform vec3 OverdriveScales;
varying float vignette;

void main()
{
  float r = texture2DRect(Image, gl_TexCoord[0].xy).r;
  float g = texture2DRect(Image, gl_TexCoord[1].xy).g;
  float b = texture2DRect(Image, gl_TexCoord[2].xy).b;
  vec3 newcorrectedcolor = vignette * vec3(r, g, b);

  /* Panel pixel luminance overdrive processing enabled? */
  if (OverdriveScales.x > 0.0) {
    vec3 overdrivecolor;

    /* Write distortion/aberration corrected color value to MRT1 for
     * use in the next rendering cycle as PrevImage input texture.
     */
    gl_FragData[1] = vec4(newcorrectedcolor, 1.0);

    /* Get pixel color of output pixel in previous frame. */
    vec3 previouscolor = texture2DRect(PrevImage, gl_FragCoord.xy).rgb;

    /* Scales < 1000 signal algorithmic / analytic overdrive correction: */
    if (OverdriveScales.x < 1000.0) {
      /* Select overdrive scaling factor. For rising pixel color components we use
       * OverdriveScales[0], for falling components we use OverdriveScales[1].
       */
      vec3 overdrive;
      overdrive.r = newcorrectedcolor.r > previouscolor.r ? OverdriveScales[0] : OverdriveScales[1];
      overdrive.g = newcorrectedcolor.g > previouscolor.g ? OverdriveScales[0] : OverdriveScales[1];
      overdrive.b = newcorrectedcolor.b > previouscolor.b ? OverdriveScales[0] : OverdriveScales[1];

      if (OverdriveScales[2] > 0.0) {
        /* Apply gamma corrected overdrive, clamp results to displayable output color range 0 - 1. */
        previouscolor = pow(previouscolor, vec3(1.0/2.2));
        newcorrectedcolor = pow(newcorrectedcolor, vec3(1.0/2.2));
        overdrivecolor = clamp(newcorrectedcolor + (newcorrectedcolor - previouscolor) * overdrive , 0.0, 1.0);
        overdrivecolor = pow(overdrivecolor, vec3(2.2));
      }
      else {
        /* Apply linear overdrive, clamp results to displayable output color range 0 - 1. */
        overdrivecolor = clamp(newcorrectedcolor + (newcorrectedcolor - previouscolor) * overdrive , 0.0, 1.0);
      }
    }
    else {
      /* LUT based correction requested. Just do a lookup at location (newcolor, oldcolor) for each of the
       * color channels separately.
       */
      overdrivecolor.r = texture2DRect(OverdriveLUT, 255.0 * vec2(newcorrectedcolor.r, previouscolor.r)).r;
      overdrivecolor.g = texture2DRect(OverdriveLUT, 255.0 * vec2(newcorrectedcolor.g, previouscolor.g)).g;
      overdrivecolor.b = texture2DRect(OverdriveLUT, 255.0 * vec2(newcorrectedcolor.b, previouscolor.b)).b;
    }

    /* Assign overdriven output color to display framebuffer MRT0. */
    gl_FragData[0] = vec4(overdrivecolor, 1.0);
  }
  else {
    /* No panel overdrive. Assign red marker color to unused MRT1.
     * and distortion/aberration corrected color to regular output MRT0.
     */
    gl_FragData[0] = vec4(newcorrectedcolor, 1.0);
    gl_FragData[1] = vec4(0.0, 0.0, 0.0, 1.0);
  }
}
