#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
#define LUT_COMPENSATION 4.0

//precision highp float;
precision mediump float;

in highp vec2 vTextureCoord;
in highp vec3 vGrainCoord;

uniform lowp samplerExternalOES uSampler;
uniform mediump sampler3D lookupSampler;
uniform mediump sampler3D grainSampler;
uniform mediump sampler3D bakeSampler;

uniform highp mat3 abcMatr;
uniform highp mat3 indexMatr;
uniform highp vec3 abcScale;

uniform float vignetteAmount;
uniform float roundness;
uniform float feather;
uniform float midpoint;
uniform float highlightContrast;
uniform float highlightMask;
uniform float lutAmount;

uniform float grainAmount;
uniform float grainSize;
uniform float grainRoughness;
uniform highp vec3 grainPos;

uniform vec2 aspect;

uniform highp mat3 preColorMatr;
uniform highp mat3 postColorMatr;

out vec4 fragmentColor;

vec3 sRGBGamma(in vec3 col)
{
    vec3 sV = step(col,vec3(0.0031308));
    return mix(max(1.055 * pow (col, vec3(1.0/2.4)) - 0.055,vec3(0.0)),(col*12.92),sV);
}

vec3 invSRGBGamma(in vec3 col)
{
    vec3 sV = step(col,vec3(0.040449936));
    return mix(max(pow ((col + 0.055)/1.055, vec3(2.4)),vec3(0.0)),(col/12.92),sV);
}

vec3 evalUndoRenderCurve(vec3 col)
{
    highp vec2 fMinMax;
    highp vec2 nMinMax;

    float eps = 0.00001;


    fMinMax.x = min(min(col.r,col.g),col.b);
    fMinMax.y = max(max(col.r,col.g),col.b);

    highp vec2 t = pow(fMinMax,vec2(3.14453125));

    nMinMax = pow(fMinMax,vec2(0.8125))*0.3828125*(1.0-t) + (1.0-pow(1.0-fMinMax,vec2(0.69140625)))*t;

    fMinMax.y = (nMinMax.y-nMinMax.x)/(fMinMax.y-fMinMax.x+eps);

    return (col-fMinMax.x)*fMinMax.y + nMinMax.x;
}

