#include "anomaly_shaders.h"
#include "common.h"

#include "lmodel.h"
#include "hmodel.h"

// Check Addons
#include "check_screenspace.h"

#ifdef SSFX_BEEFS_NVG
	#include "night_vision.h"
#endif

#ifdef SSFX_FOG
	#include "screenspace_fog.h"
#endif

#ifdef SSFX_AO
	#include "settings_screenspace_AO.h"

	uniform float4 ssfx_ao_setup;
	uniform float4 ssfx_ao_setup2;
	Texture2D ssfx_ao;
#endif

#ifdef SSFX_INDIRECT_LIGHT
	#include "settings_screenspace_IL.h"

	Texture2D ssfx_il;
	uniform float4 ssfx_il_setup;
	uniform float4 ssfx_il_setup2;
#endif

uniform float4 ssfx_hud_hemi;
Texture2D s_hud_mask;

Texture2D s_half_depth;

#include "ssao.ps"

#ifdef HDAO
#define USE_HDAO 1
#endif

#ifdef SM_5
Texture2D<float> s_occ;
#endif // SM_5

#if SSAO_QUALITY <=3
//#include "ssdo.ps"

#else
#ifndef USE_HDAO
#define USE_HDAO
#endif
#endif


#ifdef USE_HDAO
#if SSAO_QUALITY > 3
#include "ssao_hdao_new.ps"
#endif
#define USE_HDAO_CODE
#if SSAO_QUALITY <=3
#define  g_f2RTSize ( screen_res.xy )

#define g_txDepth s_position
#define g_txNormal s_position

#include "ssao_hdao.ps"
#endif
#else // USE_HDAO
#ifdef	USE_HBAO
#include "ssao_hbao.ps"
#endif	//	USE_HBAO
#endif // USE_HDAO

struct	_input
{
	float4	tc0	: TEXCOORD0;	// tc.xy, tc.w = tonemap scale
	float2	tcJ	: TEXCOORD1;	// jitter coords
	float4 pos2d : SV_Position;
};

struct	_out
{
	float4	low		: SV_Target0;
	float4	high	: SV_Target1;
};

