#version 330

in vec2 fTexCoord;
in vec3 fWorldPos;
in vec3 fCameraPos;

out vec4 OutColor;

uniform vec3 uTotalRayleigh;
uniform vec3 uTotalMie;
uniform float uSunIntensity;

uniform vec3 uSunPosition;

uniform float uRayleighCoeff;
uniform float uMieCoeff;
uniform float uMieG;

const float cRayleighZenithLength = 8.4E3;
const float cMieZenithLength = 1.25E3;

uniform sampler2D uNoiseTexSampler;
uniform float uTime;

float Rayleigh( float inTheta )
{
	return ( 3.0 / 4.0 ) * ( 1.0 + pow( cos( inTheta ), 2.0 ) );
}

float Mie( float inTheta, float inG )
{
	float numerator = pow( ( 1.0 - inG ), 2.0 );
	float denominator = pow( ( 1.0 + pow( inG, 2.0 ) - 2.0 * inG * cos( inTheta ) ), 1.5 );
	return ( 1.0 / ( 4.0 * 3.1415926 ) ) * ( numerator / denominator );
}

float SunIntensity( float inZenithAngle )
{
	return uSunIntensity * max( 0.0, 1.0 - exp( -( ( ( 3.1415926 / 2.0 ) - inZenithAngle ) / 2.0 ) ) );
}

float OpticalLength( float inZenithLength, float inZenithAngle )
{
	return inZenithLength / ( cos( inZenithAngle ) + 0.15 * pow( 93.885 - ( ( inZenithAngle * 180.0 ) / 3.1415926 ), -1.253 ) ); 
}

float fbm( vec2 inPosition )
{
	vec2 texCoords = inPosition;
	float value = 0.0;
	float speed = uTime / 100.0;
	vec2 offset = vec2( 0.0, speed * 0.25 );
	value += texture( uNoiseTexSampler, (texCoords.xy * 0.5) + offset ).w;
	value += texture( uNoiseTexSampler, (texCoords.xy * 0.25) + offset ).w;
	value += texture( uNoiseTexSampler, (texCoords.xy * 0.125) + offset ).w;
	value += texture( uNoiseTexSampler, (texCoords.xy * 0.0625) + offset ).w;
	value /= 4.0;
	
	float a = 0.45;
	float b = 0.70;
	if( value < a )
	{
		return 0.0;
	}
	else if( value > b )
	{
		return 1.0;
	}
	else
	{
		return mix( 0.0, 1.0, (value - a) / ( b - a ) );
	}
}

void main()
{
	vec3 sunDirection = normalize( uSunPosition - fWorldPos );
	float sunIntensity = uSunIntensity;//SunIntensity( acos( dot( sunDirection, vec3( 0.0, 1.0, 0.0 ) ) ) );
	
	vec3 betaR = uTotalRayleigh * uRayleighCoeff;
	vec3 betaM = uTotalMie * uMieCoeff;
	
	float zenithAngle = acos( max( 0.0, dot( vec3( 0.0, 1.0, 0.0 ), normalize( fWorldPos ) ) ) );
	float sR = OpticalLength( cRayleighZenithLength, zenithAngle );
	float sM = OpticalLength( cMieZenithLength, zenithAngle );
	
	vec3 extinctionFactor = exp( -( betaR * sR + betaM * sM ) );
	//extinctionFactor = mix( extinctionFactor, 1.0 - extinctionFactor, abs( sunDirection.y ) );
	
	float theta = acos( dot( normalize( fWorldPos - fCameraPos ), sunDirection ) );
	
	float rPhase = Rayleigh( theta );
	vec3 betaRTheta = betaR * rPhase;
	
	float mPhase = Mie( theta, uMieG ); // Make a uniform for this
	vec3 betaMTheta = betaM * mPhase;
	
	vec3 Lin = sunIntensity * ( ( betaRTheta + betaMTheta ) / ( betaR + betaM ) ) * ( 1.0 - extinctionFactor );
	
	vec3 L0 = vec3( 0.0 );// * extinctionFactor; // Base sky color
	L0 += ( 1.0 - step( cos( theta ), 0.999 ) ) * ( sunIntensity * extinctionFactor );
	float sunFactor = exp( -distance( fWorldPos, uSunPosition ) / 250 );
	L0 += vec3( 0.8, 0.6, 0.2 ) * sunFactor; 
	
	
	float occlusion = clamp( distance( fWorldPos, uSunPosition ) / 2500, 0.0, 1.0 );
	float cloudVolume = fbm( fTexCoord ) * 0.75;
	L0 += vec3( cloudVolume * occlusion );
	
	
	/*
	vec2 sunDir = ( uSunPosition - fWorldPos ).xy;
	float sunDist = length( sunDir );
	sunDir = sunDir / sunDist;
	float cloudVal = fbm( fTexCoord );
	float occlusionVal = 0.0;
	vec2 sunRay = sunDir * ( sunDist / 4.0 );
	for( int i = 1; i <= 4; ++i )
	{
		occlusionVal += fbm( fTexCoord + ( sunRay * i ) );
	}
	L0 = max( vec3( 0.0 ), vec3( L0 + ( cloudVal - occlusionVal / 10.0 ) ) );
	*/

	OutColor = vec4( L0 + Lin, 1.0 );
}