//Settings//
#include "/lib/settings.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

	#ifdef COLOR_START
		uniform float starter;
	#endif

	#if defined (OVERWORLD) && defined LENSFLARE
		#if LENS_FLARE > 0
			uniform float blindFactor;
			uniform vec3 sunPosition;
			uniform mat4 gbufferProjection;
		#endif
	#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 eBS2             =clamp01(pow(eBS,8.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        =texture(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   )) * 1.5;
				vec3 blur2=GetBloomTile(2.0, coord, vec2(0.51     , 0.0   )) * 1.2;
				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           =texture(depthtex2, (coord - 0.5) / scale + 0.5).r;
				      dirt          *=length(blur6 / (1.0 + blur6)) * DIRTY_LENS_STRENGTH;
				      blur3         *=dirt *  1.0 + 1.0;
				      blur4         *=dirt *  2.0 + 1.0;
				      blur5         *=dirt *  4.0 + 1.0;
				      blur6         *=dirt *  8.0 + 1.0;
				      blur7         *=dirt * 16.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_DIMENSION == 0
			float bloomStrength = 0.0;

		#elif BLOOM_DIMENSION == 1
			float bloomStrength = 0.5;

			#ifdef OVERWORLD
				bloomStrength *= clamp01(OVERWORLD_BLOOM_STRENGTH);
			#endif

			#ifdef NETHER
				bloomStrength *= clamp01(NETHER_BLOOM_STRENGTH);
			#endif

			#ifdef END
				bloomStrength *= clamp01(END_BLOOM_STRENGTH);
			#endif

		#endif

		#if defined BLOOM_START && BLOOM_DIMENSION > 0
			float animate = min(starter, 0.1) * 10.0;
			bloomStrength *= BLOOM_S_STRENGHT;
			bloomStrength = mix(bloomStrength, 1.0, animate);
		#endif

		#if defined LIGHT_JITTER && (defined BLOOM_JITTER || BLOOM_DIMENSION > 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


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

	}

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

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

		#if AUTO_EXPOSURE == 1
			color /= 2.0 * clamp(tempExposure, 0.001, 0.5) + 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

	////////////////////////////////////////////////////////////////////////
	///////////////////////////////LEX_AMBIANT/////////////////////////////
	//////////////////////////////////////////////////////////////////////

	#if defined (OVERWORLD) && defined LEX_AMBIANT

		vec4 getAmbient(vec4 color){

			vec4 tint=vec4(1.0, 1.0, 1.0, 1.0);
			float time;
			if(worldTime >= 22000.0)
			{// Lever du Soleil
				time=min(max((23000.0 - worldTime) / 1000.0, -1.0), 1.0);
				if(time > 0)
				{// Ciel commence à se colorier
					tint[0]=0.95 + (0.15 * (1.0 - time));
					tint[1]=0.95 - (0.05 * (1.0 - time));
					tint[2]=1.1  - (0.1  * (1.0 - time));
				}
				else
				{// Soleil Lever
					tint[0]=1.1 - (0.05 * (abs(time)));
					tint[1]=0.9 + (0.0  * (abs(time)));
					tint[2]=1.0 + (0.05 * (abs(time)));
				}
			}
			else if(worldTime>=12000.0)
			{// La nuit
				time=min(max((13000.0 - worldTime) / 1000.0, -1.0), 1.0);
				if(time > 0)
				{// Coucher de soleil
					tint[0]=1.1 + (0.15 * (1.0 - time));
					tint[1]=1.0 - (0.05 * (1.0 - time));
					tint[2]=0.9 - (0.15 * (1.0 - time));
				}
				else
				{// Commencement de la nuit
					tint[0]=1.25 - (0.3  * (abs(time)));
					tint[1]=0.95 - (0.0  * (abs(time)));
					tint[2]=0.75 + (0.35 * (abs(time)));
				}
			}
			else if(worldTime>=0.0)
			{// Jour, du crépuscule à l'aube
				time=min(max((6000.0 - worldTime)/6000.0, -1.0), 1.0);
				if(time > 0)
				{// Matin
					tint[0]=1.05 - (0.05 *(1.0 - time));
					tint[1]=0.9  + (0.1  *(1.0 - time));
					tint[2]=1.05 - (0.05 *(1.0 - time));
				}
				else
				{// Après_Midi
					tint[0]=1 + (0.1 * (abs(time)));
					tint[1]=1 - (0.0 * (abs(time)));
					tint[2]=1 - (0.1 * (abs(time)));
				}
			}
			return tint;
		}
	#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

	//////////////////////////////////////////////////////////////////////////
	/////////////////////////////////LENSFLARE///////////////////////////////
	////////////////////////////////////////////////////////////////////////

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

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


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

	#if defined (OVERWORLD) && defined LENSFLARE
		#if LENS_FLARE == 2
		#include "/lib/post/lensFlare2.glsl"
		#endif
	#endif

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

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

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

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

		vec3 temporalColor = vec3(0.0);

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

		#if BLOOM_DIMENSION > 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 LEX_AMBIANT
			color.rgba*=getAmbient(color.rgba);
		#endif

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

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

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

				float visibleSun =float(texture(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, eBS2);
					}
				#endif

				float multiplier=0.0;

				if (sunVisibility >0.0){
				multiplier=mix(multiplier, tempVisibleSun * LENS_FLARE_STRENGTH_DAY * 0.5, sunVisibility);
				}
				if (moonVisibility >0.0){
				multiplier=mix(multiplier, tempVisibleSun * LENS_FLARE_STRENGTH_NIGHT * 0.6, moonVisibility);
				}

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

			#endif
		#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 LENSFLARE
			#if LENS_FLARE > 0
				if (texCoord.x > 2.0 * pw && texCoord.x < 4.0 * pw && texCoord.y < 2.0 * ph)
					temporalData=mix(tempVisibleSun, visibleSun, 0.1);
			#endif
		#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);

		vec2 filmGrainCoord = texCoord * vec2(viewWidth, viewHeight) / 512.0;
		vec3 filmGrain = texture(noisetex, filmGrainCoord).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 * 3.14159265358979) * -0.5 + 0.5 - ang) / 3.0) * 6.28318530717959;
		      sunVec              =normalize((gbufferModelView * vec4(vec3(-sin(ang), cos(ang) * sunRotationData) * 2000.0, 1.0)).xyz);

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

#endif