#pragma parameter NEDI_WEIGHT "Nedi Weight" 1.0 -50.0 50.0 1.0
#pragma parameter NEDI_E "Nedi Bilinear" 0.0 0.0 0.3 0.01
#pragma parameter NEDI_OFFSET "Nedi Offset" 0.0 0.0 1.0 0.1
#ifdef PARAMETER_UNIFORM
uniform float NEDI_WEIGHT;
uniform float NEDI_E;
uniform float NEDI_OFFSET;
#else
#define NEDI_WEIGHT 1.0
#define NEDI_E 0.0
#define NEDI_OFFSET 0.0
#endif
// END PARAMETERS //


/* COMPATIBILITY
   - HLSL compilers
   - Cg   compilers
*/

/*
   NEDI Shader  -  pass0

   Sources ported from this discussion thread:

      http://forum.doom9.org/showthread.php?t=170727
   
   Ported by Hyllian - 2015.
*/


#define width  (IN.texture_size.x)
#define height (IN.texture_size.y)

#define px (1.0 / (2*IN.texture_size.x))
#define py (1.0 / (2*IN.texture_size.y))

#define offset NEDI_OFFSET
#define Value(xy) (tex2D(s0,tex+float2(px,py)*(xy)))//-float4(0,0.5,0.5,0))
#define Get(xy) (dot(Value(xy).rgb,float3(0.299,0.587,0.114))+offset)
#define Get4(xy) (float2(Get(xy+2*dir[0])+Get(xy+2*dir[1]),Get(xy+2*dir[2])+Get(xy+2*dir[3])))

#define sqr(x) (dot(x,x))
#define I (float2x2(1,0,0,1))


//Cramer's method
float2 solve(float2x2 A,float2 b) { return float2(determinant(float2x2(b,A[1])),determinant(float2x2(A[0],b)))/determinant(A); }



     
    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;
    };
     
    /*    VERTEX_SHADER    */
    out_vertex main_vertex
    (
        float4 position    : POSITION,
        float4 color    : COLOR,
        float2 texCoord1   : TEXCOORD0,
     
           uniform float4x4 modelViewProj,
        uniform input IN
    )
    {

	float2 tex = texCoord1;

        out_vertex OUT = {
            mul(modelViewProj, position),
            color,
            tex
        };
     
        return OUT;
    }
     
     
    float4 main_fragment(in out_vertex VAR, uniform sampler2D s0 : TEXUNIT0, uniform input IN) : COLOR
    {
        float2 tex = VAR.texCoord;

	float4 c0 = tex2D(s0,tex);

	//Skip pixels on wrong grid
 	if ((frac(tex.x*width)<0.5)||(frac(tex.y*height)<0.5)) return c0;
	
	//Define window and directions
	float2 dir[4] = {{-1,-1},{1,1},{-1,1},{1,-1}};
	float4x2 wind[4] = {{{-1,-1},{1,1},{-1,1},{1,-1}},{{-3,-1},{3,1},{-1,3},{1,-3}},{{-3,1},{3,-1},{1,3},{-1,-3}},{{-3,-3},{ 3,3},{-3, 3},{3,-3}}};

	//Initialization
	float2x2 R = 0;
	float2 r = 0;
        float m[4] = {NEDI_WEIGHT, 1.0, 1.0, 1.0};

	//Calculate (local) autocorrelation coefficients
	for (int k = 0; k<3; k+= 1){
		float4 y = float4(Get(wind[k][0]),Get(wind[k][1]),Get(wind[k][2]),Get(wind[k][3]));
		float4x2 C = float4x2(Get4(wind[k][0]),Get4(wind[k][1]),Get4(wind[k][2]),Get4(wind[k][3]));
		R += mul(transpose(C),m[k]*C);
		r += mul(y,m[k]*C);
	}
	
	//Normalize
	float n = 24;
	R /= n; r /= n;

	//Calculate a =  R^-1 . r
	float e = NEDI_E;
	float2 a = solve(R+e*e*I,r+e*e/2.0);

	//Nomalize 'a' (prevents overshoot)
	a = .25 + float2(.5,-.5)*clamp(a[0]-a[1],-1,1);

	//Calculate result
	float2x4 x = float2x4(Value(dir[0])+Value(dir[1]),Value(dir[2])+Value(dir[3]));
	float4 c = mul(float1x2(a),x);
	
	return c;//+float4(0,0.5,0.5,0);

    }

