#ifdef RENDER_FOG
	uniform sampler2D 	depthTex,
						colorTex;
#else
	#ifdef RENDER_EXP_FOG
	//	uniform sampler2D 	densityTex;
		uniform sampler2D 	depthTex,	
							colorTex;
		uniform vec3 		moonlightcolor;
		
		uniform float 	mieScale,
						mieScaleNight,
						rayScale,
						rayScaleNight;
		
	#else
		uniform sampler2D	starsTex;
		uniform sampler2D	moonTex;
		uniform vec3 		moonColor;
		uniform float		moonCoronasMul;
		
		uniform vec4	LTM0,
						LTM1,
						LTM3;
		uniform vec2 	moonRadius;
		uniform vec3  	SUN; 	// = colore del sole
		
	#endif
	uniform vec3		moondir;
	
#endif

uniform vec3		sundir;

varying vec2 		texcoord;
varying vec2		VPOS;
uniform float		inScatter;
uniform float       extintion;

uniform float 		sunpower;

uniform mat4		eyeToWorld;
uniform vec3		campos;

uniform vec3 		camParams;	// x = near, y = far

uniform vec3		horizonColor;
uniform vec3		zenithColor;
uniform vec3 		fogColor; 

uniform float		wFar;
uniform float 		wNear;

uniform vec3 		earth_center;
uniform float 		length_unit;

uniform float		waterY;

#ifdef RENDER_EXP_FOG
	
	uniform float cHeightFallof;
	////////////////////////////

	float ComputeVolumetricFog( vec3 cameraToWorldPos )
	{
		float distance=max(length( cameraToWorldPos )-wNear,0.0);
		float fogInt = distance * exp( cHeightFallof * -campos.y);
		
		if( abs(cameraToWorldPos.y) > 0.01)
		{
			float t = cHeightFallof * cameraToWorldPos.y;
			fogInt*= ( 1.0-exp( -t ) ) / t;
		}
		return fogInt;
	}
#endif

const float STARS_DISTANCE=29000.0;
float DistanceToStarsBoundary(vec3 r0, vec3 rd, float sr, out float x0, out float x1) 
{
	float a= dot(rd,rd);
	float b= dot(rd,r0)*2.0;
	float c= dot(r0,r0)-sr*sr;
	
	float discriminant=b*b-4.0*a*c;
	if(discriminant<0.0)
		return -1;
	
	if(discriminant == 0) 
		return - 0.5 * b / a; 
		
	float q = (b > 0) ? -0.5 * (b + sqrt(discriminant)) : -0.5 * (b - sqrt(discriminant)); 		
	x0 = q / a; 
    x1 = c / q; 
	if(x0<x1)
	{
		float tmp=x0;
		x0=x1;
		x1=tmp;
	}
	return max(x0,x1);
}

////////////////////////////
///// AERIAL PERSPECTIVE /////////////////////////////////////////
////////////////////////////////////////////////////////////////
vec3 GetSolarRadiance();
vec3 GetSkyRadiance(vec3 camera, vec3 view_ray, float shadow_length,
    vec3 sun_direction, out vec3 transmittance);
vec3 GetSkyRadianceWithoutPhase(vec3 camera, vec3 view_ray, float shadow_length,
    vec3 sun_direction, out vec3 transmittance);
vec3 GetSkyRadianceToPoint(vec3 camera, vec3 point, float shadow_length,
    vec3 sun_direction, out vec3 transmittance);
vec3 GetSunAndSkyIrradiance(
    vec3 p, vec3 normal, vec3 sun_direction, out vec3 sky_irradiance);
vec3 GetTrasmittanceTexture(vec2 uv);
vec3 GetScatteringTexture(vec3 uv);
float GetPhaseFunctions(vec3 view_ray, vec3 sun_direction, out float mie);
vec3 GetSunIrradiance(vec3 p, vec3 sun_direction);

