/*



LA MAYORÍA DE LOS EFECTOS Y POSTPROCESADO ESTÁN DESACTIVADOS, SÓLO ES ÚTIL PARA FXAA.



*/
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//				M I N I S T R Y  O F  G A M E S 			//
//			PostProcess Effect file for GTA IV graphics mod			//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// 		   Credits to Boris Vorontsov (ENB Series) and Tomerk (OBGE)   		//
//		   Minor optimisation and adaptation by  AgainstAllAutority		//
// 	 	Big thanks to Matso, gp45 for their help in DoF understanding  		//
// 			  Original Depth Of Field source by Matso			//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//                          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;
// Effects options (if the 'USE_...' or 'ENABLE_...' flags are disabled they are commented, prefixed with '//')
// not all features are avialable in this beta version, full is coming soon!
//#define ENABLE_DOF 1 // comment to disable depth of field (DoF)
//#define ENABLE_CHROMA 1 // comment to disable chromatic aberration (ChA, 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 (dChA)
//#define USE_SMOOTH_DOF 1 // comment it to disable smooth DoF
//#define USE_BOKEH_DOF 1 // comment it to disable bokeh DoF

// Useful constants
#define SEED Timer.w // seed for random number generation (set to 1 to make it time independent)
#define PI 3.1415926535897932384626433832795 // this one does not need commenting (I hope so) ;)
#define CHROMA_POW 65.0 // the bigger the value, the more visible chomatic aberration effect in DoF

// DoF constants (do not change DoF passes squance - performance issue)
#define DOF_SCALE 2356.1944901923449288469825374596 // PI * 750
#define FIRST_PASS 0 // [NOTE: in case of Complex 1.0 DoF do not change this value]
#define SECOND_PASS 1 // [NOTE: in case of Complex 1.0 DoF do not change this value]
#define THIRD_PASS 2 // [NOTE: in case of Complex 1.0 DoF do not change this value]
#define FOURTH_PASS 3 // [NOTE: in case of Complex 1.0 DoF do not change this value]

// Diffrent types of DoF formula [NOTE: only Complex 1.0]
#ifndef USE_MANUAL_FOCUS
#define DOF1(sd,sf) fBlurScale * abs(sd - sf) * 5.0 // blur is acquired directly as a scaled distance of the pixel depth from focus depth
#define DOF2(sd,sf) fBlurScale * pow(abs(sd - sf) * 2.0, 2.0) * 10.0 // blur is acquired as a scaled power 2 of the distance of the pixel depth from focus depth
#define DOF3(sd,sf) fBlurScale * smoothstep(fDofBias, fDofCutoff, abs(sd - sf)) // blur is acquired as a scaled cubic interpolation according to the distance of the pixel depth from focus depth
#define DOF DOF3 // select one of the above
#else
#define DOF(sd,sf) fBlurScale * smoothstep(fDofBias * tempF1.y, fDofCutoff * tempF1.z, abs(sd - sf)) // manual DoF modification [NOTE: better use Complex 1.1 version]
#endif
#define BOKEH_DOWNBLUR 0.3 // bokeh deblurification factor, the default blur scale is too big for bokeh

#define PS_ProcessPass_DepthOfField DepthOfField_Complex_1_0

// Chromatic aberration parameters
float3 fvChroma = float3(0.9995, 1.000, 1.0005);// displacement scales of red, green and blue respectively
#define fBaseRadius 0.9 // below this radius the effect is less visible
#define fFalloffRadius 1.8 // over this radius the effect is max
#define fChromaPower 5.0 // power of the chromatic displacement (curve of the 'fvChroma' vector)

// Depth of field parameters
#define fFocusBias 0.04 // bigger values for nearsightedness, smaller for farsightedness (lens focal point distance) [NOTE: only Complex 1.0]
#define fDofCutoff 0.4 // manages the smoothness of the DoF (bigger value results in wider depth of field) [NOTE: only Complex 1.0]
#define fDofBias 0.008 // distance not taken into account in DoF (all closer then the distance is in focus) [NOTE: only Complex 1.0]
#define fBlurScale 0.008 // governs image blur scale (the bigger value, the stronger blur) [NOTE: only Complex 1.0]
#define fBlurCutoff 0.2 // bluring tolerance depending on the pixel and sample depth (smaller causes objects edges to be preserved) [NOTE: only Complex 1.0]
#define fFocusDistance 1.0 // manual focus distance base

