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

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

//Varyings//
varying float star;

varying vec3 upVec, sunVec;

varying mat3 moonRotMatrix;

#if defined (OVERWORLD) && defined PLANET
varying mat3 planetRotMatrix;
#endif
#if defined (OVERWORLD) && defined NEBULA
varying mat3 nebulaRotMatrix;
#endif
#if defined (OVERWORLD) && defined GALAXY
varying mat3 galaxyRotMatrix;
#endif

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

//Uniforms//
uniform sampler2D noisetex;

#ifdef PLANET
uniform sampler2D colortex10;
#endif

#ifdef NEBULA
uniform sampler2D colortex11;
#endif

#ifdef GALAXY
uniform sampler2D colortex12;
#endif

uniform int isEyeInWater;
uniform int worldTime;
uniform int moonPhase;
#define UNIFORM_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);

	#ifdef OVERWORLD
	vec3 lightVec = sunVec * ((timeAngle < 0.5325 || timeAngle > 0.9675) ? 1.0 : -1.0);
	#else
	vec3 lightVec = sunVec;
	#endif

//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){

	float isMoon = float(VoL < 0.0);
	float sun = pow(abs(VoL), SUNSIZE * isMoon + SUNSIZE * (1 - isMoon)); //2500

	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.0075 * moonPhaseOffset * 1650.0 / SUNSIZE));
			ang = (ang + (cos(ang * PI) * -0.5 + 0.5 - ang) / 3.0) * PI * 2.0;
			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), SUNSIZE * 0.30); // 750
			sun = mix(sun, 0.0, min(moonPhaseVoL * 3.0, 1.0));
		}

	}

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

	vec3 sunMoonCol = mix(moonColor * moonVisibility, 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;
}

vec3 SunGlare(inout vec3 color, vec3 nViewPos, vec3 lightCol) {
	float VoL = dot(normalize(nViewPos), lightVec);
	float visfactor = 0.02 * (-0.8 * timeBrightness + 1.0) * (3.0 * rainStrengthS + 1.0) * (-0.8 * sunVisibility + 1.0) * (-0.8 * moonVisibility + 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);

	if (moonVisibility > 0.0)
	visibility = visibility * (-0.98 * rainStrengthS + 1.0) * ( 1.0 * moonVisibility + 1.0) * SUN_GLARE_NIGHT;
	else
	visibility = visibility * (1.0 - rainStrengthS * 0.875) * (1.0 - sunVisibility * 0.875) * SUN_GLARE_DAY;
	
	visibility *= shadowFade;

	if (cameraPosition.y < 1.0) visibility *= exp(2.0 * cameraPosition.y - 2.0);

	#ifdef SUNGLARE
	#if SUNGLARE_RAIN == 1
	if (isEyeInWater == 1) color += (SUNGLARE_UNDERWATER_STRENGTH/50.0) * lightCol * visibility;
	if (isEyeInWater == 0) color += (SUNGLARE_OUTWATER_STRENGTH/25.0) * lightCol * visibility;
	#elif SUNGLARE_RAIN == 2
	if (isEyeInWater == 1) color += (SUNGLARE_UNDERWATER_STRENGTH/50.0) * lightCol * visibility * (1.0 - rainStrengthS);
	if (isEyeInWater == 0) color += (SUNGLARE_OUTWATER_STRENGTH/25.0) * lightCol * visibility * (1.0 - rainStrengthS);
	#endif
	#endif

	return color;
}

//Includes//
#ifdef OVERWORLD

#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"
#include "/lib/atmospherics/lunar.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

