//////////////////////////////////////////////////////////////////////////////
//    ##      #####   ######   ######     ##     ####     #######  ##  ##   //
//   ####    ##   ##  # ## #    ##  ##   ####     ##       ##   #  ##  ##   //
//  ##  ##   #          ##      ##  ##  ##  ##    ##       ## #     ####    //
//  ##  ##    #####     ##      #####   ##  ##    ##       ####      ##     //
//  ######        ##    ##      ## ##   ######    ##   #   ## #     ####    //
//  ##  ##   ##   ##    ##      ##  ##  ##  ##    ##  ##   ##   #  ##  ##   //
//  ##  ##    #####    ####    #### ##  ##  ##   #######  #######  ##  ##   //
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
//      #####   ##   ##    ##     #####    #######  ######    #####         //
//     ##   ##  ##   ##   ####     ## ##    ##   #   ##  ##  ##   ##        //
//     #        ##   ##  ##  ##    ##  ##   ## #     ##  ##  #              //
//      #####   #######  ##  ##    ##  ##   ####     #####    #####         //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##        //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##        //
//     ##   ##  ##   ##  ##  ##    ## ##    ##   #   ##  ##  ##   ##        //
//      #####   ##   ##  ##  ##   #####    #######  #### ##   #####         //
/////(BSL Shaders Edit)//////////////////////////////////////By LexBoosT//////

//Settings//
#include "/lib/settings.glsl"

//Varyings//
varying float star;

varying vec3 upVec, sunVec;

varying mat3 moonRotMatrix;

//Fragment Shader///////////////////////////////////////////////////////////////////////////////////
#ifdef FSH

//Uniforms//
uniform sampler2D noisetex;

uniform int isEyeInWater;
uniform int worldTime;
uniform int moonPhase;

uniform float blindFactor;
uniform float frameCounter;
uniform float frameTimeCounter;
uniform float nightVision;
uniform float rainStrength;
uniform float rainStrengthS;
uniform float rainStrengthS3;
uniform float rainStrengthShiningStars;
uniform float shadowFade;
uniform float screenBrightness;
uniform float timeAngle, timeBrightness;
uniform float viewWidth, viewHeight;
uniform float eyeAltitude;

uniform ivec2 eyeBrightnessSmooth;

uniform mat4 gbufferModelView;
uniform mat4 gbufferModelViewInverse;
uniform mat4 gbufferProjectionInverse;

uniform vec3 moonPosition;
uniform vec3 cameraPosition;
uniform vec3 skyColor;
uniform vec3 fogColor;

//Common Variables//

float eBS = eyeBrightnessSmooth.y / 255.0;
float sunVisibility  = clamp(dot( sunVec,upVec) + 0.0625, 0.0, 0.125) * 8.0;
float moonVisibility = clamp(dot( -sunVec,upVec) + 0.0625, 0.0, 0.125) * 8.0;
float screenBrightness2 = clamp(screenBrightness, 0.0, 1.0);

vec3 lightVec = sunVec * (1.0 - 2.0 * float(timeAngle > 0.5325 && timeAngle < 0.9675));

//Common Functions//
float GetLuminance(vec3 color){
	return dot(color,vec3(0.299, 0.587, 0.114));
}
vec3 RoundSunMoon(vec3 nViewPos, vec3 sunColor, vec3 moonColor, float NdotU){
	float VoL = dot(nViewPos, sunVec);
	float isMoon = float(VoL < 0.0);
	float sun = pow(abs(VoL), 2600.0 * isMoon + 1800.0 * (1 - isMoon));

	if (isMoon > 0.0) {
		if (moonPhase >= 1) {
			float moonPhaseOffset = float(!(moonPhase == 4));
			if (moonPhase > 4) moonPhaseOffset *= -1.0;

			float ang = fract(timeAngle - (0.25 + 0.0037 * moonPhaseOffset));
			ang = (ang + (cos(ang * 3.14159265358979) * -0.5 + 0.5 - ang) / 3.0) * 6.28318530717959;
			vec2 sunRotationData2 = vec2(cos(sunPathRotation * 0.01745329251994), -sin(sunPathRotation * 0.01745329251994));
			vec3 rawSunVec2 = (gbufferModelView * vec4(vec3(-sin(ang), cos(ang) * sunRotationData2) * 2000.0, 1.0)).xyz;
		
			float moonPhaseVoL = dot(nViewPos, normalize(rawSunVec2.xyz));
			moonPhaseVoL = pow(abs(moonPhaseVoL), 750.0);
			sun = mix(sun, 0.0, min(moonPhaseVoL * 2.0, 1.0));
		}

	}

	float horizonFactor = clamp((NdotU+0.0025)*20, 0.0, 1.0);
	sun *= horizonFactor;

	vec3 sunMoonCol = mix(moonColor * (1.0 - sunVisibility), sunColor * sunVisibility, float(VoL > 0.0));

	vec3 finalSunMoon = sun * sunMoonCol * 32.0;
	finalSunMoon = pow(finalSunMoon, vec3(2.0 - min(finalSunMoon.r + finalSunMoon.g + finalSunMoon.b, 1.0)));

		if (isMoon > 0.0) finalSunMoon = min(finalSunMoon, vec3(1.0));
	return finalSunMoon;
}

