////////////////////////////////////////////////////////////////////////////////////////////////////
// Constant values
////////////////////////////////////////////////////////////////////////////////////////////////////

#define MAX_ACTIVE_LIGHT 4
#define MAX_SHADOW_PCF_SIZE 7

////////////////////////////////////////////////////////////////////////////////////////////////////
// Global values
////////////////////////////////////////////////////////////////////////////////////////////////////

#if MIX_SM_HIGH

	/****************************************
		Reserved : b0
	****************************************/
	
	//

	/****************************************
		General : b1
	****************************************/

	cbuffer cbGeneral : register( b1 )
	{
		// Camera
		float3 g_EyePos             : packoffset( c0 );
		float g_FarZInv             : packoffset( c0.w );

		// Grobal ambient
		float4 g_GlobalAmbientColor : packoffset( c1 );

		// Hemisphere light
		float4 g_HSSkyAxis          : packoffset( c2 );
		float4 g_HSGroundColor      : packoffset( c3 );
		float4 g_HSSkyColor         : packoffset( c4 );

		// Sun(Directional) light
		float4 g_SunDir             : packoffset( c5 );
		float4 g_SunColor           : packoffset( c6 );

		// Fog
		float4 g_FogParam           : packoffset( c7 );
		float3 g_FogColor           : packoffset( c8 );

		// Shadow
		float4 g_ShadowParam0       : packoffset( c9 );
		float4 g_ShadowParam1       : packoffset( c10 );

		// Atmosphere scattering
		float4 g_AS_Color           : packoffset( c11 );
		float3 g_AS_SunDir          : packoffset( c12 );
		float4 g_AS_Multipliers     : packoffset( c13 );
		float3 g_AS_HG              : packoffset( c14 );
		float3 g_AS_BetaDashR       : packoffset( c15 );
		float3 g_AS_BetaDashM       : packoffset( c16 );
		float3 g_AS_BetaRM          : packoffset( c17 );
		float3 g_AS_OneOverBetaRM   : packoffset( c18 );
	};

	/****************************************
		LocalLight : b2
	****************************************/

	cbuffer cbLocalLight : register( b2 )
	{
		float4 g_LightPos[MAX_ACTIVE_LIGHT];
		float4 g_LightDir[MAX_ACTIVE_LIGHT];
		float4 g_LightAtten[MAX_ACTIVE_LIGHT];
		float4 g_LightColor[MAX_ACTIVE_LIGHT];
		float4 g_LightParam[MAX_ACTIVE_LIGHT];
	};

	/****************************************
		Material : b3
	****************************************/
	
	//
	
#else //MIX_SM_HIGH

	/****************************************
		Reserved : c0 - c15
	****************************************/
	
	//

	/****************************************
		General : c16 - c47
	****************************************/

	// Camera
	float g_FarZInv             : register( c16 );
	float3 g_EyePos             : register( c17 );

	// Grobal ambient
	float4 g_GlobalAmbientColor : register( c18 );

	// Hemisphere light
	float4 g_HSSkyAxis          : register( c19 );
	float4 g_HSGroundColor      : register( c20 );
	float4 g_HSSkyColor         : register( c21 );

	// Directional light
	float4 g_SunDir             : register( c22 );
	float4 g_SunColor           : register( c23 );

	// Fog
	float4 g_FogParam           : register( c24 );
	float3 g_FogColor           : register( c25 );

	// Shadow
	float4 g_ShadowParam0       : register( c26 );
	float4 g_ShadowParam1       : register( c27 );

	// Atmosphere scattering
	float4 g_AS_Color           : register( c28 );
	float3 g_AS_SunDir          : register( c29 );
	float4 g_AS_Multipliers     : register( c30 );
	float3 g_AS_HG              : register( c31 );
	float3 g_AS_BetaDashR       : register( c32 );
	float3 g_AS_BetaDashM       : register( c33 );
	float3 g_AS_BetaRM          : register( c34 );
	float3 g_AS_OneOverBetaRM   : register( c35 );

	/****************************************
		LocalLight : c48 - c67
	****************************************/

	float4 g_LightPos[MAX_ACTIVE_LIGHT]   : register( c48 );
	float4 g_LightDir[MAX_ACTIVE_LIGHT]   : register( c52 );
	float4 g_LightAtten[MAX_ACTIVE_LIGHT] : register( c56 );
	float4 g_LightColor[MAX_ACTIVE_LIGHT] : register( c60 );
	float4 g_LightParam[MAX_ACTIVE_LIGHT] : register( c64 );

	/****************************************
		Material : c68 - ?
	****************************************/
	
	//

