#include "../common/samplers11.hlsl"
#include "../common/states11.hlsl"
#include "ParticleSystem2/perlin.hlsl"
#include "../common/samplers_NVG.hlsl"

Texture2D DiffuseMap;
Texture2D ResampleMap;
Texture3D Noise;
Texture2D Mask;
	
float widthTX;
float heightTX; 
float time;
float blurM;
float magn;


struct vAP_Output{
	float4 vPosition	:SV_POSITION;
	float2 vTexCoords	:TEXCOORD0;
};


struct main_out 
{
	float3 scene;
	float3 color;
};

/////////////////////////////////////
///////////NVG MOD STARRT////////////

//adding nvg fx file
#include"../common/MOD_nvg.hlsl"

/*
////////// Simple self made blur using 7 pixels////////////////////////////////////////////////
float4 blurTest(const float2 uv, const float posdata)
{	if (posdata < 0.0f) 
	{ 
	float4 sum = DiffuseMap.Sample(sDiffuseMap, uv);
	return sum;
	} else
	{
	float2 dx  = float2(1.0 / widthTX, 0.0);
	float2 sdy  = float2(0.0, 1.0 / heightTX);
    float2 sdx = dx;
	float4 sum = DiffuseMap.Sample(sDiffuseMap, uv);	
    sum += (DiffuseMap.Sample(sDiffuseMap, uv + sdx)+ DiffuseMap.Sample(sDiffuseMap, uv - sdx));
    sdx += dx;
	sum += (DiffuseMap.Sample(sDiffuseMap, uv + sdx) + DiffuseMap.Sample(sDiffuseMap, uv - sdx));
	sdx += dx;
	sum += (DiffuseMap.Sample(sDiffuseMap, uv + sdx) + DiffuseMap.Sample(sDiffuseMap, uv - sdx));
	return sum/7;
	}
 }
////////////////////////////////////////////////////////////////////////////////////////////
*/

float3 fxNVG(const float2 uv, const int nvg): SV_TARGET0
{
  const float3 rgb = DiffuseMap.Sample(sDiffuseMap, uv).rgb;			//rgb map of pixels (ie final render from game before nvg effect)
  //const float4 blur = ResampleMap.Sample(sResampleMap, uv);				//NEED TO FIGURE OUT WHAT THIS IS!!!!!!
  const float3 result = float3(0.0f, 0.0f, 0.0f);						//sets pixel to black before calculations are made.
  float3 NoiseInput = float3(uv*200, time*2);						//uv coord and time number to be fed into noise generator (perlin, simplex etc)
  
  if (nvg == NVG_A10)
   {
    //***********
    // The A-10C effect here.
    //***********
	float N = clamp(snoise(NoiseInput), 0.0f, 1.0f);		//clamp is an inclusive domain. snoise (part of default noise3D.hlsl), for snoise *100 gives large, *300 gives medium *600 gives small. 
	N = (magn*.003) * pow(N,(2500/magn));					//magn is nvg intenisty from in-game control (ranges between 0 and 200)  N = (magn*.005) * pow(N,(2500/magn));
	
    float L = dot(rgb, LUM);													//dot product of the pixels rgb value with LUM constant (ie NVG pickup ability). LUM skews the pickup to mainly red colors (like real device)
	float L2 = 1 - exp(-(magn*NVG_LIFT[NVG_A10]) * L);							// NVG_LIFT (approx 0.06) corrects multiplication factor of 'magn' value.
	float L3 = clamp(contrast * (L2 - 0.7) + 0.7, 0.0, 1.0);					// applies contrast (user set value) to image, is weighted to darks. Change both 0.7 to 0.5 for even weighting
	//L3 = L3 + N + (blur.r * (0.10 * blurM));									// N=noise blur.r = blur for high intensity, blurM = multiple lights close together overpowering NVG.
	float3 result = HSLtoRGB(float3(COLORIZE_COLOR[NVG_A10], 0.6f, L3));		// Col_Color = hue (120 degrees), 0.6f = saturation, L3 = amplified/noise impacted intensity of pixel
	


	//return N;												//shows just the noise pixels
	return result;
	
	
/*
	/////// TESTING RANGE OF VALUE
	if (magn <= 20)
		{return float(0.2f);
		}
	if (magn <= 100)
		{return float(0.5f);
		}
*/
	
  }
	else
  {
    //***********
    // The KA-50 effect here.
    //***********

    float L = dot(rgb, LUM);												//dot product of the pixels rgb value with LUM constant (ie NVG pickup ability). LUM skews the pickup to mainly red colors (like real device)
	float L2 = 1.1 - (1.03 * exp(-(magn*NVG_LIFT[NVG_KA50]) * L));			// NVG_LIFT (approx 0.06) corrects multiplication factor of 'magn' value. magn is nvg intenisty from ingame control (ranges between 0 and 200)
	float L3 = contrast * (L2 - 0.7) + 0.7;									// applies contrast (user set value) to image, is weighted to darks. Change both 0.7 to 0.5 for even weighting
	L3 = L3 + (blur.r * (0.10 * blurM));									// applies bloom blur effect since all NVG's have lenses. blur.r is general blur for high intensity, blurM is for multiple lights close together overpowering NVG.
	float3 result = HSLtoRGB(float3(COLORIZE_COLOR[NVG_KA50], 0.8f, L3));	// uses new intenisty and HSL to RGB conversion to add green tinge.
	return result;
  }
}

