/*
   Hyllian's 2xBR v3.8a + colors Shader - ported to GLSL by guest(r), colors code by guest(r)
   
   Copyright (C) 2011/2012 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.

*/

// Color variables - can edit them

const vec3 c_ch = vec3(1.0,1.0,1.0);  //  rgb color channel intensity
const float   a  = 1.15 ;              //  saturation  usable values between 0.0...2.0
const float   br = 1.00 ;              //  brightness 
const float   c  = 0.25 ;              //  contrast    usable values between 0.0...1.0


 
const   float coef          = 2.0;
const   vec3  rgbw          = vec3(14.352, 28.176, 5.472);
const   vec4  delta         = vec4(0.5, 0.5, 0.5, 0.5);

const   vec4  eq_threshold  = vec4(15.0, 15.0, 15.0, 15.0);
const   float sharpness     = 0.65;


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 );  


float contrast(float x)
{ 
  float y = x*1.1547-1.0;
  y = (sin(y*1.5707)+1.1)*0.83;
  return (1.0-c)*x + c*y;
}


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

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

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; 

    
    vec2 fp  = fract(gl_TexCoord[0].xy*OGLSize);
    vec2 TexCoord_0 = gl_TexCoord[0].xy-fp*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 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);

   interp_restriction_lv1      = vec4(notEqual(e,f))*vec4(notEqual(e,h));
   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 = smoothstep(Co - delta, Co + delta, fx);
   vec4 fx30 = smoothstep(Cx - delta, Cx + delta, fx_left);
   vec4 fx60 = smoothstep(Cy - delta, Cy + delta, fx_up);
	
    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_up   = vec4(greaterThanEqual(df(f,g),coef*df(h,c)))*interp_restriction_lv2_up;

    nc45 = ( edr *             sign(fx45));
    nc30 = ( edr * edr_left *  sign(fx30));
    nc60 = ( edr * edr_up   *  sign(fx60));
	
    px = lessThanEqual(df(e,f),df(e,h));
    nc = bvec4(nc30 + nc60 + nc45);

    vec4 final45 = nc45*fx45;
    vec4 final30 = nc30*fx30;
    vec4 final60 = nc60*fx60;

    vec4 maximo = max(max(final30, final60), final45);

         if (nc.x) {pix1 = px.x ? F : H; blend1 = maximo.x;}
    else if (nc.y) {pix1 = px.y ? B : F; blend1 = maximo.y;}
    else if (nc.z) {pix1 = px.z ? D : B; blend1 = maximo.z;}
    else if (nc.w) {pix1 = px.w ? H : D; blend1 = maximo.w;}

         if (nc.w) {pix2 = px.w ? H : D; blend2 = maximo.w;}
    else if (nc.z) {pix2 = px.z ? D : B; blend2 = maximo.z;}
    else if (nc.y) {pix2 = px.y ? B : F; blend2 = maximo.y;}
    else if (nc.x) {pix2 = px.x ? F : H; blend2 = maximo.x;}

    res1 = mix(E, pix1, blend1);
    res2 = mix(E, pix2, blend2);

    vec3 res = mix(res1, res2, step(c_df(E, res1), c_df(E, res2)));	

    vec3 color = res;

    float x = sqrt(dot(color,color));

    color.r = pow(color.r+0.005,a);
    color.g = pow(color.g+0.005,a);
    color.b = pow(color.b+0.005,a);

    gl_FragColor.xyz = contrast(x)*normalize(color*c_ch)*br;
}