//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// ENBSeries effect file
// visit http://enbdev.com for updates
// Copyright (c) 2007-2011 Boris Vorontsov
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//+++++++++++++++++++++++++++++
// Internal parameters, can be modified
//+++++++++++++++++++++++++++++
float	EBlurSamplingRange = 4.0;	// not used
float	EApertureScale = 4.0;		// not used

//+++++++++++++++++++++++++++++
// 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=Width, y=1/Width, z=ScreenScaleY, w=1/ScreenScaleY
float4	ScreenSize;
// x=generic timer in range 0..1, period of 16777216 ms (4.6 hours), w=frame time elapsed (in seconds)
float4	Timer;
// Adaptation delta time for focusing
float	FadeFactor;

// textures
texture2D texColor;
texture2D texDepth;
texture2D texNoise;
texture2D texPalette;
texture2D texFocus; // computed focusing depth
texture2D texCurr; // 4*4 texture for focusing
texture2D texPrev; // 4*4 texture for focusing

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

sampler2D SamplerDepth = sampler_state
{
	Texture   = <texDepth>;
	MinFilter = POINT;
	MagFilter = POINT;
	MipFilter = NONE;
	AddressU  = Clamp;
	AddressV  = Clamp;
	SRGBTexture = FALSE;
	MaxMipLevel = 0;
	MipMapLodBias = 0;
};

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

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

// for focus computation
sampler2D SamplerCurr = sampler_state
{
	Texture   = <texCurr>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU  = Clamp;
	AddressV  = Clamp;
	SRGBTexture = FALSE;
	MaxMipLevel = 0;
	MipMapLodBias = 0;
};

// for focus computation
sampler2D SamplerPrev = sampler_state
{
	Texture   = <texPrev>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU  = Clamp;
	AddressV  = Clamp;
	SRGBTexture = FALSE;
	MaxMipLevel = 0;
	MipMapLodBias = 0;
};
// for dof only in PostProcess techniques
sampler2D SamplerFocus = sampler_state
{
	Texture   = <texFocus>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = NONE;
	AddressU  = Clamp;
	AddressV  = Clamp;
	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;
};

////////////////////////////////////////////////////////////////////
// Begin focusing (by Boris Vorontsov)
////////////////////////////////////////////////////////////////////
VS_OUTPUT_POST VS_Focus(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;
}

//SRCpass1X=ScreenWidth;
//SRCpass1Y=ScreenHeight;
//DESTpass2X=4;
//DESTpass2Y=4;
float4 PS_ReadFocus(VS_OUTPUT_POST IN) : COLOR
{
	float res = tex2D(SamplerDepth, 0.5).x;
	return res;
}

//SRCpass1X=4;
//SRCpass1Y=4;
//DESTpass2X=4;
//DESTpass2Y=4;
float4 PS_WriteFocus(VS_OUTPUT_POST IN) : COLOR
{
	float res = 0.0;
	float curr = tex2D(SamplerCurr, 0.5).x;
	float prev = tex2D(SamplerPrev, 0.5).x;

	res = lerp(prev, curr, saturate(FadeFactor));// time elapsed factor
	res = max(res, 0.0);

	return res;
}

technique ReadFocus
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_Focus();
		PixelShader  = compile ps_3_0 PS_ReadFocus();

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

technique WriteFocus
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_Focus();
		PixelShader  = compile ps_3_0 PS_WriteFocus();

		ZEnable = FALSE;
		CullMode = NONE;
		ALPHATESTENABLE = FALSE;
		SEPARATEALPHABLENDENABLE = FALSE;
		AlphaBlendEnable = FALSE;
		FogEnable = FALSE;
		SRGBWRITEENABLE = FALSE;
	}
}
////////////////////////////////////////////////////////////////////
// End focusing code
////////////////////////////////////////////////////////////////////

/*------------------------------------------------------------------------------
				  ENB prepass modification 2.0.5 by Matso
					   Credits to Boris Vorontsov
------------------------------------------------------------------------------*/
// Effects enabling options
//#define ENABLE_DOF		1			// comment to disable depth of field
#define ENABLE_FAST_DOF	1			// comment to disable fast depth of field (never use both ENABLE_DOF and ENABLE_FAST_DOF - possible game crash or horrible FPS drop)
//#define ENABLE_SHARP	1			// comment to disable sharpening
//#define ENABLE_CHROMA	1			// comment to disable chromatic aberration (additional chromatic aberration applied beyond depth of field)

// Methods enabling options
#define USE_CHROMA_DOF	1			// comment it to disable chromatic aberration sampling in DoF
#define USE_SMOOTH_DOF	1			// comment it to disable smooth DoF
#define USE_BOKEH_DOF	1			// comment it to disable bokeh DoF (experimental)
//#define USE_ANAMFLARE	1			// comment it to disable anamorphic lens flare (not working very well -_-)
#define USE_DOUBLE_BLUR 1			// comment it to disable additional blur

