uniform sampler2D colortex9;
uniform sampler2D colortex10;
uniform sampler2D colortex8;
uniform sampler2D colortex5;
uniform sampler2D colortex6;
uniform sampler2D depthtex0;
uniform mat4 gbufferModelViewInverse;
uniform mat4 gbufferProjectionInverse;
uniform mat4 gbufferPreviousProjection;
uniform mat4 gbufferPreviousModelView;
uniform mat4 gbufferModelView;
uniform vec3 cameraPosition;
uniform vec3 previousCameraPosition;
uniform vec2 viewSize;
uniform float far;
uniform bool accum;
uniform int frameCounter;

vec2 texcoord = (gl_FragCoord.xy + vec2(0.5)) / viewSize;

#include "../../includes/debug.glsl"
#include "../../includes/Voxelization.glsl"
#include "../../includes/Random.glsl"


// Atomic color read
uniform usampler2D voxel_data_tex;
uniform usampler2D voxel_data_tex2;

vec3 DecodeColor(uvec2 enc) {
    uvec3 col;
    col.r = enc.r & ((1<<16)-1);
    col.g = enc.r >> 16;
    col.b = enc.g;
    
    vec3 color = vec3(col);
    return color / 1024.0;
}

vec3 ReadColor(ivec2 screenCoord) {
    ivec2 coord = ScreenToVoxelBuffer(screenCoord);
    
    uvec2 enc;
    
    //enc.x = texelFetch(voxel_data_tex, coord              , 0).r;
    //enc.y = texelFetch(voxel_data_tex, coord + ivec2(1, 0), 0).r;
    enc.x = texelFetch(voxel_data_tex2, coord              , 0).r;
    enc.y = texelFetch(voxel_data_tex2, coord + ivec2(1, 0), 0).r;
    
    return DecodeColor(enc);
}
/**********************************************************************/


float LinearizeDepth(float depth) {
	return -1.0 / ((depth * 2.0 - 1.0) * gbufferProjectionInverse[2].w + gbufferProjectionInverse[3].w);
}

vec3 Reproject(vec3 screenPos) {
    vec4 pos  = gbufferProjectionInverse * vec4(screenPos * 2.0 - 1.0, 1.0);
         pos /= pos.w;
         pos  = gbufferModelViewInverse * pos;
    
    pos.xyz += cameraPosition - previousCameraPosition;
    
    pos  = gbufferPreviousProjection * gbufferPreviousModelView * pos;
    pos /= pos.w;
    
    return pos.xyz * 0.5 + 0.5;
}

float Luminance(vec3 x) {
    return dot(x, vec3(0.2126, 0.7152, 0.0722));
}

vec3 CalculateViewSpacePosition(vec3 screenPos) {
    vec4 pos = gbufferProjectionInverse * vec4(screenPos * 2.0 - 1.0, 1.0);
    
    return pos.xyz / pos.w;
}

vec3 DecodeNormal(float enc) {
    const float bits = 11.0;
    
	vec4 normal;
	
	normal.y    = exp2(bits + 2.0) * floor(enc / exp2(bits + 2.0));
	normal.x    = enc - normal.y;
	normal.xy  /= exp2(vec2(bits, bits * 2.0 + 2.0));
	normal.x   -= 1.0;
	normal.xy  *= 3.14159;
	normal.xwzy = vec4(sin(normal.xy), cos(normal.xy));
	normal.xz  *= normal.w;
	
	return normal.xyz;
}

/* RENDERTARGETS: 9,10,11 */

#define TAA
#ifdef TAA
#endif

#define REPROJECT

void main() {
    ivec2 coord = ivec2(gl_FragCoord.xy);
    
    float depth = texelFetch(depthtex0, coord, 0).x;
    
    //vec3 diffuse = ReadColor(ivec2(gl_FragCoord.xy));
    vec3 diffuse = vec3(0.0);
    
    if (depth >= 1.0) {
        gl_FragData[0] = vec4(0.0, 0.0, 0.0, 1.0);
        
        exit();
        return;
    }
    
    //vec3 gbufferEncode = texelFetch(colortex6, ivec2(gl_FragCoord.xy), 0).rgb;
    vec4 gbufferEncode = texelFetch(colortex6, ivec2(gl_FragCoord.xy), 0);
    //vec3 albedo = unpackUnorm4x8(floatBitsToUint(gbufferEncode.r)).rgb * 256.0 / 255.0;
    //vec3 normal = DecodeNormal(gbufferEncode.g);
    
    //albedo = pow(albedo, vec3(2.2));
    
    //gl_FragData[0] = vec4(diffuse, 0.0);
    //gl_FragData[1] = vec4(moments, history, 0.0);
    
    // colortex9 and colortex10 values ​​must be preserved in order to composite process after.
    vec4 ct9 = texelFetch(colortex9 , ivec2(gl_FragCoord.xy), 0);
    gl_FragData[0] = vec4(ct9.rgb, gbufferEncode.w);
    
    vec4 ct10 = texelFetch(colortex10 , ivec2(gl_FragCoord.xy), 0);
    gl_FragData[1] = vec4(ct10.rgb, gbufferEncode.r);
    
    gl_FragData[2] = vec4(diffuse, 0.0);
    
    exit();
}