void SunGlare(inout vec3 color, vec3 viewPos, vec3 lightCol) {
	float VoL = dot(normalize(viewPos), lightVec);
	float visfactor = 0.05 * (-0.8 * timeBrightness + 1.0) * (3.0 * rainStrengthS + 1.0);
	float invvisfactor = 1.0 - visfactor;

	float visibility = clamp(VoL * 0.5 + 0.5, 0.0, 1.0);
    visibility = visfactor / (1.0 - invvisfactor * visibility) - visfactor;
	visibility = clamp(visibility * 1.015 / invvisfactor - 0.015, 0.0, 1.0);
	visibility = mix(1.0, visibility, 0.25 * eBS + 0.75) * (1.0 - rainStrengthS * eBS * 0.875);
	visibility *= shadowFade;
	if (cameraPosition.y < 1.0) visibility *= exp(2.0 * cameraPosition.y - 2.0);

	#ifdef LIGHT_SHAFT
	if (isEyeInWater == 1) color += 0.25 * lightCol * visibility;
	#else
	color += 0.25 * lightCol * visibility * (1.0 + 0.25 * isEyeInWater);
	#endif
}


//Includes//
#ifdef OVERWORLD
#if AURORA_COLOR == 5
#include "/lib/color/hue.glsl"
#endif

#ifdef AURORA
#include "/lib/atmospherics/aurora.glsl"
#endif
#endif

#include "/lib/color/lightColor.glsl"
#include "/lib/color/skyColor.glsl"
#include "/lib/color/endColor.glsl"
#include "/lib/util/dither.glsl"

#ifdef OVERWORLD

#ifdef CLOUDS
#include "/lib/atmospherics/ovclouds.glsl"
#endif
#ifdef STARS
#include "/lib/atmospherics/stars.glsl"
#endif
#ifdef SHININGSTARS
#include "/lib/atmospherics/shiningstars.glsl"
#endif
#ifdef SHOOTING_STARS
#include "/lib/atmospherics/shootingstars.glsl"
#endif
#endif

#include "/lib/atmospherics/sky.glsl"


