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

   Copyright (C) 2016 SimoneT - simone1tarditi@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.
    
*/

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

// 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 ) ); 
}
*/
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 texSize ){

	vec2 invTexSize = 1.0 / texSize;
   
	texCoords = texCoords * texSize - 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 = ntscrgb_2_xyz(texture(sampler, offset.xz).rgb);
	vec3 C1 = ntscrgb_2_xyz(texture(sampler, offset.yz).rgb);
	vec3 C2 = ntscrgb_2_xyz(texture(sampler, offset.xw).rgb);
	vec3 C3 = ntscrgb_2_xyz(texture(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);
}

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

void main()
{	

	vec3 e = detect3d( gl_TexCoord[0].xy, vec2( 2048.0, 1024.0) );
	vec2 Tsize = vec2( 2048.0, 1024.0);
	vec2 coord1 = (floor(gl_TexCoord[0].xy*Tsize))/Tsize;
        vec2 temp1 = 1.0/Tsize;
	//vec2 frac = smoothstep( 0.0, 1.0, fract(gl_TexCoord[0].xy*Tsize));
	vec2 frac = fract(gl_TexCoord[0].xy*Tsize);

	vec3 C0 = texture2D(OGL2Texture, coord1 + temp1 * vec2( 0.0, 0.0)).rgb;
	vec3 C1 = texture2D(OGL2Texture, coord1 + temp1 * vec2( 1.0, 0.0)).rgb;
	vec3 C2 = texture2D(OGL2Texture, coord1 + temp1 * vec2( 0.0, 1.0)).rgb;
	vec3 C3 = texture2D(OGL2Texture, coord1 + temp1 * vec2( 1.0, 1.0)).rgb;

	vec3 D = e * mix( mix( ntscrgb_2_xyz(C0), ntscrgb_2_xyz(C1), frac.x ), mix( ntscrgb_2_xyz(C2), ntscrgb_2_xyz(C3), frac.x ), frac.y );  

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

	gl_FragColor.rgb = xyz_2_srgb( X + D );
}