void main()
{
	vec4 pos;
	vec3 camposFromEarth=(campos.xyz*length_unit)-earth_center.xyz;
	vec3 Lin=vec3(0.0,0.0,0.0);
	vec3 Fex=vec3(1.0,1.0,1.0);
	vec3 sourceRadiance=vec3(0.0,0.0,0.0);
	vec3 night=vec3(0.0,0.0,0.0);
	
#ifdef RENDER_FOG
	
	pos.z = texture2D(depthTex,texcoord.st).r; 
	sourceRadiance=texture2D(colorTex,texcoord.st).rgb;
	
	if(-pos.z<wFar)
	{
		// compute position
		pos.xy=VPOS*-pos.z;
		pos.w=1.0;
		
		vec4 Wpos=eyeToWorld*pos;
		camposFromEarth.y=max(camposFromEarth.y,-earth_center.y+waterY*length_unit);
		
		vec3 Cam2WorldPos=Wpos.xyz-campos.xyz;
		Lin=GetSkyRadianceToPoint(camposFromEarth, (Wpos.xyz*length_unit)-earth_center.xyz, 0.0, sundir, Fex)*inScatter;
	}

#else
		#ifdef RENDER_EXP_FOG

		pos.z = texture2D(depthTex,texcoord.st).r; 
		sourceRadiance=texture2D(colorTex,texcoord.st).rgb;
		
		pos.xy=VPOS*-pos.z;
		pos.w=1.0;
		vec4 Wpos=eyeToWorld*pos;
		
		//float planar_density=texture2D(densityTex,Wpos.xz*0.000025).r;
		
		vec3 Cam2WorldPos=Wpos.xyz-campos.xyz;
		float delta=ComputeVolumetricFog(Cam2WorldPos);
		
		vec3 viewdir2d=normalize(vec3(Cam2WorldPos.x,0.0,Cam2WorldPos.z));//normalize(cross(sundir2d,vec3(0.0,1.0,0.0)));//normalize(vec3(Cam2WorldPos.x,0.0,Cam2WorldPos.z));
		camposFromEarth.y=-earth_center.y+((100.0+waterY)*length_unit);
		vec3 atmoColor=GetSkyRadianceWithoutPhase(camposFromEarth, viewdir2d, 0.0, sundir, Fex);
		
		vec3 sundir2d=normalize(vec3(sundir.x,0.0,sundir.z));		
		vec3 viewdir2d_flat=normalize(cross(sundir2d,vec3(0.0,1.0,0.0)));//normalize(vec3(Cam2WorldPos.x,0.0,Cam2WorldPos.z));
		vec3 atmoColor_flat=GetSkyRadianceWithoutPhase(camposFromEarth, viewdir2d_flat, 0.0, sundir, Fex);
			
		vec3 viewdir=normalize(Cam2WorldPos);
		atmoColor=mix(atmoColor,atmoColor_flat, clamp(viewdir.y,0.0,1.0));
			
		Fex=vec3(exp(-extintion*delta/*planar_density*/));
		
		// DAY ////
		float mie=0.0;
		float ray=0.0;
		ray=GetPhaseFunctions(viewdir, sundir, mie);
		Lin=(vec3(1.0)-Fex)*inScatter*fogColor*atmoColor*((ray*rayScale)+(mie*0.05*mieScale));
		
		// NIGHT ////
		float night_mie=0.0;
		float night_ray=0.0;
		night_ray=GetPhaseFunctions(viewdir, moondir, night_mie);
		Lin+=(vec3(1.0)-Fex)*fogColor*moonlightcolor*((night_ray*rayScaleNight)+(night_mie*0.5*mieScaleNight));
		
		#else	// SKYDOME
		
			// DAY ////////////////////////////////////////////////////////////////////////////
			pos.z=-wFar;
			pos.xy=VPOS*-pos.z;
			pos.w=1.0;
			vec4 Wpos=eyeToWorld*pos;	
			camposFromEarth.y=max(camposFromEarth.y,-earth_center.y);
			
			vec3 Cam2WorldPos=Wpos.xyz-campos.xyz;
			vec3 viewdir=normalize(Cam2WorldPos.xyz);
			sourceRadiance=SUN*vec3(max(dot(sundir,viewdir)-0.9999,0.0))*GetSolarRadiance();//*sunColor;// *sunpower;
			Lin=GetSkyRadiance(camposFromEarth, viewdir, 0.0, sundir, Fex)*inScatter;
			
			// NIGHT ///////////////////////////////////////////////////////////////////////////
			pos.z=-100.0;
			pos.xy=VPOS*-pos.z;
			pos.w=1.0;
			Wpos=eyeToWorld*vec4(pos.xyz,0.0);	

			// MOON
			vec4	XYproj;	
			vec2 	moonTexcoords;
			XYproj.x = dot(pos,LTM0);
			XYproj.y = dot(pos,LTM1);
			XYproj.w = dot(pos,LTM3);
			moonTexcoords=(XYproj.xy/XYproj.w);
			night+=vec3(texture2D(moonTex,clamp(((moonTexcoords-vec2(0.5))*moonRadius)+vec2(0.5),0.0,1.0)).x)*moonColor*max(dot(moondir,viewdir),0.0);
			night += vec3(pow(max(dot(moondir,viewdir),0.0),150.0))*moonColor*moonCoronasMul;
			
			// STARS
			vec3 org=vec3(0.0,19000.0,0.0);
			float de,ds;
			float dist=DistanceToStarsBoundary(org, viewdir, STARS_DISTANCE, de, ds);
			vec3 starsPoint=org+viewdir*de;
			
			float starsLum=texture2D(starsTex,vec2(starsPoint.x,starsPoint.z)*0.0003).r;
			float starsDistribution=starsLum*texture2D(starsTex,vec2(starsPoint.x,starsPoint.z)*0.000075).g*0.25;
			night +=starsDistribution*moonColor*clamp(viewdir.y-0.1,0.0,1.0);
			
			// SKY
			float gradientEXP=exp(-Wpos.y*0.05);
			night += gradientEXP*horizonColor;
			night += (1.0-gradientEXP)*zenithColor;
			
			float nightMie=0.0;
			float nightRay=0.0;
			nightRay=GetPhaseFunctions(viewdir, moondir, nightMie);
			Lin+=(vec3(1.0)-Fex)*(nightRay+nightMie)*moonCoronasMul;
			//////////////////////////////////////////////////////////////////////////////////////
			
		#endif
		
#endif
	
	gl_FragColor.xyz=(Lin+Fex*sourceRadiance.xyz) + night;
	gl_FragColor.w=1.0;
}
