#ifdef END_MANUAL_PLANET_CYCLE
	const float timeFactor = fract(END_MANUAL_PLANET_ANGLE / 360.0 + 0.282) * TAU;
#else
	float timeFactor = fract(frameTimeCounter * ((1.0 / 60.0) / END_PLANET_CYCLE) + 0.282) * TAU;
#endif

float planetShadow = smoothstep(0.62, 0.35, timeFactor) + smoothstep(1.6, 1.87, timeFactor);


vec3 CalculateStars(vec3 worldDir){
	float angleY = frameTimeCounter * 0.001;
	mat3 eyeRoataionMatrixY = mat3(cos(angleY), 0, sin(angleY), 0, 1, 0, -sin(angleY), 0, cos(angleY));

	worldDir = eyeRoataionMatrixY * worldDir;

	const float scale = 144.0;
	const float coverage = 0.037;
	const float maxLuminance = 0.04;
	const float minTemperature = 5000.0;
	const float maxTemperature = 7000.0;

	//float visibility = curve(saturate(worldDir.y));

	float cosine = dot(worldSunVector,  vec3(0, 0, 1));
	vec3 axis = cross(worldSunVector,  vec3(0, 0, 1));
	float cosecantSquared = 1.0 / dot(axis, axis);
	worldDir = cosine * worldDir + cross(axis, worldDir) + (cosecantSquared - cosecantSquared * cosine) * dot(axis, worldDir) * axis;

	vec3  p = worldDir * scale;
	ivec3 i = ivec3(floor(p));
	vec3  f = p - i;
	float r = dot(f - 0.5, f - 0.5);

	vec3 i3 = fract(i * vec3(443.897, 441.423, 437.195));
	i3 += dot(i3, i3.yzx + 19.19);
	vec2 hash = fract((i3.xx + i3.yz) * i3.zy);
	hash.y = 2.0 * hash.y - 4.0 * hash.y * hash.y + 3.0 * hash.y * hash.y * hash.y;

	float c = remapSaturate(hash.x, 1.0 - coverage, 1.0);
	return (maxLuminance * remapSaturate(r, 0.25, 0.0) * c * c) * Blackbody(mix(minTemperature, maxTemperature, hash.y));
}




vec3 H(vec3 albedo, float a){
	vec3 R = sqrt(vec3(1.0) - albedo);
	vec3 r = (1.0 - R) / (1.0 + R);
	vec3 H = r + (0.5 - r * a) * log((1.0 + a) / a);
	H *= albedo * a;

	return 1.0 / (1.0 - H);
}

vec3 ppss(vec3 albedo, vec3 normal, vec3 eyeDir, vec3 lightDir, float s){
	float NdotL = dot(normal, lightDir);
	float NdotV = dot(normal, eyeDir);
	albedo *= curve(saturate(NdotL));

	vec3 color = albedo * H(albedo, NdotL) * H(albedo, NdotV) / (4.0 * PI * (NdotL + NdotV));

	return saturate(color);
}

float Disc(float a, float s, float h){
	float disc = curve(saturate((a - (1.0 - s)) * h));
	return disc * disc;
}

void PlanetEnd2(inout vec3 color, in vec3 eye, in vec3 rayDir, in vec3 lightDir){
	// Planeta completamente removido – não adiciona nada ao céu
}



//www.shadertoy.com/view/lstSRS

mat3 RotateMatrix(float x, float y, float z){
	mat3 matx = mat3(1.0, 0.0, 0.0,
					 0.0, cos(x), sin(x),
					 0.0, -sin(x), cos(x));

	mat3 maty = mat3(cos(y), 0.0, -sin(y),
					 0.0, 1.0, 0.0,
					 sin(y), 0.0, cos(y));

	mat3 matz = mat3(cos(z), sin(z), 0.0,
					 -sin(z), cos(z), 0.0,
					 0.0, 0.0, 1.0);

	return maty * matx * matz;
}

void WarpSpace(inout vec3 eyevec, inout vec3 raypos){
	vec3 origin = vec3(0.0, 0.0, 0.0);

	float singularityDist = distance(raypos, origin);
	float warpFactor = 1.0 / (singularityDist * singularityDist + 0.000001);

	vec3 singularityVector = normalize(origin - raypos);

	float warpAmount = 0.06;

	eyevec = normalize(eyevec + singularityVector * warpFactor * warpAmount);
}


float Calculate3DNoise(vec3 position){
	vec3 p = floor(position);
	vec3 b = curve(fract(position));

	vec2 uv = 17.0 * p.z + p.xy + b.xy;
	vec2 rg = textureLod(noisetex, (uv + 0.5) / 64.0, 0.0).zx;

	return mix(rg.x, rg.y, b.z);
}

