/*
   Hyllian's 5xBR v3.2 Shader
   
   Copyright (C) 2011 Hyllian/Jararaca - sergiogdb@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.

*/

const static float3 dtt = float3(65536,255,1);
const static float3 dt = float3(1.0, 1.0, 1.0);
const static float3x3 yuv = float3x3(0.299, 0.587, 0.114, -0.169, -0.331, 0.5, 0.5, -0.419, -0.081);
const static float3 filter_cf = float3(48.0, 7.0, 6.0);
const static float3x3 yuv_filtered = float3x3(14.352, 28.176, 5.472, -1.183, -2.317, 3.5, 3.0, -2.514, -0.486);

float reduce(float3 color)
{
	return dot(color, dtt);
}

float df(float3 A, float3 B)
{
	return abs(mul(yuv_filtered, A-B));
}

bool eq(float3 A, float3 B)
{
	return all(filter_cf >= mul(yuv, A-B));
}

struct input
{
	float2 video_size;
	float2 texture_size;
	float2 output_size;
	float frame_count;
	float frame_direction;
	float frame_rotation;
};


struct out_vertex {
	float4 position : POSITION;
	float4 color    : COLOR;
	float2 texCoord : TEXCOORD0;
	float4 t1 : TEXCOORD1;
};

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

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

	OUT.position = mul(modelViewProj, position);
	OUT.color = color;

	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.xy = float2(  0,-dy); // B
	OUT.t1.zw = float2(-dx,  0); // D

	return OUT;
}

#define RULE(PE, PC, PG, PI, H5, F4, PH, PF) \
	(df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + 4*df(PH,PF))\

/*    FRAGMENT SHADER    */
float4 main_fragment(in out_vertex VAR, uniform sampler2D decal : TEXUNIT0, uniform input IN) : COLOR
{
	float2 fp = frac(VAR.texCoord*IN.texture_size);

	float2 st = step(0.5,fp);

	float2 g1 = VAR.t1.xy*(st.x + st.y - 1.0) + VAR.t1.zw*(st.x - st.y    );
	float2 g2 = VAR.t1.xy*(st.y - st.x    ) + VAR.t1.zw*(st.x + st.y - 1.0);

	float AO  = 2.0*st.y - 1.0;
	float BO  = 2.0*st.x - 1.0;
	float CO  = st.x + st.y - 0.5;

	float AX  = 0.5*st.x + 1.5*st.y - 1.0;
	float BX  = 1.5*st.x - 0.5*st.y - 0.5;
	float CX  =     st.x + 0.5*st.y - 0.5;

	float AY  = -0.5*st.x + 1.5*st.y - 0.5;
	float BY  =  1.5*st.x + 0.5*st.y - 1.0;
	float CY  =  0.5*st.x +     st.y - 0.5;

	float3 A = tex2D(decal, VAR.texCoord +g1+g2).xyz;
	float3 B = tex2D(decal, VAR.texCoord +g1   ).xyz;
	float3 C = tex2D(decal, VAR.texCoord +g1-g2).xyz;
	float3 D = tex2D(decal, VAR.texCoord    +g2).xyz;
	float3 E = tex2D(decal, VAR.texCoord       ).xyz;
	float3 F = tex2D(decal, VAR.texCoord    -g2).xyz;
	float3 G = tex2D(decal, VAR.texCoord -g1+g2).xyz;
	float3 H = tex2D(decal, VAR.texCoord -g1   ).xyz;
	float3 I = tex2D(decal, VAR.texCoord -g1-g2).xyz;

	float3  C1 = tex2D(decal,VAR.texCoord +2.0*g1-g2   ).xyz;
	float3  G0 = tex2D(decal,VAR.texCoord -g1+2.0*g2   ).xyz;
	float3  C4 = tex2D(decal,VAR.texCoord +g1-2.0*g2   ).xyz;
	float3  F4 = tex2D(decal,VAR.texCoord    -2.0*g2   ).xyz;
	float3  I4 = tex2D(decal,VAR.texCoord -g1-2.0*g2   ).xyz;
	float3  G5 = tex2D(decal,VAR.texCoord -2.0*g1+g2   ).xyz;
	float3  H5 = tex2D(decal,VAR.texCoord -2.0*g1      ).xyz;
	float3  I5 = tex2D(decal,VAR.texCoord -2.0*g1-g2   ).xyz;
	float3  B1 = tex2D(decal,VAR.texCoord +2.0*g1      ).xyz;
	float3  D0 = tex2D(decal,VAR.texCoord +2.0*g2      ).xyz;

	float a = reduce(A);
	float b = reduce(B);
	float c = reduce(C);
	float d = reduce(D);
	float e = reduce(E);
	float f = reduce(F);
	float g = reduce(G);
	float h = reduce(H);
	float i = reduce(I);

	float  c1 = reduce( C1);
	float  g0 = reduce( G0);
	float  c4 = reduce( C4);
	float  f4 = reduce( F4);
	float  i4 = reduce( I4);
	float  g5 = reduce( G5);
	float  h5 = reduce( H5);
	float  i5 = reduce( I5);
	float  b1 = reduce( B1);
	float  d0 = reduce( D0);

	bool inex, ex, esqu, cima, diag, e_i, kei, mei, ex_ck, ex_em;
	bool fx_1, fx_2, fx_3, fx_4, fx_5;

	fx_1        = (AO*fp.y+BO*fp.x > CO);
	fx_2        = (AX*fp.y+BX*fp.x > CX);
	fx_3        = (AY*fp.y+BY*fp.x > CY);
	fx_4        = (BY*fp.y+AY*(1-fp.x) > CY);
	fx_5        = (BX*(1-fp.y)+AX*fp.x > CX);

	e_i = (RULE( E, C, G, I, H5, F4, H, F) < RULE( H, D, I5, F, I4, B, E, I));
	kei = (RULE( E, A, I, C, F4, B1, F, B) < RULE( F, H, C4, B, C1, D, E, C));
	mei = (RULE( E, I, A, G, D0, H5, D, H) < RULE( D, B, G0, H, G5, F, E, G));

	float3 px   = (df(E,F) <= df(E,H)) ? F : H;
	float3 px_c = (df(E,B) <= df(E,F)) ? B : F;
	float3 px_e = (df(E,H) <= df(E,D)) ? H : D;

	ex    = e!=f && e!=h;
	ex_ck = e!=b && e!=f;
	ex_em = e!=h && e!=d;
	inex  = !eq(E,F) && !eq(E,H);

	esqu = !eq(G,D) && (eq(H,G) || eq(F,G));

	cima = !eq(B,C) && (eq(F,C) || eq(H,C));

	bool r1 = ( e_i && ex && (fx_1 || f==g && fx_2 || h==c && fx_3) );
	bool r2 = ( ex_ck && kei && b==i && fx_5 );
	bool r3 = ( ex_em && mei && d==i && fx_4 );

	float3 res = r1 ? px : r2 ? px_c : r3 ? px_e : E;

	return float4(res, 1.0);
}