#endif //MIX_SM_HIGH

////////////////////////////////////////////////////////////////////////////////////////////////////
// Macros : Global values
////////////////////////////////////////////////////////////////////////////////////////////////////

// General //

#define INV_FAR_Z g_FarZInv // Inverse far z ( float )
#define EYE_POS   g_EyePos  // Eye position( float3 )

// Global ambient //

#define GLOBAL_AMBIENT_COLOR g_GlobalAmbientColor.rgb // Color ( float3 )
#define GLOBAL_SHADE_FACTOR g_GlobalAmbientColor.a // Shade factor ( float )

// Hemisphere light //

#define HEMISPHERE_ENABLED      ( g_HSSkyAxis.w > 0.5 ) // Enabled ( bool )
#define HEMISPHERE_AXIS         g_HSSkyAxis.xyz         // Axis ( float3 )
#define HEMISPHERE_GROUND_COLOR g_HSGroundColor.rgb     // Ground color ( float3 )
#define HEMISPHERE_GROUND_SCALE g_HSGroundColor.a       // Ground scaler ( float )
#define HEMISPHERE_SKY_COLOR    g_HSSkyColor.rgb        // Sky color ( float3 )
#define HEMISPHERE_SKY_SCALE    g_HSSkyColor.a          // Sky scaler ( float )

// Sun //

#define SUN_ENABLED ( g_SunDir.w > 0.5 ) // Enabled ( bool )
#define SUN_DIR     g_SunDir.xyz         // Direction ( float3 )
#define SUN_COLOR   g_SunColor.rgb       // Color ( float3 )
#define SUN_SCALE   g_SunColor.a         // Scaler ( float )

// Fog //

#define FOG_ENABLED ( g_FogParam.w > 0.5f ) // Enabled ( bool )
#define FOG_P0      g_FogParam.x            // Paramter0 ( float )
#define FOG_P1      g_FogParam.y            // Paramter1 ( float )
#define FOG_COLOR   g_FogColor.rgb          // Color ( float3 )

// Shadow //

#define SHADOW_ENABLED            ( g_ShadowParam0.w > 0.5 ) // Enabled ( bool )
#define SHADOW_DEPTH_BIAS         g_ShadowParam0.x           // Depth Bias ( float )
#define SHADOW_DEPTH_SLOPE_SCALE  g_ShadowParam0.y           // Depth SlopeScale ( float )
#define SHADOW_DEPTH_BIAS_CLAMP   g_ShadowParam0.z           // Depth Bias Clamp ( float )
#define SHADOW_PCF_RANGE          g_ShadowParam1.x           // PCF ( Size - 1 ) * 0.5 ( float )
#define SHADOW_PCF_MUL            g_ShadowParam1.y           // PCF 1.0 / ( Size * Size ) ( float )
#define SHADOW_TEXEL_SIZE         g_ShadowParam1.zw          // Texel Size ( float2 )

// Atmosphere scattering //