// Useful constants
#define SEED			Timer.x
#define PI				3.1415926535897932384626433832795
#define CHROMA_POW		65.0								// the bigger the value, the more visible chomatic aberration effect in DoF

// Fast DoF constants
#define DOF_SCALE		2356.1944901923449288469825374596	// PI * 750
#define FIRST_PASS		2	// donnot change it!
#define SECOND_PASS		3	// donnot change it!
#define THIRD_PASS		0	// donnot change it!
#define FOURTH_PASS		1	// donnot change it!
#define DOF(sd,sf)		fApertureScale * smoothstep(fApertureBias, fApertureCutoff, abs(sd - sf))

// Chromatic aberration parameters
float3 fvChroma = float3(0.995, 1.000, 1.005);	// displacement scales of red, green and blue respectively
float fBaseRadius = 0.9;						// below this radius the effect is less visible
float fFalloffRadius = 1.8;						// over this radius the effects is maximal
float fChromaPower = 1.0;						// power of the chromatic displacement (curve of the 'fvChroma' vector)

// Sharpen parameters
float fSharpScale = 0.32;						// intensity of sharpening
float2 fvTexelSize = float2(1.0 / 1920.0, 1.0 / 1080.0);	// set your resolution sizes

// Depth of field parameters
float fFocusBias = 0.045;						// bigger values for nearsightedness, smaller for farsightedness (lens focal point distance)
float fApertureScale = 0.004;					// governs image blur scale (the bigger value, the stronger blur)
float fApertureCutoff = 0.25;					// manages the smoothness of the DoF (bigger value results in wider depth of field)
float fApertureBias = 0.07;						// distance not taken into account in DoF (try out sub-zero values ;))

// (pseudo-) Bokeh parameters
float fBokehCurve = 8.0;						// the larger the value, the more visible the bokeh effect is
//float fBokehBlurFalloff = 4.0;
float fBokehLight = 0.012;						// governs overall brightness of the outcome

// Grain parameters
float fGrainFreq = 2000.0;						// movie grain frequency
float fGrainScale = 0.02;						// effect scale

// Anamorphic flare parameters (by default not used)
float fLuminance = 0.85;						// bright pass luminance value 
float fBlur = 2000.0;							// blur amount, manages the size of the flare
float fIntensity = 0.25;						// effect intensity

/**
 * Chromatic aberration function - given texture coordinate and a focus value
 * retrieves chromatically distorted color of the pixel. Each of the color
 * channels are displaced according to the pixel coordinate and its distance
 * from the center of the image. Also the DoF out-of-focus value is applied.
 * (http://en.wikipedia.org/wiki/Chromatic_aberration)
 */
float4 ChromaticAberration(float2 tex, float outOfFocus)
{
	float d = distance(tex, float2(0.5, 0.5));
	float f = smoothstep(fBaseRadius, fFalloffRadius, d + outOfFocus * d);
	float3 chroma = pow(f + fvChroma, fChromaPower);
	
	float2 tr = ((2.0 * tex - 1.0) * chroma.r) * 0.5 + 0.5;
	float2 tg = ((2.0 * tex - 1.0) * chroma.g) * 0.5 + 0.5;
	float2 tb = ((2.0 * tex - 1.0) * chroma.b) * 0.5 + 0.5;
	
	float3 color = float3(tex2D(SamplerColor, tr).r, tex2D(SamplerColor, tg).g, tex2D(SamplerColor, tb).b) * (1.0 - f);
	
	return float4(color, 1.0);
}

/**
 * Chromatic aberration done accoriding to the focus factor provided.
 */
float4 ChromaticAberrationFocus(float2 tex, float outOfFocus)
{
	float3 chroma = pow(fvChroma, CHROMA_POW * outOfFocus);

	float2 tr = ((2.0 * tex - 1.0) * chroma.r) * 0.5 + 0.5;
	float2 tg = ((2.0 * tex - 1.0) * chroma.g) * 0.5 + 0.5;
	float2 tb = ((2.0 * tex - 1.0) * chroma.b) * 0.5 + 0.5;
	
	float3 color = float3(tex2D(SamplerColor, tr).r, tex2D(SamplerColor, tg).g, tex2D(SamplerColor, tb).b) * (1.0 - outOfFocus);
	
	return float4(color, 1.0);
}

/**
 * Pseudo-random number generator - returns a number generated according to the provided vector.
 */
float Random(float2 co)
{
    return frac(sin(dot(co.xy, float2(12.9898, 78.233))) * 43758.5453);
}