#if MC_VERSION >= 11605
#if defined PLANET || defined NEBULA || defined GALAXY
#include "/lib/atmospherics/skyimage.glsl"
#endif
#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 || defined SHININGSTARS
		float dither = Bayer128(gl_FragCoord.xy);
	#endif

	#ifdef OVERWORLD
		#ifdef CLOUDS
			vec4 cloud = DrawCloud(viewPos.xyz * 1000000.0, dither, lightCol, ambientCol, NdotU);
				 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);
			float VoL = dot(nViewPos, sunVec);
			#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 = vec3(12.0, 13.8, 15.9) / 35.7;

				vec3 roundSunMoon = RoundSunMoon(nViewPos, sunColor, moonColor, NdotU, VoL);
				#ifdef CLOUDS
						roundSunMoon *= max(1.0 - cloudMask * (rainStrengthShiningStars + 1.0), 0.0) * (1.0 - rainStrengthShiningStars);
					#else
						roundSunMoon *= 1.0 - max(rainStrengthS, rainStrengthShiningStars);
				#endif
					albedo.rgb += roundSunMoon;
			#endif
			
			vec4 wpos = gbufferModelViewInverse * viewPos;
			wpos /= wpos.w;
			float alt = normalize(wpos.xyz).y;
			wpos.xyz = getLunarCoord(wpos.xyz);
			float altfade = clamp(alt/0.4,0.0,1.0);

			vec3 starcolor = albedo.rgb;

			#ifdef STARS
			vec3 starsAlbedo = starcolor.rgb;
			if (moonVisibility > 0.0) DrawStars(starsAlbedo.rgb, viewPos.xyz);
			starcolor.rgb = mix(starcolor.rgb, starsAlbedo,clamp(1.0 - cloudMask*CLOUD_OPACITY*2.20,0.0,1.0));
			#endif
			
			#ifdef SHININGSTARS
			if(alt > 0.0){
				starcolor.rgb = DrawConstellations(starcolor.rgb,wpos.xyz,dither);
			}
			#endif
			
			#if MC_VERSION >= 11605

					#ifdef PLANET
					starcolor.rgb = drawPlanetImage(starcolor.rgb,albedo.rgb, vec2(0.2* PLANET_SIZE_X,0.2* PLANET_SIZE_Y), wpos.xyz, colortex10,PLANET_OPACITY);
					#endif

					#ifdef NEBULA
					starcolor.rgb = drawNebulaImage(starcolor.rgb, vec2(0.2* NEBULA_SIZE_X,0.2*NEBULA_SIZE_Y), wpos.xyz, colortex11,NEBULA_OPACITY);
					#endif

					#ifdef GALAXY
					starcolor.rgb = drawGalaxyImage(starcolor.rgb, vec2(0.2* GALAXY_SIZE_X,0.2*GALAXY_SIZE_Y), wpos.xyz, colortex12,GALAXY_OPACITY);
					#endif
			#endif

		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));

		#ifdef AURORA
		albedo.rgb += clamp((1.0 - cloudMask*CLOUD_OPACITY*2.20) * DrawAurora(viewPos.xyz * 1000000.0, dither, AURORA_QUALITY*2),0.0,1.0);
		#endif
	
		#if defined END || defined OVERWORLD
		#ifdef SHOOTING_STARS
		albedo.rgb = mix(albedo.rgb,DrawShootingStar(albedo.rgb, viewPos.xyz, 1.0,dither),1.0 - cloudMask);
		#if NUM_SHOOTING_STARS >= 2
		albedo.rgb = mix(albedo.rgb,DrawShootingStar(albedo.rgb, viewPos.xyz, 1.2,dither),1.0 - cloudMask);
		#if NUM_SHOOTING_STARS >= 3
		albedo.rgb = mix(albedo.rgb,DrawShootingStar(albedo.rgb, viewPos.xyz, 1.4,dither),1.0 - cloudMask);
		#if NUM_SHOOTING_STARS >= 4
		albedo.rgb = mix(albedo.rgb,DrawShootingStar(albedo.rgb, viewPos.xyz, 1.6,dither),1.0 - cloudMask);
		#endif
		#endif
		#endif
		#endif
		#endif

		#ifdef CLOUDS
		if(star < 0.5) albedo.rgb = mix(albedo.rgb, cloud.rgb, cloud.a);
		#endif
	
		SunGlare(albedo, nViewPos.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(0.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);

	#if defined (OVERWORLD) && defined PLANET
	planetRotMatrix = rotmat(PLANET_ROTX,PLANET_ROTY,PLANET_ROTZ);
	#endif

	#if defined (OVERWORLD) && defined NEBULA
	nebulaRotMatrix = rotmat(NEBULA_ROTX,NEBULA_ROTY,NEBULA_ROTZ);
	#endif

	#if defined (OVERWORLD) && defined GALAXY
	galaxyRotMatrix = rotmat(GALAXY_ROTX,GALAXY_ROTY,GALAXY_ROTZ);
	#endif

	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