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

//Settings//

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

#include "/settings/globalSettings.glsl"

//Varyings//
varying vec2 texCoord;
varying vec3 sunVec, upVec, eastVec;
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;

	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  = 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( 1.0,  0.0),
		vec2( 0.0,  1.0),
		vec2(-1.0,  0.0),
		vec2( 0.0, -1.0)
	);

	#ifdef GLOWING_ENTITY_FIX
	vec2 glowOffsets[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)
	);
	#endif

	//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 GLOWING_ENTITY_FIX
	void GlowOutline(inout vec3 color){
			for(int i = 0; i < 16; i++){
				vec2  glowOffset=glowOffsets[i] / vec2(viewWidth, viewHeight);
				float glowSample=texture2D(colortex3, texCoord.xy + glowOffset).b;
				if(glowSample < 0.5){
					if  (i < 8) color.rgb=vec3(0.05);
					else color.rgb       =vec3(0.4118, 0.4118, 0.4118);
					break;
				}
			}
		}
	#endif

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

			#if  AO_QUALITY ==1 && AA > 0
			vec2 halfView    =vec2(viewWidth, viewHeight) / 2.0;
			vec2 coord1      =(floor(texCoord * halfView + 1.0)) / halfView;
			vec2 coord2      =texCoord * 0.5;
			#else
				vec2 coord1=texCoord;
				vec2 coord2=texCoord;
			#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

	#ifdef AURORA
	#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 defined OVERWORLD && REALISTIC_CLOUDS > 0
	#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

		#if defined LOST_GLARE && (!defined LIGHT_SHAFT && defined LIGHT_SHAFT_END || defined LIGHT_SHAFT && defined LIGHT_SHAFT_END)
		#include "/lib/atmospherics/lostglare.glsl"
		#elif defined LOST_GLARE && defined LIGHT_SHAFT && !defined LIGHT_SHAFT_END
		#endif

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

		#ifdef AURORA_END
		#include "/lib/atmospherics/auroraEnd.glsl"
		#endif
	#endif

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

		#if AA > 1
			dither = fract(16.0 * frameTimeCounter + dither);
		#endif

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

		vec3 nViewPos=normalize(viewPos.xyz);

		#if defined LOST_GLARE && defined BLACK_HOLE && defined END
			vec3 worldPos = mat3(gbufferModelViewInverse) * viewPos.xyz;
			float VoL = clamp01(dot(nViewPos, sunVec));
		#elif !defined LOST_GLARE && defined BLACK_HOLE && defined END|| defined LOST_GLARE && !defined BLACK_HOLE && defined END
		#endif

		#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 = texture2D(colortex3, texCoord).b;
			#endif

			vec3 worldPos=ViewToWorld(viewPos.xyz);

			#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;
			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 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){
					#ifdef OVERWORLD
						vec3 skyRefPos    =reflect(nViewPos, normal);
							skyReflection=GetSkyColor(skyRefPos, true);

						#ifdef REFLECTION_ROUGH
							float cloudMixRate=pow2(smoothness) * (3.0 - 2.0 * smoothness);
						#else
							float cloudMixRate=1.0;
						#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 > 0
								vec4 cloud        =DrawCloud(skyRefPos * 100.0, dither, lightCol, ambientCol, 2);
									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);

					#endif

					#ifdef NETHER
						skyReflection=netherCol.rgb * 0.2;
					#endif

					#ifdef END
						skyReflection=endCol.rgb * 0.1;
					#endif
				}

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

				color.rgb+=reflection.rgb * (fresnel3 * SMOOTHNESS_METAL_REFLECTION_STRENGTH);
			}

			#endif

			#ifdef GLOWING_ENTITY_FIX
				if (isGlowing > 0.9975){
					GlowOutline(color.rgb);
				}
			#endif

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

			#ifdef FULL_BORDER
				color.rgb = fullborder(color.rgb);
			#endif

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

		}else{

			#ifdef SKY_BLUR
				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 += textureLod(colortex0, texCoordM, 0).rgb;
					else skyBlurColor += color.rgb;
				}
				color.rgb = skyBlurColor / 4.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 = DrawEndAurora(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

				#if defined END && defined LIGHT_SHAFT_END && defined LOST_GLARE
					color.rgb = LostGlare(color.rgb, viewPos.xyz);
				#endif

				#if defined LOST_GLARE && defined BLACK_HOLE
					getBlackHole(color.rgb, worldPos, VoL);
				#elif !defined LOST_GLARE && defined BLACK_HOLE || defined LOST_GLARE && !defined BLACK_HOLE
				#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 (blindFactor > 0.0 || darknessFactor > 0.0) color.rgb *= 1.0 - max(blindFactor, darknessFactor);
		}

		#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

	//Uniforms//
	uniform mat4 gbufferModelView;

	//Common Variables//
	#ifdef OVERWORLD
		float timeAngleM = timeAngle;
	#else
		float timeAngleM = 0.25;
	#endif

	//Include//
	#include "/lib/util/moonrot.glsl"

	//Program//
	void main(){
		texCoord=gl_MultiTexCoord0.xy;

		gl_Position=ftransform();

		const vec2 sunRotationData=vec2(cos(sunPathRotation * 0.01745329251994),-sin(sunPathRotation * 0.01745329251994));
		float ang                 =fract(timeAngleM - 0.25);
		      ang                 =(ang+(cos(ang * PI) * -0.5 + 0.5 - ang) / 3.0) * TAU;
		vec3  usunvec             =vec3(-sin(ang), cos(ang) * sunRotationData);

		sunVec=normalize((gbufferModelView * vec4(usunvec * 2000.0, 1.0)).xyz);

		upVec=normalize(gbufferModelView[1].xyz);
		eastVec=normalize(gbufferModelView[0].xyz);
	}

#endif