/**
 * Movie grain function - returns a random, time scaled value for the given pixel coordinate.
 */
float Grain(float3 tex)
{
	float r = Random(tex.xy);
	float grain = sin(PI * tex.z * r * fGrainFreq) * fGrainScale * r;
	return grain;
}

/**
 * Bright pass - rescales sampled pixel to emboss bright enough value.
 */
float3 BrightPass(float2 tex)
{
	float3 c = tex2D(SamplerColor, tex).rgb;
    float3 bC = max(c - float3(fLuminance, fLuminance, fLuminance), 0.0);
    float bright = dot(bC, 1.0);
    bright = smoothstep(0.0f, 0.5, bright);
    return lerp(0.0, c, bright);
}

float3 BrightColor(float3 c)
{
    float3 bC = max(c - float3(fLuminance, fLuminance, fLuminance), 0.0);
    float bright = dot(bC, 1.0);
    bright = smoothstep(0.0f, 0.5, bright);
    return lerp(0.0, c, bright);
}

/**
 * Anamorphic sampling function - scales pixel coordinate
 * to stratch the image along one of the axels.
 * (http://en.wikipedia.org/wiki/Anamorphosis)
 */
float3 AnamorphicSample(int axis, float2 tex, float blur)
{
	tex = 2.0 * tex - 1.0;
	if (!axis) tex.x /= -blur;
	else tex.y /= -blur;
	tex = 0.5 * tex + 0.5;
	return BrightPass(tex);
}

/**
 * Converts pixel color to gray-scale.
 */
float GrayScale(float3 sample)
{
	return dot(sample, float3(0.3, 0.59, 0.11));
}

///// Shaders ////////////////////////////////////////////////////////////////////////////////
// Vertex shader (Boris code)
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;
}

// Sharpen pixel shader (Matso code)
float4 PS_ProcessPass_Sharpen(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float2 coord = IN.txcoord.xy;
	float4 Color = 9.0 * tex2D(SamplerColor, coord.xy);
	
	Color -= tex2D(SamplerColor, coord.xy + float2(-fvTexelSize.x, fvTexelSize.y) * fSharpScale);
	Color -= tex2D(SamplerColor, coord.xy + float2(0.0, fvTexelSize.y) * fSharpScale);
	Color -= tex2D(SamplerColor, coord.xy + float2(fvTexelSize.x, fvTexelSize.y) * fSharpScale);
	Color -= tex2D(SamplerColor, coord.xy + float2(fvTexelSize.x, 0.0) * fSharpScale);
	Color -= tex2D(SamplerColor, coord.xy + float2(fvTexelSize.x, -fvTexelSize.y) * fSharpScale);
	Color -= tex2D(SamplerColor, coord.xy + float2(0.0, -fvTexelSize.y) * fSharpScale);
	Color -= tex2D(SamplerColor, coord.xy + float2(-fvTexelSize.x, -fvTexelSize.y) * fSharpScale);
	Color -= tex2D(SamplerColor, coord.xy + float2(-fvTexelSize.x, 0.0) * fSharpScale);
	
	Color.a = 1.0;
	return Color;
}

// Anamorphic lens flare pixel shader (Matso code)
float4 PS_ProcessPass_Anamorphic(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float4 res;
	float2 coord = IN.txcoord.xy;
	float3 anamFlare = AnamorphicSample(0, coord.xy, fBlur) * float3(0.0, 0.0, 1.0);
	res.rgb = anamFlare * fIntensity;
	res.a = 1.0;
	return res;
}