float CalculateCloudFBM(vec3 position, vec3 shift){
	const int octaves = 4;
	const float octAlpha = 0.87;
	const float octScale = 2.5;
	const float octShift = (octAlpha / octScale) / octaves;

	float accum = 0.0;
	float alpha = 0.5;

	for (int i = 0; i < octaves; i++) {
		accum += alpha * Calculate3DNoise(position);
		position = (position + shift) * octScale;
		alpha *= octAlpha;
	}

	return accum + octShift;
}

float CalculateCloudFBM_LQ(vec3 position, vec3 shift){
	const int octaves = 3;
	const float octAlpha = 0.9;
	const float octScale = 2.0;
	const float octShift = (octAlpha / octScale) / octaves;

	float accum = 0.0;
	float alpha = 0.5;

	for (int i = 0; i < octaves; i++) {
		accum += alpha * Calculate3DNoise(position);
		position = (position + shift) * octScale;
		alpha *= octAlpha;
	}

	return accum + octShift;
}

float pcurve(float x){
	float x2 = x * x;
	return 12.207 * x2 * x2 * (1.0 - x);
}

void BlackHole_AccretionDisc_Stars(inout vec3 color, in vec3 rayDir, in vec3 lightDir){
	const float steps = 50.0;
	const float rSteps = 1.0 / steps;
	const float stepLength = 0.2;

	const float discRadius = 2.25;
	const float discWidth = 3.5;
	const float discInner = discRadius - discWidth * 0.5;
	const float discOuter = discRadius + discWidth * 0.5;

	#ifdef TAA
		float noise = BlueNoiseTemproal().x;
	#else
		float noise = InterleavedGradientNoise(gl_FragCoord.xy);
	#endif

	vec3 eye = -lightDir * 16.0;
	vec3 rayPos = eye + rayDir * 3.0;

	mat3 rotation = RotateMatrix(0.1, 0.0, -0.35);


	vec3 result = vec3(0.0);
	float transmittance = 1.0;

	rayPos += rayDir * stepLength * noise;

	for(int i = 0; i < steps; i++){
		if(transmittance < 0.0001) break;

		WarpSpace(rayDir, rayPos);
		rayPos += rayDir * stepLength;

		{
			vec3 discPos = rotation * rayPos;

			float r = length(discPos);
			float p = atan2(-discPos.zx);
			float h = discPos.y;

			float radialGradient = 1.0 - saturate((r - discInner) / discWidth * 0.5);
			float dist = abs(h);

			float discThickness = 0.1 * radialGradient;

			float fr = abs(r - discInner) + 0.4;
			fr = fr * fr;
			float fade = fr * fr * 0.04;
   			float bloomFactor = 1.0 / (h * h * 40.0 + fade + 0.00002);
			bloomFactor *= saturate(2.0 - abs(dist) / discThickness);
			bloomFactor = bloomFactor * bloomFactor;


			float dr = pcurve(radialGradient);
			float density = dr;

			density *= saturate(1.0 - abs(dist) / discThickness);
			density = saturate(density * 0.7);
			density = saturate(density + bloomFactor * 0.1);

			if (density > 0.0001){
				#ifdef ACCRETIONDISC_DETAIL_ALONG_LONGTITUDE
					vec3 discCoord = vec3(r, p * (1.0 - radialGradient * 0.5), h * 0.1) * 3.5;
					float fbm = CalculateCloudFBM(discCoord, frameTimeCounter * vec3(0.1, 0.07, 0.0));
				#else
					vec3 discCoord = vec3(r, 0.0, h * 0.1) * 3.5;
					float fbm = CalculateCloudFBM(discCoord, frameTimeCounter * vec3(0.03, 0.05, 0.0));
				#endif
				fbm = fbm * fbm;
				fbm = fbm * fbm;

				density *= fbm * dr;

				float gr = 1.0 - radialGradient;
				gr = gr * gr;
				float glowStrength = 1.0 / (gr * gr * 400.0 + 0.002);
				vec3 glow = Blackbody(2700.0 + glowStrength * 50.0) * glowStrength;

				#ifdef ACCRETIONDISC_DOPPLER_EFFECT
					glow *= sin(p - 1.07) * 0.75 + 1.0;
				#endif
				
				float stepTransmittance = exp2(-density * 7.0);
				float integral = 1.0 - stepTransmittance;
				transmittance *= stepTransmittance;

				result += integral * transmittance * glow;
			}

			vec2 t = vec2(1.0, 0.01);
			float torusDist = length(length(discPos + vec3(0.0, -0.05, 0.0)) - t);
			float bloomDisc = 1.0 / (pow(torusDist, 3.5) + 0.001);
			vec3 col = Blackbody(12000.0);
			bloomDisc *= step(0.5, r);

			result += col * bloomDisc * 0.1 * transmittance;
		}
	}
	result *= rSteps;

	#if STAR_TYPE > 0
		color += CalculateStars(rayDir);
	#endif

	color *= transmittance;

	color += result;
}

