#include "inout.hlsl"

// fxStructs.h
#define	FX_POST_PROCESS_NONE					0
#define	FX_POST_PROCESS_GREYSCALE				1
#define	FX_POST_PROCESS_GREYSCALE_RED			2
#define	FX_POST_PROCESS_GREYSCALE_GREEN			3
#define	FX_POST_PROCESS_GREYSCALE_BLUE			4
#define	FX_POST_PROCESS_INVERT					5
#define	FX_POST_PROCESS_SEPIA					6
#define	FX_POST_PROCESS_BW						7
#define	FX_POST_PROCESS_CHROMATIC_ABERRATION	8
#define	FX_POST_PROCESS_GAUSSIAN_BLUR_X			9
#define	FX_POST_PROCESS_GAUSSIAN_BLUR_Y			10
#define	FX_POST_PROCESS_WIGGLE_X				11
#define	FX_POST_PROCESS_WIGGLE_Y				12
#define	FX_POST_PROCESS_BRIGHT_PASS				13
#define	FX_POST_PROCESS_EDGE_DETECTION			14
#define	FX_POST_PROCESS_PIXEL_DISTORTION		15
#define	FX_POST_PROCESS_CUBIC_LENS_DISTORTION	16
#define	FX_POST_PROCESS_VHS_TAPE				17

Texture2D ShaderTexture;
SamplerState SampleType;

cbuffer ParamBuffer
{
	int		PB_PostProcessFilter;
	int		PB_bHasTexture;
	int		PB_bHasBlending;
	float	PB_fBlendFactor;
	int		PB_bUseColorAlpha;
	int		PB_bRadialBlur;

	int PB_texWidth;
	int PB_texHeight;

	int	PB_time;
	float3 PB_paddy;
};

cbuffer LineBuffer
{
	float4 LB_Line[4096];
};

static const float fLuminance = 0.08f;
static const float fMiddleGray = 0.18f;
static const float fWhiteCutoff = 0.8f;
static const int g_cKernelSize = 13;
//float2 TexelKernel[g_cKernelSize];
static const float PixelKernel[g_cKernelSize] =
{
  -6.0f,
  -5.0f,
  -4.0f,
  -3.0f,
  -2.0f,
  -1.0f,
   0.0f,
   1.0f,
   2.0f,
   3.0f,
   4.0f,
   5.0f,
   6.0f,
};
static const float BlurWeight[g_cKernelSize] = 
{
  0.002216,
  0.008764,
  0.026995,
  0.064759,
  0.120985,
  0.176033,
  0.199471,
  0.176033,
  0.120985,
  0.064759,
  0.026995,
  0.008764,
  0.002216,
};

float rand_1_05(in float2 uv)
{
    float2 noise = (frac(sin(dot(uv ,float2(12.9898,78.233)*2.0)) * 43758.5453));
    return abs(noise.x + noise.y) * 0.5;
}

