float CloudSample(vec2 coord, vec2 wind, float currentStep, float sampleStep, float sunCoverage) {

	float noiseBase = texture2D(noisetex, coord * 0.25 + wind).r;
	float detailZ = floor(currentStep * float(CLOUD_THICKNESS) + 0.5) * 0.04;
	float noiseDetail = texture2D(noisetex, coord * 0.5 - wind * 2.0 + detailZ).b;

	#if CLOUDS == 2
	noiseBase = texture2D(colortex8, coord * 0.25 + wind).r;
	detailZ = floor(currentStep * float(CLOUD_THICKNESS) + 0.5) * 0.04;
	noiseDetail = texture2D(colortex8, coord * 0.5 - wind * 2.0 + detailZ).b;
	#endif

	float noiseCoverage = abs(currentStep - 0.125) * (currentStep > 0.125 ? 1.14 : 8.0);
	noiseCoverage = noiseCoverage * noiseCoverage * 4.0;
	
	float noise = mix(noiseBase, noiseDetail, 0.0476 * CLOUD_DETAIL) * 21.0 - noiseCoverage;
	noise = mix(noise, 21.0, 0.33 * rainStrength);
	float multiplier = CLOUD_DENSITY * CLOUD_THICKNESS / 4.0 * sampleStep;
	multiplier *= (1.0 - 0.9 * rainStrength);

	#if CLOUDS == 2
	noise = max(noise - (sunCoverage * 3.0 + CLOUD_AMOUNT + 0.6), 0.0) * multiplier;
	noise = noise / pow(pow(noise, 2.5) + 1.0, 0.4);
	#else
	noise = max(noise - (sunCoverage * 3.0 + CLOUD_AMOUNT), 0.0) * multiplier;
	noise = noise / pow(pow(noise, 2.5) + 1.0, 0.4);
	#endif

	return noise;
}

vec4 DrawCloud(vec3 viewPos, float dither, vec3 lightCol, vec3 ambientCol) {
	#ifdef TAA
	dither = fract(16.0 * frameTimeCounter + dither);
	#endif

	int samples = CLOUD_THICKNESS * 2;
	
	float cloud = 0.0, cloudLighting = 0.0;

	float sampleStep = 1.0 / samples;
	float currentStep = dither * sampleStep;
	
	float VoU = dot(normalize(viewPos), upVec);
	float VoL = dot(normalize(viewPos), lightVec);
	float VoS = dot(normalize(viewPos), sunVec);
	
		float sunCoverage = pow(clamp(abs(VoL) * 2.0 - 1.0, 0.0, 1.0), 12.0) * (1.0 - rainStrength);

		#if CLOUDS == 2
		sunCoverage = pow(clamp(abs(VoL) * 2.0 - 1.0, 0.0, 1.0), 40.0) * (1.0 - rainStrength) * (1.0 - clamp((dot(sunVecM22, upVec) + 0.04) * 1.2, 0.0, 1.0) - moonVisibility22);
		#endif

	vec2 wind = vec2(
		frametime * CLOUD_SPEED * 0.0005,
		sin(frametime * CLOUD_SPEED * 0.05) * 0.001
	) * CLOUD_HEIGHT / 15.0;

	vec3 cloudColor = vec3(0.0);

	if (VoU > 0.004) {

		vec3 wpos = normalize((gbufferModelViewInverse * vec4(viewPos, 1.0)).xyz);
		for(int i = 0; i < samples; i++) {
			if (cloud > 0.99) break;

			vec3 planeCoord = wpos * ((CLOUD_HEIGHT + currentStep * CLOUD_THICKNESS) / wpos.y) * 0.004;
			vec2 coord = cameraPosition.xz * 0.00025 + planeCoord.xz;

			float noise = CloudSample(coord, wind, currentStep, sampleStep, sunCoverage);

			float halfVoL = VoL * shadowFade * 0.5 + 0.5;
			float halfVoLSqr = halfVoL * halfVoL;
			float noiseLightFactor = (2.0 - 1.5 * VoL * shadowFade) * CLOUD_DENSITY / 2.0;
			float sampleLighting = pow(currentStep, 1.125 * halfVoLSqr + 0.875) * 0.8 + 0.2;
			sampleLighting *= 1.0 - pow(noise, noiseLightFactor);

			cloudLighting = mix(cloudLighting, sampleLighting, noise * (1.0 - cloud * cloud));
			cloud = mix(cloud, 1.0, noise);

			currentStep += sampleStep;
		}	
		float scattering = pow(VoL * shadowFade * 0.5 + 0.5, 6.0);
		cloudLighting = mix(cloudLighting, 1.0, (1.0 - cloud * cloud) * scattering * 0.5);

		vec3 cloudColorCorrectionNight = moonPhase_I_Multiplier * vec3(0.0 + 0.3*clamp((dot(-sunVec22, upVec) + 0.04) * 4.0, 0.0, 1.0), 0.0 + 0.5*clamp((dot(-sunVec22, upVec) + 0.04) * 4.0, 0.0, 1.0), 0.0)/255;

		cloudColor = mix(
			(ambientCol + cloudColorCorrectionNight) * (0.6 + (0.4 * sunVisibility*(1.0 - clamp((dot(sunVecM22, upVec) + 0.04) * 8.0, 0.0, 1.0)))),

			(lightCol * sqrt(lightCol) + cloudColorCorrectionNight) * (0.85 + 1.15 * scattering)
			 * (1.0 - 0.22 * rainStrength + (0.75*(VoS * 0.4 + 0.6) - 0.75)*sunVisibility*(1.0 - clamp((dot(sunVecM22, upVec) + 0.04) * 8.0, 0.0, 1.0))),

			cloudLighting
		);


		cloudColor *= 1.0 - 0.6 * rainStrength;
		cloud *= clamp(1.0 - exp(-20.0 * VoU + 0.1 + 0.4 * rainStrength), 0.0, 1.0) * (1.0 - 0.6 * rainStrength);
							//this part affects cloud view distance
	}

	//just brightness here
	cloudColor *= (CLOUD_BRIGHTNESS + 0.4 - 0.4 * clamp((dot(sunVecM22, upVec) + 0.04) * 4.4, 0.0, 1.0) - 0.4 * clamp((dot(-sunVec, upVec) + 0.04) * 3.2, 0.0, 1.0))
		 * (0.5 - 0.18 * clamp((dot(-sunVec, upVec) + 0.05) * 3.0, 0.0, 1.0) - 0.12* (1.0 - sunVisibility) * (1.0 - rainStrength));

	//night clouds gradient correction
	cloudColor *= (1.0 - 0.48 * VoU * clamp((dot(-sunVec, upVec) + 0.05) * 3.0, 0.0, 1.0));



	#ifdef WEATHER_PERBIOME
	cloud *= (1.0 - 0.8 * isDesert * rainStrength)*(1.0 - 0.8 * isMesa * rainStrength);
	#endif


	#if MC_VERSION >= 11800
	cloudColor *= clamp((cameraPosition.y + 70.0) / 8.0, 0.0, 1.0);
	#else
	cloudColor *= clamp((cameraPosition.y + 6.0) / 8.0, 0.0, 1.0);
	#endif
	
	if (isEyeInWater == 3.0) {
	cloudColor = vec3(0.1, 0.16, 0.2) * (1.0 - 0.99 * moonVisibility) * eBS;
	}

	return vec4(cloudColor, cloud * cloud * CLOUD_OPACITY);
}

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

