////////////////////////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "../../../types.txt"
#include "../common.ps.txt"

#include "common.ps.txt"

////////////////////////////////////////////////////////////////////////////////////////////////////
// Structures
////////////////////////////////////////////////////////////////////////////////////////////////////

struct PS_INPUT
{
#if MIX_SM_HIGH
	float4 pos      : SV_POSITION;
#endif //MIX_SM_HIGH
	float3 worldPos : TEXCOORD0;
	float2 tex      : TEXCOORD1;
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// Grobal values
////////////////////////////////////////////////////////////////////////////////////////////////////

#if MIX_SM_HIGH

	cbuffer cbInput : register( b0 )
	{
		float3 g_AS_SunColor;
		float4 g_AS_NightColor;
		float4 g_BaseParam;
		float4 g_CloudColor;
		float4 g_CloudLayer[2];
		float4 g_CloudParams;
	};

	#if ENABLE_BASE_TEXTURE
		Texture2D    g_BaseTexture : register( t0 );
		SamplerState g_BaseSampler : register( s0 );
	#endif //ENABLE_BASE_TEXTURE

	#if ENABLE_CLOUD_TEXTURE
		Texture2D    g_CloudTexture0 : register( t1 );
		SamplerState g_CloudSampler0 : register( s1 );
		Texture2D    g_CloudTexture1 : register( t2 );
		SamplerState g_CloudSampler1 : register( s2 );
	#endif //ENABLE_CLOUD_TEXTURE
	
#else //MIX_SM_HIGH

	float3 g_AS_SunColor   : register( c0 );
	float4 g_AS_NightColor : register( c1 );
	float4 g_BaseParam     : register( c2 );
	float4 g_CloudColor    : register( c3 );
	float4 g_CloudLayer[2] : register( c4 );
	float4 g_CloudParams   : register( c6 );

	#if ENABLE_BASE_TEXTURE
		sampler g_BaseSampler : register( s0 );
	#endif //ENABLE_BASE_TEXTURE

