/*
   Hyllian's 5xBR v4.0 (LEVEL 2) + Sepia2 Shader
   
   Copyright (C) 2011/2014 Hyllian/Jararaca - sergiogdb@gmail.com

  
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

   Incorporates some of the ideas from SABR shader. Thanks to Joshua Street.

Shader notes:

	Shader level 1: a cornering

	Shader level 2: b cornering

	Shader level 3: c cornering

	Shader level 4: d cornering

*/



uniform vec4 OGL2Param;
 
const   float XBR_SCALE = 3.0;


const   float coef          = 2.0;
const   vec3  rgbw          = vec3(14.352, 28.176, 5.472);
const   vec4  eq_threshold  = vec4(15.0, 15.0, 15.0, 15.0);


const   vec2 OGLSize    = vec2( 1024.0, 512.0);
const   vec2 OGLInvSize = vec2( 0.0009765625, 0.001953125); 
const   vec2 dx         = vec2( 0.0009765625, 0.0);
const   vec2 dy         = vec2( 0.0, 0.001953125 );
const   vec2 x2         = vec2( 0.001953125 , 0.0);
const   vec2 y2         = vec2( 0.0 , 0.00390625 );
const   vec4 xy         = vec4( 0.0009765625, 0.001953125,-0.0009765625,-0.001953125);  
const   vec4 zw         = vec4( 0.001953125 , 0.001953125,-0.001953125 ,-0.00390625 );  
const   vec4 wz         = vec4( 0.0009765625, 0.00390625 ,-0.0009765625,-0.00390625 );  


vec4 noteq(vec4 A, vec4 B)
{
	return vec4(notEqual(A, B));
}

vec4 not(vec4 A)
{
	return vec4(1.0)-A;
}

vec4 df(vec4 A, vec4 B)
{
    return abs(A-B);
}

vec4 eq(vec4 A, vec4 B)
{
return vec4(lessThan(df(A, B),eq_threshold));
}


vec4 weighted_distance(vec4 a, vec4 b, vec4 c, vec4 d, vec4 e, vec4 f, vec4 g, vec4 h)
{
    return (df(a,b) + df(a,c) + df(d,e) + df(d,f) + 4.0*df(g,h));
}


float c_df(vec3 c1, vec3 c2) {
                        vec3 df = abs(c1 - c2);
                        return df.r + df.g + df.b;
                }
				
				
uniform sampler2D OGL2Texture;

