//	K ENB Evolution   
//	Sharp Kinematic Filter v6.0
//	I'm using additional sharpening to 'un-clean' and 'noise' blacks and outlines at very high resolutions and CSSAO-CSSIL Scales
//	May be usefull to generate some 'noise' in outlines at regular resolutions as well a/o increased CSSAO-CSSIL Scales
//	Copyright (c) 2007-2013 Boris Vorontsov

/**
 *	KYO : 
 *	B&W Filter originally tweaked by Anthemios aka Trilville	
 *	Tweaked by midhras to re-introduce colour and emulate occlusion
 *	Tweaked by Kyo to re-introduce sharpening and grain methods
 *	Static and Dynamic grain formulas - ENABLE ONE ONLY - See below 
 */

//Enable Separation by 625 scanlines
//#define ESCANLINE

//First Filter
float3 GrayFilter=float3(0.5285, 0.515, 0.515);	// 0.520	// 0.55 //<-[KYO : More pizza]	// 0.52885	// 0.5285
float Brightness=1.092225;	// 1.097225		// 1.10 //<-[KYO : Highlights - Counterbalance with NoiseMixCurve below]
float ClampLow=0.000005;
float ClampHigh=15.25;

float NoiseMixCurve=0.02885;	// 0.02875 	// 0.03	// [Works like black level (set higher if no SSAO-AO-HBAO) - This will suck colours away however _ Effect is rather discreet here] 
float NoiseMixMultiplier=0.15;
float AdditiveNoiseFactor=0.0075; 		// [More ANF = more noise] // [Comment this line to disable the B&W filter entirely]
float MultiplicativeNoiseMin=-0.45;
float MultiplicativeNoiseMax=-0.45;

float BlurSamplingRange=0.05;//horizontal blur

//-------------------------------------------------------------------------------------------------------

//Then Sharpen
//enable sharpening
#define ESHARPENING

//if defined, color sharpen, otherwise sharp by gray
#define ESHARPENINGCOLOR

//-------------------------------------------------------------------------------------------------------

//Last Kinematize
//enable Static noise in dark areas
#define ESTATICNOISE

//enable Dynamic noise in dark areas
//#define EDYNAMICNOISE

float SamplingRange=1.0; 	// sharpening or blurring range		// 0.25;
float SharpeningAmount=0.727;	// 1.0;	//1.1;	//0.725;
//float ScanLineAmount=2.0;	// 0.0;  //[KYO : less noise, cleaner lines - Uncomment and comment below]
//float ScanLineRepeat=0.3333;  // 0.5, 0.3333, 0.25, 0.125, so on //[KYO : less noise, cleaner lines - Uncomment and comment below]
float ScanLineAmount=0.0;	// 0.0;  //[KYO : more noise]
float ScanLineRepeat=0.0; 	// 0.0;  //[KYO : more noise]

#ifdef EDYNAMICNOISE
float NoiseAmount=0.125;   // 0.12	// 0.145
float NoiseDiffusion=0.5;		// [KYO : ranges from 0.1 to 1.9]
#endif

#ifdef ESTATICNOISE
float NoiseAmount=0.0175;  // 0.125	// 0.145
float NoiseDiffusion=0.5;		// [KYO : ranges from 0.1 to 1.9]
#endif


//-------------------------------------------------------------------------------------------------------
/**
 *	External parameters, do not modify
 *	Keyboard controlled temporary variables (in some versions exists in the config file) 
 *	Press and hold key 1,2,3...8 together with PageUp or PageDown to modify
 *	By default all set to 1.0
 */
float4	tempF1; //0,1,2,3
float4	tempF2; //5,6,7,8
float4	tempF3; //9,0
//x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds)
float4	Timer;
//x=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY
float4	ScreenSize;
//changes in range 0..1, 0 means full quality, 1 lowest dynamic quality (0.33, 0.66 are limits for quality levels)
float	EAdaptiveQualityFactor;
//fov in degrees
float	FieldOfView;

//textures
texture2D texColor;
texture2D texNoise;

