/*HQ4X with NTSC TV colors emulation - Coded by 2017 Sunwalker
hq4x filter from https://www.shadertoy.com/view/MslGRS

SimoneT NTSC TV colors emulation 1.0 Shader
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.
*/

#version 120

uniform sampler2D OGL2Texture;
uniform sampler2D OGL2Texture0;
uniform vec4 OGL2Param;

#define NTSC 1.

//HQ4X Settings
#define s  .990000                              // min = 0.1; max = 10.0; "Strength Smoothing"
#define Smoothing  1.000000                    //min = 0.0; max = 1.0; "Smoothing"
#define Weight_Decrease_Factor  -1.100000     //min = -2.0; max = 0.0; "Weight Decrease Factor"
#define max_w  0.750000                      //min = 0.0; max = 1.0; "Max Filter Weight"
#define min_w  0.030000                     //min = 0.0; max = 1.0; "Min Filter Weight"
#define lum_add  0.330000                  //min = 0.0; max = 1.0; "Effects Smoothing"

float texture_size_x = 1024.0;
float texture_size_y = 512.0;

float x = s*(1. / texture_size_x);
float y = s*(1. / texture_size_y);

vec2 OGLSize = vec2(texture_size_x, texture_size_y);
vec2 OGLInvSize = vec2(1. / texture_size_x, 1. / texture_size_y);



vec3 HQ4X(sampler2D OGL2Texture, vec2 uv) {
	
	vec3 dt = 1.0 * vec3(1.0, 1.0, 1.0);

	vec2 dg1 = vec2(x, y);
	vec2 dg2 = vec2(-x, y);

	vec2 sd1 = dg1 * 0.5;
	vec2 sd2 = dg2 * 0.5;

	vec2 ddx = vec2(x, 0.0);
	vec2 ddy = vec2(0.0, y);

	vec4 t1 = vec4(uv - sd1, uv - ddy);
	vec4 t2 = vec4(uv - sd2, uv + ddx);
	vec4 t3 = vec4(uv + sd1, uv + ddy);
	vec4 t4 = vec4(uv + sd2, uv - ddx);
	vec4 t5 = vec4(uv - dg1, uv - dg2);
	vec4 t6 = vec4(uv + dg1, uv + dg2);

	vec3 c = texture2D(OGL2Texture, uv).rgb;

	vec3 i1 = texture2D(OGL2Texture, t1.xy).rgb;
	vec3 i2 = texture2D(OGL2Texture, t2.xy).rgb;
	vec3 i3 = texture2D(OGL2Texture, t3.xy).rgb;
	vec3 i4 = texture2D(OGL2Texture, t4.xy).rgb;

	vec3 o1 = texture2D(OGL2Texture, t5.xy).rgb;
	vec3 o3 = texture2D(OGL2Texture, t6.xy).rgb;
	vec3 o2 = texture2D(OGL2Texture, t5.zw).rgb;
	vec3 o4 = texture2D(OGL2Texture, t6.zw).rgb;

	vec3 s1 = texture2D(OGL2Texture, t1.zw).rgb;
	vec3 s2 = texture2D(OGL2Texture, t2.zw).rgb;
	vec3 s3 = texture2D(OGL2Texture, t3.zw).rgb;
	vec3 s4 = texture2D(OGL2Texture, t4.zw).rgb;

	float ko1 = dot(abs(o1 - c), dt);
	float ko2 = dot(abs(o2 - c), dt);
	float ko3 = dot(abs(o3 - c), dt);
	float ko4 = dot(abs(o4 - c), dt);

	float k1 = min(dot(abs(i1 - i3), dt), max(ko1, ko3));
	float k2 = min(dot(abs(i2 - i4), dt), max(ko2, ko4));

	float w1 = k2; if (ko3 < ko1) w1 *= ko3 / ko1;
	float w2 = k1; if (ko4 < ko2) w2 *= ko4 / ko2;
	float w3 = k2; if (ko1 < ko3) w3 *= ko1 / ko3;
	float w4 = k1; if (ko2 < ko4) w4 *= ko2 / ko4;

	c = (w1 * o1 + w2 * o2 + w3 * o3 + w4 * o4 + 0.001 * c) / (w1 + w2 + w3 + w4 + 0.001);
	w1 = Weight_Decrease_Factor * dot(abs(i1 - c) + abs(i3 - c), dt) / (0.125 * dot(i1 + i3, dt) + lum_add);
	w2 = Weight_Decrease_Factor * dot(abs(i2 - c) + abs(i4 - c), dt) / (0.125 * dot(i2 + i4, dt) + lum_add);
	w3 = Weight_Decrease_Factor * dot(abs(s1 - c) + abs(s3 - c), dt) / (0.125 * dot(s1 + s3, dt) + lum_add);
	w4 = Weight_Decrease_Factor * dot(abs(s2 - c) + abs(s4 - c), dt) / (0.125 * dot(s2 + s4, dt) + lum_add);

	w1 = clamp(w1 + Smoothing, min_w, max_w);
	w2 = clamp(w2 + Smoothing, min_w, max_w);
	w3 = clamp(w3 + Smoothing, min_w, max_w);
	w4 = clamp(w4 + Smoothing, min_w, max_w);

	return (
		w1 * (i1 + i3) +
		w2 * (i2 + i4) +
		w3 * (s1 + s3) +
		w4 * (s2 + s4) +
		c) / (2.0 * (w1 + w2 + w3 + w4) + 1.0);
}


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

// NTSC RGB to sRGB
vec3 ntscrgb_2_srgb(vec3 c) {
	return xyz_2_srgb(ntscrgb_2_xyz(c));
}

void main() {

	vec3 color;
	vec2 uv = gl_TexCoord[0].xy;
	color = HQ4X(OGL2Texture0, uv).xyz;

	gl_FragColor.xyz = mix(color, ntscrgb_2_srgb(color).xyz, NTSC);
}