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

//Settings//

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

#include "/settings/globalSettings.glsl"

//Varyings//
varying vec2 texCoord;
varying vec3 sunVec, upVec, eastVec;

//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 AO)
	uniform sampler2D colortex3;
	#endif

	#ifdef GLOWING_ENTITY_FIX
	uniform sampler2D colortex13;
	#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;
	const bool colortex6MipmapEnabled = true;
	#endif

	#if REFRACTION > 0
	const bool colortex14MipmapEnabled = true;
	#endif

	//Common Variables//
	float eBS = eyeBrightnessSmooth.y / 240.0;
	float sunVisibility  = clamp00125(dot( sunVec, upVec) + 0.0625) * 8.0;
	float moonVisibility = clamp00125(dot( -sunVec, upVec) + 0.0625) * 8.0;
	float screenBrightness2 = clamp01(screenBrightness);

	vec3 lightVec = sunVec * (1.0 - 2.0 * float(timeAngle > 0.5325 && timeAngle < 0.9675));

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

	vec2 aoOffsets[4] = vec2[4](
				vec2( 0.0,  1.0),
				vec2( 0.0, -1.0),
				vec2( 1.0,  0.0),
				vec2(-1.0,  0.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) * 0.5;
				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

		#ifdef FBM
		#include "/lib/atmospherics/fbm.glsl"
		#endif
	#endif

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

	//Program//
	void main() {
		vec4 color  = texture2D(colortex0, texCoord);
		float z     = texture2D(depthtex0, texCoord).r;

		float dither= Bayer64(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){

			#ifdef GLOWING_ENTITY_FIX
				float isGlowing = texture2D(colortex13, texCoord).r;
			#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;
							 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){
						vec3 skyRefPos    =reflect(nViewPos, normal);

						#if defined (OVERWORLD)

							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, 15) * (AURORA_REFLECTION_STRENGTH * 2.0) * cloudMixRate;
								}
								#endif
							#endif

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

							float NoU            =clampInv11(dot(normal, upVec));
							float NoE            =clampInv11(dot(normal, eastVec));
							float vanillaDiffuse =(0.25 * NoU + 0.75) + (0.5 - abs(NoE)) * (1.0 - abs(NoU)) * 0.1;
								vanillaDiffuse*=vanillaDiffuse;

							#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;
							skyRefPos *= 1000000.0;

							#if defined END_STARS_REF && defined END_STARS
								vec3 endStars = vec3(0.0);
								vec3 endStarsRef = DrawEndStars(color.rgb, skyRefPos);
								endStarsRef += endStars;
								skyReflection += endStarsRef * END_STARS_REF_STRENGTH_W * 0.5;
							#endif

							#if defined END_AURORA_REF && defined AURORA_END
								vec3 endAurora = vec3(0.0);
								vec3 endAuroraRef = DrawAurora(skyRefPos, dither, 15);
								endAuroraRef += endAurora;
								skyReflection += endAuroraRef * END_AURORA_REF_STRENGTH_W;
							#endif

							#if defined END_SHOOTING_STARS_REF && defined SHOOTING_STARS_END
								vec3 endShootingStar = vec3(0.0);
								vec3 endShootingStarRef = vec3(0.0);

								for (int i = 0; i < NUM_SHOOTING_STARS; i++) {
									float size = 1.0 + (i * 0.2);
									endShootingStarRef = DrawShootingStar(color.rgb, skyRefPos, size, dither);
								}

								endShootingStarRef += endShootingStar;
								skyReflection += endShootingStarRef * END_SHOOTING_STARS_REF_STRENGTH_W;
							#endif

							#if defined END_FBM_REF && defined FBM
								vec3 endFBM = vec3(0.0);
								vec3 endFBMRef = doFullSkyFBM(color.rgb, skyRefPos);
								endFBMRef += endFBM;
								skyReflection += endFBMRef * END_FBM_REF_STRENGTH_W * 0.5;
							#endif

						#endif
					}

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

					color.rgb = clamp01(color.rgb * (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)
					);

					#if defined (GLOWING_ENTITY_RGB)
						vec3 colorGlow = clamp01(vec3(hue2(frameTimeCounter * 0.1)));
            				 colorGlow = pow(colorGlow, vec3(2.2)) * 1.0 * 0.5;
					#else
						vec3 colorGlow = vec3(0.5);
					#endif

					for (int i = 0; i < 16; i++) {
						vec2  glowOffset = glowOutlineOffsets[i] / (vec2(viewWidth, viewHeight) * 0.5);
						float glowSample = texture2D(colortex13, texCoord.xy + glowOffset).r;
						if (glowSample < 0.5) {
							color.rgb = (i < 4) ? vec3(0.0) : colorGlow;
							break;
						}
					}
				}

			#endif

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

			#ifdef AO
				color.rgb *= GetAmbientOcclusion(z);
			#endif

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

		}else{

			#if SKY_BLUR == 1

				vec2 skyBlurOffset[4] = vec2[4](vec2( 0.0,  1.0),
										vec2( 0.0, -1.0),
										vec2( 1.0,  0.0),
										vec2(-1.0,  0.0));
				vec2 wh = vec2(viewWidth, viewHeight);
				vec3 skyBlurColor = color.rgb;
				for(int i = 0; i < 4; 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 = mix(color.rgb, skyBlurColor / 5.0, sunVisibility);

			#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, 15);
				#endif

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

				#ifdef SHOOTING_STARS_END
					for (int i = 0; i < NUM_SHOOTING_STARS; i++) {
						float size = 1.0 + (i * 0.2);
						color.rgb = DrawShootingStar(color.rgb, viewPos.xyz, size, dither);
					}
				#endif

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

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

				#ifdef FBM
					color.rgb = doFullSkyFBM(color.rgb, viewPos.xyz);
				#endif

			#endif

			#ifdef UNDERWATER_SKY_OPACITY
				if (isEyeInWater == 1) {
					float NdotU2 = Max0(dot(nViewPos, upVec));
					vec3 colorSkyOp = color.rgb;
					colorSkyOp.rgb = mix(color.rgb, 0.1 * pow(rawWaterColorSqrt.rgb * (1.0 - blindFactor), vec3(2.0)), 1 - NdotU2 * NdotU2);
					colorSkyOp.rgb *= UNDERWATER_SKY_BRIGHTNESS;
					color.rgb = mix(color.rgb, colorSkyOp.rgb, sunVisibility);
				}
			#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;

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

		#if REFRACTION > 0
		/* RENDERTARGETS: 0,5,14 */
		gl_FragData[2] = vec4(0.0, 0.0, 0.0, 1.0);
		#endif

	}

#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
