/*//////////////////////////////////////////////////////////////////////////////
//    ##      #####   ######   ######     ##     ####     #######  ##  ##     //
//   ####    ##   ##  # ## #    ##  ##   ####     ##       ##   #  ##  ##     //
//  ##  ##   #          ##      ##  ##  ##  ##    ##       ## #     ####      //
//  ##  ##    #####     ##      #####   ##  ##    ##       ####      ##       //
//  ######        ##    ##      ## ##   ######    ##   #   ## #     ####      //
//  ##  ##   ##   ##    ##      ##  ##  ##  ##    ##  ##   ##   #  ##  ##     //
//  ##  ##    #####    ####    #### ##  ##  ##   #######  #######  ##  ##     //
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
//      #####   ##   ##    ##     #####    #######  ######    #####           //
//     ##   ##  ##   ##   ####     ## ##    ##   #   ##  ##  ##   ##          //
//     #        ##   ##  ##  ##    ##  ##   ## #     ##  ##  #                //
//      #####   #######  ##  ##    ##  ##   ####     #####    #####           //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##          //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##          //
//     ##   ##  ##   ##  ##  ##    ## ##    ##   #   ##  ##  ##   ##          //
//      #####   ##   ##  ##  ##   #####    #######  #### ##   #####           //
/////(BSL Shaders Edit)//////////////////////////////////////By LexBoosT//////*/

//Settings//

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

#include "/settings/globalSettings.glsl"

//Varyings//
varying vec2 texCoord;
varying vec3 normal;

