#version 330

layout(std140) uniform Transformation {
	mat4 mView;
	mat4 mProjection;
	mat4 mViewProjection;
	mat4 mInverseViewProjection;
	vec3 vCameraPos;
	vec3 vCameraDir;
	float fNearClipPlane;
	vec3 vCameraUp;
	float fFarClipPlane;
};

uniform vec2 u_vCloudRes;
uniform vec3 u_vColorCloudBright;
uniform vec3 u_vColorCloudDark;
uniform sampler2D u_Clouds;
uniform sampler2D u_Scene;
uniform sampler2D u_Depth;


in vec2 vs_TexCoord0;
in vec3 vs_WorldPos;
out vec4 fs_Color;

// ------------------------------------------------
// SKY
// ------------------------------------------------
const vec3 AdditonalSunColor = vec3(1.0, 0.98, 0.8)/2.5;
const vec3 LowerHorizonColour = vec3(0.815, 1.141, 1.54)/3;
const vec3 UpperHorizonColour = vec3(0.986, 1.689, 2.845)/3;
const vec3 UpperSkyColour = vec3(0.16, 0.27, 0.63);//*0.8;
const vec3 GroundColour = vec3(0.31, 0.41, 0.7)*0.8;
const vec3 LightDirection = vec3( 0.707106, 0.707106, 0.0 );
const float LowerHorizonHeight = -0.4;
const float UpperHorizonHeight = -0.1;
const float SunAttenuation = 2;
vec3 ComputeSkyColor( in vec3 ray )
{
	vec3 color;

	// background
	vec3 vExtraColor = u_vColorCloudDark * 1.3;
	float heightValue = ray.y;	// mirror..
	if(heightValue < LowerHorizonHeight)
		color = mix(GroundColour, LowerHorizonColour, (heightValue+1) / (LowerHorizonHeight+1));
	else if(heightValue < UpperHorizonHeight)
		color = mix(LowerHorizonColour, vExtraColor, (heightValue-LowerHorizonHeight) / (UpperHorizonHeight - LowerHorizonHeight));
	else
		color = mix(vExtraColor, UpperSkyColour, (heightValue-UpperHorizonHeight) / (1.0-UpperHorizonHeight));
	
	// Sun
	float angle = max(0, dot(ray, LightDirection));
	color += (pow(angle, SunAttenuation) + pow(angle, 10000)*10) * AdditonalSunColor;

	return color;//min(vec3(1,1,1), color);
}


void main()
{
	// Sample the cloud from low res picture (with 4 neighbourhood),
	// the scene and the depth
	vec3 vColorCloud0 = texture( u_Clouds, vs_TexCoord0 ).rgb;
	vec3 vColorScene = texture( u_Scene, vs_TexCoord0 ).rgb;
	float fZ = texture( u_Depth, vs_TexCoord0 ).r;

	// Transform Z and test again (this removes artifacts where clouds overlay
	// the scene).
	float f_n = fFarClipPlane - fNearClipPlane;
	fZ = 0.5 * (- fNearClipPlane / (fZ*f_n-fFarClipPlane));
	
	// Is it a background pixel?
	vec3 vRay = vs_WorldPos - vCameraPos;
	vec3 vBackColor = ComputeSkyColor( normalize( vRay ) );
	if( fZ >= 0.49999 )
	{
//		vec3 vRay = vs_WorldPos - vCameraPos;
		vColorScene = vBackColor;//ComputeSkyColor( normalize( vRay ) );
		fZ *= 2;
	} else
	{
		// depth fog
		vColorScene = mix( vColorScene, GroundColour, 2*fZ );
		vColorScene = mix( vColorScene, vBackColor, 4*fZ*fZ );
	}
	
	// Has current pixel totaly wrong depth?
	vec2 vLightDensity = vColorCloud0.rg;
	float fZError = abs(fZ - vColorCloud0.z);
	if( fZError > 0.01 )
	{
		// Choose the cloud sample, which has the best fitting depth.
		ivec2 vCloudTex = ivec2( u_vCloudRes * vs_TexCoord0 );
		vec3 vColorCloud1 = texelFetch( u_Clouds, vCloudTex+ivec2(-1, 0), 0 ).rgb;
		vec3 vColorCloud2 = texelFetch( u_Clouds, vCloudTex+ivec2( 1, 0), 0 ).rgb;
		vec3 vColorCloud3 = texelFetch( u_Clouds, vCloudTex+ivec2( 0,-1), 0 ).rgb;
		vec3 vColorCloud4 = texelFetch( u_Clouds, vCloudTex+ivec2( 0, 1), 0 ).rgb;
		vec3 vColorCloud5 = texelFetch( u_Clouds, vCloudTex+ivec2( 1, 1), 0 ).rgb;
		vec3 vColorCloud6 = texelFetch( u_Clouds, vCloudTex+ivec2( 1,-1), 0 ).rgb;
		vec3 vColorCloud7 = texelFetch( u_Clouds, vCloudTex+ivec2(-1, 1), 0 ).rgb;
		vec3 vColorCloud8 = texelFetch( u_Clouds, vCloudTex+ivec2(-1,-1), 0 ).rgb;
	
		vec4 vZEs = abs( vec4( fZ - vColorCloud1.z, fZ - vColorCloud2.z, fZ - vColorCloud3.z, fZ - vColorCloud4.z ) );
		vec4 vZEs2 = abs( vec4( fZ - vColorCloud5.z, fZ - vColorCloud6.z, fZ - vColorCloud7.z, fZ - vColorCloud8.z ) );
		vLightDensity = (vZEs.x < vZEs.y) ? vColorCloud1.rg : vColorCloud2.rg; fZError = min( vZEs.x, vZEs.y );
		vLightDensity = (vZEs.z < fZError) ? vColorCloud3.rg : vLightDensity; fZError = min( vZEs.z, fZError );
		vLightDensity = (vZEs.w < fZError) ? vColorCloud4.rg : vLightDensity; fZError = min( vZEs.w, fZError );
		vLightDensity = (vZEs2.x < fZError) ? vColorCloud5.rg : vLightDensity; fZError = min( vZEs2.x, fZError );
		vLightDensity = (vZEs2.y < fZError) ? vColorCloud6.rg : vLightDensity; fZError = min( vZEs2.y, fZError );
		vLightDensity = (vZEs2.z < fZError) ? vColorCloud7.rg : vLightDensity; fZError = min( vZEs2.z, fZError );
		vLightDensity = (vZEs2.w < fZError) ? vColorCloud8.rg : vLightDensity;
	}
	
	vec3 vFinalCloudColor = mix( u_vColorCloudDark, u_vColorCloudBright, vLightDensity.r );
	fs_Color.rgb = mix( vColorScene, vFinalCloudColor, vLightDensity.g );
	fs_Color.a = 1;
//	fs_Color.rgb = mix( u_vColorCloudDark, u_vColorCloudBright, vLightDensity.r );
//	fs_Color.a = vLightDensity.g;
}