/* Shader for color correction of RGB and Luminance textures by CLUT lookup.
 * Uses a RGB color lookup table, encoded in a texture, to independently
 * lookup corresponding remapped output red, green or blue intensity values
 * for given input red, green or blue intensity values in the input texture.
 *
 * This shader is used by PsychColorCorrection() in 'LookupTable' mode,
 * as part of PTB's built-in stimulus color correction.
 *
 * (w)2009 by Mario Kleiner. Licensed under MIT license.
*/

#extension GL_ARB_texture_rectangle : enable

uniform sampler2DRect   ICMCLUT;
uniform float           ICMPrescale;
uniform float           ICMMaxInputValue;

/* Allowable range for output values: To be initialized by PsychColorCorrection() typically: */
uniform vec2            ICMClampToColorRange;

vec4 icmTransformColor(vec4 incolor)
{
    vec4 outcolor;
    vec3 lutcolor1, lutcolor2, incolor1, incolor2;

    /* Return alpha component unmodified: */
    outcolor.a = incolor.a;

    /* Clamp input to valid 0-ICMMaxInputValue range: */
    incolor.rgb = clamp(incolor.rgb, vec3(0.0), vec3(ICMMaxInputValue));

    /* Remap them to index in resolution range: */
    incolor.rgb = incolor.rgb * ICMPrescale;
    incolor1 = floor(incolor.rgb) + 0.5;
    incolor2 = incolor1 + 1.0;

    /* Lookup values for each channel in rows of texture: Perform linear */
    /* filtering manual by dual-lookup and mix. This way we work on old hw as well: */
    lutcolor1.r  = texture2DRect(ICMCLUT, vec2(incolor1.r, 0.5)).r;
    lutcolor2.r  = texture2DRect(ICMCLUT, vec2(incolor2.r, 0.5)).r;

    lutcolor1.g  = texture2DRect(ICMCLUT, vec2(incolor1.g, 1.5)).r;
    lutcolor2.g  = texture2DRect(ICMCLUT, vec2(incolor2.g, 1.5)).r;

    lutcolor1.b  = texture2DRect(ICMCLUT, vec2(incolor1.b, 2.5)).r;
    lutcolor2.b  = texture2DRect(ICMCLUT, vec2(incolor2.b, 2.5)).r;

    outcolor.rgb = mix(lutcolor1, lutcolor2, fract(incolor.rgb));

    /* Clamp outcolor to range given by ICMClampToColorRange: */
    outcolor.rgb = clamp(outcolor.rgb, vec3(ICMClampToColorRange[0]), vec3(ICMClampToColorRange[1]));

    return(outcolor);
}


float icmTransformColor1(float incolor)
{
    float outcolor;
    float lutcolor1, lutcolor2, incolor1, incolor2;

    /* Clamp input to valid 0-ICMMaxInputValue range: */
    incolor = clamp(incolor, 0.0, ICMMaxInputValue);

    /* Remap them to index in resolution range: */
    incolor = incolor * ICMPrescale;
    incolor1 = floor(incolor) + 0.5;
    incolor2 = incolor1 + 1.0;

    /* Lookup values for each channel in rows of texture: */
    lutcolor1 = texture2DRect(ICMCLUT, vec2(incolor1, 0.5)).r;
    lutcolor2 = texture2DRect(ICMCLUT, vec2(incolor2, 0.5)).r;
    outcolor  = mix(lutcolor1, lutcolor2, fract(incolor));

    /* Clamp outcolor to range given by ICMClampToColorRange: */
    outcolor = clamp(outcolor, ICMClampToColorRange[0], ICMClampToColorRange[1]);

    return(outcolor);
}