void DrawStars(inout vec3 color, vec3 viewPos) {
	vec3 wpos = vec3(gbufferModelViewInverse * vec4(viewPos * 100.0, 1.0));
	vec3 planeCoord = wpos / (wpos.y + length(wpos.xz));
	vec2 wind = vec2(frametime, 0.0);
	vec2 coord = planeCoord.xz * 0.4 + cameraPosition.xz * 0.0001 + wind * 0.00125;
	coord = floor(coord * 1024.0) / 1024.0;
	
	float VoU = clamp(dot(normalize(viewPos), normalize(upVec)), 0.0, 1.0);
	float VoL = dot(normalize(viewPos), sunVec);
	float multiplier = sqrt(sqrt(VoU)) * 5.0 * STARS_VISIBILITY * (1.0 - rainStrength);

		#if STARS_START == 1
		multiplier = sqrt(sqrt(VoU)) * 5.0 * STARS_VISIBILITY * (1.0 - rainStrength) * pow((1.0 - clamp((dot(sunVecM22, upVec) + 0.04) * 8.0, 0.0, 1.0)), 2);
		#endif

		#if STARS_START == 2
		multiplier = sqrt(sqrt(VoU)) * 5.0 * STARS_VISIBILITY * (1.0 - rainStrength) * clamp((dot(-sunVecM22, upVec) + 0.04) * 2.2, 0.0, 1.0);
		#endif

		#if STARS_START == 3
		multiplier = sqrt(sqrt(VoU)) * 5.0 * STARS_VISIBILITY * (1.0 - rainStrength) * clamp((dot(-sunVec, upVec) + 0.04) * 4.0, 0.0, 1.0);
		#endif

		#if STARS_START == 4
		multiplier = sqrt(sqrt(VoU)) * 5.0 * STARS_VISIBILITY * (1.0 - rainStrength) * pow(clamp((dot(-sunVec, upVec) + 0.04) * 3.2, 0.0, 1.0), 2);
		#endif

		#if STARS_START == 5
		multiplier = sqrt(sqrt(VoU)) * 5.0 * STARS_VISIBILITY * (1.0 - rainStrength) * (1.0 - clamp((dot(sunVec22, upVec) + 0.04) * 8.0, 0.0, 1.0));
		#endif
	
	float star = 1.0;
	if (VoU > 0.0) {
		star *= GetNoise(coord.xy);
		star *= GetNoise(coord.xy + 0.10);
		star *= GetNoise(coord.xy + 0.23);
	}
	star = clamp(star - 0.8125, 0.0, 1.0) * multiplier;

	#if MC_VERSION >= 11800
	star *= clamp((cameraPosition.y + 70.0) / 8.0, 0.0, 1.0);
	#else
	star *= clamp((cameraPosition.y + 6.0) / 8.0, 0.0, 1.0);
	#endif
	
	float moonFade = smoothstep(-0.997,-0.992, VoL);
	star *= moonFade;
	
	color += star * pow(lightNight, vec3(0.8));

	if (isEyeInWater == 3.0) {
	color = vec3(0.1, 0.16, 0.2) * (1.0 - 0.99 * moonVisibility) * eBS;
	}
}