sampler2D SamplerColor = sampler_state
{
	Texture   = <texColor>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU  = Clamp;
	AddressV  = Clamp;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};

sampler2D SamplerNoise = sampler_state
{
	Texture   = <texNoise>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU  = Wrap;
	AddressV  = Wrap;
	SRGBTexture=FALSE;
	MaxMipLevel=0;
	MipMapLodBias=0;
};


struct VS_OUTPUT_POST
{
	float4 vpos  : POSITION;
	float2 txcoord : TEXCOORD0;
};

struct VS_INPUT_POST
{
	float3 pos  : POSITION;
	float2 txcoord : TEXCOORD0;
};


VS_OUTPUT_POST VS_PostProcess(VS_INPUT_POST IN)
{
	VS_OUTPUT_POST OUT;

	float4 pos=float4(IN.pos.x,IN.pos.y,IN.pos.z,1.0);

	OUT.vpos=pos;
	OUT.txcoord.xy=IN.txcoord.xy;

	return OUT;
}

//1
float4 PS_ProcessColor(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 res;
	float4 coord=0.0;
	coord.xy=IN.txcoord.xy;

	float4 origcolor=tex2Dlod(SamplerColor, coord);

	//black-white filter
	//origcolor.xyz=dot(origcolor.xyz, GrayFilter.xyz);
	//MIDHRAS : add comment to line above to regain colour but keep TV noise.
	//scale
	origcolor.xyz*=Brightness;
	//limit
	origcolor.xyz=clamp(origcolor.xyz, ClampLow, ClampHigh);


	//noise
	coord.xy=IN.txcoord.xy*ScreenSize.y*4000.0;
	coord.y+=frac(Timer.x * 140000.0);
	float4 noisebig=tex2D(SamplerNoise, coord);
	float mixfact=noisebig.x;
	mixfact=saturate((mixfact-0.5)*5.0);

	coord.xy=IN.txcoord.xy*ScreenSize.x*0.008;
	coord.x+=frac((noisebig.y)*frac(Timer.x*100000.0)*1.3);
	coord.y+=frac(Timer.x*160000.0);
	float4 noisecolor=tex2D(SamplerNoise, coord);
	noisecolor.w=lerp(noisecolor.x, noisecolor.y, mixfact);


	//mix gray with noise
	mixfact=dot(origcolor.xyz, 2.133);
	mixfact=pow(saturate(NoiseMixMultiplier*mixfact), NoiseMixCurve);
	noisecolor.x=noisecolor.w*AdditiveNoiseFactor;
	noisecolor.w=lerp(MultiplicativeNoiseMin, MultiplicativeNoiseMax, noisecolor.w);
	res.xyz=lerp(origcolor.xyz*noisecolor.w+noisecolor.x, origcolor.xyz, mixfact);

	res.w=1.0;
	return res;
}

//2
float4 PS_ProcessHorizontalBlur(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 res;
	float4 coord=0.0;

	coord.xy=IN.txcoord.xy;

	coord.w=0.0;

	int i=0;

	float4 tcol=0.0;
	float2 invscreensize=ScreenSize.y;
	float offset=-2.0;
	for (i=0; i<5; i++)
	{
		coord.x=IN.txcoord.x+offset*invscreensize*BlurSamplingRange;
		float4 ct=tex2Dlod(SamplerColor, coord);

		tcol+=ct;
		offset+=1.0;
	}
	res.xyz=tcol.xyz*0.2;

	res.w=1.0;
	return res;
}

