uniform sampler2D 			colorTex,
							normalTex,
							matTex,
							posTex;
							
#ifdef SHADOWS
	uniform sampler2D		shadowmask;
#endif

// ------------ ATMOSPHERE ------------------------------

varying vec4		WPOS;
uniform float 		length_unit;
uniform vec3 		earth_center;
uniform vec3 		sundirW;
uniform mat4		eyeToWorld;
uniform vec3 		campos;

/*vec3 GetSunAndSkyIrradiance(
    vec3 p, vec3 normal, vec3 sun_direction, out vec3 sky_irradiance);*/
vec3 GetSunIrradiance(vec3 p, vec3 sun_direction);

// -------------------------------------------------------

uniform vec3 specularPalette[8];
uniform vec3 scatterPalette[8];

uniform float		srcRadius;

varying vec2 		texcoord;
uniform vec3		moonlightcolor;
uniform vec3		lightcolor;
uniform vec3		lightdir;
uniform float		lightscale;
uniform float		cOfs;
uniform vec2 		ofs;
varying vec2		VPOS;
float				Pi=3.14159265359;

uniform float 		wFar;

vec4 decode(vec4 enc)
{
    vec2 fenc = enc.xy*4.0-2.0;
    float f = dot(fenc,fenc);
    float g = sqrt(1.0-f/4.0);
    vec4 n;
    n.xy = fenc.xy*g;
    n.z = 1.0-f/2.0;
	n.w=enc.w;
    return n;
}

// ------------------ PBR ---------------------------------
float phong_diffuse()
{
	return (1.0 / Pi);
}

vec3 fresnel_factor(vec3 f0, float f90, float product)
{
	return f0 + (vec3(f90) - f0) * pow(1.0 - product, 5.0);
	//return mix(f0, vec3(1.0), pow(1.01 - product, 5.0));
}

float D_GGX(float a2, float NdH)
{
	//float m = roughness * roughness;
	float d = (NdH * a2 - NdH) * NdH + 1.0;
	return a2 / (Pi*d*d);
}

float G_schlick(float roughness, float NdV, float NdL)
{
	float r=(roughness+1.0)/2.0;
	float k=r*r*0.5;//0.125;
	float V = NdV * (1.0 - k) + k;
	float L = NdL * (1.0 - k) + k;
	return /*1.0/*/0.25/(V*L);
}

float G_Smith( float a2, float NdV, float NdL )
{
	float V = NdV + sqrt( NdV * (NdV - NdV * a2) + a2 );
	float L = NdL + sqrt( NdL * (NdL - NdL * a2) + a2 );
	return 1.0/( V*L );
}

float G_SmithJointApprox( float a, float NdV, float NdL )
{
	float V = NdL * ( NdV * ( 1 - a ) + a );
	float L = NdV * ( NdL * ( 1 - a ) + a );
	return 0.5 /( V+L );
}

vec3 CookTorrance(float NdL, float NdV, float NdH, vec3 F, float rough, float a)
{
	float a2=a*a;
	float D = D_GGX(a2, NdH);
	float G = G_SmithJointApprox(a,NdV, NdL);
	return max(D*G,0.0)*F; 
} 
// -----------------------------------------------------------------