//Fragment Shader///////////////////////////////////////////////////////////////////////////////////
#ifdef FSH

	//Uniforms//
	uniform sampler2D noisetex;

	uniform int frameCounter;
	uniform int isEyeInWater;

	#ifndef WEATHER_PERBIOME
		uniform float isCold;
	#endif

	uniform float blindFactor, darknessFactor, nightVision;
	uniform float far, near;
	uniform float frameTimeCounter;
	uniform float rainStrength;
	uniform float rainStrengthS;
	uniform float screenBrightness;
	uniform float viewWidth, viewHeight, aspectRatio;
	uniform float eyeAltitude;

	#ifdef UNDERGROUND_SKY
	uniform float isEyeInCave;
	#endif

	uniform int moonPhase;
	#define UNIFORM_MOONPHASE

	uniform ivec2 eyeBrightnessSmooth;

	uniform vec3 cameraPosition;

	uniform mat4 gbufferProjection, gbufferPreviousProjection, gbufferProjectionInverse;
	uniform mat4 gbufferModelView, gbufferPreviousModelView, gbufferModelViewInverse;
	uniform mat4 shadowProjection;
	uniform mat4 shadowModelView;

	uniform vec3 moonPosition;
	uniform vec3 skyColor;
	uniform vec3 fogColor;

	uniform sampler2D colortex0;

	#if (defined ADVANCED_MATERIALS || defined GLOWING_ENTITY_FIX || defined AO)
	uniform sampler2D colortex3;
	#endif

	uniform sampler2D depthtex0;
	uniform sampler2D depthtex1;

	#ifdef AO
	uniform sampler2D colortex4;
	#endif

	#if (defined ADVANCED_MATERIALS && defined REFLECTION_SPECULAR)
	uniform vec3 previousCameraPosition;

	uniform sampler2D colortex6;
	uniform sampler2D colortex1;
	#endif

	//Optifine Constants//
	#ifdef AO
	const bool colortex4MipmapEnabled = true;
	#endif

	#if (defined ADVANCED_MATERIALS && defined REFLECTION_SPECULAR)
	const bool colortex0MipmapEnabled = true;
	#endif

	//Common Variables//

	float eBS               = eyeBrightnessSmooth.y / 240.0;
	float sunVisibility     = calculateSunVisibility(sunVec, upVec);
	float moonVisibility    = calculateMoonVisibility(sunVec, upVec);
	float screenBrightness2 = clamp01(screenBrightness);

	#ifdef OVERWORLD
		vec3 lightVec = sunVec * ((timeAngle < 0.5325 || timeAngle > 0.9675) ? 1.0 : -1.0);
	#else
		vec3 lightVec = sunVec;
	#endif

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

	float computeVanillaDiffuse(float NoU, float NoE) {
    float diffuse = (0.25 * NoU + 0.75) + (0.5 - abs(NoE)) * (1.0 - abs(NoU)) * 0.1;
    return diffuse * diffuse;
    }

	vec2 aoOffsets[4] = vec2[4](
		vec2( 1.0,  0.0),
		vec2( 0.0,  1.0),
		vec2(-1.0,  0.0),
		vec2( 0.0, -1.0)
	);

	//Common Functions//
	float GetLuminance(vec3 color){
	return dot(color,vec3(0.299, 0.587, 0.114));
	}

	float GetLinearDepth(float depth) {
		return (2.0 * near) / (far + near - depth * (far - near));
	}

	#ifdef AO
		float GetAmbientOcclusion(float z) {
			float ao = 0.0;
			float tw = 0.0;
			float lz = GetLinearDepth(z);

			vec2 coord1 = texCoord;
			vec2 coord2 = texCoord;

			#if AO_QUALITY == 1 && AA > 0
				vec2 halfView = vec2(viewWidth, viewHeight) / 2.0;
				coord1 = (floor(texCoord * halfView + 1.0)) / halfView;
				coord2 = texCoord * 0.5;
			#endif

			for (int i = 0; i < 4; i ++) {
				vec2 offset = aoOffsets [i] / vec2(viewWidth, viewHeight);
				float samplez = GetLinearDepth(texture2D(depthtex0, coord1 + offset * 2.0).r);
				float wg = Max0(1.0 - 2.0 * far * abs(lz - samplez));
				ao += texture2D(colortex4, coord2 + offset).r * wg;
				tw += wg;
			}
			ao /= tw;
			if (tw < 0.0001)
				ao = texture2D(colortex4, coord2).r;

			float aoStrength = AO_STRENGTH;

			#if (AO_QUALITY == 2 || (AO_QUALITY == 1 && AA <= 1))
			aoStrength *= 0.75;
			#endif

			return pow(ao, aoStrength);
		}
	#endif

	//Includes//

	#ifdef END
	#include "/lib/color/lightColor.glsl"
	#endif

	#include "/lib/color/dimensionColor.glsl"
	#include "/lib/color/skyColor.glsl"
	#include "/lib/color/blocklightColor.glsl"
	#include "/lib/color/waterColor.glsl"
	#include "/lib/util/dither.glsl"
	#include "/lib/util/spaceConversion.glsl"

	#if (defined OVERWORLD || defined END)
	#include "/lib/atmospherics/sky.glsl"
	#endif

	#include "/lib/atmospherics/fog.glsl"
	#include "/lib/atmospherics/waterFog.glsl"

	#ifdef FULL_BORDER
	#include "/lib/outline/fullBorder.glsl"
	#endif

	#ifdef OUTLINE_ENABLED
	#include "/lib/outline/outlineOffset.glsl"
	#include "/lib/outline/blackOutline.glsl"
	#endif

	#if ((defined AURORA && defined OVERWORLD) || (defined AURORA_END && defined END))
	#include "/lib/atmospherics/aurora.glsl"
	#endif

	#if (defined ADVANCED_MATERIALS && defined REFLECTION_SPECULAR)
	#include "/lib/util/encode.glsl"
	#include "/lib/reflections/raytrace.glsl"
	#include "/lib/reflections/complexFresnel.glsl"
	#include "/lib/surface/materialDeferred.glsl"
	#include "/lib/reflections/roughReflections.glsl"
	#endif

	#if REALISTIC_CLOUDS == 1 && defined OVERWORLD
	#include "/lib/atmospherics/ovclouds.glsl"
	#endif

	#ifdef END

		#ifdef BLACK_HOLE
		#include "/lib/atmospherics/vortex.glsl"
		#endif

		#ifdef END_STARS
		#include "/lib/atmospherics/endstars.glsl"
		#endif

		#ifdef LOST_GLARE
		#include "/lib/atmospherics/lostglare.glsl"
		#endif

		#ifdef SHOOTING_STARS_END
		#include "/lib/atmospherics/shootingstars.glsl"
		#endif
	#endif

	//Program//
	void main() {
		vec4  color =texelFetch(colortex0, texelCoord, 0);
		float z     =texelFetch(depthtex0, texelCoord, 0).r;
		float dither=BlueNoise(gl_FragCoord.xy);
	    	  dither=animateDither(dither);

		vec4 screenPos =vec4(texCoord, z, 1.0);
		vec4 viewPos   =gbufferProjectionInverse * (screenPos * 2.0 - 1.0);
		     viewPos  /=viewPos.w;

		vec3 nViewPos=normalize(viewPos.xyz);
		vec3 worldPos=ViewToWorld(viewPos.xyz);
		vec4 cloud = vec4(0.0);
		float NdotS = clamp01(dot(nViewPos, sunVec));

		#ifdef OUTLINE_ENABLED
			vec4 outerOutline = vec4(0.0), innerOutline = vec4(0.0);
			Outline(color.rgb, false, outerOutline, innerOutline);

			color.rgb = mix(color.rgb, innerOutline.rgb, innerOutline.a);
		#endif

		if (z < 1.0){

			#if (defined ADVANCED_MATERIALS || defined GLOWING_ENTITY_FIX || defined AO)
			float isGlowing = texelFetch(colortex3, texelCoord, 0).b;
			#endif

			#ifdef AO
			float ao = clamp01(GetAmbientOcclusion(z));
			float ambientOcclusion = ao;
			#endif

			#if (defined ADVANCED_MATERIALS && defined REFLECTION_SPECULAR)
			float smoothness = 0.0, skyOcclusion = 0.0, metalness = 0.0;
			vec3 normal = vec3(0.0), fresnel3 = vec3(0.0);

			GetMaterials(smoothness, skyOcclusion, normal, fresnel3, texCoord);
			float smoothnessP = smoothness;

		if (smoothness > 0.0){
				vec4 reflection   =vec4(0.0);
				vec3 skyReflection=vec3(0.0);

				float cloudMixRate= 1.0;
				float ssrMask = clamp01(length(fresnel3) * 400 - 1.0);
				if(ssrMask > 0.0){

				#ifdef REFLECTION_ROUGH
					float roughness=1.0 - smoothnessP;

					roughness*=roughness;
					roughness*=roughness;

					vec3 roughPos   =worldPos + cameraPosition;
					     roughPos  *=1000.0;
					vec3 roughNoise =texture2D(noisetex, roughPos.xz + roughPos.y).rgb;
					     roughNoise =ROUGH_NOISE * (roughNoise - vec3(0.5));

					roughNoise*=roughness;

					normal    +=roughNoise;
					reflection =RoughReflection(viewPos.xyz, normal, dither, smoothness);
				#else
					reflection =RoughReflection(viewPos.xyz, normal, dither, smoothness);
				#endif

				reflection.a *= ssrMask;
				}

				if (reflection.a < 1.0){
					#if defined (OVERWORLD)
						vec3 skyRefPos    =reflect(nViewPos, normal);
							 skyReflection=GetSkyColor(skyRefPos, true);

						#ifdef REFLECTION_ROUGH
							cloudMixRate = smoothness * smoothness * (3.0 - 2.0 * smoothness);
						#endif

						#ifdef METAL_AURORA_REFLECTION
							#ifdef AURORA
							if (moonVisibility > 0.0){
								skyReflection+=DrawAurora(skyRefPos * 100.0, dither, 6) * cloudMixRate;
							}
							#endif
						#endif

						#ifdef METAL_CLOUDS_REFLECTION
							#if REALISTIC_CLOUDS == 1
									 cloud        =DrawCloud(skyRefPos * 100.0, dither, lightCol, ambientCol, 4);
									 skyReflection=mix(skyReflection, cloud.rgb, cloud.a * cloudMixRate);
							#endif
						#endif

						float NoU            =clampInv11(dot(normal, upVec));
						float NoE            =clampInv11(dot(normal, eastVec));
						float vanillaDiffuse =computeVanillaDiffuse(NoU, NoE);

						#ifdef CLASSIC_EXPOSURE
							skyReflection *= 4.0 - 3.0 * eBS;
						#endif

						skyReflection = mix(vanillaDiffuse * minLightCol * ((isEyeInWater == 1) ? MINLIGHT_U_I : MINLIGHT_I),
										skyReflection, skyOcclusion);

					#elif defined (NETHER)
						skyReflection=netherCol.rgb * 0.2;

					#elif defined (END)
						skyReflection=endCol.rgb * 0.1;
					#endif
				}

				reflection.rgb=max(mix(skyReflection, reflection.rgb, reflection.a), vec3(0.0));

				color.rgb = clamp01(color.rgb * (1.0 - fresnel3 * 0.5 * (1.0 - metalness)) + reflection.rgb * (fresnel3 * SMOOTHNESS_METAL_REFLECTION_STRENGTH));
			}

			#endif

			#ifdef GLOWING_ENTITY_FIX
				if (isGlowing > 0.9975) {
					const vec2 glowOutlineOffsets[16] = vec2[16](
												  		vec2( 0.0, -1.0),
												  		vec2(-1.0,  0.0),
												 		vec2( 1.0,  0.0),
												 		vec2( 0.0,  1.0),
												 		vec2(-1.0, -2.0),
												 		vec2( 0.0, -2.0),
											 	  		vec2( 1.0, -2.0),
												  		vec2(-2.0, -1.0),
												 		vec2( 2.0, -1.0),
												 		vec2(-2.0,  0.0),
												  		vec2( 2.0,  0.0),
												  		vec2(-2.0,  1.0),
												 		vec2( 2.0,  1.0),
												  		vec2(-1.0,  2.0),
												  		vec2( 0.0,  2.0),
												 		vec2( 1.0,  2.0)
					);

						for(int i = 0; i < 16; i++) {
							vec2  glowOffset=glowOutlineOffsets[i] / vec2(viewWidth, viewHeight);
							float glowSample=texture2D(colortex3, texCoord.xy + glowOffset).b;
							if(glowSample < 0.5){
								if  (i < 8) color.rgb=vec3(0.1725, 0.1686, 0.1686);
								else        color.rgb=vec3(0.6078, 0.6078, 0.6078);
								break;
							}
						}
				}
			#endif

			#ifdef AO
				if (isGlowing < 0.505)
					color.rgb *= ambientOcclusion;
			#endif

			#ifdef FULL_BORDER
				color.rgb = fullborder(color.rgb, depthtex1, texCoord, viewWidth, viewHeight, near, far);
			#endif

			#ifdef FOG
				color.rgb = Fog(color.rgb, viewPos.xyz);
			#endif

		}else{

			#ifdef SKY_BLUR
				const vec2 skyBlurOffset[2] = vec2[2](vec2( 0.0,  1.0),
											  		  vec2(-1.0,  0.0));
				vec2 wh = vec2(viewWidth, viewHeight);
				vec3 skyBlurColor = color.rgb;
				for(int i = 0; i < 2; i++) {
					vec2 texCoordM = texCoord + skyBlurOffset[i] / wh;
					float depth = texture2D(depthtex0, texCoordM).r;
					if (depth == 1.0) skyBlurColor += texture2D(colortex0, texCoordM).rgb;
					else skyBlurColor += color.rgb;
				}
				color.rgb = skyBlurColor / 2.0;
			#endif

			#ifdef NETHER
				color.rgb = netherCol.rgb * NETHER_FOG_COLOR_M;
			#endif

			#ifdef END

				#ifdef ENDER_SKY_COLOR_CUSTOM
					color.rgb = vec3(endColCustom.rgb * (0.035 + 0.02 * screenBrightness2));
					color.rgb = pow(color.rgb, vec3(1.0)) * 10;
				#else
					color.rgb = vec3(endCol.rgb * (0.035 + 0.02 * screenBrightness2));
					color.rgb = pow(color.rgb, vec3(1.0)) * 10;
				#endif

				#ifdef AURORA_END
					color.rgb = DrawAurora(viewPos.xyz, dither, 20);
				#endif

				#ifdef END_STARS
					color.rgb = DrawEndStars(color.rgb, viewPos.xyz);
				#endif

				#ifdef SHOOTING_STARS_END
					#if NUM_SHOOTING_STARS >= 1
						color.rgb = DrawShootingStar(color.rgb, viewPos.xyz, 1.0, dither);
					#elif NUM_SHOOTING_STARS >= 2
						color.rgb = DrawShootingStar(color.rgb, viewPos.xyz, 1.2, dither);
					#elif NUM_SHOOTING_STARS >= 3
						color.rgb = DrawShootingStar(color.rgb, viewPos.xyz, 1.4, dither);
					#elif NUM_SHOOTING_STARS >= 4
						color.rgb = DrawShootingStar(color.rgb, viewPos.xyz, 1.6, dither);
					#endif
				#endif

				#ifdef LOST_GLARE
					color.rgb = LostGlare(color.rgb, nViewPos);
				#endif

				#ifdef BLACK_HOLE
					color.rgb = getBlackHole(color.rgb, worldPos, NdotS);
				#endif

			#endif

			#ifdef UNDERWATER_SKY_OPACITY
				if (isEyeInWater == 1) {
					float NdotU2 = Max0(dot(nViewPos, upVec));
					color.rgb = mix(color.rgb, 0.1 * pow(rawWaterColorSqrt.rgb * (1.0 - blindFactor), vec3(2.0)), 1 - NdotU2 * NdotU2);
					color.rgb *= UNDERWATER_SKY_BRIGHTNESS;
				}
			#endif

			if (isEyeInWater == 2){

				color.rgb = vec3(1.0, 0.3, 0.01);

			}

			#if MC_VERSION >= 11900
			if (blindFactor > 0.0 || darknessFactor > 0.0) color.rgb *= 1.0 - max(blindFactor, darknessFactor);
			#else
			if (blindFactor > 0.0) color.rgb *= 1.0 - blindFactor;
			#endif

		}

		#ifdef OUTLINE_ENABLED
			color.rgb = mix(color.rgb, outerOutline.rgb, outerOutline.a);
		#endif

		vec3 reflectionColor = pow(color.rgb, vec3(0.125)) * 0.5;

		/*DRAWBUFFERS:05*/
		gl_FragData[0] = vec4(color);
		gl_FragData[1] = vec4(reflectionColor, float(z < 1.0));

	}

#endif

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

	//Program//
	void main(){
		texCoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;

		gl_Position=ftransform();

		upVec=normalize(gbufferModelView[1].xyz);
		eastVec=normalize(gbufferModelView[0].xyz);
		vec2 sunRotationData = getSunRotationData();
		vec3 usunvec = getUsunvec(sunRotationData);
		sunVec = getSunVec(usunvec, sunRotationData);

	}

#endif
