

#define BLACKHOLE_LQ


#include "/Lib/UniformDeclare.glsl"
#include "/Lib/Utilities.glsl"


/* RENDERTARGETS: 8 */
layout(location = 0) out vec4 framebuffer_altOutput;

layout(rgba16f) uniform writeonly image2D FBIMG_DIFFUSE_TEMPORAL;



ivec2 texelCoord = ivec2(gl_FragCoord.xy);
vec2 texCoord = gl_FragCoord.xy * UNIFORM_PIXEL_SIZE;

#ifdef DIMENSION_OVERWORLD
	in vec3 worldShadowVector;
	in vec3 worldSunVector;

	in vec3 colorShadowlight;
	in vec3 colorSunlight;
	in vec3 colorMoonlight;

	in vec3 colorSkylight;

	in vec2 fogTime;
#endif

uniform sampler2D shadowtex0;
uniform sampler2D shadowtex1;

uniform sampler2D shadowcolor0;

uniform sampler3D voxelData3D;

#ifdef PT_IRC
	uniform sampler3D irradianceCache3D;
	uniform sampler3D irradianceCache3D_Alt;
#endif


#include "/Lib/GbufferData.glsl"
#include "/Lib/Uniform/GbufferTransforms.glsl"
#include "/Lib/BasicFunctions/TemporalNoise.glsl"
#ifdef DIMENSION_OVERWORLD
#include "/Lib/BasicFunctions/PrecomputedAtmosphere.glsl"
#endif
#ifdef DIMENSION_NETHER
	#include "/Lib/BasicFunctions/NetherColor.glsl"
#endif

#include "/Lib/PathTracing/Voxelizer/VoxelProfile.glsl"
#include "/Lib/Uniform/ShadowTransforms.glsl"

#ifdef DIMENSION_OVERWORLD
	#include "/Lib/IndividualFunctions/WaterFog.glsl"

	#define VFOG_LQ
	#include "/Lib/IndividualFunctions/VolumetricFog.glsl"
#endif
#ifdef DIMENSION_END
	#include "/Lib/IndividualFunctions/EndSky.glsl"
#endif

