/* COMPATIBILITY 
   - HLSL compilers
   - Cg   compilers
   - FX11 compilers
*/

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

#include "../../compat_includes.inc"
uniform COMPAT_Texture2D(decal) : TEXUNIT0;
uniform float4x4 modelViewProj;

struct out_vertex {
	float4 position : COMPAT_POS;
	float2 texCoord : TEXCOORD0;
	float4 t1 : TEXCOORD1;
	float4 t2 : TEXCOORD2;
	float4 t3 : TEXCOORD3;
	float4 t4 : TEXCOORD4;
	float4 t5 : TEXCOORD5;
#ifndef HLSL_4
	float4 Color    : COLOR;
#endif
};

/*    VERTEX_SHADER    */
out_vertex main_vertex(COMPAT_IN_VERTEX)
{
	out_vertex OUT;
#ifdef HLSL_4
	float4 position = VIN.position;
	float2 texCoord = VIN.texCoord;
#else
	OUT.Color = color;
#endif
	OUT.position = mul(modelViewProj, position);

	float2 ps = float2(1.0/COMPAT_texture_size.x, 1.0/COMPAT_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;
}

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

float3 scale3xSFX(float2 texture_size, float4 t1, float4 t2, float4 t3, float4 t4, float4 t5, float2 texCoord, COMPAT_Texture2D(decal))
{
	// subpixel determination
	float2 fp = floor(3.0 * frac(texCoord*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 = COMPAT_SamplePoint(decal, t1.yw).xyz;
	float3 d = COMPAT_SamplePoint(decal, t2.xw).xyz;
	float3 e = COMPAT_SamplePoint(decal, t2.yw).xyz;
	float3 f = COMPAT_SamplePoint(decal, t2.zw).xyz;
	float3 h = COMPAT_SamplePoint(decal, 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 = COMPAT_SamplePoint(decal, t1.xw).xyz;
	float3 C = COMPAT_SamplePoint(decal, t1.zw).xyz;
	float3 G = COMPAT_SamplePoint(decal, t3.xw).xyz;
	float3 I = COMPAT_SamplePoint(decal, 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 = COMPAT_SamplePoint(decal, t4.xy).xyz;
	float3 K = COMPAT_SamplePoint(decal, t4.zw).xyz;
	float3 L = COMPAT_SamplePoint(decal, t5.xy).xyz;
	float3 M = COMPAT_SamplePoint(decal, 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));
}

float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output
{
	return float4(scale3xSFX(COMPAT_texture_size, VOUT.t1, VOUT.t2, VOUT.t3, VOUT.t4, VOUT.t5, VOUT.texCoord, decal), 1.0);
}
COMPAT_END