#include "/lib/common.glsl"

#define COMPOSITE15

#ifdef FSH

// VSH Data //
in vec2 texCoord;

// Uniforms //
uniform int frameCounter;

#ifdef MOTION_BLUR
uniform float frameTimeCounter;
#endif

uniform float viewWidth, viewHeight;
uniform float aspectRatio;

uniform sampler2D depthtex0;
uniform sampler2D depthtex1;
uniform sampler2D colortex1;
uniform sampler2D colortex2;

#ifdef DISTANT_HORIZONS
uniform sampler2D dhDepthTex0;
uniform mat4 dhProjectionInverse;
#endif

#ifdef VOXY
uniform sampler2D vxDepthTexOpaque, vxDepthTexTrans;
uniform mat4 vxProjInv;
#endif

#if defined MOTION_BLUR || defined TAA
uniform vec3 cameraPosition, previousCameraPosition;

uniform mat4 gbufferPreviousProjection;
uniform mat4 gbufferPreviousModelView, gbufferModelViewInverse;
#endif

uniform mat4 gbufferProjectionInverse;

// Includes //
#ifdef MOTION_BLUR
#include "/lib/util/bayerDithering.glsl"
#include "/lib/post/motionBlur.glsl"
#endif

#ifdef FXAA
#include "/lib/antialiasing/fxaa.glsl"
#endif

#ifdef TAA
#include "/lib/util/reprojection.glsl"
#include "/lib/antialiasing/taa.glsl"
#endif

#if defined TAA && (defined DISTANT_HORIZONS || defined VOXY)
float noxaraTemporalViewDistance(vec2 coord, float depth, mat4 inverseProjection) {
	if (depth >= 1.0) return 1e20;
	vec4 viewPosition = inverseProjection * vec4(coord * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
	return length(viewPosition.xyz / max(abs(viewPosition.w), 0.00001));
}
#endif

// Main //
void main() {
	#ifdef MOTION_BLUR
	float z1 = texture2D(depthtex1, texCoord).r;
	#endif

	#ifdef TAA
	float taaDepth = texture2D(depthtex0, texCoord).r;
	float taaReprojectionValidity = 1.0;
	#if defined DISTANT_HORIZONS || defined VOXY
	float vanillaTaaDistance = noxaraTemporalViewDistance(texCoord, taaDepth, gbufferProjectionInverse);
	#endif
	#ifdef DISTANT_HORIZONS
	float dhTaaDepth = texture2D(dhDepthTex0, texCoord).r;
	float dhTaaDistance = noxaraTemporalViewDistance(texCoord, dhTaaDepth, dhProjectionInverse);
	// Reject only when DH is the visible source; a nearer vanilla surface keeps
	// its valid TAA history even if a DH LOD exists behind it.
	taaReprojectionValidity *= float(dhTaaDistance >= vanillaTaaDistance - 0.01);
	#endif
	#ifdef VOXY
	float vxOpaqueTaaDepth = texture2D(vxDepthTexOpaque, texCoord).r;
	float vxTransTaaDepth = texture2D(vxDepthTexTrans, texCoord).r;
	float vxOpaqueTaaDistance = noxaraTemporalViewDistance(texCoord, vxOpaqueTaaDepth, vxProjInv);
	float vxTransTaaDistance = noxaraTemporalViewDistance(texCoord, vxTransTaaDepth, vxProjInv);
	float nearestVxTaaDistance = min(vxOpaqueTaaDistance, vxTransTaaDistance);
	// Voxy uses its own temporal transforms.  Reject history only where its
	// opaque or translucent geometry is actually in front of vanilla geometry.
	taaReprojectionValidity *= float(nearestVxTaaDistance >= vanillaTaaDistance - 0.01);
	#endif
	#endif

    vec3 color = texture2D(colortex1, texCoord).rgb;

	//Fast ApproXimate Anti-Aliasing
	#ifdef FXAA
		 color = FXAA311(color);	
	#endif

	//Motion Blur
	#ifdef MOTION_BLUR
		 color = getMotionBlur(color, z1);
	#endif

	//Temporal Anti-Aliasing
	vec4 previousColor = vec4(texture2D(colortex2, texCoord).r, 0.0, 0.0, 0.0);
	#ifdef TAA
	     previousColor = TemporalAA(color, previousColor.r, taaDepth, taaReprojectionValidity);
	#endif

	// Explicitly preserve the startup-clock texel through this final temporal
	// pass. This is required both with and without TAA enabled.
	#ifdef NOXARA_STARTUP_SIGNATURE
	ivec2 signatureStateTexel = ivec2(min(20, int(viewWidth) - 1), max(int(viewHeight) - 1, 0));
	if (ivec2(gl_FragCoord.xy) == signatureStateTexel) {
		previousColor.r = texelFetch(colortex2, signatureStateTexel, 0).r;
	}
	#endif

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

#endif

//**//**//**//**//**//**//**//**//**//**//**//**//**//**//

#ifdef VSH

// VSH Data //
out vec2 texCoord;

void main() {
	texCoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy;

	gl_Position = ftransform();
}

#endif