float4 PostProcess_PS(PIT_PP input) : SV_TARGET
{
	float fTexWidth		= 1.0f / PB_texWidth;
	float fTexHeight	= 1.0f / PB_texHeight;

	float4 finalColor;

	if ( PB_bHasTexture )
	{
		finalColor = ShaderTexture.Sample(SampleType, input.tex);
	}
	else
	{
		finalColor = input.color;
	}

	if ( PB_bHasBlending )
	{
		if ( PB_bUseColorAlpha )
		{
			if (PB_bHasTexture)
			{
				if (PB_bRadialBlur)
				{
					finalColor.a = input.color.a;
				}
				else
				{
					finalColor.a = ShaderTexture.Sample(SampleType, input.tex).w * PB_fBlendFactor;
				}
			}
			else
			{
				finalColor.a = input.color.a * (finalColor.r + finalColor.g + finalColor.b) / 3.0f;
			}
		}
		else
		{
			finalColor.a = PB_fBlendFactor;
		}
	}
	else
	{
		finalColor.a = 1.0f;
	}

	[forcecase]
	switch ( PB_PostProcessFilter )
	{
		case FX_POST_PROCESS_NONE:
		{
			finalColor = finalColor;
		}
		break;
		case FX_POST_PROCESS_GREYSCALE:
		{
			finalColor.rgb = (finalColor.r + finalColor.g + finalColor.b) / 3.0f;
		}
		break;
		case FX_POST_PROCESS_GREYSCALE_RED:
		{
			finalColor.gb = (finalColor.r + finalColor.g + finalColor.b) / 3.0f;
		}
		break;
		case FX_POST_PROCESS_GREYSCALE_GREEN:
		{
			finalColor.rb = (finalColor.r + finalColor.g + finalColor.b) / 3.0f;
		}
		break;
		case FX_POST_PROCESS_GREYSCALE_BLUE:
		{
			finalColor.rg = (finalColor.r + finalColor.g + finalColor.b) / 3.0f;
		}
		break;
		case FX_POST_PROCESS_INVERT:
		{
			finalColor.r = 1.0f - finalColor.r;
			finalColor.g = 1.0f - finalColor.g;
			finalColor.b = 1.0f - finalColor.b;
		}
		break;
		case FX_POST_PROCESS_SEPIA:
		{
			finalColor.r = (finalColor.r * 0.393) + (finalColor.g * 0.769) + (finalColor.b * 0.189);
			finalColor.g = (finalColor.r * 0.349) + (finalColor.g * 0.686) + (finalColor.b * 0.168);    
			finalColor.b = (finalColor.r * 0.272) + (finalColor.g * 0.534) + (finalColor.b * 0.131);
		}
		break;
		case FX_POST_PROCESS_BW:
		{
			finalColor.rgb = (finalColor.r + finalColor.g + finalColor.b) / 3.0f; 
			if (finalColor.r < 0.2 || finalColor.r > 0.9) finalColor.r = 0; else finalColor.r = 1.0f;
			if (finalColor.g < 0.2 || finalColor.g > 0.9) finalColor.g = 0; else finalColor.g = 1.0f;
			if (finalColor.b < 0.2 || finalColor.b > 0.9) finalColor.b = 0; else finalColor.b = 1.0f;
		}
		break;
		case FX_POST_PROCESS_CHROMATIC_ABERRATION:
		{
			float k =  -0.15f;
			float kcube = 0.15f;

			float r2 = (input.tex.x-0.5) * (input.tex.x-0.5) + (input.tex.y-0.5) * (input.tex.y-0.5);       
			float f = 0;
       
 			if( kcube == 0.0)
			{
                f = 1 + r2 * k;
			}
			else
			{
                f = 1 + r2 * (k + kcube * sqrt(r2));
			}
       
			float x = f*(input.tex.x-0.5)+0.5;
			float y = f*(input.tex.y-0.5)+0.5;
			float3 inputDistord = ShaderTexture.Sample(SampleType, float2(x, y));
			float3 inputOriginal = ShaderTexture.Sample(SampleType, float2(input.tex.x, input.tex.y));
 
			finalColor = float4(inputDistord.r, inputOriginal.g, inputOriginal.b, 1.0f);
		}
		break;
		case FX_POST_PROCESS_GAUSSIAN_BLUR_X:
		{
			finalColor.rgb = float3(0.0f, 0.0f, 0.0f);

			for (int i = 0; i < g_cKernelSize; i++)
			{ 
				float2 finalTex = input.tex;
				finalTex.x += PixelKernel[i] * fTexWidth;
        finalColor.rgb += ShaderTexture.Sample(SampleType, finalTex) * BlurWeight[i];
			}
		}
		break;
		case FX_POST_PROCESS_GAUSSIAN_BLUR_Y:
		{
			finalColor.rgb = float3(0.0f, 0.0f, 0.0f);

			for (int i = 0; i < g_cKernelSize; i++)
			{ 
				float2 finalTex = input.tex;
				finalTex.y += PixelKernel[i] * fTexHeight;
        finalColor.rgb += ShaderTexture.Sample(SampleType, finalTex) * BlurWeight[i];
			}
		}
		break;
		case FX_POST_PROCESS_WIGGLE_X:
		{	
			float fSin = sin(PB_time * 0.01f) * 20.0f;
			float fSin2 = sin(PB_time * 0.01f) * 20.0f;
			float2 sepTex;
			float4 sepColor;

			finalColor = ShaderTexture.Sample(SampleType, input.tex);

			sepTex = input.tex;
			sepTex.x += fTexWidth * fSin * 1.0f;
			sepColor = ShaderTexture.Sample(SampleType, sepTex);
			finalColor.r = sepColor.r;

			sepTex = input.tex;
			sepTex.y -= fTexHeight * fSin2 * 1.0f;
			sepColor = ShaderTexture.Sample(SampleType, sepTex);
			finalColor.b = sepColor.b;


/*

			float4 rgbColor = ShaderTexture.Sample(SampleType, input.tex);
			float2 wiggleTex = input.tex;
			wiggleTex.x = wiggleTex.x + (cos(wiggleTex.x * 32.0f)) * fTexWidth * cos(PB_time * 0.001f) * 10.0f;
			wiggleTex.y = wiggleTex.x + (cos(wiggleTex.x * 32.0f)) * fTexWidth * cos(PB_time * 0.002f) * 10.0f;

			float4 wiggleColor = ShaderTexture.Sample(SampleType, wiggleTex);
			finalColor = rgbColor;
			finalColor.r = wiggleColor.r;
			finalColor.b = wiggleColor.b;
*/
/*
			float fTime = (float)PB_time * 0.0001f;
			float x = 0.0f;
			float y = 0.0f;
			float xy = 0.0f;
			float d = 0.0f;
			float s = 0.0f;

			float r = 0.0f;
			float g = 0.0f;
			float b = 0.0f;

			s = 1.0f + 1.0f * sin(fTime);

			x = 1.0f * sin( (input.tex.x + fTime ) * s * 4.0f);
			y = 1.0f * sin( (input.tex.y + fTime ) * s * 8.0f );
			xy =1.0f * sin( (input.tex.x + input.tex.y + fTime) * s * 4.0f);
			d = 1.0f * sin( sqrt( input.tex.x * input.tex.x + input.tex.y * input.tex.y + fTime ) * s * 8.0f );
			r = (x + y + xy + d) / 4.0f;

			x = 1.0f * sin( (input.tex.x + fTime ) * s * 8.0f);
			y = 1.0f * sin( (input.tex.y + fTime ) * s * 2.0f );
			xy =1.0f * sin( (input.tex.x + input.tex.y + fTime) * s * 8.0f);
			d = 1.0f * sin( sqrt( input.tex.x * input.tex.x + input.tex.y * input.tex.y + fTime ) * s * 2.0f );
			g = (x + y + xy + d) / 4.0f;

			x = 1.0f * sin( (input.tex.x + fTime ) * s * 2.0f);
			y = 1.0f * sin( (input.tex.y + fTime ) * s * 4.0f );
			xy =1.0f * sin( (input.tex.x + input.tex.y + fTime) * s * 2.0f);
			d = 1.0f * sin( sqrt( input.tex.x * input.tex.x + input.tex.y * input.tex.y + fTime ) * s * 4.0f );
			b = (x + y + xy + d) / 4.0f;

			finalColor = float4(r, g, b, 0.0f);
*/
		}
		break;
		case FX_POST_PROCESS_WIGGLE_Y:
		{
			float2 wiggleTex = input.tex;
			wiggleTex.y = wiggleTex.y + (cos(wiggleTex.y * 32.0f) * fTexHeight * 16.0f);

			finalColor = ShaderTexture.Sample(SampleType, wiggleTex);
		}
		break;
		case FX_POST_PROCESS_BRIGHT_PASS:
		{
/*
			finalColor *= fMiddleGray / ( fLuminance + 0.001f );
			finalColor *= ( 1.0f + ( finalColor / ( fWhiteCutoff * fWhiteCutoff ) ) );
			finalColor -= 5.0f;

			finalColor = max( finalColor, 0.0f );

			finalColor /= ( 10.0f + finalColor);
*/
			finalColor.rgb = pow(finalColor.rgb, 2.0f) * 3.0f;
		}
		break;
		case FX_POST_PROCESS_EDGE_DETECTION:
		{
		  float4 lum = float4(0.30, 0.59, 0.11, 1);
 
		  // TOP ROW
		  float s11 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(-1.0f / PB_texWidth, -1.0f / PB_texHeight)), lum);   // LEFT
		  float s12 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(0, -1.0f / 768.0f)), lum);             // MIDDLE
		  float s13 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(1.0f / PB_texWidth, -1.0f / PB_texHeight)), lum);    // RIGHT
 
		  // MIDDLE ROW
		  float s21 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(-1.0f / PB_texWidth, 0)), lum);                // LEFT
		  // Omit center
		  float s23 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(-1.0f / PB_texWidth, 0)), lum);                // RIGHT
 
		  // LAST ROW
		  float s31 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(-1.0f / PB_texWidth, 1.0f / PB_texHeight)), lum);    // LEFT
		  float s32 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(0, 1.0f / PB_texHeight)), lum);              // MIDDLE
		  float s33 = dot(ShaderTexture.Sample(SampleType, input.tex + float2(1.0f / PB_texWidth, 1.0f / PB_texHeight)), lum); // RIGHT
 
		  // Filter
		  float t1 = s13 + s33 + (2 * s23) - s11 - (2 * s21) - s31;
		  float t2 = s31 + (2 * s32) + s33 - s11 - (2 * s12) - s13;
 
		  if (((t1 * t1) + (t2 * t2)) > 0.05)
		  {
//		    finalColor = float4(0,0,0,1);
			finalColor = float4(1,1,1,1);
		  }
		  else
		  {
//			finalColor = float4(1,1,1,1);
		    finalColor = float4(0,0,0,1);
//			finalColor = finalColor;
		  }
		}
		break;
		case FX_POST_PROCESS_PIXEL_DISTORTION:
		{
		  int iSeed = 11111;
		  float fNoiseAmount = 0.01f;

		  float fNoiseX = iSeed * 1.0f * sin(input.tex.x * input.tex.y + 1.0f);
		  fNoiseX = fmod(fNoiseX, 8) * fmod(fNoiseX, 4); 

		  float fDistortX = fmod(fNoiseX, fNoiseAmount);
		  float fDistortY = fmod(fNoiseX, fNoiseAmount + 0.004f);
 
		  float2 fDistortTex = float2(fDistortX, fDistortY);

 		  finalColor = ShaderTexture.Sample(SampleType, input.tex + fDistortTex);
		  finalColor.a = 1.0f;
		}
		break;
		case FX_POST_PROCESS_CUBIC_LENS_DISTORTION:
		{
			// lens distortion coefficient
			float k =  -1.9f;
//			float k = PB_padding;
//			float k =  1.0f;
//			float k = -0.15f;
       
			// cubic distortion value
			float kcube = 0.25f;
//			float kcube = 0.0f;       
       

			float r2 = (input.tex.x-0.5) * (input.tex.x-0.5) + (input.tex.y-0.5) * (input.tex.y-0.5);       
			float f = 0;
       
 
			// only compute the cubic distortion if necessary
			if( kcube == 0.0)
			{
                f = 1 + r2 * k;
			}
			else
			{
                f = 1 + r2 * (k + kcube * sqrt(r2));
			}
       
			// get the right pixel for the current position
			float x = f*(input.tex.x-0.5)+0.5;
			float y = f*(input.tex.y-0.5)+0.5;
			float3 inputDistord = ShaderTexture.Sample(SampleType, float2(x, y));

 			finalColor = float4(inputDistord.r,inputDistord.g,inputDistord.b,1);
		}
		break;
		case FX_POST_PROCESS_VHS_TAPE:
		{
			int fLinePos = PB_texHeight * input.tex.y;

			float2 texPos;
			float4 sepColor;

			float fPosX = LB_Line[fLinePos].x + LB_Line[fLinePos].w;

			texPos = input.tex;
			texPos.x -= fPosX * fTexWidth;
			finalColor = ShaderTexture.Sample(SampleType, texPos);

			texPos = input.tex;
			texPos.x -= fPosX * fTexWidth * 1.20f;
			sepColor = ShaderTexture.Sample(SampleType, texPos);
			finalColor.r = sepColor.r;

			texPos = input.tex;
			texPos.x -= fPosX * fTexHeight * 1.30f;
			sepColor = ShaderTexture.Sample(SampleType, texPos);
			finalColor.g = sepColor.g;

			texPos = input.tex;
			texPos.x -= fPosX * fTexHeight * 1.40f;
			sepColor = ShaderTexture.Sample(SampleType, texPos);
			finalColor.b = sepColor.b;

			if (texPos.x < 0.001f)
			{
				finalColor = float4(0.0f, 0.0f, 0.0f, 0.0f);
			}
		}
		break;
	}

	return finalColor;
}