#define AS_ENABLED          ( g_AS_Color.w > 0.5 ) // Enabled ( bool )
#define AS_COLOR            ( g_AS_Color.rgb )     // Color ( float3 )
#define AS_SUN_DIR          g_AS_SunDir.xyz        // Sun direction ( float3 )
#define AS_LIN_SCALE        g_AS_Multipliers.x     // Lin scaler ( float )
#define AS_FEX_SCALE        g_AS_Multipliers.yzw   // Fex scaler ( float3 )
#define AS_HG_M             g_AS_HG.x              // HG 1.0 - hg * hg ( float )
#define AS_HG_P             g_AS_HG.y              // HG 1.0 + hg * hg ( float )
#define AS_HG_T             g_AS_HG.z              // HG 2.0 * hg ( float )
#define AS_BETA_DASH_R      g_AS_BetaDashR         // Beta dash R ( float3 )
#define AS_BETA_DASH_M      g_AS_BetaDashM         // Beta dash M ( float3 )
#define AS_BETA_RM          g_AS_BetaRM            // Beta RM ( float3 )
#define AS_ONE_OVER_BETA_RM g_AS_OneOverBetaRM     // One over beta RM ( float3 )

// LocalLight //

#define LO_EXIST( index )     ( g_LightPos[index].w > 0.5 ) // Common : Is enabled ( bool )
#define LO_SPOT( index )      ( g_LightDir[index].w > 0.5 ) // Common : Is spot ( bool )
#define LO_POS( index )       g_LightPos[index].xyz         // Common : Position ( float3 )
#define LO_RANGE( index )     g_LightParam[index].x         // Common : Range ( float )
#define LO_COLOR( index )     g_LightColor[index]           // Common : Color ( float4 )
#define LO_ATTEN( index )     g_LightAtten[index].xyz       // Common : Atten ( float3 )
#define LO_DIR( index )       g_LightDir[index].xyz         // Spot   : Direction ( float3 )
#define LO_INNER_COS( index ) g_LightParam[index].y         // Spot   : Inner cos angle ( float )
#define LO_OUTER_COS( index ) g_LightParam[index].z         // Spot   : Outer cos angle ( float )
#define LO_EXP( index )       g_LightParam[index].w         // Spot   : Exprosure ( float )
#define LO_DIST_DIFF( index ) g_LightParam[index].y         // Point  : Range diff ( float )

////////////////////////////////////////////////////////////////////////////////////////////////////
// Functions
////////////////////////////////////////////////////////////////////////////////////////////////////

// Fog ////

#if ENABLE_FOG

	float ComputeFogRatio( float projPosW )
	{
		return saturate( FOG_P0 + projPosW * FOG_P1 );
	}

	#if ENABLE_ATMOSPHERE

		float3 ApplyFog( float3 srcColor, float3 dir, float dist, float ratio )
		{
			float3 output;
			
			if( FOG_ENABLED )
			{
				if( AS_ENABLED )
				{
					float theta;
					float phase1;
					float phase2;
					float3 extinction;
					float3 fex;
					float3 lin;
				
					////////////////////////////////////////////////////////////////////////////////////////////////////

					theta = dot( -AS_SUN_DIR, dir.xyz );

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

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

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

					extinction = exp( -AS_BETA_RM * dist );

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

					fex = extinction;
					fex *= AS_FEX_SCALE;
					fex *= AS_COLOR;

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

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

					lin = ( betaRay + betaMie ) * AS_ONE_OVER_BETA_RM * ( 1.0 - extinction );
					lin *= AS_LIN_SCALE;
					lin *= AS_COLOR;

					output = srcColor;
					output *= lerp( fex, float3( 1.0, 1.0f, 1.0 ), ratio );
					output += ( lin * FOG_COLOR ) * ( 1.0 - ratio );
				}
				else
				{
					output = lerp( FOG_COLOR, srcColor, ratio );
				}
			}
			else
			{
				output = srcColor;
			}
			
			return output;
		}

	#else //ENABLE_ATMOSPHERE
	
		float3 ApplyFog( float3 srcColor, float ratio )
		{
			float3 output;
			
			if( FOG_ENABLED )
			{
				output = lerp( FOG_COLOR, srcColor, ratio );
			}
			else
			{
				output = srcColor;
			}
			
			return output;
		}

	#endif //ENABLE_ATMOSPHERE

#endif //ENABLE_FOG
