/*//////////////////////////////////////////////////////////////////////////////
//    ##      #####   ######   ######     ##     ####     #######  ##  ##     //
//   ####    ##   ##  # ## #    ##  ##   ####     ##       ##   #  ##  ##     //
//  ##  ##   #          ##      ##  ##  ##  ##    ##       ## #     ####      //
//  ##  ##    #####     ##      #####   ##  ##    ##       ####      ##       //
//  ######        ##    ##      ## ##   ######    ##   #   ## #     ####      //
//  ##  ##   ##   ##    ##      ##  ##  ##  ##    ##  ##   ##   #  ##  ##     //
//  ##  ##    #####    ####    #### ##  ##  ##   #######  #######  ##  ##     //
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
//      #####   ##   ##    ##     #####    #######  ######    #####           //
//     ##   ##  ##   ##   ####     ## ##    ##   #   ##  ##  ##   ##          //
//     #        ##   ##  ##  ##    ##  ##   ## #     ##  ##  #                //
//      #####   #######  ##  ##    ##  ##   ####     #####    #####           //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##          //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##          //
//     ##   ##  ##   ##  ##  ##    ## ##    ##   #   ##  ##  ##   ##          //
//      #####   ##   ##  ##  ##   #####    #######  #### ##   #####           //
/////(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, 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      =max(1.0 - 2.0 * far * abs(lz - samplez), 0.0);
					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 && defined CLOUDS
	#include "/lib/atmospherics/ovclouds.glsl"
	#endif

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

		#if defined END && defined LIGHT_SHAFT_END && defined LOST_GLARE
		#include "/lib/atmospherics/lostglare.glsl"
		#endif

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

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

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

		vec3 nViewPos=normalize(viewPos.xyz);
		float lViewPos=length(viewPos.xyz);
		float NdotU   =dot(nViewPos, upVec);

		#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);
			smoothness *= smoothness;


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

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


				#ifdef REFLECTION_ROUGH
					float roughness=1.0 - smoothness;

					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(normalize(viewPos.xyz), normal);
							skyReflection=GetSkyColor(skyRefPos, true);

						#ifdef REFLECTION_ROUGH
							float cloudMixRate=smoothness * 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, 8) * cloudMixRate;
							}
							#endif
						#endif

						#ifdef METAL_CLOUDS_REFLECTION
							#ifdef CLOUDS
								vec4 cloud        =DrawCloud(skyRefPos * 100.0, dither, lightCol, ambientCol, 3);
									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;

						skyReflection = mix(
							vanillaDiffuse * minLightCol * ((isEyeInWater == 1) ? MINLIGHT_U_I : MINLIGHT_I),
							skyReflection * (4.0 - 3.0 * eBS),
							skyOcclusion
						);
					#endif

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

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

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

				color.rgb+=reflection.rgb * (fresnel3 * SPECULAR_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 NETHER
				color.rgb = netherCol.rgb * 0.04;
			#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 END_STARS
					color.rgb = DrawEndStars(color.rgb, viewPos.xyz);
				#endif

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

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

			#ifdef UNDERWATER_SKY_OPACITY
			if (isEyeInWater == 1) {
						float NdotU2 = max(dot(normalize(viewPos.xyz), upVec), 0.0);
						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){
				#ifdef EMISSIVE_RECOLOR
				color.rgb = pow(blocklightCol / BLOCKLIGHT_I, vec3(4.0)) * 2.0;
				#else
				color.rgb = vec3(1.0, 0.3, 0.01);
				#endif
			}

			if (blindFactor > 0.0) color.rgb *= 1.0 - blindFactor;
		}

		#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 * 3.14159265358979) * -0.5 + 0.5 - ang) / 3.0) * 6.28318530717959;
		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
