/*
   SimoneT mixed 3D/2D games + TV colors emulation Shader v 1.2

   Copyright (C) 2016 SimoneT - simone1tarditi@gmail.com

   part of code taken from "Directional Cubic Convolution Interpolation"
   created by Dengwen Zhou and Xiaoliu Shen.

   https://en.wikipedia.org/wiki/Directional_Cubic_Convolution_Interpolation 

   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.
    
*/

uniform sampler2D OGL2Texture;
uniform vec4 OGL2Size;
uniform vec4 OGL2InvSize;
uniform vec4 OGL2Param;

vec3 detect3d( vec2 texCoords, vec2 texSize ){

	vec2 pos = (floor(texCoords*texSize)+0.5)/texSize;

        vec2 temp = 1.0/texSize;
	vec2 shift = temp;

	vec2 swirl = fract((texCoords*texSize)/2.0);

	( swirl.x < 0.5 ) ?  (shift.x = shift.x) : (shift.x = -shift.x) ;
	( swirl.y < 0.5 ) ?  (shift.y = shift.y) : (shift.y = -shift.y) ;

	vec3 a = texture2D(OGL2Texture, pos + shift * vec2( 0.0, 0.0)).rgb;
	vec3 b = texture2D(OGL2Texture, pos + shift * vec2( 1.0, 0.0)).rgb;
	vec3 c = texture2D(OGL2Texture, pos + shift * vec2( 0.0, 1.0)).rgb;
	vec3 d = texture2D(OGL2Texture, pos + shift * vec2( 1.0, 1.0)).rgb; 

	vec3 x3d = vec3 ( 0.0 );
	vec3 x2d = vec3 ( 1.0 );

	vec3 e;

	( a == b && b == c && c == d ) ? ( e = x2d  ) : ( e = x3d );

	return e;
}

vec4 cubic(float v){
	vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v;
	vec4 s = n * n * n;
	float x = s.x;
	float y = s.y - 4.0 * s.x;
	float z = s.z - 4.0 * s.y + 6.0 * s.x;
	float w = 6.0 - x - y - z;
	return vec4(x, y, z, w) * (1.0/6.0);
}

vec3 textureBicubic( sampler2D sampler, vec2 texCoords ){

	vec2 invTexSize = 1.0 / OGL2Size.xy;
   
	texCoords = texCoords * OGL2Size.xy - 0.5;
   
	vec2 fxy = fract(texCoords);
	texCoords -= fxy;

	vec4 xcubic = cubic(fxy.x);
	vec4 ycubic = cubic(fxy.y);

	vec4 c = texCoords.xxyy + vec2(-0.5, +1.5).xyxy;
    
	vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
	vec4 offset = c + vec4(xcubic.yw, ycubic.yw) / s;
    
	offset *= invTexSize.xxyy;
    
	vec3 C0 = texture2D(sampler, offset.xz).rgb;
	vec3 C1 = texture2D(sampler, offset.yz).rgb;
	vec3 C2 = texture2D(sampler, offset.xw).rgb;
	vec3 C3 = texture2D(sampler, offset.yw).rgb;

	float sx = s.x / (s.x + s.y);
	float sy = s.z / (s.z + s.w);

	return mix( mix(C3, C2, sx), mix(C1, C0, sx), sy);
}

// conversion from NTSC RGB Reference White D65 ( color space used by NA/Japan TV's ) to XYZ

vec3 ntscrgb_2_xyz( vec3 c ) {

	//Inverse Companding
	c = clamp( c, 0.0, 1.0 );
	vec3 v = vec3( pow( c.r, 2.2 ), pow( c.g, 2.2 ), pow( c.b, 2.2  ) ); 
	return v *
        mat3(  0.6068909,  0.1735011,  0.2003480,
 	       0.2989164,  0.5865990,  0.1144845,
 	       0.0000000,  0.0660957,  1.1162243 );
}

// conversion from XYZ to sRGB Reference White D65 ( color space used by windows ) 

vec3 xyz_2_srgb( vec3 c ) {

	vec3 v =  c *         
	mat3(  3.2404542, -1.5371385, -0.4985314,
	      -0.9692660,  1.8760108,  0.0415560,
 	       0.0556434, -0.2040259,  1.0572252 );

	//Companding
	v.r = ( v.r > 0.0031308 ) ? (( 1.055 * pow( v.r, ( 1.0 / 2.4 ))) - 0.055 ) : 12.92 * v.r;
	v.g = ( v.g > 0.0031308 ) ? (( 1.055 * pow( v.g, ( 1.0 / 2.4 ))) - 0.055 ) : 12.92 * v.g;
	v.b = ( v.b > 0.0031308 ) ? (( 1.055 * pow( v.b, ( 1.0 / 2.4 ))) - 0.055 ) : 12.92 * v.b;
	return clamp( v, 0.0, 1.0 );
}
 