void main()
{
    vec4 edr, edr_left, edr_up;                     // px = pixel, edr = edge detection rule
    vec4 interp_restriction_lv1, interp_restriction_lv2_left, interp_restriction_lv2_up;
    vec4 nc30, nc60, nc45;                          // new_color
    vec4 fx, fx_left, fx_up, final_fx;              // inequations of straight lines.
    vec3 res1, res2, pix1, pix2;
    bvec4 nc, px;
    float blend1, blend2; 

    vec4 delta  = vec4(1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE, 1.0/XBR_SCALE);
    vec4 deltaL = vec4(0.5/XBR_SCALE, 1.0/XBR_SCALE, 0.5/XBR_SCALE, 1.0/XBR_SCALE);
    vec4 deltaU = deltaL.yxwz;


    vec2 fp  = fract(gl_TexCoord[0].xy*OGLSize);
    vec2 TexCoord_0 = gl_TexCoord[0].xy-fp*OGLInvSize + 0.5*OGLInvSize;

    vec3 A  = texture2D(OGL2Texture, TexCoord_0 + xy.zw ).xyz;
    vec3 B  = texture2D(OGL2Texture, TexCoord_0     -dy ).xyz;
    vec3 C  = texture2D(OGL2Texture, TexCoord_0 + xy.xw ).xyz;
    vec3 D  = texture2D(OGL2Texture, TexCoord_0 - dx    ).xyz;
    vec3 E  = texture2D(OGL2Texture, TexCoord_0         ).xyz;
    vec3 F  = texture2D(OGL2Texture, TexCoord_0 + dx    ).xyz;
    vec3 G  = texture2D(OGL2Texture, TexCoord_0 + xy.zy ).xyz;
    vec3 H  = texture2D(OGL2Texture, TexCoord_0     +dy ).xyz;
    vec3 I  = texture2D(OGL2Texture, TexCoord_0 + xy.xy ).xyz;
    vec3 A1 = texture2D(OGL2Texture, TexCoord_0 + wz.zw ).xyz;
    vec3 C1 = texture2D(OGL2Texture, TexCoord_0 + wz.xw ).xyz;
    vec3 A0 = texture2D(OGL2Texture, TexCoord_0 + zw.zw ).xyz;
    vec3 G0 = texture2D(OGL2Texture, TexCoord_0 + zw.zy ).xyz;
    vec3 C4 = texture2D(OGL2Texture, TexCoord_0 + zw.xw ).xyz;
    vec3 I4 = texture2D(OGL2Texture, TexCoord_0 + zw.xy ).xyz;
    vec3 G5 = texture2D(OGL2Texture, TexCoord_0 + wz.zy ).xyz;
    vec3 I5 = texture2D(OGL2Texture, TexCoord_0 + wz.xy ).xyz;
    vec3 B1 = texture2D(OGL2Texture, TexCoord_0 - y2    ).xyz;
    vec3 D0 = texture2D(OGL2Texture, TexCoord_0 - x2    ).xyz;
    vec3 H5 = texture2D(OGL2Texture, TexCoord_0 + y2    ).xyz;
    vec3 F4 = texture2D(OGL2Texture, TexCoord_0 + x2    ).xyz;

    vec4 b  = vec4(dot(B ,rgbw), dot(D ,rgbw), dot(H ,rgbw), dot(F ,rgbw));
    vec4 c  = vec4(dot(C ,rgbw), dot(A ,rgbw), dot(G ,rgbw), dot(I ,rgbw));
    vec4 d  = b.yzwx;
    vec4 e  = vec4(dot(E,rgbw));
    vec4 f  = b.wxyz;
    vec4 g  = c.zwxy;
    vec4 h  = b.zwxy;
    vec4 i  = c.wxyz;
    vec4 i4 = vec4(dot(I4,rgbw), dot(C1,rgbw), dot(A0,rgbw), dot(G5,rgbw));
    vec4 i5 = vec4(dot(I5,rgbw), dot(C4,rgbw), dot(A1,rgbw), dot(G0,rgbw));
    vec4 h5 = vec4(dot(H5,rgbw), dot(F4,rgbw), dot(B1,rgbw), dot(D0,rgbw));
    vec4 f4 = h5.yzwx;
    vec4 c1 = i4.yzwx;
    vec4 g0 = i5.wxyz;
    
    vec4 Ao = vec4( 1.0, -1.0, -1.0, 1.0 );
    vec4 Bo = vec4( 1.0,  1.0, -1.0,-1.0 );
    vec4 Co = vec4( 1.5,  0.5, -0.5, 0.5 );
    vec4 Ax = vec4( 1.0, -1.0, -1.0, 1.0 );
    vec4 Bx = vec4( 0.5,  2.0, -0.5,-2.0 );
    vec4 Cx = vec4( 1.0,  1.0, -0.5, 0.0 );
    vec4 Ay = vec4( 1.0, -1.0, -1.0, 1.0 );
    vec4 By = vec4( 2.0,  0.5, -2.0,-0.5 );
    vec4 Cy = vec4( 2.0,  0.0, -1.0, 0.5 );
    
// These inequations define the line below which interpolation occurs.
	
    fx      = (Ao*fp.y+Bo*fp.x); 
	
    fx_left = (Ax*fp.y+Bx*fp.x);
	
    fx_up   = (Ay*fp.y+By*fp.x);

    if (OGL2Param.z == 0.0)
    {    interp_restriction_lv1 = sign(noteq(e,f) * noteq(e,h));}

    if (OGL2Param.z == 1.0)
    {    interp_restriction_lv1 = sign(noteq(e,f) * noteq(e,h) * ( not(eq(f,b)) * not(eq(h,d)) + eq(e,i) * not(eq(f,i4)) * not(eq(h,i5)) + eq(e,g) + eq(e,c)));}

    if (OGL2Param.z == 2.0)
    {    interp_restriction_lv1 = sign(noteq(e,f)*noteq(e,h)*(not(eq(f,b))* not(eq(h,d)) + eq(e,i) * not(eq(f,i4)) * not(eq(h,i5)) + eq(e,g) + eq(e,c) )  * (noteq(f,f4)* noteq(f,i) + noteq(h,h5) * noteq(h,i) + noteq(h,g) + noteq(f,c) + eq(b,c1) * eq(d,g0)));}

    if (OGL2Param.z == 3.0)
    {    interp_restriction_lv1 = sign(noteq(e,f) * noteq(e,h) * ( not(eq(f,b)) * not(eq(f,c)) + not(eq(h,d)) * not(eq(h,g)) + eq(e,i) * (not(eq(f,f4)) * not(eq(f,i4)) + not(eq(h,h5)) * not(eq(h,i5))) + eq(e,g) + eq(e,c)) );}

    interp_restriction_lv2_left = vec4(notEqual(e,g))*vec4(notEqual(d,g));
    interp_restriction_lv2_up   = vec4(notEqual(e,c))*vec4(notEqual(b,c));

    vec4 fx45 = clamp((fx + delta -Co)/(2*delta ),0.0,1.0);
    vec4 fx30 = clamp((fx_left + deltaL -Cx)/(2*deltaL),0.0,1.0);
    vec4 fx60 = clamp((fx_up + deltaU -Cy)/(2*deltaU),0.0,1.0);
	
    edr      = vec4(lessThan(weighted_distance( e, c, g, i, h5, f4, h, f), weighted_distance( h, d, i5, f, i4, b, e, i)))*interp_restriction_lv1;
    edr_left = vec4(lessThanEqual(coef*df(f,g),df(h,c)))*interp_restriction_lv2_left*edr; 
    edr_up   = vec4(greaterThanEqual(df(f,g),coef*df(h,c)))*interp_restriction_lv2_up*edr;

    fx45 = edr*fx45;
    fx30 = edr_left*fx30;
    fx60 = edr_up*fx60;

    px = lessThanEqual(df(e,f),df(e,h));
    vec4 maximo = max(max(fx30, fx60), fx45);    

    mat4x3 pix = mat4x3(mix(E, mix(H, F, float(px.x)), maximo.x), 
                        mix(E, mix(F, B, float(px.y)), maximo.y),
                        mix(E, mix(B, D, float(px.z)), maximo.z),
                        mix(E, mix(D, H, float(px.w)), maximo.w));

    vec4 pixel = vec4(dot(pix[0],rgbw),dot(pix[1],rgbw),dot(pix[2],rgbw),dot(pix[3],rgbw));

    vec4 diff = df(pixel,e);

    vec3 res = pix[0];
    float mx = diff.x;

    if (diff.y > mx) {res = pix[1]; mx = diff.y;}
    if (diff.z > mx) {res = pix[2]; mx = diff.z;}
    if (diff.w > mx) {res = pix[3];} 

    vec3 ColorTone   = vec3(1.40, 1.10, 0.90);
    float GreyPower  = 0.11;                    
    float SepiaPower = 0.58;                    

    vec3 sepia = res;

    float grey = dot(sepia, vec3(0.2126, 0.7152, 0.0722));
	
    sepia *= ColorTone;
	
    vec3 blends = (grey * GreyPower) + (res / (GreyPower + 1.0));

    sepia = mix(blends, sepia, SepiaPower);


    gl_FragColor.xyz = sepia;
}