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

//Settings//

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

#include "/settings/globalSettings.glsl"

#include "/settings/color/colorGradingSettings.glsl"

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

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

	//Uniforms//
	uniform sampler2D colortex0;
	uniform sampler2D colortex1;
	uniform sampler2D colortex2;
	uniform sampler2D noisetex;
	uniform sampler2D depthtex0;

	uniform int isEyeInWater;

	uniform int moonPhase;
	#define UNIFORM_MOONPHASE

	uniform float frameTimeCounter;
	uniform float rainStrengthS;
	uniform float screenBrightness;
	uniform float viewWidth, viewHeight, aspectRatio;

	uniform ivec2 eyeBrightnessSmooth;

	#ifdef DIRTY_LENS
		uniform sampler2D depthtex2;
	#endif

	#if defined COLOR_START || defined BLOOM_START
		uniform float starter;
	#endif

	#ifdef ENABLE_DARKNESS_EFFECT
		#if MC_VERSION >= 11900
			uniform float darknessFactor;
		#endif
	#endif

	#if defined (OVERWORLD) && defined LENS_FLARE
		uniform float blindFactor;
		uniform vec3 sunPosition;
		uniform mat4 gbufferProjection;
	#endif

	#ifdef UNDERGROUND_SKY
	uniform vec3 cameraPosition;
	#endif

	//Optifine Constants//
	const bool colortex2Clear = false;

	#if AUTO_EXPOSURE > 0
		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);
	float pw               =1.0 / viewWidth;
	float ph               =1.0 / viewHeight;

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

	vec3 GetBloomTile(float lod, vec2 coord, vec2 offset) {
		float scale        =exp2(lod);
		float resScale     =1.25 * min(360.0, viewHeight) / viewHeight;
		vec2  centerOffset =vec2(0.125 * pw, 0.125 * ph);
		vec3  bloom        =texture2D(colortex1, (coord / scale + offset) * resScale + centerOffset).rgb;
		      bloom       *=bloom; bloom*=bloom * 32.0;
		return bloom;
	}

	void Bloom(inout vec3 color, vec2 coord){

				vec3 blur1=GetBloomTile(1.0, coord, vec2(0.0      , 0.0   ));
				vec3 blur2=GetBloomTile(2.0, coord, vec2(0.51     , 0.0   ));
				vec3 blur3=GetBloomTile(3.0, coord, vec2(0.51     , 0.26  ));
				vec3 blur4=GetBloomTile(4.0, coord, vec2(0.645    , 0.26  ));
				vec3 blur5=GetBloomTile(5.0, coord, vec2(0.7175   , 0.26  ));
				vec3 blur6=GetBloomTile(6.0, coord, vec2(0.645    , 0.3325)) * 0.9;
				vec3 blur7=GetBloomTile(7.0, coord, vec2(0.670625 , 0.3325)) * 0.7;

			#ifdef DIRTY_LENS
				float newAspectRatio =1.777777777777778 / aspectRatio;
				vec2  scale          =vec2(max(newAspectRatio, 1.0), max(1.0 / newAspectRatio, 1.0));
				float dirt           =texture2D(depthtex2, (coord - 0.5) / scale + 0.5).r;
				      dirt          *=length(blur6 / (1.0 + blur6)) * DIRTY_LENS_STRENGTH;
				      blur3 *= dirt *  2.0 + 1.0;
					  blur4 *= dirt *  4.0 + 1.0;
					  blur5 *= dirt *  8.0 + 1.0;
					  blur6 *= dirt * 16.0 + 1.0;
					  blur7 *= dirt * 32.0 + 1.0;
			#endif

			#if BLOOM_RADIUS == 1
				vec3 blur = blur1 * 0.667;
			#elif BLOOM_RADIUS == 2
				vec3 blur = (blur1 + blur2) * 0.37;
			#elif BLOOM_RADIUS == 3
				vec3 blur = (blur1 + blur2 + blur3) * 0.27;
			#elif BLOOM_RADIUS == 4
				vec3 blur = (blur1 + blur2 + blur3 + blur4) * 0.212;
			#elif BLOOM_RADIUS == 5
				vec3 blur = (blur1 + blur2 + blur3 + blur4 + blur5) * 0.175;
			#elif BLOOM_RADIUS == 6
				vec3 blur = (blur1 + blur2 + blur3 + blur4 + blur5 + blur6) * 0.151;
			#elif BLOOM_RADIUS == 7
				vec3 blur = (blur1 + blur2 + blur3 + blur4 + blur5 + blur6 + blur7) * 0.137;
			#endif

			vec3 dirtblur = (blur1 + blur2 + blur3 + blur4 + blur5 + blur6 + blur7) * 0.137;

		#ifndef DIRTY_LENS
			blur = mix(blur,dirtblur,0.0);
		#else
			blur = mix(blur,dirtblur,dirt);
		#endif


		#if BLOOM < 1
			float bloomStrength = 0.0;

		#elif BLOOM > 0
			float bloomStrength = 0.85;

			#ifdef OVERWORLD
				bloomStrength *= OVERWORLD_BLOOM_STRENGTH;
			#endif

			#ifdef NETHER
				bloomStrength *= NETHER_BLOOM_STRENGTH;
			#endif

			#ifdef END
				bloomStrength *= END_BLOOM_STRENGTH;
			#endif

		#endif

		#if defined LIGHT_JITTER && (defined BLOOM_JITTER || BLOOM > 0)
			const float speed=JITTER_SPEED;
			float jitter1       =1.0-sin(frameTimeCounter*1.4*speed+cos(frameTimeCounter*6.9*speed)-sin(frameTimeCounter*9.5*speed))*JITTER_STRENGTH1;
			float jitter2       =1.0-sin(frameTimeCounter*1.4*speed+cos(frameTimeCounter*3.0*speed)-sin(frameTimeCounter*4.5*speed))*JITTER_STRENGTH2;
			float jitter3       =1.0-sin(frameTimeCounter*1.4*speed+cos(frameTimeCounter*1.5*speed)-sin(frameTimeCounter*2.5*speed))*JITTER_STRENGTH3;
			      bloomStrength*=jitter1 * jitter2 * jitter3;
		#endif

		#ifdef ENABLE_DARKNESS_EFFECT
			#if MC_VERSION >= 11900
				bloomStrength = mix(bloomStrength, WARDEN_BLOOM_MULTIPLIER, darknessFactor);
			#endif
		#endif

		#if defined BLOOM_START && BLOOM > 0

			#ifdef ANIM_MOVE
				float animate = min(starter, 0.1) * 10.0;
			#else
				float animate = 0.0;
			#endif

			bloomStrength *= BLOOM_S_STRENGTH;
			bloomStrength = mix(min(bloomStrength,5), 1.0, animate);
		#endif

		color = mix(color, blur, 0.2 * bloomStrength);

	}

	void AutoExposure(inout vec3 color, inout float exposure, float tempExposure) {
		float exposureLod = log2(viewWidth * 0.7);

		exposure = length(textureLod(colortex0, vec2(0.5), exposureLod).rgb);
		exposure = max(exposure, 0.0001);

		#if AUTO_EXPOSURE == 1
			color /= 2.0 * tempExposure + 0.125;
		#else
			color /= 3.0 * tempExposure;
		#endif
	}

	void ColorGrading(inout vec3 color){
		vec3 cgColor = 	pow(color.r, CG_RC) * pow(vec3(CG_RR, CG_RG, CG_RB) / 255.0, vec3(2.2)) +
						pow(color.g, CG_GC) * pow(vec3(CG_GR, CG_GG, CG_GB) / 255.0, vec3(2.2)) +
						pow(color.b, CG_BC) * pow(vec3(CG_BR, CG_BG, CG_BB) / 255.0, vec3(2.2));
		vec3 cgMin = 	pow(vec3(CG_RM, CG_GM, CG_BM) / 255.0, vec3(2.2));
		color = (cgColor * (1.0 - cgMin) + cgMin) * vec3(CG_RI, CG_GI, CG_BI);

		vec3 cgTint = 	pow(vec3(CG_TR, CG_TG, CG_TB) / 255.0, vec3(2.2)) * GetLuminance(color) * CG_TI;
		color = mix(color, cgTint, CG_TM);
	}

	void BSLTonemap(inout vec3 color) {
		color = color * exp2(2.0 + TONEMAP_EXPOSURE);
		color = color / pow(pow(color, vec3(TONEMAP_WHITE_CURVE)) + 1.0, vec3(1.0 / TONEMAP_WHITE_CURVE));
		color = pow(color, mix(vec3(TONEMAP_LOWER_CURVE), vec3(TONEMAP_UPPER_CURVE), sqrt(color)));
	}

	void ColorSaturation(inout vec3 color){
		float grayVibrance = (color.r + color.g + color.b) / 3.0;
		float graySaturation = grayVibrance;
		if (SATURATION < 1.00) graySaturation = GetLuminance(color);

		float mn       =min(color.r, min(color.g, color.b));
		float mx       =max(color.r, max(color.g, color.b));
		float sat      =(1.0 - (mx - mn)) * (1.0 - mx) * grayVibrance * 5.0;
		vec3  lightness=vec3((mn + mx) * 0.5);

		color = mix(color, mix(color, lightness, 1.0 - VIBRANCE), sat);
		color = mix(color, lightness, (1.0 - lightness) * (2.0 - VIBRANCE) / 2.0 * abs(VIBRANCE - 1.0));
		color = color * SATURATION - graySaturation * (SATURATION - 1.0);
	}


	/*////////////////////////////////////////////////////////////////////////
	//////////////////////////////BOTW_MAPPING///////////////////////////////
	//////////////////////////////////////////////////////////////////////*/

	#if defined (OVERWORLD) && defined BOTW
	vec3 BOTWTonemap(vec3 color){
		color=pow(color,vec3(1./1.2));

		float mixrgb=(color.r + color.g + color.b)/3.5;
		float weight=BOTWSAT + (1.0 - pow(1.0 - 1.0 * mixrgb, 2.0)) * 0.08;

		return mix(vec3(mixrgb), color, weight);
	}
	#endif

	/*//////////////////////////////////////////////////////////////////////////
	/////////////////////////////////HDR///////////////////////////////////////
	////////////////////////////////////////////////////////////////////////*/

	#ifdef HDR
	vec3 LexHDR(in vec3 color){
		vec3 LexHDRImage;

		vec3 ExpositionGlobal=color * GLOBAL_EXPOSITION;

		vec3 SousExposition=color / SOUS_EXPOSITION;

		LexHDRImage=mix(SousExposition, ExpositionGlobal, color);

		return LexHDRImage;
	}
	#endif

	/*//////////////////////////////////////////////////////////////////////////
	/////////////////////////////////LENS_FLARE/////////////////////////////////
	////////////////////////////////////////////////////////////////////////*/

	#if defined (OVERWORLD) && defined LENS_FLARE
		vec2 GetLightPos(){
			vec4 tpos     =gbufferProjection * vec4(sunPosition, 1.0);
				 tpos.xyz/=tpos.w;
			return tpos.xy / tpos.z * 0.5;
		}
	#endif

	//Includes//
	#include "/lib/color/lightColor.glsl"

	#if defined (OVERWORLD) && defined LENS_FLARE
		#include "/lib/post/lensFlare.glsl"
	#endif

	//Program//
	void main(){
		vec2 newTexCoord = texCoord;

		vec2 filmGrainCoord = texCoord * vec2(viewWidth, viewHeight) / 512.0;
		vec3 filmGrain = texture2D(noisetex, filmGrainCoord).rgb;

		vec4 color = texture2D(colortex0, newTexCoord).rgba;

		#if AUTO_EXPOSURE > 0
			float tempExposure = texture2D(colortex2, vec2(pw, ph)).r;
		#endif

		#if defined (OVERWORLD) && defined LENS_FLARE
			float tempVisibleSun = texture2D(colortex2, vec2(3.0 * pw, ph)).r;
		#endif

		vec3 temporalColor = vec3(0.0);

		#if AA > 1
			temporalColor = texture2D(colortex2, texCoord).gba;
		#endif

		#if BLOOM > 0
			Bloom(color.rgb, newTexCoord);
		#endif

		#if AUTO_EXPOSURE > 0
			float exposure = 1.0;
			AutoExposure(color.rgb, exposure, tempExposure);
		#endif

		#ifdef COLOR_GRADING
			ColorGrading(color.rgb);
		#endif

		BSLTonemap(color.rgb);

		#if defined (OVERWORLD) && defined BOTW
			color.rgb=clamp01(BOTWTonemap(color.rgb));
		#endif

		#ifdef HDR
			color.rgb=LexHDR(color.rgb);
		#endif

		#if defined (OVERWORLD) && defined LENS_FLARE
			vec2  lightPos=GetLightPos();
			float truePos =sign(sunVec.z);

			#ifdef NEWMOON_DISABLER_STUFF
				float moonPhaseOffsetLensFlare =1.0 - (float((moonPhase == 4)) * (1.0- sunVisibility));
			#else
				float moonPhaseOffsetLensFlare = 1.0;
			#endif

			float visibleSun =float(texture2D(depthtex0, lightPos + 0.5).r >= 1.0);
					visibleSun*=max(1.0 - isEyeInWater, eBS) * (1.0 - blindFactor) * (1.0 - rainStrengthS);

			#ifdef UNDERGROUND_SKY
				if (isEyeInWater<1){
				visibleSun *= mix(clamp01((cameraPosition.y - 48.0) / 16.0), 1.0, eBS);
				}
			#endif

			#ifdef ENABLE_DARKNESS_EFFECT
				#if MC_VERSION >= 11900
					visibleSun *= 1.0 - darknessFactor;
				#endif
			#endif

			float multiplier=0.0;

			multiplier = mix(mix(multiplier, tempVisibleSun * LENS_FLARE_STRENGTH_NIGHT * 0.6, 1.0) * moonPhaseOffsetLensFlare,
							 mix(multiplier, tempVisibleSun * LENS_FLARE_STRENGTH_DAY * 0.5, 1.0),
							 sunVisibility);

			if (multiplier > 0.001) LensFlare(color.rgb, lightPos, truePos, multiplier);
		#endif

		float temporalData=0.0;

		#if AUTO_EXPOSURE > 0
			if (texCoord.x < 2.0 * pw && texCoord.y < 2.0 * ph)
				temporalData=mix(tempExposure, sqrt(exposure), 0.016);
		#endif

		#if defined (OVERWORLD) && defined LENS_FLARE
			if (texCoord.x > 2.0 * pw && texCoord.x < 4.0 * pw && texCoord.y < 2.0 * ph)
				temporalData=mix(tempVisibleSun, visibleSun, 0.1);
		#endif

		#ifdef BSL_VIGNETTE
			color.rgb*=1.0 - length(texCoord.xy - 0.5) * FORCE_BSL_VIGNETTE * (1.0 - GetLuminance(color.rgb));
		#endif

		color.rgb=pow(color.rgb, vec3(1.0 / 2.2));

		ColorSaturation(color.rgb);

		color.rgb += (filmGrain - 0.25) / 128.0;

		/*DRAWBUFFERS:12*/
		gl_FragData[0] = clamp01(color);
		gl_FragData[1] = vec4(temporalData,temporalColor);
	}

#endif

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

	//Uniforms//
	uniform mat4 gbufferModelView;

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

	//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;
		      sunVec              =normalize((gbufferModelView * vec4(vec3(-sin(ang), cos(ang) * sunRotationData) * 2000.0, 1.0)).xyz);

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

#endif