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

//Settings//
#include "/lib/settings.glsl"

//Varyings//
varying vec2 texCoord;

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

//Uniforms//
uniform float viewWidth, viewHeight;
uniform float frameTimeCounter;

uniform ivec2 eyeBrightnessSmooth;

#if defined DOF || defined EXTRA_CIRCULAR_DOF
uniform float aspectRatio;
#endif

#ifdef DOF
uniform float centerDepthSmooth;
#endif

uniform mat4 gbufferProjection;

uniform sampler2D colortex0;
uniform sampler2D depthtex1;

#ifdef FLOU_EAU
uniform int isEyeInWater;
#endif

#ifdef DISTANCE_BLUR
uniform sampler2D depthtex0;
uniform mat4 gbufferProjectionInverse;
#endif

#if defined DISTANCE_BLUR || defined RAIN_BLUR_CAM
uniform float rainStrengthS2;
#endif

//Optifine Constants//
const bool colortex0MipmapEnabled = true;


//Common Functions//
#if AA >0
mat2 rotate(float angle) {
	return mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
}
#endif

#ifdef DOF
float GetCircleStandardDOF(float z, float centerDepthSmooth) {
	#if defined (NETHER) && (defined DOF || defined DISTANCE_BLUR)
	float DOF_STRENGTH = NETHER_DOF_STRENGTH;
	#endif
	#if defined (OVERWORLD) && (defined DOF || defined DISTANCE_BLUR)
	float DOF_STRENGTH = OVERWORLD_DOF_STRENGTH;
	#endif
	#if defined (END) && (defined DOF || defined DISTANCE_BLUR)
	float DOF_STRENGTH = END_DOF_STRENGTH;
	#endif

	float coc = abs(z - centerDepthSmooth) / 0.6;
	return coc / (1 / DOF_STRENGTH + coc);
}
#endif

//Includes//

#include "/lib/util/dither.glsl"
#include "/lib/util/dofOffsets.glsl"

//Common Functions//
float eBS = eyeBrightnessSmooth.y / 240.0;
float eBS2 = clamp(pow(eBS,8.0),0.0,1.0);

vec3 ChromaAberration(vec3 color) {
  vec2 offset = texCoord - 0.5;

  offset *= vec2(0.125) * CHROMA_STRENGTH;
  offset *= pow(distance(texCoord.st, vec2(1.0)), 2.5);
	#ifdef CHROMATIC_ABERRATION
		#if defined (OVERWORLD) && defined CHROMATIC_ABERRATION_O
			color.r = texture2D(colortex0, texCoord.st - offset).r;
			color.g = texture2D(colortex0, texCoord.st - (offset * 0.5)).g;
			color.b = texture2D(colortex0, texCoord.st).b;
		#elif defined (NETHER) && defined CHROMATIC_ABERRATION_N
			color.r = texture2D(colortex0, texCoord.st - offset).r;
			color.g = texture2D(colortex0, texCoord.st - (offset * 0.5)).g;
			color.b = texture2D(colortex0, texCoord.st).b;
		#elif defined (END) && defined CHROMATIC_ABERRATION_E
			color.r = texture2D(colortex0, texCoord.st - offset).r;
			color.g = texture2D(colortex0, texCoord.st - (offset * 0.5)).g;
			color.b = texture2D(colortex0, texCoord.st).b;
		#endif

	#endif
  return color;
}


