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

//Settings//

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

#include "/settings/globalSettings.glsl"

//Varyings//
#ifdef AO
varying vec2 texCoord;
#endif

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

	//Uniforms//
	#ifdef AO
		uniform float far, near;
		uniform float frameTimeCounter;
		uniform float viewWidth, viewHeight, aspectRatio;

		uniform mat4 gbufferProjection;

		uniform sampler2D depthtex0;
	#endif

	uniform int frameCounter;

	//Includes//
	#ifdef AO
		#include "/lib/util/dither.glsl"
	#endif

	//Common Functions//
	#ifdef AO

		float GetLinearDepth(float depth) {
		return (2.0 * near) / (far + near - depth * (far - near));
		}

		vec2 OffsetDist(float x, int s) {
			float n = fract(x * 1.414) * PI;
			return vec2(cos(n), sin(n)) * x / s;
		}

			float AmbientOcclusion(sampler2D depth, vec2 coord) {
			float ao = 0.0;
			float dither = Bayer64(gl_FragCoord.xy);

			#if AO_QUALITY == 1
				#if AA > 1
					int samples=12;
				#else
					int samples=4;
				#endif

			#elif AO_QUALITY ==2
			int samples     =4;

			#elif AO_QUALITY ==3
			int samples     =12;

			#elif AO_QUALITY ==4
			int samples     =24;
			#endif

			#if AO_QUALITY ==1 && AA > 0
			    coord       *=2.0;
			    coord       +=0.5 / vec2(viewWidth, viewHeight);

				if (coord.x < 0.0 || coord.x > 1.0 || coord.y < 0.0 || coord.y > 1.0) return 1.0;
			#endif

			#if AO_FOVSCALE ==1
				float fovScaleAO = 3.425;
			#elif AO_FOVSCALE ==2
				float fovScaleAO = 2.74;
			#elif AO_FOVSCALE ==3
				float fovScaleAO = 2.055;
			#elif AO_FOVSCALE ==4
				float fovScaleAO = 1.37;
			#elif AO_FOVSCALE ==5
				float fovScaleAO = 0.685;
			#endif

			#if AA > 1
				float ditherAnimate = 1.61803398875 * mod(float(frameCounter), 3600.0);
				dither = fract(dither + ditherAnimate);
			#endif

			float d=texture2D(depth, coord).r;
			if(d >= 1.0) return 1.0;
			float hand=float(d < 0.56);
			      d   =GetLinearDepth(d);

			float sampleDepth =0.0, angle=0.0, dist=0.0;
			float fovScale    =gbufferProjection[1][1] / fovScaleAO;
			float distScale   =max((far - near) * d + near, 6.0);
			vec2  scale       =0.4 * vec2(1.0 / aspectRatio, 1.0) * fovScale / distScale;
			      scale      *=vec2(0.5, 1.0);

			for(int i = 1; i <= samples; i++) {
				vec2 offset=OffsetDist(i + dither, samples) * scale;

				      sampleDepth           =GetLinearDepth(texture2D(depth, coord + offset).r);
				float aosample              =(far - near) * (d - sampleDepth) * 2.0;
				if    (hand > 0.5) aosample*=1024.0;
				      angle                 =clamp01(0.5 - aosample);
				      dist                  =clamp01(0.25 * aosample - 1.0);

				   sampleDepth           =GetLinearDepth(texture2D(depth, coord - offset).r);
				   aosample              =(far - near) * (d - sampleDepth) * 2.0;
				if (hand > 0.5) aosample*=1024.0;
				   angle                +=clamp01(0.5 - aosample);
				   dist                 +=clamp01(0.25 * aosample - 1.0);

				ao+=clamp01(angle + dist);
			}
			ao/=samples;

			return ao;
		}
	#endif

	//Program//
	void main() {
		#ifdef AO
			float ao = AmbientOcclusion(depthtex0, texCoord);
		#else
			float ao = 1.0;
		#endif

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

#endif

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

	//Uniforms//
	#ifdef AO
		uniform mat4 gbufferModelView;
	#endif

	//Common Variables//

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

			gl_Position = ftransform();
		#else
			gl_Position = vec4(0.0);
		#endif
	}

#endif