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

vec2 OffsetDist(float x) {
	float n = fract(x * 8.0) * 3.1415;
    return vec2(cos(n), sin(n)) * x;
}

/*
  AO_CORE macro generates the ambient occlusion function body.
  Parameters:
    DEPTH_TEX     - sampler to read depth from
    LINEAR_DEPTH  - function/macro to linearize depth
    NEAR_PLANE    - near plane distance
    FAR_PLANE     - far plane distance
    RADIUS        - sampling radius
    HAND_CHECK    - whether to detect hand (1 or 0)
*/
#define AO_CORE(DEPTH_TEX, LINEAR_DEPTH, NEAR_PLANE, FAR_PLANE, RADIUS, HAND_CHECK) \
{ \
	float ao = 0.0; \
	float depth = texture2D(DEPTH_TEX, texCoord).r; \
	if(depth >= 1.0) return 1.0; \
	float hand = HAND_CHECK * float(depth < AO_HAND_DEPTH_THRESHOLD); \
	depth = LINEAR_DEPTH(depth); \
	dither = TemporalDither(dither); \
	float currentStep = AO_STEP_INCREMENT * dither + AO_STEP_INITIAL; \
	float radius = float(RADIUS); \
	float fovScale = gbufferProjection[1][1] / AO_FOV_REFERENCE; \
	float distScale = max((FAR_PLANE - NEAR_PLANE) * depth + NEAR_PLANE, AO_MIN_DIST); \
	vec2 scale = radius * vec2(1.0 / aspectRatio, 1.0) * fovScale / distScale; \
	float mult = (AO_STRENGTH_MULT / radius) * (FAR_PLANE - NEAR_PLANE) * (hand > 0.5 ? AO_HAND_SCALE : 1.0); \
	for(int i = 0; i < AO_SAMPLE_COUNT; i++) { \
		vec2 offset = OffsetDist(currentStep) * scale; \
		float angle = 0.0, dist = 0.0; \
		for(int j = 0; j < AO_DIR_COUNT; j++){ \
			float sampleDepth = LINEAR_DEPTH(texture2D(DEPTH_TEX, texCoord + offset).r); \
			float aoSample = (depth - sampleDepth) * mult / currentStep; \
			angle += clamp(0.5 - aoSample, 0.0, 1.0); \
			dist += clamp(0.25 * aoSample - 1.0, 0.0, 1.0); \
			offset = -offset; \
		} \
		ao += clamp(angle + dist, 0.0, 1.0); \
		currentStep += AO_STEP_INCREMENT; \
	} \
	ao *= AO_NORMALIZE; \
	return ao; \
}

float AmbientOcclusion(float dither)
AO_CORE(depthtex0, GetLinearDepth, near, far, AO_RADIUS, 1)

#ifdef DISTANT_HORIZONS
float DHAmbientOcclusion(float dither)
AO_CORE(dhDepthTex0, GetDHLinearDepth, dhNearPlane, dhFarPlane, AO_RADIUS_DH, 0)
#endif