	#if ENABLE_CLOUD_TEXTURE
		sampler g_CloudSampler0 : register( s1 );
		sampler g_CloudSampler1 : register( s2 );
	#endif //ENABLE_CLOUD_TEXTURE

#endif //MIX_SM_HIGH

////////////////////////////////////////////////////////////////////////////////////////////////////
// Macros
////////////////////////////////////////////////////////////////////////////////////////////////////

//Textures
#if MIX_SM_HIGH
	#define TEX_BASE( uv ) g_BaseTexture.Sample( g_BaseSampler, uv )
	#define TEX_CLOUD_0( uv ) g_CloudTexture0.Sample( g_CloudSampler0, uv )
	#define TEX_CLOUD_1( uv ) g_CloudTexture1.Sample( g_CloudSampler1, uv )
#else //MIX_SM_HIGH
	#define TEX_BASE( uv ) tex2D( g_BaseSampler, uv )
	#define TEX_CLOUD_0( uv ) tex2D( g_CloudSampler0, uv )
	#define TEX_CLOUD_1( uv ) tex2D( g_CloudSampler1, uv )
#endif //MIX_SM_HIGH

//Atmosphare
#define AS_SUN_COLOR g_AS_SunColor
#define AS_NIGHT_COLOR g_AS_NightColor.rgb
#define AS_NIGHT_RATIO g_AS_NightColor.a

//Base
#define TEX_BASE_SCALE g_BaseParam.x
#define TEX_BASE_ALPHA g_BaseParam.y

//Color
#define CLOUD_COLOR g_CloudColor

//Layer
#define CLOUD_UV_OFFSET( index ) ( g_CloudLayer[index].xy )
#define CLOUD_SCALE( index ) ( g_CloudLayer[index].z )
#define CLOUD_OPACITY( index ) ( g_CloudLayer[index].w )

//Params ( Atmosphere )
//CLOUD_DARKNESS_MIN 0.2
//CLOUD_DARKNESS_MAX 0.98
#define CLOUD_CORNER_THRESHOLD g_CloudParams.x //0.14
#define CLOUD_CORNER_MUL g_CloudParams.y //1.0 / ( 1.0 - CLOUD_CORNER_THRESHOLD )
#define CLOUD_DARKNESS g_CloudParams.z // max( 0.0, dot( float3( 0.0, 1.0, 0.0 ), SUN_DIR ) ) -> clamp( 1.0 - exp( -cloudDarkness * 4.0 ), CLOUD_DARKNESS_MIN, CLOUD_DARKNESS_MAX )

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main function
////////////////////////////////////////////////////////////////////////////////////////////////////

float4 main( PS_INPUT input ) : MSV_TARGET0
{
	float3 vec;
	float3 dir;
	float dist;
	float theta;
	float phase1;
	float phase2;
	float3 extinction;
	float3 betaRay;
	float3 betaMie;
	float3 inscatter;
	
#if ( ENABLE_BASE_TEXTURE || ENABLE_CLOUD_TEXTURE )
	float2 tex;
	float4 texColor;
	float3 sunColor;
#endif //( ENABLE_BASE_TEXTURE || ENABLE_CLOUD_TEXTURE )

#if ENABLE_CLOUD_TEXTURE

	#if ENABLE_CLOUD_LAYER
		float4 tmpColor;
	#endif //ENABLE_CLOUD_LAYER

	#if ENABLE_CLOUD_LIGHTING
		float3 lightDir;
		float3 cloudDir;
		float3 cloudCross;
		float3 cloudNorm;
		float cloudLdotN;
	#endif //ENABLE_CLOUD_LIGHTING

#endif //ENABLE_CLOUD_TEXTURE

	float4 output;

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

	vec = input.worldPos - g_EyePos;
	dir = normalize( vec );
	dist = length( vec );

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

	theta = dot( AS_SUN_DIR, dir );

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

	phase1 = 1.0 + theta * theta;
	phase2 = pow( abs( rsqrt( AS_HG_P - AS_HG_T * theta ) ), 2.9 ) * AS_HG_M;

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

	extinction = exp( -AS_BETA_RM * dist );

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

	betaRay = AS_BETA_DASH_R * phase1;
	betaMie = AS_BETA_DASH_M * phase2;

	inscatter = ( betaRay + betaMie ) * AS_ONE_OVER_BETA_RM * ( 1.0 - extinction );

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

	inscatter *= AS_LIN_SCALE;
	inscatter *= AS_SUN_COLOR;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	
	inscatter = lerp( inscatter, AS_NIGHT_COLOR, AS_NIGHT_RATIO );

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

#if ENABLE_BASE_TEXTURE
	tex = ApplyTexScale( input.tex, TEX_BASE_SCALE );
	texColor = TEX_BASE( tex );
	output.rgb = lerp( inscatter, texColor.rgb, texColor.a * TEX_BASE_ALPHA );
	output.a = 1.0;
#else //ENABLE_BASE_TEXTURE
	output = float4( inscatter, 1.0 );
#endif //ENABLE_BASE_TEXTURE

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

#if ENABLE_CLOUD_TEXTURE

	tex = ApplyTexScale( input.tex, CLOUD_SCALE( 0 ) );
	texColor = TEX_CLOUD_0( tex + CLOUD_UV_OFFSET( 0 ) );
	texColor.a *= CLOUD_OPACITY( 0 );

	#if ENABLE_CLOUD_LAYER
		tex = ApplyTexScale( input.tex, CLOUD_SCALE( 1 ) );
		tmpColor = TEX_CLOUD_1( tex + CLOUD_UV_OFFSET( 1 ) );
		tmpColor.a *= CLOUD_OPACITY( 1 );

		texColor.rgb = lerp( texColor.rgb, tmpColor.rgb, tmpColor.a );
		texColor.a = min( texColor.a + tmpColor.a, 1.0 );
	#endif //ENABLE_CLOUD_LAYER

	texColor *= CLOUD_COLOR;
	
	#if ENABLE_CLOUD_LIGHTING

		lightDir = -AS_SUN_DIR;

		cloudDir = normalize( EYE_POS - input.worldPos );
		cloudCross = cross( lightDir, cloudDir );
	
		cloudNorm = lerp( cloudCross, cloudDir, max( 0.0, texColor.a - CLOUD_CORNER_THRESHOLD ) * CLOUD_CORNER_MUL );
		cloudNorm = normalize( cloudNorm );

		// AS_NIGHT_RATIO( 1.0 ) : Not lighting
		cloudLdotN = max( 0.0, dot( lightDir, cloudNorm ) ) * max( 0.0, 1.0 - AS_NIGHT_RATIO );

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

//		phase1 = 1.0 + theta * theta;
		phase2 = abs( rsqrt( AS_HG_P - AS_HG_T * theta ) ) * AS_HG_M;

//		extinction = exp( -AS_BETA_RM * dist );

//		betaRay = AS_BETA_DASH_R * phase1;
		betaMie = AS_BETA_DASH_M * phase2;

		inscatter = ( betaRay + betaMie ) * AS_ONE_OVER_BETA_RM * ( 1.0 - extinction );

		inscatter *= AS_LIN_SCALE;
		inscatter *= AS_SUN_COLOR;
	
		inscatter = lerp( inscatter, AS_NIGHT_COLOR, AS_NIGHT_RATIO );
	
		////////////////////////////////////////////////////////////////////////////////////////////////////
	
		output.rgb = lerp( output.rgb, texColor.rgb, texColor.a );
//		output.rgb = lerp( output.rgb, inscatter * CLOUD_DARKNESS, cloudLdotN );
//		output.rgb = lerp( output.rgb, texColor.rgb * CLOUD_DARKNESS, cloudLdotN );
		output.rgb = lerp( output.rgb, min( texColor.rgb, inscatter ) * CLOUD_DARKNESS, cloudLdotN );

	#else //ENABLE_CLOUD_LIGHTING
		output.rgb = lerp( output.rgb, texColor.rgb, texColor.a );
	#endif //ENABLE_CLOUD_LIGHTING

#endif //ENABLE_CLOUD_TEXTURE

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

	return output;
}