//Program//
void main(){
	
	vec4 screenPos = vec4(gl_FragCoord.xy / vec2(viewWidth, viewHeight), gl_FragCoord.z, 1.0);
	vec4 viewPos = gbufferProjectionInverse * (screenPos * 2.0 - 1.0);
	viewPos /= viewPos.w;
	
	vec3 nViewPos = normalize(viewPos.xyz);

	float NdotU = dot(nViewPos, upVec);


		float cloudMask = 0.0;

	#if defined CLOUDS || defined AURORA || defined SHOOTING_STARS
		float dither = Bayer64(gl_FragCoord.xy);
	#endif

	#ifdef OVERWORLD
		#ifdef CLOUDS
			vec4 cloud = DrawCloud(viewPos.xyz * 1000000.0, dither, lightCol, ambientCol);
				 cloudMask = min((cloud.a / (CLOUD_OPACITY * 2.0)), 0.25) + (cloud.a / (CLOUD_OPACITY * 2.0)) * 0.5;
		#endif
	#endif

	#ifdef OVERWORLD
			vec3 albedo = GetSkyColor(viewPos.xyz,false);
			
			#ifdef WHITE_WORLD
			#ifdef SKYW
			albedo.rgb = vec3(0.5);
			#endif
			#endif
			#ifdef BLACK_WORLD
			#ifdef SKYW
			albedo.rgb = vec3(0.0);
			#endif
			#endif
			
			#ifdef ROUND_SUN_MOON
				vec3 sunColor = vec3(0.9, 0.35, 0.05);
				vec3 moonColor = sqrt(lightNight);

				vec3 roundSunMoon = RoundSunMoon(nViewPos, sunColor, moonColor, NdotU);
				#ifdef CLOUDS
						roundSunMoon *= max(1.0 - cloudMask * (rainStrengthS3 + 1.0), 0.0) * (1.0 - rainStrengthS3);
					#else
						roundSunMoon *= 1.0 - max(rainStrength, rainStrengthS3);
				#endif
					albedo.rgb += roundSunMoon;
			#endif
	
			#ifdef STARS
			vec3 starsAlbedo = albedo;
			if (moonVisibility > 0.0) DrawStars(starsAlbedo.rgb, viewPos.xyz);
			albedo = mix(albedo, starsAlbedo,clamp(1.0 - cloudMask*CLOUD_OPACITY*2.20,0.0,1.0));
			#endif
			
			#ifdef SHININGSTARS
			
			vec4 wpos = gbufferModelViewInverse * viewPos;
			wpos /= wpos.w;
			float alt = normalize(wpos.xyz).y;
			if(alt > 0.0){
				wpos.xyz = getLunarCoord(wpos.xyz);

				if (moonVisibility > 0.0)
				{
					ivec2 constell = getConstell(wpos.xyz);

					int linestart = 0;
					int starstart1 = 0;
					int starstart2 = 0;

					if(constell.x== 0)
					{
						linestart = starstart1 = 0;
					}
					else
					{
						linestart = constellations[constell.x-1].y;
						starstart1 = constellations[constell.x-1].x;
					}
					int lineend = constellations[constell.x].y;
					int starend1 = constellations[constell.x].x;
					int starend2 =0;
					if(constell.y >= 0)
					{
						if(constell.y== 0)
						{
							starstart2 = 0;
						}
						else
						{
							starstart2 = constellations[constell.y-1].x;
						}
						starend2 = constellations[constell.y].x;
					}
					
					vec3 starcolor = albedo.rgb;

					#ifdef CONSTELLATIONS
					for(int i = linestart; i < lineend; i++)
					{
						starcolor.rgb = DrawLine(starcolor.rgb, stars[lines[i].x],stars[lines[i].y],wpos.xyz);
					}
					#endif

					// test jointures entre constellations (decommenter pour tester)
					//if(constell.y >= 0) starcolor = vec3(1.0,0.0,0.0);
					for(int i = starstart1; i < starend1; i++)
					{
						starcolor.rgb = DrawShiningStar(starcolor.rgb,wpos.xyz,stars[i],dither);
					}
					if(constell.y >= 0)
					{
						for(int i = starstart2; i < starend2; i++)
						{
							starcolor.rgb = DrawShiningStar(starcolor.rgb,wpos.xyz,stars[i],dither);
						}
					}
					float altfade = clamp(alt/0.4,0.0,1.0);
					albedo.rgb = mix(albedo.rgb, clamp(starcolor.rgb,0.0,1.0), (1.0-rainStrengthShiningStars)*altfade*clamp(1.0-cloudMask*CLOUD_OPACITY*2.20,0.0,1.0));
				}
			}

			#endif
	
		#ifdef AURORA
		albedo.rgb += clamp((1.0 - cloudMask*CLOUD_OPACITY*2.20) * DrawAurora(viewPos.xyz * 1000000.0, dither, AURORA_QUALITY),0.0,1.0);
		#endif
	
		#ifdef SHOOTING_STARS
		albedo.rgb = DrawShootingStar(albedo.rgb, viewPos.xyz, 1.0,dither);
		#if NUM_SHOOTING_STARS >= 2
		albedo.rgb = DrawShootingStar(albedo.rgb, viewPos.xyz, 1.2,dither);
		#if NUM_SHOOTING_STARS >= 3
		albedo.rgb = DrawShootingStar(albedo.rgb, viewPos.xyz, 1.4,dither);
		#if NUM_SHOOTING_STARS >= 4
		albedo.rgb = DrawShootingStar(albedo.rgb, viewPos.xyz, 1.6,dither);
		#endif
		#endif
		#endif
		#endif
	
		#ifdef CLOUDS
		if(star < 0.5) albedo.rgb = mix(albedo.rgb, cloud.rgb, cloud.a);
		#endif
	
		SunGlare(albedo, viewPos.xyz, lightCol);
	
		albedo.rgb *= (4.0 - 3.0 * eBS) * (1.0 + nightVision);

		if (eyeAltitude < 2.0) albedo.rgb *= min(clamp((eyeAltitude-1.0), 0.0, 1.0) + pow(max(NdotU, 0.0), 32.0), 1.0);

	#endif
	
	#ifdef END
	vec3 albedo = vec3(1.0);
	#endif
	
	
	/* DRAWBUFFERS:0 */
	gl_FragData[0] = vec4(albedo.rgb, 1.0 - star);
	#if defined OVERWORLD && defined CLOUDS
	/* DRAWBUFFERS:04 */
	gl_FragData[1]=vec4(cloud.a,0.,0.,0.);
	#endif
}

#endif

//Vertex Shader/////////////////////////////////////////////////////////////////////////////////////
#ifdef VSH

//Uniforms//
uniform float timeAngle;

uniform mat4 gbufferModelView;

//Includes//

#include "/lib/util/moonrot.glsl"

//Program//
void main(){
	const vec2 sunRotationData=vec2(cos(sunPathRotation*.01745329251994),-sin(sunPathRotation*.01745329251994));
	float ang=fract(timeAngle-.25);
	ang=(ang+(cos(ang*3.14159265358979)*-.5+.5-ang)/3.)*6.28318530717959;
	vec3 usunvec = vec3(-sin(ang),cos(ang)*sunRotationData);
	sunVec=normalize((gbufferModelView*vec4(usunvec*2000.,1.)).xyz);
	
    moonRotMatrix = getMoonRotMatrix(usunvec);

	upVec=normalize(gbufferModelView[1].xyz);
	
	gl_Position=ftransform();
	
	star=float(gl_Color.r==gl_Color.g&&gl_Color.g==gl_Color.b&&gl_Color.r>0.);
}

#endif