//
// Atmospheric scattering fragment shader
//
// Author: Sean O'Neil
//
// Copyright (c) 2004 Sean O'Neil
//

uniform float4x4 matViewProjection;
uniform float4x4 matRot;
uniform float4x4 matWorldInverseTranspose;

uniform float3 v3CameraPos;
uniform float3 v3LightPos;
uniform float3 v3InvWavelength;
//uniform float  fCameraHeight;
uniform float fCameraHeight2;
uniform float fOuterRadius;
uniform float fOuterRadius2;
uniform float fInnerRadius;
//uniform float fInnerRadius2;
uniform float fScale;
uniform float fScaleOverScaleDepth;

struct VS_INPUT
{
	float4 Position		: POSITION;
	float2 TexCoord		: TEXCOORD0;
	float4 Normal		: NORMAL;
};

struct VS_OUTPUT
{
  float4 Position		: POSITION;
  float4 FrontColor		: COLOR0;
  float4 SecondaryColor	: COLOR1;
  float2 TexCoord		: TEXCOORD0;
  float4 Normal			: TEXCOORD1;
};

float scale( float fCos )
{
	float fScaleDepth = 0.25;
	float x = 1.0 - fCos;
	return fScaleDepth * exp( -0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))) );
}

VS_OUTPUT main( VS_INPUT IN )
{	
	float fKrESun		= 0.0375;
	float fKmESun		= 0.0225;
	float fKr4PI		= 0.0314159;
	float fKm4PI		= 0.0188496;
	float fScaleDepth	= 0.25;

	VS_OUTPUT OUT;

	// Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
	float3 v3Pos = mul( matRot, IN.Position ).xyz;
	//v3Pos.x = -v3Pos.x;
	float3 v3Ray = v3Pos - v3CameraPos;
	float fFar = length( v3Ray );
	v3Ray /= fFar;

	// Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
	float B = 2.0 * dot( v3CameraPos, v3Ray );
	float C = fCameraHeight2 - fOuterRadius2;
	float fDet = max( 0.0, B*B - 4.0 * C );
	float fNear = 0.5 * (-B - sqrt( fDet ));

	// Calculate the ray's starting position, then calculate its scattering offset
	float3 v3Start = v3CameraPos + v3Ray * fNear;
	fFar -= fNear;
	float fDepth = exp( (fInnerRadius - fOuterRadius) / fScaleDepth );
	float fCameraAngle = dot( -v3Ray, v3Pos ) / length( v3Pos );
	float fLightAngle = dot( v3LightPos, v3Pos ) / length( v3Pos );
	float fCameraScale = scale( fCameraAngle );
	float fLightScale = scale( fLightAngle );
	float fCameraOffset = fDepth * fCameraScale;
	float fTemp = (fLightScale + fCameraScale);

	// Initialize the scattering loop variables
	float fSampleLength = fFar / 2.0;
	float fScaledLength = fSampleLength * fScale;
	float3 v3SampleRay = v3Ray * fSampleLength;
	float3 v3SamplePoint = v3Start + v3SampleRay * 0.5;

	// Now loop through the sample rays
	float3 v3FrontColor = float3( 0.0, 0.0, 0.0 );
	float3 v3Attenuate;
	for( int i = 0; i < 2; i++ )
	{
		float fHeight = length( v3SamplePoint );
		float fDepth = exp( fScaleOverScaleDepth * (fInnerRadius - fHeight) );
		float fScatter = fDepth * fTemp - fCameraOffset;
		v3Attenuate = exp( -fScatter * (v3InvWavelength * fKr4PI + fKm4PI) );
		v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
		v3SamplePoint += v3SampleRay;
	}

	OUT.FrontColor.a = 1.0;
	OUT.FrontColor.rgb = v3FrontColor * (v3InvWavelength * fKrESun + fKmESun);

	// Calculate the attenuation factor for the ground
	OUT.SecondaryColor.a = 1.0;
	OUT.SecondaryColor.rgb = v3Attenuate;

	OUT.Position = mul( matViewProjection, IN.Position );
	OUT.TexCoord = IN.TexCoord;

	//float4 vNormRot = mul( matRot, IN.Normal );
	OUT.Normal = mul( matWorldInverseTranspose, IN.Normal );

	return( OUT );
}
