//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 colortex9;
	#endif

	#ifdef NEBULA
		uniform sampler2D colortex10;
	#endif

	#ifdef GALAXY
		uniform sampler2D colortex11;
	#endif

	uniform int isEyeInWater;
	uniform int moonPhase;
	#define UNIFORM_MOONPHASE

	uniform float blindFactor;
	uniform float frameTimeCounter;
	uniform float nightVision;
	uniform float rainStrength;
	uniform float rainStrengthS;
	uniform float rainStrengthShiningStars;
	uniform float screenBrightness;
	uniform float eyeAltitude;
	uniform float far;

	uniform float viewWidth, viewHeight;

	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 / 240.0;
	float eBS2             =clamp01(pow(eBS,8.0));
	float sunVisibility    =clamp00125(dot( sunVec,upVec) + 0.0625) * 8.0;
	float moonVisibility   =clamp00125(dot( -sunVec,upVec) + 0.0625) * 8.0;
	float screenBrightness2=clamp01(screenBrightness);

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

	float GetNoise(vec2 pos){
	return fract(sin(dot(pos,vec2(12.9898,4.1414)))*43758.5453);
	}

	vec3 RoundSunMoon(vec3 nViewPos, vec3 sunColor, vec3 moonColor, float NdotU, float VoL){

	const float PI = 3.1415927;

		float isMoon = float(VoL < 0.0);
		float sun = pow(abs(VoL), SUNSIZE * isMoon + SUNSIZE * (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.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);
				      sun             =mix(sun, 0.0, min(moonPhaseVoL * 3.0, 1.0));
			}

		}

		#ifdef HORIZON_SUN_MOON
			float horizonFactor = clamp01((NdotU+0.0025) * 20.0);
			sun *= horizonFactor;
			moonColor *= 1.0 - sunVisibility;
			sunColor *= sunVisibility;
		#endif

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

		#ifdef UNDERGROUND_SKY
			if (isEyeInWater<1){
			finalSunMoon *= mix(clamp01((cameraPosition.y - 48.0) / 16.0), 1.0, eBS2);
			}
		#endif

		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=clamp01(VoL * 0.5 + 0.5);
		      visibility=visfactor / (1.0 - invvisfactor * visibility) - visfactor;
		      visibility=clamp01(visibility * 1.015 / invvisfactor - 0.015);

		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 MC_VERSION >= 11800
			visibility *= clamp01((cameraPosition.y + 70.0) / 8.0);
		#else
			visibility *= clamp01((cameraPosition.y + 6.0) / 8.0);
		#endif

		#ifdef UNDERGROUND_SKY
			if (isEyeInWater<1){
			visibility *= mix(clamp01((cameraPosition.y - 48.0) / 16.0), 1.0, eBS2);
			}
		#endif

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

		#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/dimensionColor.glsl"
	#include "/lib/color/skyColor.glsl"
	#include "/lib/util/dither.glsl"
	#include "/lib/atmospherics/lunar.glsl"

	#ifdef ROUND_SUN_MOON
	#include "/lib/color/sunmoonColor.glsl"
	#endif

	#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(){
		vec3 albedo = vec3(0.0);

		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 = InterleavedGradientNoise(gl_FragCoord.xy);
		#endif

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

		#ifdef OVERWORLD
				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 = sunCol.rgb;
					vec3 moonColor = moonCol.rgb;

					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
						if (sunVisibility > 0){
						albedo.rgb += roundSunMoon * SUN_I;
						}
						if (moonVisibility > 0){
						albedo.rgb += roundSunMoon * MOON_I;
						}
				#endif

				vec4 wpos = gbufferModelViewInverse * viewPos;
				wpos /= wpos.w;
				float alt = normalize(wpos.xyz).y;
				wpos.xyz = getLunarCoord(wpos.xyz);
				float altfade = clamp01(alt/0.4);

				vec3 starcolor = albedo.rgb;

				#if MC_VERSION >= 11605
						#ifdef NEBULA
						starcolor.rgb = drawNebulaImage(starcolor.rgb, vec2(0.2* NEBULA_SIZE_X,0.2*NEBULA_SIZE_Y), wpos.xyz, colortex10,NEBULA_OPACITY);
						#endif
				#endif

				#ifdef STARS
					vec3 starsAlbedo = starcolor.rgb;
					if (moonVisibility > 0.0) DrawStars(starsAlbedo.rgb, viewPos.xyz);
					starcolor.rgb = mix(starcolor.rgb, starsAlbedo,clamp01(1.0 - cloudMask*CLOUD_OPACITY*2.20));
				#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, colortex9, PLANET_OPACITY);
					#endif

					#ifdef GALAXY
					if (moonVisibility > 0.0){
					starcolor.rgb = drawGalaxyImage(starcolor.rgb, vec2(0.2 * GALAXY_SIZE_X, 0.2 * GALAXY_SIZE_Y), wpos.xyz, colortex11, GALAXY_OPACITY);
					}
					#endif

				#endif

			albedo.rgb = mix(albedo.rgb, clamp01(starcolor.rgb), (1.0-rainStrengthShiningStars)*altfade*clamp01(1.0-cloudMask*CLOUD_OPACITY*2.20));

			#ifdef AURORA
			if (moonVisibility > 0.0){
				albedo.rgb += clamp01((1.0 - cloudMask*CLOUD_OPACITY*2.20) * DrawAurora(viewPos.xyz * 1000000.0, dither, 20));
			}
			#endif

			#if defined OVERWORLD
				#ifdef SHOOTING_STARS
				if (moonVisibility > 0.0){
				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);

		#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.0, 0.0);
		#endif
	}

#endif

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

//Uniforms//

uniform mat4 gbufferModelView;

//Common Variables//
#ifdef OVERWORLD
	float timeAngleM = timeAngle;
#else
	float timeAngleM = 0.25;
#endif

//Includes//

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

//Program//
void main(){
	const vec2 sunRotationData=vec2(cos(sunPathRotation * 0.01745329251994),-sin(sunPathRotation * 0.01745329251994));
	float ang                 =fract(timeAngleM - 0.25);
	      ang                 =(ang+(cos(ang * 3.14159265358979) * -0.5 + 0.5 - ang) / 3.0) * 6.28318530717959;
	vec3  usunvec             =vec3(-sin(ang), cos(ang) * sunRotationData);
	      sunVec              =normalize((gbufferModelView * vec4(usunvec * 2000.0, 1.0)).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