void main(void)
{
    vec2 fMinMax;
    vec2 nMinMax;
    vec2 endPin;

    float pinWeight;
    float eps = 0.00001;

    const highp mat3 fromSRGBMatr = mat3(0.529285,0.098394,0.016823,
                                         0.330046,0.873493,0.117671,
                                         0.140669,0.028113,0.865506);

    const highp mat3 toSRGBMatr = mat3(2.034302,-0.228882,-0.00842285,
                                        -0.727295,1.23168945,-0.15332,
                                        -0.307007,-0.00280762,1.16174316);

      highp vec4 col = texture(uSampler, vTextureCoord.st);

    highp vec3 rgbCol = col.rgb;

    rgbCol = preColorMatr * rgbCol;
    rgbCol = max(rgbCol,vec3(0.0,0.0,0.0));

    rgbCol = invSRGBGamma(rgbCol);
    rgbCol = fromSRGBMatr * rgbCol;

    rgbCol = clamp(rgbCol,0.0001,0.999);

    rgbCol = evalUndoRenderCurve(rgbCol);

    // White Balance

    rgbCol = indexMatr * rgbCol;
    rgbCol *= abcScale;
    vec3 colorThresh = abcScale*0.25;
    vec3 colorScale = 1.0/(abcScale*0.75);
    float t1 = max(rgbCol.r, rgbCol.g);
    vec2 recT;
    recT = max ((rgbCol.rg - colorThresh.xy) * colorScale.xy, 0.0);
    recT = recT * recT;
    rgbCol.rg = mix(rgbCol.rg, vec2(t1), recT);
    t1 = max(0.5 * (rgbCol.r + rgbCol.g), rgbCol.b);
    recT.x = max((rgbCol.b - colorThresh.z) * colorScale.z, 0.0);
    recT.x = recT.x * recT.x;
    rgbCol.b = mix(rgbCol.b, t1, recT.x);
    rgbCol = abcMatr * rgbCol;
    rgbCol = clamp(rgbCol,0.0,1.0);

    // Vignette

    vec2 pos = vTextureCoord - 0.5;
    float dlFactor = 1.0-max(sign(vignetteAmount),0.0);
    vec3 resultColor = mix(vec3(1.0,1.0,1.0),vec3(0.0,0.0,0.0),dlFactor);
    float blackShift = dlFactor*0.28;
    float maskShift = mix(2.4,0.334,dlFactor);
    float absAmount = abs(vignetteAmount);
    vec2 circlePos = pos*aspect;
    float circleLen = length(circlePos)*0.95;
    float elipseLen = length(pos)*1.15;
    float rectRadius = 1.0-(2.0*max(-roundness-0.5,0.0)*0.86);
    vec2 minValue = max(2.0*abs(circlePos)-aspect+rectRadius,0.0);
    float rectLen = length(minValue)*0.576;
    rectLen /= rectRadius;
    float rectFactor = min(1.0,max(-roundness,0.0)*2.0);
    elipseLen = mix(elipseLen,rectLen,rectFactor);
    elipseLen = mix(elipseLen,circleLen,max(roundness,0.0));
    elipseLen = pow(1.0-elipseLen,0.8125);
    float addVal = midpoint*0.3 + elipseLen*max(midpoint,0.0)*0.5 - feather*0.3;
    float start = mix(0.495,-0.25+blackShift,feather) - addVal;
    float end = mix(0.505,0.4+blackShift,feather) - addVal;
    float maskFactor = 1.0 - (1.0 - smoothstep(start,end,elipseLen))*pow(absAmount,maskShift);
    float maxScale = mix(maskFactor,1.0,highlightContrast);
    float v = max(max(rgbCol.r,rgbCol.g),rgbCol.b);
    v = max(v*1.21951219512195 - 0.21951219512195,0.0);
    maskFactor = mix(maskFactor,maxScale,v);
    rgbCol = mix(rgbCol,resultColor,1.0-maskFactor);

    // Bake LUT

    rgbCol = clamp(rgbCol,0.0,1.0);

     // *** VF-162 ***
     // Certain combinations of Android hardware, OS, and GPU drivers
     // are failing to properly perform 'pow(rgbCol,vec3(1.0/LUT_COMPENSATION))''
     // and instead seem to be returning a value of 1.0. Since LUT_COMPENSATION
     // is presently 4.0, we can work around this bug by calling sqrt(rgbCol) twice in
     // lieu of calling pow(rgbCol, 1.0/4.0)
    //rgbCol = pow(rgbCol,vec3(1.0/LUT_COMPENSATION));
    rgbCol = sqrt(rgbCol);
    rgbCol = sqrt(rgbCol);
    rgbCol = texture(bakeSampler,rgbCol).rgb;
    rgbCol = pow(rgbCol,vec3(LUT_COMPENSATION));

    // Grain

    vec4 grainCoord = texture(grainSampler,vGrainCoord);

    float grainTime = fract(grainPos.z/64.0);
    float grainZ = 1.0-grainCoord.g;
    grainCoord.xy = fract(vTextureCoord.st *  grainPos.xy/128.0);
    grainCoord.z = fract(grainZ+grainTime);
    grainCoord.w = 1.0;
    grainCoord = texture(grainSampler,grainCoord.xyz);

    vec3 mask = clamp(rgbCol * 20.0    + 0.0,0.0,1.0) * clamp(rgbCol * -20.0 + 20.0,0.0,1.0);
    vec2 highFreq = grainCoord.rb;
    highFreq.x = 0.4 + grainCoord.r - grainCoord.g*0.8;

    vec2 freq = mix(highFreq,grainCoord.rg,grainRoughness);
    float grainFreq = mix(freq.x,freq.y,grainSize);

    rgbCol += grainAmount*(grainFreq-0.5)*mask;

    rgbCol = toSRGBMatr * rgbCol;
    col.rgb = sRGBGamma(rgbCol);

    // Profile 3D Lookup
    col.rgb = clamp(col.rgb,0.0,1.0);
    col.rgb = mix(col.rgb,texture(lookupSampler,col.rgb).rgb,lutAmount);

    col.rgb = postColorMatr * col.rgb;

    fragmentColor = col;


}