float4 drawNVG(const float2 uv, const int nvg): SV_TARGET0
{	if (RenderMode == 0)
		{return float4(fxNVG(uv, nvg), 1.0f); 
		} 
	
	const float3 mask = maskNVG(uv);
	
	if (mask.z <= 0.0f)
		{return float4(0.0f ,0.0f , 0.0f, 0.0f);
		}
	
	if (RenderMode == 1)	
		{return float4(fxNVG(uv, nvg), mask.x);
		}
		
	if (RenderMode == 2)
		{return float4(lerp(fxNVG(uv, nvg),(0.0f ,0.0f , 0.0f), mask.y), mask.z);
		}
} 

	
float4 psNVG(in const vAP_Output v, uniform int nvg): SV_TARGET0 		//uniform int nvg is just 0 or 1 from game telling us which aircraft is being used.
{
	const float2 uv = v.vTexCoords.xy;								// coordinates of pixel
	const float4 nvg_effect = drawNVG(uv, nvg);						// creates nvg effect (ring and inside ring)
	const float4 rgb = DiffuseMap.Sample(sDiffuseMap, uv);			// standard rgb values of each pixel (to be used for outside ring)
	return lerp(rgb, nvg_effect, nvg_effect.a);						// if nvg_effect.a = 0  then returns standard pixels. if nvg_effect.a = 1 then will return nvg effected pixels. Inbetween 1 and 0 is a mix according to x*(1-s)+y*s where s is nvg_effect.a
	
	
	//const float zdist = getDepth(uv);								// find z buffer using abc data
	//const float4 rgb = blurTest(uv, 1);							// blur test code line
	
}


//////////////////////////////
//////////////////////////////
//////// END NVG MOD//////////  
  
#define LOW_NOISE
main_out main_base(const vAP_Output v)
{
	main_out ret_val;
	float2 uv = v.vTexCoords.xy;
	ret_val.scene = DiffuseMap.Sample(ClampLinearSampler, uv).rgb;	
	float3 blur   = ResampleMap.Sample(ClampLinearSampler, uv).rgb;
	float R = 0.89;
	float L = pow(dot(ret_val.scene, LUM), R);	
	float K = 0.08;
	
#ifdef LOW_NOISE
	//
	//float noise = 0.6*noise2D(frac(uv+time));
	//noise = lerp(noise, 0, L);	   	
	//ret_val.color = float3(0, K * ((L * magn + blur.r * blurM) + noise), 0);
	//
	
	ret_val.color = float3(0, min(1, K * (L * magn + blur.r * blurM)), 0);
									//K * ((L * magn + blur.r * blurM) + noise)		ORIGINAL
#else
	ret_val.color = float3(0, min(1, K * (L * magn + blur.r * blurM)), 0);		// without noise
							//min(1, K * (L * magn + blur.r * blurM))		ORIGINAL
#endif
	
	return ret_val;
};