void main(){
	float depth = texelFetch(depthtex0, texelCoord, 0).x;

	#ifdef LOD_RENDERING
		if (depth == 1.0) depth = -texelFetch(LOD_DEPTH_TEX_0, texelCoord, 0).x;
	#endif

	if (abs(depth) == 1.0) discard;

	bool isSmooth = false;
	GbufferData gbuffer = GetGbufferDataTranslucent(isSmooth);
	MaterialMask materialMask = CalculateMasks(gbuffer.materialID);

	float roughness = gbuffer.material.metalness > 229.5 / 255.0 ? -gbuffer.material.roughness : gbuffer.material.roughness;
	imageStore(FBIMG_DIFFUSE_TEMPORAL, texelCoord, vec4(gbuffer.worldNormal, roughness));

	framebuffer_altOutput = vec4(0.0);

	if (gbuffer.material.reflectionStrength > 0.0){
		vec3 viewPos = ViewPos_From_ScreenPos(texCoord, depth);
		#ifdef LOD_RENDERING
			if (depth < 0.0) viewPos = ViewPos_From_ScreenPos_LOD(texCoord, -depth);
		#endif
		vec3 worldPos = mat3(gbufferModelViewInverse) * viewPos.xyz;
		vec3 worldDir = normalize(worldPos.xyz);

		vec3 hitWorldPos = texelFetch(FBTEX_SST_TEMPORAL, texelCoord, 0).xyz;

		framebuffer_altOutput = texelFetch(FBTEX_ALT_OUTPUT, texelCoord, 0);
		vec3 reflection = framebuffer_altOutput.rgb;

		vec3 rayDir = hitWorldPos.xyz - worldPos;
		float hitDist = length(rayDir);
		rayDir /= max(hitDist, 1e-20);

		float specular = 1.0;
		if (gbuffer.material.metalness < 229.5 / 255.0 && !isSmooth){
			vec3 h = normalize(rayDir - worldDir);
			float LdotH = saturate(dot(rayDir, h));
			float NdotL = saturate(dot(gbuffer.worldNormal, rayDir));
			float NdotV = saturate(dot(-worldDir, gbuffer.worldNormal));

			specular *= F_Schlick(LdotH, gbuffer.material.metalness, 1.0).x;
			specular *= V_Schlick(NdotL, NdotV + 0.8, gbuffer.material.roughness);
		}

		if (hitDist > 0.0){

			float dist = length(worldPos);
			#ifdef LOD_RENDERING
				float farDist = max(float(LOD_RENDER_DISTANCE), far) * 1.4;
				#ifdef DH_LIMIT_VFOG_DIST
					farDist = min(2048.0, farDist);
				#endif
			#else
				float farDist = far * 1.4;
			#endif
			
			#ifdef DIMENSION_OVERWORLD
				float rayDist = max(min(hitDist + dist, farDist) - dist, 0.0);
				vec3 endPos = worldPos + rayDir * rayDist;
				float globalCloudShadow = 1.0 - wetness * (RAIN_SHADOW * 0.985);	


				#if (defined UNDERWATER_VFOG && defined VFOG_REFLECTION) || defined WATER_FOG
					if (isEyeInWater == 1){
						float k = 1.0 - (1.0 / (WATER_IOR * WATER_IOR)) * (1.0 - worldShadowVector.y * worldShadowVector.y);
						vec3 shadowVectorRefracted = -worldShadowVector * (1.0 / WATER_IOR);
						shadowVectorRefracted.y -= (1.0 / WATER_IOR) * -worldShadowVector.y + sqrt(k);
						float VdotSR = dot(shadowVectorRefracted, rayDir);

						#ifdef WATER_FOG
							WaterFog(reflection, rayDir, hitDist, VdotSR);
						#endif

						#ifdef UNDERWATER_VFOG
						#ifdef VFOG_REFLECTION
							reflection += UnderwaterVolumetricFog(worldPos, endPos, rayDir, VdotSR, globalCloudShadow);
						#endif
						#endif
					}
				#endif

				if (isEyeInWater == 0){
					#ifdef LANDSCATTERING
						#ifdef LOD_RENDERING
							LandAtmosphericScattering(reflection, rayDist, worldPos, endPos, rayDir, hitDist > 5e4);
						#else
							#ifdef LANDSCATTERING_REFLECTION
								LandAtmosphericScattering(reflection, rayDist, worldPos, endPos, rayDir, hitDist > 5e4);
							#endif
						#endif
					#endif

					#ifdef VFOG
					#ifdef VFOG_REFLECTION
						float fogTimeFactor = 1.0;
						#ifndef VFOG_IGNORE_WORLDTIME
							#ifndef DISABLE_LOCAL_PRECIPITATION
								fogTimeFactor *= mix(fogTime.x, VFOG_RAIN_DENSITY_MUL, wetness * (1.0 - eyeNoPrecipitationSmooth * 0.7));
							#else
								fogTimeFactor *= mix(fogTime.x, VFOG_RAIN_DENSITY_MUL, wetness);
							#endif
						#else
							#ifndef DISABLE_LOCAL_PRECIPITATION
								fogTimeFactor *= mix(1.0, VFOG_RAIN_DENSITY_MUL, wetness * (1.0 - eyeNoPrecipitationSmooth * 0.7));
							#else
								fogTimeFactor *= mix(1.0, VFOG_RAIN_DENSITY_MUL, wetness);
							#endif					
						#endif

						if (fogTimeFactor > 0.01) VolumetricFog(reflection, worldPos, endPos, rayDir, globalCloudShadow, fogTimeFactor);
					#endif
					#endif
				}

			#endif

			#ifdef DIMENSION_NETHER
				dist = min(dist, 200.0);
				float rayDist = min(hitDist + dist, 200.0);

				NetherFog(reflection, dist, rayDist);

			#endif

			#ifdef DIMENSION_END
				if (hitDist > 5e4){
					BlackHole_AccretionDisc_Stars(reflection, rayDir, shadowModelViewInverseEnd[2]);
					PlanetEnd2(reflection, vec3(0.0), rayDir);
				}

				float rayDist = hitDist + dist;

				EndFog(reflection, rayDist, rayDir, shadowModelViewInverseEnd[2]);

				//if(isEyeInWater == 1) reflection *= vec3(0.5, 0.55, 0.7);
			#endif

		}

		reflection *= saturate(specular);

		framebuffer_altOutput = vec4(reflection, framebuffer_altOutput.a);
	}
}