// NTSC RGB to sRGB

vec3 ntscrgb_2_srgb( vec3 c ) { 

	return xyz_2_srgb( ntscrgb_2_xyz( c ) ); 
}

float diff( vec3 a, vec3 b ) {

	vec3 luma = vec3(0.299, 0.587, 0.114);
	float temp;
	temp = abs(dot(a,luma)-dot(b,luma));
	return temp;
}

vec3 Diagonal( vec2 coord ) {

	vec2 texSize = vec2( 2048.0, 1024.0 );

	vec2 shift = 1.0/texSize;

	vec2 TexCoord = (floor(coord*texSize)+0.5)/texSize;

/*

	+----+----+----+----+----+
	| 20 | 21 | 22 | 23 | 24 |
	+----+----+----+----+----+
	| 15 | 16 | 17 | 18 | 19 |
	+----+----2----3----+----+
	| 10 | 11 | 12 | 13 | 14 |
	+----+----0----1----+----+
	| 05 | 06 | 07 | 08 | 09 |
	+----+----+----+----+----+
	| 00 | 01 | 02 | 03 | 04 |
	+----+----+----+----+----+

*/

	vec3 C00 = texture2D(OGL2Texture, TexCoord + shift * vec2(-2.0,-2.0)).rgb;
	vec3 C01 = texture2D(OGL2Texture, TexCoord + shift * vec2(-1.0,-2.0)).rgb;
	vec3 C02 = texture2D(OGL2Texture, TexCoord + shift * vec2( 0.0,-2.0)).rgb;
	vec3 C03 = texture2D(OGL2Texture, TexCoord + shift * vec2( 1.0,-2.0)).rgb;
	vec3 C04 = texture2D(OGL2Texture, TexCoord + shift * vec2( 2.0,-2.0)).rgb;

	vec3 C05 = texture2D(OGL2Texture, TexCoord + shift * vec2(-2.0,-1.0)).rgb;
	vec3 C06 = texture2D(OGL2Texture, TexCoord + shift * vec2(-1.0,-1.0)).rgb;
	vec3 C07 = texture2D(OGL2Texture, TexCoord + shift * vec2( 0.0,-1.0)).rgb;
	vec3 C08 = texture2D(OGL2Texture, TexCoord + shift * vec2( 1.0,-1.0)).rgb;
	vec3 C09 = texture2D(OGL2Texture, TexCoord + shift * vec2( 2.0,-1.0)).rgb;

	vec3 C10 = texture2D(OGL2Texture, TexCoord + shift * vec2(-2.0, 0.0)).rgb;
	vec3 C11 = texture2D(OGL2Texture, TexCoord + shift * vec2(-1.0, 0.0)).rgb;
	vec3 C12 = texture2D(OGL2Texture, TexCoord + shift * vec2( 0.0, 0.0)).rgb;
	vec3 C13 = texture2D(OGL2Texture, TexCoord + shift * vec2( 1.0, 0.0)).rgb;
	vec3 C14 = texture2D(OGL2Texture, TexCoord + shift * vec2( 2.0, 0.0)).rgb;

	vec3 C15 = texture2D(OGL2Texture, TexCoord + shift * vec2(-2.0, 1.0)).rgb;
	vec3 C16 = texture2D(OGL2Texture, TexCoord + shift * vec2(-1.0, 1.0)).rgb;
	vec3 C17 = texture2D(OGL2Texture, TexCoord + shift * vec2( 0.0, 1.0)).rgb;
	vec3 C18 = texture2D(OGL2Texture, TexCoord + shift * vec2( 1.0, 1.0)).rgb;
	vec3 C19 = texture2D(OGL2Texture, TexCoord + shift * vec2( 2.0, 1.0)).rgb;

	vec3 C20 = texture2D(OGL2Texture, TexCoord + shift * vec2(-2.0, 2.0)).rgb;
	vec3 C21 = texture2D(OGL2Texture, TexCoord + shift * vec2(-1.0, 2.0)).rgb;
	vec3 C22 = texture2D(OGL2Texture, TexCoord + shift * vec2( 0.0, 2.0)).rgb;
	vec3 C23 = texture2D(OGL2Texture, TexCoord + shift * vec2( 1.0, 2.0)).rgb;
	vec3 C24 = texture2D(OGL2Texture, TexCoord + shift * vec2( 2.0, 2.0)).rgb;

/*

	+----+----+----+----+----+
	| 20 | 21 | 22 | 23 | 24 |
	+----/----/----/----/----+
	| 15 | 16 | 17 | 18 | 19 |
	+----/----/----/----/----+
	| 10 | 11 | 12 | 13 | 14 |
	+----/----/----/----/----+
	| 05 | 06 | 07 | 08 | 09 |
	+----/----/----/----/----+
	| 00 | 01 | 02 | 03 | 04 |
	+----+----+----+----+----+

*/

	float C03C09 = distance(C03,C09);
	float C02C08 = distance(C02,C08);
	float C08C14 = distance(C08,C14);
	float C01C07 = distance(C01,C07);
	float C07C13 = distance(C07,C13);
	float C13C19 = distance(C13,C19);
	float C00C06 = distance(C00,C06);
	float C06C12 = distance(C06,C12);
	float C12C18 = distance(C12,C18);
	float C18C24 = distance(C18,C24);
	float C05C11 = distance(C05,C11);
	float C11C17 = distance(C11,C17);
	float C17C23 = distance(C17,C23);
	float C10C16 = distance(C10,C16);
	float C16C22 = distance(C16,C22);
	float C15C21 = distance(C15,C21);

/*

	+----+----+----+----+----+
	| 20 | 21 | 22 | 23 | 24 |
	+----\----\----\----\----+
	| 15 | 16 | 17 | 18 | 19 |
	+----\----\----\----\----+
	| 10 | 11 | 12 | 13 | 14 |
	+----\----\----\----\----+
	| 05 | 06 | 07 | 08 | 09 |
	+----\----\----\----\----+
	| 00 | 01 | 02 | 03 | 04 |
	+----+----+----+----+----+

*/

	float C01C05 = distance(C01,C05);
	float C02C06 = distance(C02,C06);
	float C06C10 = distance(C06,C10);
	float C03C07 = distance(C03,C07);
	float C07C11 = distance(C07,C11);
	float C11C15 = distance(C11,C15);
	float C04C08 = distance(C04,C08);
	float C08C12 = distance(C08,C12);
	float C12C16 = distance(C12,C16);
	float C16C20 = distance(C16,C20);
	float C09C13 = distance(C09,C13);
	float C13C17 = distance(C13,C17);
	float C17C21 = distance(C17,C21);
	float C14C18 = distance(C14,C18);
	float C18C22 = distance(C18,C22);
	float C19C23 = distance(C19,C23);

/*


	+----+----+----+----+
	| 15 | 16 | 17 | 18 |
	+----+----+----+----+
	| 10 | 11 | 12 | 13 |
	+----+----0----+----+
	| 05 | 06 | 07 | 08 |
	+----+----+----+----+
	| 00 | 01 | 02 | 03 |
	+----+----+----+----+

*/

	float d01 = C02C08 + 
	  	    C01C07 + C07C13 + 
	            C00C06 + C06C12 + C12C18 +
	            C05C11 + C11C17 + 
	            C10C16 ;

	float d02 = C01C05 + 
	  	    C02C06 + C06C10 + 
	            C03C07 + C07C11 + C11C15 +
	            C08C12 + C12C16 + 
	            C13C17 ;

/*

	+----+----+----+----+
	| 16 | 17 | 18 | 19 |
	+----+----+----+----+
	| 11 | 12 | 13 | 14 |
	+----+----1----+----+
	| 06 | 07 | 08 | 09 |
	+----+----+----+----+
	| 01 | 02 | 03 | 04 |
	+----+----+----+----+

*/

	float d11 = C03C09 + 
	  	    C02C08 + C08C14 + 
	            C01C07 + C07C13 + C13C19 +
	            C06C12 + C12C18 + 
	            C11C17 ;

	float d12 = C02C06 + 
	  	    C03C07 + C07C11 + 
	            C04C08 + C08C12 + C12C16 +
	            C09C13 + C13C17 + 
	            C14C18 ;

/*

	+----+----+----+----+
	| 20 | 21 | 22 | 23 |
	+----+----+----+----+
	| 15 | 16 | 17 | 18 |
	+----+----2----+----+
	| 10 | 11 | 12 | 13 |
	+----+----+----+----+
	| 05 | 06 | 07 | 08 |
	+----+----+----+----+


*/

	float d21 = C07C13 + 
	  	    C06C12 + C12C18 + 
	            C05C11 + C11C17 + C17C23 +
	            C10C16 + C16C22 + 
	            C15C21 ;

	float d22 = C06C10 + 
	  	    C07C11 + C11C15 + 
	            C08C12 + C12C16 + C16C20 +
	            C13C17 + C17C21 + 
	            C18C22 ;

/*

	+----+----+----+----+
	| 21 | 22 | 23 | 24 |
	+----+----+----+----+
	| 16 | 17 | 18 | 19 |
	+----+----3----+----+
	| 11 | 12 | 13 | 14 |
	+----+----ì----+----+
	| 06 | 07 | 08 | 09 |
	+----+----+----+----+

*/

	float d31 = C08C14 + 
	  	    C07C13 + C13C19 + 
	            C06C12 + C12C18 + C18C24 +
	            C11C17 + C17C23 + 
	            C16C22 ;

	float d32 = C07C11 + 
	  	    C08C12 + C12C16 + 
	            C09C13 + C13C17 + C17C21 +
	            C14C18 + C18C22 + 
	            C19C23 ;

	float w01 = 1.0 / (1.0 + pow(d01,5.0));
	float w02 = 1.0 / (1.0 + pow(d02,5.0));

	float w11 = 1.0 / (1.0 + pow(d11,5.0));
	float w12 = 1.0 / (1.0 + pow(d12,5.0));

	float w21 = 1.0 / (1.0 + pow(d21,5.0));
	float w22 = 1.0 / (1.0 + pow(d22,5.0));

	float w31 = 1.0 / (1.0 + pow(d31,5.0));
	float w32 = 1.0 / (1.0 + pow(d32,5.0));

	float weight01 = w01 / (w01 + w02);
	float weight02 = w02 / (w01 + w02);

	float weight11 = w11 / (w11 + w12);
	float weight12 = w12 / (w11 + w12);

	float weight21 = w21 / (w21 + w22);
	float weight22 = w22 / (w21 + w22);

	float weight31 = w31 / (w31 + w32);
	float weight32 = w32 / (w31 + w32);

	float X = 8.0;
	float Y = 2.0 * X + 2.0;

	vec3 DR0 = ( X * ( C06 + C12 ) + C00 + C18 ) / Y; 
	vec3 UR0 = ( X * ( C07 + C11 ) + C03 + C15 ) / Y; 

	vec3 DR1 = ( X * ( C07 + C13 ) + C01 + C19 ) / Y; 
	vec3 UR1 = ( X * ( C08 + C12 ) + C04 + C16 ) / Y; 

	vec3 DR2 = ( X * ( C11 + C17 ) + C05 + C23 ) / Y; 
	vec3 UR2 = ( X * ( C12 + C16 ) + C08 + C20 ) / Y; 

	vec3 DR3 = ( X * ( C12 + C18 ) + C06 + C24 ) / Y; 
	vec3 UR3 = ( X * ( C13 + C17 ) + C09 + C21 ) / Y; 

	vec3 sum0 = DR0 * weight01 + UR0 * weight02; 
	vec3 sum1 = DR1 * weight11 + UR1 * weight12;
	vec3 sum2 = DR2 * weight21 + UR2 * weight22;
	vec3 sum3 = DR3 * weight31 + UR3 * weight32;

	vec2 frac = pow(fract(gl_TexCoord[0].xy*texSize),vec2(3.0));
	//vec2 frac = smoothstep( 0.0, 1.0, fract(gl_TexCoord[0].xy*texSize));
	//vec2 frac = 1.0-cos(fract(gl_TexCoord[0].xy*texSize));

	return pow((sum0*(1.0-frac.x)+sum1*frac.x)*(1.0-frac.y)+(sum2*(1.0-frac.x)+sum3*frac.x)*frac.y,vec3(1.05));

}

void main()
{

	vec3 e = detect3d( gl_TexCoord[0].xy, vec2( 2048.0, 1024.0) );

	vec3 C4 = ( 1.0 - e ) * ( textureBicubic(OGL2Texture, gl_TexCoord[0].xy) );

	vec3 C0 = e * Diagonal( gl_TexCoord[0].xy );

	gl_FragColor.rgb = ntscrgb_2_srgb( C0 + C4 );

}