vec3 DepthOfField(vec3 color, float z){
	
	#if defined (NETHER) && (defined DOF || defined DISTANCE_BLUR)
		float DISTANCE_BLUR_STRENGTH = NETHER_DISTANCE_BLUR_STRENGTH;
		float DOF_STRENGTH = NETHER_DOF_STRENGTH;
	#endif
	#if defined (OVERWORLD) && (defined DOF || defined DISTANCE_BLUR)
		float DISTANCE_BLUR_STRENGTH = OVERWORLD_DISTANCE_BLUR_STRENGTH;
		float DOF_STRENGTH = OVERWORLD_DOF_STRENGTH;
	#endif
	#if defined (END) && (defined DOF || defined DISTANCE_BLUR)
		float DISTANCE_BLUR_STRENGTH = END_DISTANCE_BLUR_STRENGTH;
		float DOF_STRENGTH = END_DOF_STRENGTH;
	#endif
	
	vec3 dof = vec3(0.0);
	float noise = InterleavedGradientNoise(gl_FragCoord.xy);
	float hand = float(z < 0.56);
	float fovScale = gbufferProjection[1][1] / 1.37;
	float fovScale2 = gbufferProjection[1][1] / 2.74;

	#if AA > 0
		noise = fract(noise + frameTimeCounter * 38.34718);
		mat2 rotation = rotate(noise * 2.0 * 3.1415);
	#endif

	#ifdef DISTANCE_BLUR
		float z0 = texture2D(depthtex0, texCoord.xy).r;
		vec4 screenPos = vec4(texCoord.x, texCoord.y, z0, 1.0);
		vec4 viewPos = gbufferProjectionInverse * (screenPos * 2.0 - 1.0);
		viewPos /= viewPos.w;
		
		float coc1 = max(min(length(viewPos) * 0.001, 0.1) * DISTANCE_BLUR_STRENGTH * (1.0 + (rainStrengthS2 * eBS * RAIN_BLUR_MULT)) / 256 , 0.001);
	#else
		float coc1 = 0;
	#endif
	
	#ifdef DOF
		float coc2 = GetCircleStandardDOF(z, centerDepthSmooth);
	
		#ifdef EXTRA_CIRCULAR_DOF
			float coc2dist = max(clamp(abs(1 - centerDepthSmooth), 0.0, 0.002) / EXTRA_CIRCULAR_DOF_STRENGTH * DOF_STRENGTH - 0.001, 0.001); // 0.6
			float coc2center = max(length((texCoord.xy*2.0-1.0)*vec2(aspectRatio,1.0)),0.001);
			coc2 = max(coc2,coc2dist*coc2center);
		#endif
	
	#else
		float coc2 = 0;
	#endif
	
			float coc = max(coc1,coc2);

	#ifdef FLOU_EAU
		if (float(isEyeInWater) > 0.9) coc = max(FACTEUR_FLOU_EAU / 2 ,coc);
	#endif
	
	#ifdef RAIN_BLUR_CAM
		vec2 spos = texCoord.xy *2.0 - 1.0;
		float blurVignette = clamp(pow(length(spos),RAIN_BLUR_CAM_INTENSITY),0.0,1.0);
		coc = max(coc, rainStrengthS2 * eBS2 * blurVignette * 20.0);
	#endif

	coc = coc / sqrt(coc * coc + 0.1);
	float chromaOffset = CHROMA_STRENGTH /100.0;
	chromaOffset *= coc;
	
	if (coc * 0.5 > 1.0 / max(viewWidth, viewHeight) && hand < 0.5){
		#if BLUR_QUALITY == 1
		int nbOffsets = 6;
		#endif
		#if BLUR_QUALITY == 2
		int nbOffsets = 9;
		#endif
		#if BLUR_QUALITY == 3
		int nbOffsets = 15;
		#endif
		#if BLUR_QUALITY == 4
		int nbOffsets = 18;
		#endif
		#if BLUR_QUALITY == 5
		int nbOffsets = 30;
		#endif
		#if BLUR_QUALITY == 6
		int nbOffsets = 45;
		#endif
		#if BLUR_QUALITY == 7
		int nbOffsets = 60;
		#endif
		#if BLUR_QUALITY == 8
		int nbOffsets = 75;
		#endif
		
		for(int i = 0; i < nbOffsets; i++) {
			vec2 offset = dofOffsets[i] * coc * 0.0085 * fovScale * vec2(1.0 / aspectRatio, 1.0);
			
			#if AA >0
			offset = rotation * offset;
			#endif

			float lod = log2(viewHeight * aspectRatio * coc * 0.75 / 320.0);
			#ifdef CHROMATIC_ABERRATION
				#ifdef OVERWORLD 
					#ifdef CHROMATIC_ABERRATION_O
						dof.r += texture2DLod(colortex0, texCoord + offset+vec2(chromaOffset*fovScale2,0.0), lod).r;
						dof.g += texture2DLod(colortex0, texCoord + offset, lod).g;
						dof.b += texture2DLod(colortex0, texCoord + offset-vec2(chromaOffset*fovScale2,0.0), lod).b;
					#else
						dof += texture2DLod(colortex0, texCoord + offset, lod).rgb;
					#endif
				#endif
				#ifdef NETHER 
					#ifdef CHROMATIC_ABERRATION_N
						dof.r += texture2DLod(colortex0, texCoord + offset+vec2(chromaOffset*fovScale2,0.0), lod).r;
						dof.g += texture2DLod(colortex0, texCoord + offset, lod).g;
						dof.b += texture2DLod(colortex0, texCoord + offset-vec2(chromaOffset*fovScale2,0.0), lod).b;
					#else
						dof += texture2DLod(colortex0, texCoord + offset, lod).rgb;
					#endif
				#endif
				#ifdef END 
					#ifdef CHROMATIC_ABERRATION_E
						dof.r += texture2DLod(colortex0, texCoord + offset+vec2(chromaOffset*fovScale2,0.0), lod).r;
						dof.g += texture2DLod(colortex0, texCoord + offset, lod).g;
						dof.b += texture2DLod(colortex0, texCoord + offset-vec2(chromaOffset*fovScale2,0.0), lod).b;
					#else
						dof += texture2DLod(colortex0, texCoord + offset, lod).rgb;
					#endif
				#endif
			#else
			dof += texture2DLod(colortex0, texCoord + offset, lod).rgb;
			#endif
		}
		dof /= nbOffsets;
	}
	else dof = color;
	return dof;
}

//Includes//
#ifdef BLACK_OUTLINE
#include "/lib/outline/outlineOffset.glsl"
#include "/lib/outline/depthOutline.glsl"
#endif


void main(){
	vec3 color = texture2DLod(colortex0,texCoord, 0.0).rgb;
	float z = texture2D(depthtex1, texCoord.st).x;

	
	#ifdef BLACK_OUTLINE
	DepthOutline(z);
	#endif

	if(z > 0.56){
		#ifdef CHROMATIC_ABERRATION

			color = ChromaAberration(color);

		#endif
	}

	#if (defined DOF || defined DISTANCE_BLUR) || (defined OVERWORLD || defined NETHER || defined END)
	color = DepthOfField(color, z);
	#endif

	/*DRAWBUFFERS:0*/
	gl_FragData[0]=vec4(color,1.0);
}

#endif

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

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

#endif