#line 1

uniform bool u_convertTosRGB;
uniform float u_scale;
uniform float u_gridScale;
uniform vec2 u_textureSize;

#ifdef OVERLAY
uniform bool u_showOutlineWhenZoomed;
uniform vec4 u_viewRect;
uniform sampler2D overlay;
uniform sampler2D overlayRenderMask;
uniform vec4 u_overlayColor;
in vec2 overlayTexcoords;
in vec2 texelCoords;
#endif

#ifdef REGION_OF_INTEREST
uniform vec4 u_roiRect;
uniform vec4 u_roiLineColor;
in vec2 position;

bool inside_line (vec2 pos, float width, float ix0, float iy0, float ix1, float iy1)
{
    if ((pos.x >= (ix0 - width)) && (pos.x <= (width + ix1)))
    {
        if ((pos.y >= (iy0 - width)) && (pos.y <= (width + iy1)))
        {
            return true;
        }
    }

    return false;
}
#endif

out vec4 results[1];

void main()
{
    vec4 ldr_sample2 = vec4(0);
    float iScale = 1.0 / u_scale;
    
#ifdef OVERLAY
    float overlaySample = 0;
    if (u_showOutlineWhenZoomed && texture(overlayRenderMask, overlayTexcoords).r != 0)
    {
        float scale = max(1.0, u_scale);
        if (gl_FragCoord.x <= u_viewRect.x + scale ||
            gl_FragCoord.y <= u_viewRect.y + scale ||
            gl_FragCoord.x >= u_viewRect.z - scale ||
            gl_FragCoord.y >= u_viewRect.w - scale)
        {
            overlaySample = 1;
        }
    }
    
    if (u_scale < u_gridScale)
    {
        // Solid Overlay
        overlaySample = max(texture(overlay, overlayTexcoords).r, overlaySample);
        ldr_sample2 = vec4(overlaySample * u_overlayColor.rgb, overlaySample);
        
        if (overlaySample != 1.0)
        {
            // Make overlay thicker depending on scale
            ivec2 texturePosition = ivec2(floor(texelCoords));
            
            // these values were selected based on what looked decent
            float scale = min(iScale, 2.0);
            float scaleFactor = max(smoothstep(0.2, 1.6, scale) * 2.0, 1.5);

            int radius = int(floor(scale * scaleFactor));
            float minDist = radius + 1;
            
            for (int i = texturePosition.x - radius; i < texturePosition.x + radius; ++i)
            {
                for (int j = texturePosition.y - radius; j < texturePosition.y + radius; ++j)
                {
                    ivec2 pos = ivec2(i, j);
                    if (texelFetch(overlay, pos, 0).r != 0)
                    {
                        overlaySample = 1.0;
                        minDist = min(distance(texturePosition, pos), minDist);
                    }
                }
            }
            
            // Make overlay smoother when zoomed out
            float alphaFactor = smoothstep(0.01, 0.55, 1 / minDist) * 0.9; // these values were selected based on what looked decent
            ldr_sample2 = vec4(overlaySample * u_overlayColor.rgb, overlaySample * alphaFactor);
        }
    }
    else
    {
        overlaySample = max(texture(overlay, overlayTexcoords).r, overlaySample);
        
        // Anti-aliased grid
        vec2 lineHalfWidth= vec2(iScale * 0.25);
        vec2 smoothingWidth= vec2(iScale * 0.75);
        const vec2 h= vec2(0.5);
        vec2 lineAlpha= smoothstep(lineHalfWidth, lineHalfWidth + smoothingWidth, abs(fract(texelCoords + h) - h));
        
        // Use luminance as grid color
        float luminance = dot(vec3(0.2126, 0.7152, 0.0722), ldr_sample2.rgb);
        luminance = clamp(luminance, 0.25, 0.75);
        vec4 lineColor = vec4(luminance, luminance, luminance, 1.0);
        
        ldr_sample2 = mix(mix(lineColor, ldr_sample2, min(lineAlpha.x, lineAlpha.y)), vec4(u_overlayColor.rgb, 1.0), overlaySample);
    }
#endif
    
#ifdef REGION_OF_INTEREST
    float lineWidth = 1.0 * iScale;
    float x0 = u_roiRect.x;
    float y0 = u_roiRect.y;
    float x1 = u_roiRect.z;
    float y1 = u_roiRect.w;

    if ((inside_line (position, lineWidth, x0, y0, x1, y0)) ||
        (inside_line (position, lineWidth, x0, y1, x1, y1)) ||
        (inside_line (position, lineWidth, x0, y0, x0, y1)) ||
        (inside_line (position, lineWidth, x1, y0, x1, y1)))
    {
        ldr_sample2 = u_roiLineColor;
    }
#endif
    
    results[0] = ldr_sample2;

    /*
     * From: http://www.khronos.org/registry/gles/extensions/EXT/EXT_sRGB.txt
     *
     * From linear to sRGB
     *      {  0.0,                          cl        <= 0
     *      {  12.92 * cl,                   0         <  cl < 0.0031308
     * cs = {  1.055 * cl^0.41666 - 0.055,   0.0031308 <= cl < 1
     *      {  1.0,                                       cl >= 1
     *
     * Assume cs is the sRGB component in the range [0,1].
     */
    if (u_convertTosRGB)
    {
        float components[3];
        components[0] = results[0].r;
        components[1] = results[0].g;
        components[2] = results[0].b;
        const float darkScale = 12.92;
        const float darkThreshold = 0.0031308;
        const float lightScale = 1.055;
        const float lightExponent = 0.4166;
        const float lightShift = 0.055;
        for(int i = 0; i < 3; ++i)
        {
           if(components[i] < 0.0)
               components[i] = 0.0;
           else if(components[i] < darkThreshold)
               components[i] *= darkScale;
           else if(components[i] < 1.0)
               components[i] = lightScale * pow(components[i], lightExponent) - lightShift;
           else
               components[i] = 1.0;
        }
        results[0].rgb = vec3(components[0], components[1], components[2]);
    }
}