// Bokeh parameters
#define fBokehCurve 10.0 // the larger the value, the more visible the bokeh effect is (not used with brightness limiting)
#define fBokehIntensity 0.95 // governs bokeh brightness (not used with brightness limiting)
#define fBokehConstant 0.5 // constant value of the bokeh weighting
#define fBokehMaxLevel 45.0 // bokeh max brightness level (scale factor for bokeh samples)
#define fBokehMin 0.001 // min input cutoff (anything below is 0)
#define fBokehMax 1.925 // max input cutoff (anything above is 1)
#define fBokehMaxWeight 25.0 // any weight above will be clamped
float2 fvTexelSize = float2(1.0 / 1280.0, 1.0 / 1024.0);

// Bokeh formulas
#define fBokehLuminance 0.956 // bright pass of the bokeh weight used with radiant version of the bokeh
#define BOKEH_RADIANT float3 bct = ct.rgb;float b = GrayScale(bct) + fBokehConstant + length(bct) // classic, prior 4.0.0 version of the bokeh formula
#define BOKEH_PASTEL float3 bct = BrightBokeh(ct.rgb);float b = dot(bct, bct) + fBokehConstant // new, less disturbing and more smooth version
#define BOKEH_VIBRANT float3 bct = BrightBokeh(ct.rgb);float b = GrayScale(ct.rgb) + dot(bct, bct) + fBokehConstant // compilation of the two above, bokeh apears only for very bright pixels
#define BOKEH_FORMULA BOKEH_RADIANT //BOKEH_RADIANT //BOKEH_PASTEL // // choose one of the above

// Bokeh options [NOTE: in case of using hexagonal shape, adjust 'fRadius' to make the effect more pronounced]
//#define USE_NATURAL_BOKEH 1 // more natural bokeh shape (comment to disable)
//#define USE_OCTAGONAL_BOKEH 1 // octagonal bokeh shape (comment to disable)
#define USE_HEXAGONAL_BOKEH 1 // hexagonal bokeh shape (comment to disable)
//#define USE_BRIGHTNESS_LIMITING 1 // bokeh brightness limiting (comment to disable)
#define USE_ENHANCED_BOKEH 1 // more pronounced bokeh (comment to disable)
#define DEFAULT_OFFSETS { -0.9, -0.3, 0.3, 0.9 }

float offset[4] = DEFAULT_OFFSETS;
#ifndef USE_NATURAL_BOKEH
#ifdef USE_OCTAGONAL_BOKEH
float2 tds[4] = { float2(-0.306, 0.739), float2(0.306, 0.739), float2(-0.739, 0.306), float2(-0.739, -0.306) }; // Octagonal bokeh sampling directions
#endif
#ifdef USE_HEXAGONAL_BOKEH
float2 tds[4] = { float2(0.0, 0.75), float2(0.6495, 0.375), float2(-0.6495, 0.375), float2(0.0, 0.0) }; // Hexagonal bokeh sampling directions
#endif
#else
float2 tds[16] = {
float2(0.2007, 0.9796),
float2(-0.2007, 0.9796),
float2(0.2007, 0.9796),
float2(-0.2007, 0.9796),

float2(0.8240, 0.5665),
float2(0.5665, 0.8240),
float2(0.8240, 0.5665),
float2(0.5665, 0.8240),

float2(0.9796, 0.2007),
float2(0.9796, -0.2007),
float2(0.9796, 0.2007),
float2(0.9796, -0.2007),

float2(-0.8240, 0.5665),
float2(-0.5665, 0.8240),
float2(-0.8240, 0.5665),
float2(-0.5665, 0.8240)
};
#endif

texture2D texColor;
texture2D texNoise;
sampler2D SamplerColor = sampler_state
{
Texture = <texColor>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = Mirror;
AddressV = Mirror;
SRGBTexture = FALSE;
MaxMipLevel = 9;
MipMapLodBias = 0;
};
sampler2D SamplerNoise = sampler_state
{
Texture = <texNoise>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
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_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;
}
float4 PS_AgainstAllAutority(VS_OUTPUT_POST IN) : COLOR
{
#ifndef USE_MANUAL_FOCUS
float res = tex2D(SamplerColor, 0.5).a;
#else
float res = fFocusDistance * tempF1.x;
#endif
return res;
}
technique ReadFocus
{
pass P0
{
VertexShader = compile vs_3_0 VS_Focus();
PixelShader = compile ps_3_0 PS_AgainstAllAutority();

ZEnable = FALSE;
CullMode = NONE;
ALPHATESTENABLE = FALSE;
SEPARATEALPHABLENDENABLE = FALSE;
AlphaBlendEnable = FALSE;
FogEnable = FALSE;
SRGBWRITEENABLE = FALSE;
}
}
float4 ChromaticAberration(float2 tex)
{
float d = distance(tex, float2(0.5, 0.5));
float f = smoothstep(fBaseRadius, fFalloffRadius, 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);
}
float4 ChromaticAberration(float2 tex, float outOfFocus)
{
float d = distance(tex, float2(0.5, 0.5));
float f = smoothstep(fBaseRadius, fFalloffRadius, d);
float3 chroma = pow(f + fvChroma, CHROMA_POW * outOfFocus * 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 - outOfFocus);

return float4(color, 1.0);
}
float3 BrightBokeh(float3 c)
{
	float3 bC = max(c - float3(fBokehLuminance, fBokehLuminance, fBokehLuminance), 0.0);
	float bright = dot(bC, 1.0);
	bright = smoothstep(0.0f, 0.5, bright);
	return lerp(0.0, c, bright);
}
float GrayScale(float3 sample)
{
	return dot(sample, float3(0.3, 0.59, 0.11));
}
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;
}