//	TODO:	DX10: Replace Sample with Load
#ifndef MSAA_OPTIMIZATION
_out main ( _input I )
#else
_out main ( _input I, uint iSample : SV_SAMPLEINDEX )
#endif
{
	gbuffer_data gbd = gbuffer_load_data( GLD_P(I.tc0, I.pos2d, ISAMPLE) );
	
	// Sample the buffers:
	float4	P = float4( gbd.P, gbd.mtl );	// position.(mtl or sun)
	float4	N = float4( gbd.N, gbd.hemi );		// normal.hemi
	float4	D = float4( gbd.C, gbd.gloss );		// rgb.gloss
	
#ifndef USE_MSAA
	float4	L = s_accumulator.Sample( smp_nofilter, I.tc0);	// diffuse.specular
#else
	float4   L = s_accumulator.Load( int3( I.tc0 * screen_res.xy, 0 ), ISAMPLE );
#endif

#ifndef SSFX_NEWGLOSS
	if (abs(P.w - MAT_FLORA) <= 0.05) {
		// Reapply distance factor to fix overtly glossy plants in distance
		// Unfortunately some trees etc don't seem to use the same detail shader
		float	fAtten = 1 - smoothstep(0, 50, P.z);
		D.a	*= (fAtten * fAtten);
	}
#endif

	// static sun
	float mtl = P.w;

#ifdef USE_R2_STATIC_SUN
	float sun_occ = P.w*2;

	mtl = xmaterial;
	L += SRGBToLinear(D.rgb * Ldynamic_color.rgb * sun_occ) * plight_infinity	(mtl, P.xyz, N.xyz, D.xyzw, Ldynamic_dir);
#endif


	//  Calculate SSAO

#ifdef USE_MSAA
	int2	texCoord = I.pos2d;
#endif
	
	float3 occ = float3(1.0,1.0,1.0);

#ifdef USE_HDAO
#ifdef SM_5
#if SSAO_QUALITY > 3
     occ = s_occ.Sample( smp_nofilter, I.tc0);	
#else // SSAO_QUALITY > 3
	 occ = calc_hdao( CS_P(P, N, I.tc0, I.tcJ, I.pos2d, ISAMPLE ) );
#endif // SSAO_QUALITY > 3
#else // SM_5
#if SSAO_QUALITY > 3
	 occ = calc_new_hdao( CS_P(P, N, I.tc0, I.tcJ, I.pos2d, ISAMPLE ) );
#else // SSAO_QUALITY > 3
	 occ = calc_hdao( CS_P(P, N, I.tc0, I.tcJ, I.pos2d, ISAMPLE ) );
#endif // SSAO_QUALITY > 3
#endif // SM_5
#else // USE_HDAO
#ifdef USE_HBAO
	 occ = calc_hbao( P.z, N, I.tc0, I.pos2d );
#else // USE_HBAO
	occ = 0;//calc_ssdo(P, N, I.tc0, I.pos2d, ISAMPLE);
#endif
#endif // USE_HDAO

#ifdef SSAO_QUALITY
	occ = compute_colored_ao(occ.x, D.xyz);
#endif

	L.rgb += L.a * SRGBToLinear(D.rgb); //illum in alpha

	// HUD Mask
	float HudMask = s_hud_mask.Sample(smp_linear, I.tc0).r;

	// HUD hemi
	float env_fac = 1.0 - saturate(dot(env_color.rgb, 0.15f));
	float hud_hemi = N.w + ssfx_hud_hemi.x * env_fac;
	
	// hemisphere
	float3 hdiffuse, hspecular;
	hmodel	(hdiffuse, hspecular, mtl, lerp(hud_hemi, N.w, HudMask), D, P.xyz, N.xyz);

	// IL Implementation
#ifdef SSFX_INDIRECT_LIGHT

	float3 IL_sample = ssfx_il.Sample(smp_linear, I.tc0 / ssfx_il_setup.x).rgb;

	// Lower highs ~ Higher lows.
	IL_sample *= 1.0f / (1.0 + IL_sample);
	
	// Apply HUD intensity
	IL_sample *= lerp(ssfx_il_setup2.y, 1.0f, HudMask);

	// Vibrance
	IL_sample = vibrance( IL_sample, ssfx_il_setup.z );

	hdiffuse *= lerp(1.0f, IL_sample * (30.0f * ssfx_il_setup.y), IL_sample); // 30
		
#endif

	// AO implementation
#ifdef SSFX_AO
	hdiffuse.rgb *= ssfx_ao.Sample(smp_linear, I.tc0).www;
#else
	hdiffuse *= occ;
#endif
	
	hdiffuse.rgb = saturate(hdiffuse.rgb);

	float3 color	= L.rgb + hdiffuse.rgb;
	color 			= LinearTosRGB(color); 			//gamma correct

#ifdef SSFX_BEEFS_NVG
	//// SOME NVG SHIT ////
	float lua_param_nvg_generation = floor(shader_param_8.x);			// 1, 2, or 3
	float lua_param_nvg_num_tubes = frac(shader_param_8.x) * 10.0f;		// 1, 2, 4, 1.1, or 1.2
	float lua_param_nvg_gain_current = floor(shader_param_8.y) / 10.0f; 
	float lua_param_vignette_current = floor(shader_param_8.z) / 100.0f;

	// NVG reduces gloss to 0 inside mask	
	D.a *= (1.0 - compute_lens_mask(aspect_ratio_correction(I.tc0), lua_param_nvg_num_tubes));
	//// END NVG SHIT ////
#endif

////////////////////////////////////////////////////////////////////////////////

	// here should be distance fog
#ifdef SSFX_FOG
	float3 		WorldP			= mul(m_inv_V, float4(P.xyz, 1));
	float		fog				= SSFX_HEIGHT_FOG(P.xyz, WorldP.y, color);
#else
	float		distance		= length		(P.xyz);
	float		fog				= saturate		(distance*fog_params.w + fog_params.x);
				color			= lerp			(color,fog_color,fog);
#endif

	float		skyblend		= saturate		(fog*fog);

	float		tm_scale		= I.tc0.w; // interpolated from VS

	_out		o;
	
#ifndef SSFX_BEEFS_NVG

	tonemap(o.low, o.high, color, tm_scale);
	o.low.a = skyblend;
	o.high.a = skyblend;

	return o;

#else
	/////////// BEEFS NVGS CHANGES ///////////
	if (lua_param_nvg_generation > 0.0f && compute_lens_mask(aspect_ratio_correction(I.tc0), lua_param_nvg_num_tubes) == 1.0f)
	{
		float lua_param_nvg_gain_offset = floor(shader_param_8.w) / 10.0f;
		tonemap(o.low, o.high, color, 10.0f * lua_param_nvg_gain_offset);

		// Turn split tonemapping data to YUV and discard UV
		o.low.r = dot(o.low.rgb, luma_conversion_coeff);
		o.high.r = dot(o.high.rgb, luma_conversion_coeff);

		o.low.r *= 4.0f;
		o.high.r *= 4.0f;

		// Turn s_accumulator data in to YUV and discard UV
		o.low.g = pow(dot(L.rgb, luma_conversion_coeff),2.0f)*1.3f;
		o.high.g = o.low.g;

		// Turn albedo into YUV and discard UV
		o.low.b = dot(D.rgb, luma_conversion_coeff);
		o.high.b = o.low.b;
		
		o.low *= lua_param_nvg_gain_current;
		o.high *= lua_param_nvg_gain_current;
			
		// Extra
		o.low.a = skyblend;
		o.high.a = skyblend;
				

		// APPLY VIGNETTE
		float vignette = calc_vignette(lua_param_nvg_num_tubes, I.tc0, lua_param_vignette_current+0.02);
		
		o.high = clamp(o.high,0.0,1.0);
		o.low= clamp(o.low,0.0,1.0);
		
		o.high.rgb *= vignette;
		o.low.rgb *= vignette;

	}
	else
	{
		tonemap(o.low, o.high, color, tm_scale);
		o.low.a = skyblend;
		o.high.a = skyblend;
	}		
	return o;
#endif

}