//3
float4 PS_ProcessSharpen(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
float4 res;
float4 coord=0.0;

coord.xy=IN.txcoord.xy;
float4 origcolor;

coord.w=0.0;


origcolor=tex2Dlod(SamplerColor, coord);

// coord.x=IN.txcoord.x-(1.5/ScreenSize);
// float4 lshift=tex2Dlod(SamplerColor, coord);
// coord.x=IN.txcoord.x+(1.5/ScreenSize);
// float4 rshift=tex2Dlod(SamplerColor, coord);


float2 offset[8]=
{
 float2(1.0, 1.0),
 float2(-1.0, -1.0),
 float2(-1.0, 1.0),
 float2(1.0, -1.0),

 float2(1.41, 0.0),
 float2(-1.41, 0.0),
 float2(0.0, 1.41),
 float2(0.0, -1.41)
};
int i=0;

float4 tcol=origcolor;
float invscreensize=1.0/ScreenSize;
for (i=0; i<8; i++)		//[KYO : EXQ - This will impact blacks, so compensate via effect.fx] 		
//for (i=0; i<4; i++)		//[KYO : Standard Q - This leaves black levels alone]
{
 float2 tdir=offset[i].xy;
 coord.xy=IN.txcoord.xy+tdir.xy*invscreensize*SamplingRange;//*1.0;
 float4 ct=tex2Dlod(SamplerColor, coord);

 tcol+=ct;
}
//tcol*=0.2; // 1.0/(4+1)	//[KYO : Standard Q - This leaves black levels alone]
tcol*=0.111; // 1.0/(8+1)	//[KYO : EXQ - This will impact blacks, so compensate via effect.fx] 	  	

/*
//not interesting
#ifdef EBLURRING
//blur
res=tcol;
#endif
*/

//sharp
#ifdef ESHARPENING

#ifdef ESHARPENINGCOLOR
//color
res=origcolor*(1.0+((origcolor-tcol)*SharpeningAmount));
#else
 //non color
float difffact=dot((origcolor.xyz-tcol.xyz), 0.333);
res=origcolor*(1.0+difffact*SharpeningAmount);
#endif

//less sharpening for bright pixels
float rgray=origcolor.z; //blue fit well
//float rgray=max(origcolor.x, max(origcolor.y, origcolor.z));
rgray=pow(rgray, 3.0);
res=lerp(res, origcolor, saturate(rgray));

#endif

//Dynamic grain noise
#ifdef EDYNAMICNOISE
float origgray=max(res.x, res.y);//dot(res.xyz, 0.333);
origgray=max(origgray, res.z);
coord.xy=IN.txcoord.xy*16.0 + frac(Timer.x * 400000.0 + Timer.x);	//[KYO : set how fast grain displacement shall be]
float4 cnoi=tex2Dlod(SamplerNoise, coord);
res=lerp(res, (cnoi.x+0.5)*res, NoiseAmount*saturate(1.0-origgray*NoiseDiffusion));
#endif

//Static grain noise
#ifdef ESTATICNOISE
float origgray=max(res.x, res.y);//dot(res.xyz, 0.333);
origgray=max(origgray, res.z);
coord.xy=IN.txcoord.xy*16.0 + origgray;
float4 cnoi=tex2Dlod(SamplerNoise, coord);
res=lerp(res, (cnoi.x+0.5)*res, NoiseAmount*saturate(1.0-origgray*NoiseDiffusion));	
#endif

	res.w=1.0;
	return res;
}

//4
float4 PS_ProcessScanlines(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 res;
	float4 coord=0.0;

	coord.xy=IN.txcoord.xy;
	float4 origcolor;
	coord.w=0.0;

	coord.y=floor(coord.y*625.0)*0.0016;//625 vertical lines
	res=tex2Dlod(SamplerColor, coord);

	res.w=1.0;
	return res;
}

technique PostProcess
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessColor();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess2
{
	pass P0
	{

		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessHorizontalBlur();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

technique PostProcess3
{
   pass P0
   {

		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessSharpen();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}

#ifdef ESCANLINE
technique PostProcess4
{
	pass P0
	{

		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader  = compile ps_3_0 PS_ProcessScanlines();

		DitherEnable=FALSE;
		ZEnable=FALSE;
		CullMode=NONE;
		ALPHATESTENABLE=FALSE;
		SEPARATEALPHABLENDENABLE=FALSE;
		AlphaBlendEnable=FALSE;
		StencilEnable=FALSE;
		FogEnable=FALSE;
		SRGBWRITEENABLE=FALSE;
	}
}
#endif //ESCANLINE