/*//////////////////////////////////////////////////////////////////////////////
//    ##      #####   ######   ######     ##     ####     #######  ##  ##     //
//   ####    ##   ##  # ## #    ##  ##   ####     ##       ##   #  ##  ##     //
//  ##  ##   #          ##      ##  ##  ##  ##    ##       ## #     ####      //
//  ##  ##    #####     ##      #####   ##  ##    ##       ####      ##       //
//  ######        ##    ##      ## ##   ######    ##   #   ## #     ####      //
//  ##  ##   ##   ##    ##      ##  ##  ##  ##    ##  ##   ##   #  ##  ##     //
//  ##  ##    #####    ####    #### ##  ##  ##   #######  #######  ##  ##     //
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
//      #####   ##   ##    ##     #####    #######  ######    #####           //
//     ##   ##  ##   ##   ####     ## ##    ##   #   ##  ##  ##   ##          //
//     #        ##   ##  ##  ##    ##  ##   ## #     ##  ##  #                //
//      #####   #######  ##  ##    ##  ##   ####     #####    #####           //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##          //
//          ##  ##   ##  ######    ##  ##   ## #     ## ##        ##          //
//     ##   ##  ##   ##  ##  ##    ## ##    ##   #   ##  ##  ##   ##          //
//      #####   ##   ##  ##  ##   #####    #######  #### ##   #####           //
/////(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 viewWidth, viewHeight, aspectRatio;

		uniform mat4 gbufferProjection;

		uniform sampler2D depthtex0;
		uniform sampler2D noisetex;
	#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 dither) {
			float ao = 0.0;
			float fovScaleAO = 0.0;
			int samples = 0;
			vec2 offset = vec2(0.0);

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

			#elif AO_QUALITY == 2
					samples=6;

			#elif AO_QUALITY == 3
					samples=12;
			#endif

			#if AO_QUALITY == 1 && AA > 0
			    coord       *=2.0;
			    coord       +=0.5 / vec2(viewWidth, viewHeight);
				if (any(greaterThan(coord, vec2(1.0))) || any(lessThan(coord, vec2(0.0)))) {
				return 1.0;
				}
			#endif

			#if AO_FOVSCALE ==1
				fovScaleAO = 3.425;
			#elif AO_FOVSCALE ==2
				fovScaleAO = 2.74;
			#elif AO_FOVSCALE ==3
				fovScaleAO = 2.055;
			#elif AO_FOVSCALE ==4
				fovScaleAO = 1.37;
			#elif AO_FOVSCALE ==5
				fovScaleAO = 0.685;
			#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.5 * vec2(1.0 / aspectRatio, 1.0) * fovScale / distScale;
			      scale      *=vec2(0.5, 1.0);

			for(int i = 0; i <= samples; i++) {
				offset = OffsetDist(i + dither, samples) * scale;
				float aosample = 0.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);

				   	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() {

		float ao = 1.0;

		#ifdef AO
			float dither = BlueNoise(gl_FragCoord.xy);
				  dither = animateDither(dither);
			ao = AmbientOcclusion(depthtex0, texCoord, dither);
		#endif

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

#endif

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

	//Program//
	void main() {
		#ifdef AO
			texCoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;

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

#endif