main_out main_alternative(const vAP_Output v)
{
	main_out ret_val;

	float2 uv = v.vTexCoords.xy;
	
	ret_val.scene = DiffuseMap.Sample(ClampLinearSampler, uv).rgb;
	float3 noiseUV = float3(uv * float2(widthTX / 75.0, heightTX / 75.0), frac((time * 10.0) / 64.0));
//	float noise   = tex3D(sNoise, noiseUV).r;
	float noise   = Noise.Sample(WrapLinearSampler, noiseUV).r;
	float3 blur   = ResampleMap.Sample(ClampLinearSampler, uv).rgb;

	float dst = frac(uv.y + time);
	dst *= (1 - dst);

	noise = pow((1.0 - dst), 4.0) * noise;
	
	float R = 1.0;
	float L = pow(dot(ret_val.scene, LUM), R);

	float3 color = float3(0.08 * (L * magn + blur.r * blurM),
						  0.08 * (L * magn + blur.r * blurM),
						  0.08 * (L * magn + blur.r * blurM));
 	ret_val.color = color * saturate(0.7 + 0.3 * noise);

	return ret_val;
};

vAP_Output vsMain(const float2 pos: POSITION0, uint vid: SV_VertexID) {
	vAP_Output res;
	res.vPosition = float4(pos, 0, 1.0);
	res.vTexCoords = float2(pos.x*0.5+0.5, -pos.y*0.5+0.5); 
	//res.pos = float4(quad[vid], 0, 1); // added line for depth???
	return res;
}

float4 psMain(const vAP_Output v): SV_TARGET0 {
	main_out data = main_base(v);
	float mask    = Mask.Sample(ClampSampler, v.vTexCoords.xy).r;
	data.color    = lerp(data.scene,data.color, mask);
	return(float4(data.color, 1.0f));
}

float4 psMainNoMask(const vAP_Output v): SV_TARGET0 {
	main_out data = main_base(v);	
	return(float4(data.color, 1.0f));
}

float4 psMain_alternative(const vAP_Output v): SV_TARGET0 {
	main_out data = main_alternative(v);
	float mask    = Mask.Sample(ClampSampler, v.vTexCoords.xy).r;
	data.color    = lerp(data.scene,data.color, mask);
	return(float4(data.color, 1.0f));
}

float4 psMainNoMask_alternative(const vAP_Output v): SV_TARGET0 {
	main_out data = main_alternative(v);
	return(float4(data.color, 1.0f));
}

float4 ResampleLum4x4(const vAP_Output v): SV_TARGET0 {
	const float dx = 1.0 / widthTX;
	const float dy = 1.0 / heightTX;
	
	float2 uv = v.vTexCoords.xy;
	
	float lSum = 0;
	
	for(int y = 0; y < 4; y++)
		for(int x = 0; x < 4; x++){
			float2 duv = float2((x - 1.5f) * dx, (y - 1.5f) * dy);
			lSum += dot( DiffuseMap.Sample(ClampLinearSampler, duv + uv).rgb, LUM);
	}
	
	lSum /= 16;
	if(lSum < 0.2) lSum = 0.0;
	
	return float4(lSum, lSum, lSum, 1.0);
}