/*
//maybe improve and add that for "fantasy" / "minecraft dungeons" style preset in the future
void DrawEndStars(inout vec3 color, vec3 viewPos) {

	vec3 wpos = vec3(gbufferModelViewInverse * vec4(viewPos * 100.0, 1.0));
	vec3 planeCoord = wpos / (wpos.y + length(wpos.xz));
	vec2 coord = planeCoord.xz * 0.4 + cameraPosition.xz * 0.0001;
	coord = floor(coord * 1024.0) / 1024.0;
	
	float VoU = clamp(dot(normalize(viewPos), normalize(upVec)), 0.0, 1.0);
//	float multiplier = sqrt(sqrt(VoU)) * 5.0 * STARS_VISIBILITY;


	float star = 1.0;
//	if (VoU > 0.0) {
		star *= GetNoise(coord.xy);
		star *= GetNoise(coord.xy + 0.10);
		star *= GetNoise(coord.xy + 0.23);
//	}
//	star = clamp(star - 0.8125, 0.0, 1.0) * multiplier;
	star = clamp(star - 0.8125, 0.0, 1.0);


	color += star * pow(vec3(4.0), vec3(0.8));

	if (isEyeInWater == 3.0) {
	color = vec3(0.1, 0.16, 0.2);
	}
}
*/

#ifdef AURORA
#include "/lib/color/auroraColor.glsl"

float AuroraSample(vec2 coord, vec2 wind, float VoU) {
	float noise = texture2D(noisetex, coord * 0.0625  + wind * 0.25).b * 3.0;
		  noise+= texture2D(noisetex, coord * 0.03125 + wind * 0.15).b * 3.0;

	noise = max(1.0 - 4.0 * (0.5 * VoU + 0.5) * abs(noise - 3.0), 0.0);

	return noise;
}

vec3 DrawAurora(vec3 viewPos, float dither, int samples) {
	#ifdef TAA
	dither = fract(16.0 * frameTimeCounter + dither);
	#endif
	
	float sampleStep = 1.0 / samples;
	float currentStep = dither * sampleStep;

	float VoU = dot(normalize(viewPos), upVec);

	#ifdef AURORA_ONLY_AT_NIGHT
	float visibility = moonVisibility * (1.0 - rainStrength) * (1.0 - rainStrength);
	#else
	float visibility = (1.0 - rainStrength) * (1.0 - rainStrength);
	#endif

	#ifdef AURORA_PERBIOME
	visibility *= isCold * isCold;
	#endif

	vec2 wind = vec2(
		frametime * CLOUD_SPEED * 0.000125,
		sin(frametime * CLOUD_SPEED * 0.05) * 0.00025
	);

	vec3 aurora = vec3(0.0);

	if (VoU > 0.0 && visibility > 0.0) {
		vec3 wpos = normalize((gbufferModelViewInverse * vec4(viewPos, 1.0)).xyz);
		for(int i = 0; i < samples; i++) {
			vec3 planeCoord = wpos * ((8.0 + currentStep * 7.0) / wpos.y) * 0.004;

			vec2 coord = cameraPosition.xz * 0.00004 + planeCoord.xz;
			coord += vec2(coord.y, -coord.x) * 0.3;

			float noise = AuroraSample(coord, wind, VoU);
			
			if (noise > 0.0) {
				noise *= texture2D(noisetex, coord * 0.125 + wind * 0.25).b;
				noise *= 0.5 * texture2D(noisetex, coord + wind * 16.0).b + 0.75;
				noise = noise * noise * 3.0 * sampleStep;
				noise *= max(sqrt(1.0 - length(planeCoord.xz) * 3.75), 0.0);

				vec3 auroraColor = mix(auroraLowCol, auroraHighCol, pow(currentStep, 0.4));
				aurora += noise * auroraColor * exp2(-6.0 * i * sampleStep);
			}
			currentStep += sampleStep;
		}
	}
	#if MC_VERSION >= 11800
	visibility *= clamp((cameraPosition.y + 70.0) / 8.0, 0.0, 1.0);
	#else
	visibility *= clamp((cameraPosition.y + 6.0) / 8.0, 0.0, 1.0);
	#endif

	if (isEyeInWater == 3.0) {
	visibility *= 0.0;
	}

	return aurora * visibility;
}
#endif