// Fast depth of field pixel shader (Matso code)
float4 PS_ProcessPass_FastDoF(VS_OUTPUT_POST IN, float2 vPos : VPOS, uniform int axis) : COLOR
{
	float4 res;
	float2 coord = IN.txcoord.xy;
	float4 tcol = tex2D(SamplerColor, coord.xy);
	float sd = tex2D(SamplerDepth, coord).x;

#ifndef USE_SMOOTH_DOF
	float sf = tex2D(SamplerDepth, 0.5).x - fFocusBias;
#else
	float sf = tex2D(SamplerFocus, 0.5).x - fFocusBias * 2.0;
#endif
	float outOfFocus = DOF(sd, sf);
		
	float offset[4] = { -1.282, -0.524, 0.524, 1.282 };
	float2 tdirs[4] = { float2(1.0, 0.0), float2(0.0, 1.0), float2(0.707, 0.707), float2(-0.707, 0.707) };
	//float2 taps[4] = { float2(-1.282, 0.524), float2(0.524, -1.282), float2(-1.282, -0.524), float2(0.524, 1.282) };
	float blur = DOF_SCALE * outOfFocus;
#ifdef USE_BOKEH_DOF
	float wValue = (1.0 + pow(length(tcol.rgb) + 0.1, fBokehCurve)) * (1.0 - fBokehLight);	// special recipe from papa Matso ;)
#else
	float wValue = 1.0;
#endif
	
	tdirs[axis].x *= fvTexelSize.x;
	tdirs[axis].y *= fvTexelSize.y;
	
#ifdef USE_BOKEH_DOF
	blur *= 0.25;
#endif
		
	for (int i = 0; i < 4; i++)
	{
		//float2 t = taps[i] * fvTexelSize;
		
		float2 tdir = offset[i] * tdirs[axis] * blur;
		//float2 tdir = blur * (tdirs[axis] + t);
		coord.xy = IN.txcoord.xy + tdir.xy;
#ifdef USE_CHROMA_DOF
		float4 ct = ChromaticAberrationFocus(coord.xy, outOfFocus);
#else
		float4 ct = tex2D(SamplerColor, coord.xy);
#endif

#ifndef USE_BOKEH_DOF
		float w = 1.0 + abs(offset[i]);	// weight blur for better effect
#else	
		float ds = tex2D(SamplerDepth, coord.xy).x;
		float offs = DOF(ds, sf);
		
	#if USE_BOKEH_DOF == 1	// my own pseudo-bokeh weighting
		float b = GrayScale(ct.rgb) + length(ct.rgb) + 0.1;
		float w = pow(b, fBokehCurve) + abs(offset[i]);
	#endif
#endif
		tcol += ct * w;
		wValue += w;
	}

	tcol /= wValue;
		
	res.xyz = tcol.xyz;
	res.w = 1.0;
	return res;
}

// Chromatic abrration with no DoF (Matso code)
float4 PS_ProcessPass_Chroma(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR
{
	float2 coord = IN.txcoord.xy;
	float4 result = ChromaticAberration(coord.xy, 0.0);
	result.a = 1.0;
	return result;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_SHARP
	technique PostProcess
	{
		pass P0
		{
			VertexShader = compile vs_3_0 VS_PostProcess();
			PixelShader  = compile ps_3_0 PS_ProcessPass_Sharpen();

			DitherEnable = FALSE;
			ZEnable = FALSE;
			CullMode = NONE;
			ALPHATESTENABLE = FALSE;
			SEPARATEALPHABLENDENABLE = FALSE;
			AlphaBlendEnable = FALSE;
			StencilEnable = FALSE;
			FogEnable = FALSE;
			SRGBWRITEENABLE = FALSE;
		}
		#ifdef USE_ANAMFLARE
			pass P1
			{
				AlphaBlendEnable = true;
				SrcBlend = One;
				DestBlend = One;
				
				PixelShader = compile ps_3_0 PS_ProcessPass_Anamorphic();
			}
		#endif
	}
#endif

#ifndef ENABLE_FAST_DOF
	#ifdef ENABLE_CHROMA
		#ifndef ENABLE_SHARP
			technique PostProcess
		#else
			technique PostProcess2
		#endif
		{
			pass P0
			{
				VertexShader = compile vs_3_0 VS_PostProcess();
				PixelShader  = compile ps_3_0 PS_ProcessPass_Chroma();

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

#ifndef ENABLE_CHROMA
	#ifdef ENABLE_FAST_DOF
		#ifndef ENABLE_SHARP
			technique PostProcess
		#else
			technique PostProcess2
		#endif
		{
			pass P0
			{
				VertexShader = compile vs_3_0 VS_PostProcess();
				PixelShader  = compile ps_3_0 PS_ProcessPass_FastDoF(FIRST_PASS);

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

		#ifndef ENABLE_SHARP
			technique PostProcess2
		#else
			technique PostProcess3
		#endif
		{
			pass P0
			{
				VertexShader = compile vs_3_0 VS_PostProcess();
				PixelShader  = compile ps_3_0 PS_ProcessPass_FastDoF(SECOND_PASS);

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

		#ifdef USE_DOUBLE_BLUR
			#ifndef ENABLE_SHARP
				technique PostProcess3
			#else
				technique PostProcess4
			#endif
			{
				pass P0
				{
					VertexShader = compile vs_3_0 VS_PostProcess();
					PixelShader  = compile ps_3_0 PS_ProcessPass_FastDoF(THIRD_PASS);

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

			#ifndef ENABLE_SHARP
				technique PostProcess4
			#else
				technique PostProcess5
			#endif
			{
				pass P0
				{
					VertexShader = compile vs_3_0 VS_PostProcess();
					PixelShader  = compile ps_3_0 PS_ProcessPass_FastDoF(FOURTH_PASS);

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