float4 BlurX_gauss(const vAP_Output v): SV_TARGET0 {
	float2 tx = v.vTexCoords.xy;
    float2 dx  = float2(1.0 / widthTX, 0.0);
    float2 sdx = dx;
    
    float3 sum = ResampleMap.Sample(ClampLinearSampler, tx).rgb * 0.134598;
		
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.127325;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.107778;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.081638;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.055335;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.033562;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.018216;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx ).rgb)* 0.008847;
    sdx += dx;
    
    return float4(sum, 1.0);
}

float4 BlurY_gauss(const vAP_Output v): SV_TARGET0 {
	float2 tx = v.vTexCoords.xy;
    float2 dx  = float2(0.0, 1.0 / heightTX);
    float2 sdx = dx;
    
    float3 sum = ResampleMap.Sample(ClampLinearSampler, tx).rgb * 0.134598;
		
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.127325;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.107778;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.081638;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.055335;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.033562;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx).rgb)* 0.018216;
    sdx += dx;
    sum += (ResampleMap.Sample(ClampLinearSampler, tx + sdx).rgb + ResampleMap.Sample(ClampLinearSampler, tx - sdx ).rgb)* 0.008847;
    sdx += dx;
    
    return float4(sum, 1.0);
}



technique10 FinalPass{
	pass P0{
		SetVertexShader(CompileShader(vs_4_0, vsMain()));
		SetGeometryShader(NULL);
		//SetPixelShader(CompileShader(ps_4_0, psMain()));				// stock NVG
		SetPixelShader(CompileShader(ps_4_0, psNVG(NVG_A10)));			// Modded NATO style NVG in allied aircraft
		//SetPixelShader(CompileShader(ps_4_0, psNVG(NVG_KA50)));		// Modded russian style NVG in allied aircraft
		
		SetDepthStencilState(disableDepthBuffer, 0);
		SetBlendState(disableAlphaBlend, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
		SetRasterizerState(cullNone);      
	}
}


technique10 FinalPassNoMask{
	pass P0{
		SetVertexShader(CompileShader(vs_4_0, vsMain()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, psMainNoMask()));

		SetDepthStencilState(disableDepthBuffer, 0);
		SetBlendState(disableAlphaBlend, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
		SetRasterizerState(cullNone);      
	}
}

technique10 Resample{
	pass P0{
		SetVertexShader(CompileShader(vs_4_0, vsMain()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, ResampleLum4x4()));

		SetDepthStencilState(disableDepthBuffer, 0);
		SetBlendState(disableAlphaBlend, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
		SetRasterizerState(cullNone);      
	}
}

technique10 BlurX{
	pass P0{
		SetVertexShader(CompileShader(vs_4_0, vsMain()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, BlurX_gauss()));
	}
}

technique10 BlurY{
	pass P0{
		SetVertexShader(CompileShader(vs_4_0, vsMain()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, BlurY_gauss()));
	}
}

technique10 FinalPassAlternative{
	pass P0{
		SetVertexShader(CompileShader(vs_4_0, vsMain()));
		SetGeometryShader(NULL);
		//SetPixelShader(CompileShader(ps_4_0, psMain_alternative()));  //stock Russian NVG
		SetPixelShader(CompileShader(ps_4_0, psNVG(NVG_KA50)));  		// Modded russian NVG in russian aircraft
		//SetPixelShader(CompileShader(ps_4_0, psNVG(NVG_A10)));  		// Modded NATO NVG in russian aircraft
		
		SetDepthStencilState(disableDepthBuffer, 0);
		SetBlendState(disableAlphaBlend, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
		SetRasterizerState(cullNone);      
	}
}

technique10 FinalPassNoMaskAlternative{
	pass P0{
		SetVertexShader(CompileShader(vs_4_0, vsMain()));
		SetGeometryShader(NULL);
		SetPixelShader(CompileShader(ps_4_0, psMainNoMask_alternative()));

		SetDepthStencilState(disableDepthBuffer, 0);
		SetBlendState(disableAlphaBlend, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xFFFFFFFF);
		SetRasterizerState(cullNone);      
	}
}