void main()
{
	vec2	Zproj;
	vec4	XYproj;	

	vec4 color = texture2D(colorTex,texcoord.st);
	vec4 encoded = texture2D(normalTex,texcoord.st);
	vec4 normal = decode(encoded);
	float reflPow=encoded.z;//*16.0;

	float thickness=normal.a;
	float scatter=color.a;//mat.x;
	
	vec4 pos;
	pos.z = texture2D(posTex,texcoord.st).r;
	vec4 mat = texture2D(matTex,texcoord.st);	// x=shininess, y=fresnel
	
	// get colors
	float metal=mat.x*step(scatter,0.0);	// if(scatter > 0) metal = 0
	
	int i1=int(mat.x*256.0);
	int i2=i1;
	i1=i1/8;
	i2=i2-(i1*8);
	vec3 scatterColor=pow(scatterPalette[i2],vec3(2.2));
	
	pos.xy=VPOS.xy*-pos.z;
	pos.w=1.0;
	
	float shadowOcc=1.0;
	
#ifdef SHADOWS

	shadowOcc=1.0-texture2D(shadowmask,texcoord.st).r;

#endif

	vec4 finalcolor=color;
	
	if(shadowOcc>0.0)
	{
		// atmosphere ////////////
		vec3 Wpos;
		Wpos=(eyeToWorld*pos).xyz;
		Wpos=(Wpos*length_unit)-earth_center.xyz;
		vec3 sunColor = GetSunIrradiance(Wpos, sundirW);
		//////////////////////////
		
		float rough=clamp(sqrt(mat.y),0.05,1.0);
		float a=rough*rough;
		vec3 REFL=mix(vec3(0.08)*reflPow*reflPow,color.xyz/*reflPow*/,metal);//max(ffresnel.x,0.0);
	
		vec3 E=-pos.xyz;
		E=normalize(E);
		
		vec3 R=reflect(-E,normal.xyz);
		vec3 L=lightdir;
		float r= sin(srcRadius);
		float d= cos(srcRadius);
		float DdotR=dot(L,R);
		vec3 S = R-DdotR*L;
		L = DdotR < d ? normalize(d*L+normalize(S)*r) : R;
				
		// compute all vectors
		vec3 H = L+E;
		H=normalize(H);
		float NdotH = clamp(dot(H,normal.xyz),0.0,1.0);
		float EdotH = clamp(dot(E,H),0.0,1.0);
		float NdotE = clamp(dot(normal.xyz,E),0.0,1.0);
		float NdotL = clamp(dot(L,normal.xyz),0.0,1.0);
		float dNdotL= clamp(dot(lightdir,normal.xyz),0.0,1.0);
		
		// specular
		vec3 specfresnel=vec3(0.0,0.0,0.0);
		vec3 specular=vec3(0.0,0.0,0.0);		
		/*if(REFL.x>0.0)
		{*/
			float rmax = max(max(REFL.r, REFL.g), REFL.b);
			float REFL90 = clamp(rmax*25.0,0.0,1.0);
			specfresnel=fresnel_factor(REFL, REFL90, EdotH);
			specular = CookTorrance(NdotL, NdotE, NdotH, specfresnel, rough, a) * NdotL;
		//}
		
		// diffuse
		float scatterNdotL=(dNdotL+scatter)/(1+scatter);
		scatterNdotL=max(scatterNdotL,0.0);
		float finalscatter = smoothstep(0.0,0.3,scatterNdotL)*smoothstep(0.6,0.3,scatterNdotL);
		float finalNdotL=mix(scatterNdotL,dNdotL,metal);
		vec3 finalScatterColor=mix(vec3(scatterColor*finalscatter*scatter*color.xyz),vec3(0.0),metal);
		vec3 diffuse = ((vec3(1.0) - specfresnel) * phong_diffuse() * finalNdotL) + finalScatterColor;
			
		// backscatter
		vec3 backScatter=vec3(0.0,0.0,0.0);
		if(thickness>0.0)
		{
			vec3 LTLight=L-normal.xyz;
			float LTdot=pow(clamp(dot(E,-LTLight),0.0,1.0),2.0)*scatter*thickness*0.33;
			backScatter = mix(vec3(LTdot)*color.xyz*scatterColor,vec3(0.0),metal);
		}
		
		// final color
		finalcolor = mix(color,vec4(0.0),metal)*vec4(diffuse,1.0) + vec4(specular,1.0) + vec4(backScatter,1.0);
		
		gl_FragColor.xyz=max((lightcolor.xyz*sunColor.xyz*lightscale + moonlightcolor)*finalcolor.xyz*shadowOcc,0.0);
	}
	else
	{
		discard;
	}
	
	gl_FragColor.a=0.0;
}