void BlackHole_AccretionDisc_Reflection(inout vec3 color, in vec3 rayDir, in vec3 lightDir){
	const float steps = 30.0;
	const float rSteps = 1.0 / steps;
	const float stepLength = 0.2;

	const float discRadius = 2.25;
	const float discWidth = 3.5;
	const float discInner = discRadius - discWidth * 0.5;
	const float discOuter = discRadius + discWidth * 0.5;


	float noise = BlueNoiseTemproal().x;

	vec3 eye = -lightDir * 16.0;
	vec3 rayPos = eye + rayDir * 4.0;

	mat3 rotation = RotateMatrix(0.1, 0.0, -0.35);


	vec3 result = vec3(0.0);
	float transmittance = 1.0;

	rayPos += rayDir * stepLength * noise;

	for(int i = 0; i < steps; i++){
		if(transmittance < 0.0001) break;

		WarpSpace(rayDir, rayPos);
		rayPos += rayDir * stepLength;

		{
			vec3 discPos = rotation * rayPos;

			float r = length(discPos);
			float p = atan2(-discPos.zx);
			float h = discPos.y;

			float radialGradient = 1.0 - saturate((r - discInner) / discWidth * 0.5);
			float dist = abs(h);

			float discThickness = 0.1 * radialGradient;

			float fr = abs(r - discInner) + 0.4;
			fr = fr * fr;
			float fade = fr * fr * 0.04;
   			float bloomFactor = 1.0 / (h * h * 40.0 + fade + 0.00002);
			bloomFactor *= saturate(2.0 - abs(dist) / discThickness);
			bloomFactor = bloomFactor * bloomFactor;


			float dr = pcurve(radialGradient);
			float density = dr;

			density *= saturate(1.0 - abs(dist) / discThickness);
			density = saturate(density * 0.7);
			density = saturate(density + bloomFactor * 0.1);

			if (density > 0.0001){
				#ifdef ACCRETIONDISC_DETAIL_ALONG_LONGTITUDE
					vec3 discCoord = vec3(r, p * (1.0 - radialGradient * 0.5), h * 0.1) * 3.5;
					float fbm = CalculateCloudFBM(discCoord, frameTimeCounter * vec3(0.1, 0.07, 0.0));
				#else
					vec3 discCoord = vec3(r, 0.0, h * 0.1) * 3.5;
					float fbm = CalculateCloudFBM(discCoord, frameTimeCounter * vec3(0.03, 0.05, 0.0));
				#endif

				float fbm2 = fbm * fbm;
				density *= fbm2 * fbm2 * fbm;
				density *= dr;

				float gr = 1.0 - radialGradient;
				gr = gr * gr;
				float glowStrength = 1.0 / (gr * gr * 400.0 + 0.002);
				vec3 glow = Blackbody(2700.0 + glowStrength * 50.0) * glowStrength;

				#ifdef ACCRETIONDISC_DOPPLER_EFFECT
					glow *= sin(p - 1.07) * 0.75 + 1.0;
				#endif

				float stepTransmittance = exp2(-density * 7.0);
				float integral = 1.0 - stepTransmittance;
				transmittance *= stepTransmittance;

				result += integral * transmittance * glow;
			}

			vec2 t = vec2(1.0, 0.01);
			float torusDist = length(length(discPos + vec3(0.0, -0.05, 0.0)) - t);
			float bloomDisc = 1.0 / (pow(torusDist, 3.5) + 0.001);
			vec3 col = Blackbody(12000.0);
			bloomDisc *= step(0.5, r);

			result += col * bloomDisc * 0.1 * transmittance;
		}
	}
	result *= rSteps;

	color *= transmittance;

	color += result;
}

vec3 EndFog(float dist, vec3 worldDir){
	float VdotL = dot(worldShadowVector, worldDir);

	float angleX = -1.57079633 + (0.2 * sin(timeFactor + 3.0) - 0.1) - 0.008 * sin(timeFactor + 4.7);
	float angleY = timeFactor;

	mat3 eyeRoataionMatrixX = mat3(1.0, 0.0, 0.0, 0.0, cos(angleX), -sin(angleX), 0.0, sin(angleX), cos(angleX));
	mat3 eyeRoataionMatrixY = mat3(cos(angleY), 0.0, sin(angleY), 0.0, 1.0, 0.0, -sin(angleY), 0.0, cos(angleY));
	mat3 eyeRoataionMatrix = eyeRoataionMatrixX * eyeRoataionMatrixY;

	worldDir = eyeRoataionMatrix * worldDir;

	dist = min(dist, 512.0);
	float h = abs(worldDir.z) * dist * 0.03;
	float density = (1.0 - exp(-h)) / h * dist;

	density *= MiePhaseFunction(0.3, VdotL) * 10.0 * planetShadow + 0.25;

	density *= planetShadow * 0.93 + 0.07;

	return vec3(density * 1e-5 * SUNLIGHT_INTENSITY);
}