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

#if AURORA_COLOR == 6
	#include "/lib/color/auroraColor.glsl"
#endif

#if (defined AURORA_END && defined END)
	#include "/lib/color/auroraEndColor.glsl"
#endif

float AuroraNoise(vec2 coord, vec2 wind, float cosT) {
    const float kTexelSize1 = 0.03125;
    const float kTexelSize2 = 0.015625;
    const float kMaxFalloffDist = 1.0;
    const float kColorShapeScale = 5.0;
    const float kDistScale = 0.9;

    vec2 texCoord1 = coord * kTexelSize1 + wind * 0.15;
    vec2 texCoord2 = coord * kTexelSize2 + wind * 0.075;
    vec4 noiseVals1 = texture2D(noisetex, texCoord1);
    vec4 noiseVals2 = texture2D(noisetex, texCoord2);

    float noise = (noiseVals1.b + noiseVals2.b) * 2.5;
    float distFromMid = abs(noise - 2.5);

    float falloff = max(0.0, 1.0 - 8.0 * (0.5 * cosT + 0.5) * distFromMid / kMaxFalloffDist);
    float color = max(0.0, (noiseVals1.r + noiseVals2.r) * 0.5 - distFromMid * kDistScale);
    float shape = max(0.0, (noiseVals1.g + noiseVals2.g) * 0.5 - distFromMid * kDistScale);

    return falloff * (color * kColorShapeScale) * shape;
}

vec3 DrawAurora(vec3 viewPos, float dither, int sampleCount) {

	float gradientMix = dither / sampleCount;
	float cosT = dot(normalize(viewPos), upVec);

	#ifdef OVERWORLD
		const float auroraSpeed = AURORA_SPEED;
		const float auroraDistance = AURORA_DISTANCE;
		const float auroraSize = AURORA_SIZE;
		const float auroraVisibility = AURORA_VISIBILITY;
		const float auroraGradient = COLOR_GRADIENT;
	#else
		const float auroraSpeed = AURORA_END_SPEED;
		const float auroraDistance = AURORA_END_DISTANCE;
		const float auroraSize = AURORA_END_SIZE;
		const float auroraVisibility = AURORA_END_VISIBILITY;
		const float auroraGradient = COLOR_END_GRADIENT;
	#endif

	#ifdef OVERWORLD
		float visibility = pow2((1.0 - rainStrengthS));
			  visibility *= 1.0 - sunVisibility;
	#else
		float visibility = 1.0;
	#endif

	#if (defined OVERWORLD && defined WEATHER_PERBIOME && defined AURORA_WEATHER_PERBIOME)
		visibility *= pow2(isCold);
	#endif

	vec2 wind = vec2(frameTimeCounter * auroraSpeed * 0.000125, sin_approx(frameTimeCounter * auroraSpeed * 0.05) * 0.00025);

	vec3 aurora = vec3(0.0);

	if (cosT > 0.0 && visibility > 0.0) {
		vec3 wpos = normalize((gbufferModelViewInverse * vec4(viewPos, 1.0)).xyz);
		for (int i = 0; i < sampleCount; i ++) {
			vec3 planeCoord = wpos * ((auroraDistance + (i + dither) * auroraSize / sampleCount) / wpos.y) * 0.004;
			vec2 coord = cameraPosition.xz * 0.00004 + planeCoord.xz;
			coord += vec2(coord.y, - coord.x) * 2.5;

			float noise = AuroraNoise(coord, wind, cosT);

			float colorGradient = COLOR_GRADIENT;

			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  = pow2(noise) * 3.0 / sampleCount;
				noise *= Max0(sqrt(1.0 - length(planeCoord.xz) * 3.75));

				#ifdef OVERWORLD
					#if AURORA_COLOR == 1
						vec3 auroraColor = mix(vec3(0.1, 1.0, 0.5), vec3(0.3451, 0.0, 0.4118), pow(gradientMix, colorGradient));

					#elif AURORA_COLOR == 2
						vec3 auroraColor = mix(vec3(0.1, 1.0, 0.5), vec3(0.0, 0.0, 0.7216), pow(gradientMix, colorGradient));

					#elif AURORA_COLOR == 3
						vec3 auroraColor = mix(vec3(0.1, 1.0, 0.5), vec3(0.6667, 0.0, 0.0), pow(gradientMix, colorGradient));

					#elif AURORA_COLOR == 4
						vec3 auroraColor = mix(vec3(0.1, 1.0, 0.5), vec3(0.6157, 0.6275, 0.0), pow(gradientMix, colorGradient));

					#elif AURORA_COLOR == 5
						vec3 auroraColor = mix(hue2(frameTimeCounter * RAINBOW_COLOR_AURORA_1_SPEED + RAINBOW_COLOR_AURORA_1_START), hue2(frameTimeCounter * RAINBOW_COLOR_AURORA_2_SPEED + RAINBOW_COLOR_AURORA_2_START), pow(gradientMix, colorGradient));

					#elif AURORA_COLOR == 6
						vec3 auroraColor = mix(auroraLowCol, auroraHighCol, pow(gradientMix, colorGradient));
					#endif
				#else
						vec3 auroraColor = mix(auroraEndLowCol, auroraEndHighCol, pow(gradientMix, colorGradient));
				#endif

				aurora += noise * auroraColor * exp2(- 6.0 * i / sampleCount) * auroraVisibility;
				aurora *= 1.0 - exp(- (10.0 - 9.0 * rainStrengthS) * cosT);
			}
			gradientMix += 1.0 / sampleCount;
		}
	}

	return aurora * visibility;
}