// Simple pass through shader (Matso code) [NOTE: not used]
float4 PS_ProcessPass_None(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR0
{
float4 res;
float2 coord = IN.txcoord.xy;
res.rgb = tex2D(SamplerColor, coord.xy).rgb;
res.a = 1.0;
return res;
}

// Complex 1.0 depth of field pixel shader (Matso code)
float4 DepthOfField_Complex_1_0(VS_OUTPUT_POST IN, float2 vPos : VPOS, uniform int axis) : COLOR0
{
float4 res;
float2 base = IN.txcoord.xy;
float4 tcol = tex2D(SamplerColor, base.xy);
float sd = (axis == FIRST_PASS) ? tex2D(SamplerColor, base).a : tcol.a; // acquire scene depth for the pixel
res = tcol;

#ifndef USE_SMOOTH_DOF // sample focus value
float sf = tex2D(SamplerColor, 0.5).a - fFocusBias;
#else
float sf = tex2D(SamplerColor, 0.5).a - fFocusBias * 2.0;
#endif
float outOfFocus = DOF(sd, sf);
float blur = DOF_SCALE * outOfFocus;
float wValue = 1.0;

#ifdef USE_MANUAL_BLUR_SCALE
blur *= tempF1.w;
#endif

#ifdef USE_BOKEH_DOF
blur *= BOKEH_DOWNBLUR; // should bokeh be used, decrease blur a bit
#endif

for (int i = 0; i < 4; i++)
{
#ifndef USE_NATURAL_BOKEH
float2 tdir = tds[axis] * fvTexelSize * blur * offset[i];
#else
float2 tdir = tds[axis * 4 + i] * fvTexelSize * blur * offset[i];
#endif

float2 coord = base + tdir.xy;
#ifdef USE_CHROMA_DOF
float4 ct = ChromaticAberration(coord, outOfFocus); // chromatic aberration sampling
#else
float4 ct = tex2D(SamplerColor, coord);
#endif
float sds = tex2D(SamplerColor, coord).a;

if ((abs(sds - sd) / sd) < fBlurCutoff) { // blur 'bleeding' control
#ifndef USE_BOKEH_DOF
float w = 1.0 + abs(offset[i]); // weight blur for better effect
#else
#if USE_BOKEH_DOF == 1
BOKEH_FORMULA;
#ifndef USE_BRIGHTNESS_LIMITING // all samples above max input will be limited to max level
float w = pow(b * fBokehIntensity, fBokehCurve);
#else
#ifdef USE_ENHANCED_BOKEH
float w = smoothstep(fBokehMin, fBokehMax, b * b) * fBokehMaxLevel;
#else
float w = smoothstep(fBokehMin, fBokehMax, b) * fBokehMaxLevel;
#endif
#endif
#ifdef USE_WEIGHT_CLAMP
w = min(w, fBokehMaxWeight);
#endif
w += abs(offset[i]) + blur;
#endif
#ifdef USE_SWITCHABLE_MODE
float w = 1.0 + abs(offset[i]);

if (tempF2.z > 0.99f) {
BOKEH_FORMULA;
w += smoothstep(fBokehMin, fBokehMax, b * b) * fBokehMaxLevel + blur;
}
#endif
#endif
tcol += ct * w;
wValue += w;
}
}
tcol /= wValue;

res.rgb = tcol.rgb;
res.w = (axis == FOURTH_PASS) ? 1.0 : sd;
return res;
}
// Chromatic abrration with no DoF (Matso code)
float4 PS_ProcessPass_Chroma(VS_OUTPUT_POST IN, float2 vPos : VPOS) : COLOR0
{
float2 coord = IN.txcoord.xy;
float4 result = ChromaticAberration(coord.xy);
result.a = 1.0;
return result;
}

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

		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_ProcessPass_DepthOfField(SECOND_PASS);

		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_ProcessPass_DepthOfField(THIRD_PASS);

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

technique PostProcess4
{
	pass P0
	{
		VertexShader = compile vs_3_0 VS_PostProcess();
		PixelShader = compile ps_3_0 PS_ProcessPass_DepthOfField(FOURTH_PASS);

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