/*
	Scale3xSFX
	by Sp00kyFox, 2015

Filter:	Nearest
Scale:	3x

Scale3SFX improves upon the original Scale3x by avoiding the occurence of artifacts and smoothing out 45° edges.

*/


#pragma parameter YTR "SCALE3xSFX Y Threshold" 48.0 0.0 255.0 1.0
#pragma parameter UTR "SCALE3xSFX U Threshold"  7.0 0.0 255.0 1.0
#pragma parameter VTR "SCALE3xSFX V Threshold"  6.0 0.0 255.0 1.0

#ifdef PARAMETER_UNIFORM
	uniform float YTR, UTR, VTR;
#else
	#define YTR 48.0
	#define UTR  7.0
	#define VTR  6.0
#endif


const static float3x3 YUV  = float3x3(0.299, -0.168736, 0.5, 0.587, -0.331264, -0.418688, 0.114, 0.5, -0.081312);	// transponed
static float3 thresh = float3(YTR, UTR, VTR)/255.0;


bool eq(float3 A, float3 B){
	return all(abs(A-B) <= thresh);
}

bool neq(float3 A, float3 B){
	return any(abs(A-B) > thresh);
}

struct input
{
	float2 video_size;
	float2 texture_size;
	float2 output_size;
};


struct out_vertex {
	float4 position : POSITION;
	float2 texCoord : TEXCOORD0;
	float4 t1 : TEXCOORD1;
	float4 t2 : TEXCOORD2;
	float4 t3 : TEXCOORD3;
	float4 t4 : TEXCOORD4;
	float4 t5 : TEXCOORD5;
};

/*    VERTEX_SHADER    */
out_vertex main_vertex
(
	float4 position	: POSITION,
	float2 texCoord : TEXCOORD0,

   	uniform float4x4 modelViewProj,
	uniform input IN
)
{
	out_vertex OUT;

	OUT.position = mul(modelViewProj, position);

	float2 ps = float2(1.0/IN.texture_size.x, 1.0/IN.texture_size.y);
	float dx = ps.x;
	float dy = ps.y;

	OUT.texCoord = texCoord;
	OUT.t1 = texCoord.xxxy + float4(  -dx,    0,   dx,  -dy);	// A, B, C
	OUT.t2 = texCoord.xxxy + float4(  -dx,    0,   dx,    0);	// D, E, F
	OUT.t3 = texCoord.xxxy + float4(  -dx,    0,   dx,   dy);	// G, H, I
	OUT.t4 = texCoord.xyxy + float4(    0,-2*dy,-2*dx,    0);	// J, K
	OUT.t5 = texCoord.xyxy + float4( 2*dx,    0,    0, 2*dy);	// L, M

	return OUT;
}


float3 main_fragment(in out_vertex VAR, uniform sampler2D decal : TEXUNIT0, uniform input IN) : COLOR
{
	// subpixel determination
	float2 fp = floor(3.0 * frac(VAR.texCoord*IN.texture_size));

	/*
		    J
		  A B C		E0 E1 E2
		K D E F L	E3 E4 E5
		  G H I		E6 E7 E8
		    M
	*/

	// reading the texels & color space conversion
	float3 b = tex2D(decal, VAR.t1.yw).xyz;
	float3 d = tex2D(decal, VAR.t2.xw).xyz;
	float3 e = tex2D(decal, VAR.t2.yw).xyz;
	float3 f = tex2D(decal, VAR.t2.zw).xyz;
	float3 h = tex2D(decal, VAR.t3.yw).xyz;

	float4x3 tmp = mul(float4x3(b,d,e,f), YUV);
	float3 B = tmp[0], D = tmp[1], E = tmp[2], F = tmp[3], H = mul(h, YUV);

	float3 A = tex2D(decal, VAR.t1.xw).xyz;
	float3 C = tex2D(decal, VAR.t1.zw).xyz;
	float3 G = tex2D(decal, VAR.t3.xw).xyz;
	float3 I = tex2D(decal, VAR.t3.zw).xyz;

	tmp = mul(float4x3(A,C,G,I), YUV);
	A = tmp[0], C = tmp[1], G = tmp[2], I = tmp[3];

	float3 J = tex2D(decal, VAR.t4.xy).xyz;
	float3 K = tex2D(decal, VAR.t4.zw).xyz;
	float3 L = tex2D(decal, VAR.t5.xy).xyz;
	float3 M = tex2D(decal, VAR.t5.zw).xyz;

	tmp = mul(float4x3(J,K,L,M), YUV);
	J = tmp[0], K = tmp[1], L = tmp[2], M = tmp[3];



	// equality checks
	bool AE = eq(A,E), AJ = eq(A,J), AK = eq(A,K), BD = eq(B,D), BF = eq(B,F), CE = eq(C,E), CJ = eq(C,J), CL = eq(C,L), DH = eq(D,H), EG = eq(E,G), EI = eq(E,I), FH = eq(F,H), GK = eq(G,K), GM = eq(G,M), IL = eq(I,L), IM = eq(I,M);

	// parent condition
	bool par0 = !(BF || DH);
	bool par1 = !(BD || FH);
	
	// diagonal condition
	bool dia0 = AE || EI;
	bool dia1 = CE || EG;

	// artifact prevention
	bool art0 = BD && par0 && (!AE || dia1 || AJ || AK);
	bool art2 = BF && par1 && (!CE || dia0 || CJ || CL);
	bool art6 = DH && par1 && (!EG || dia0 || GK || GM);
	bool art8 = FH && par0 && (!EI || dia1 || IL || IM);



	// rules
	float3 E0 = art0 || BD && (CE && !CJ && !AE || EG && !AE && !GK) ? 0.5*(b+d) : e;
	float3 E2 = art2 || BF && (AE && !AJ && !CE || EI && !CE && !IL) ? 0.5*(b+f) : e;
	float3 E6 = art6 || DH && (AE && !AK && !EG || EI && !EG && !IM) ? 0.5*(h+d) : e;
	float3 E8 = art8 || FH && (CE && !CL && !EI || EG && !EI && !GM) ? 0.5*(h+f) : e;

	float3 E1 = art0 && !CE || art2 && !AE ? b : e;
	float3 E3 = art0 && !EG || art6 && !AE ? d : e;
	float3 E5 = art8 && !CE || art2 && !EI ? f : e;
	float3 E7 = art8 && !EG || art6 && !EI ? h : e;


	// subpixel output
	return fp.y == 0 ? (fp.x == 0 ? E0 : fp.x == 1 ? E1 : E2) : (fp.y == 1 ? (fp.x == 0 ? E3 : fp.x == 1 ? e : E5) : (fp.x == 0 ? E6 : fp.x == 1 ? E7 : E8));
}
