


vec3 toClipSpace3Prev(vec3 viewSpacePosition) {
    return projMAD(gbufferPreviousProjection, viewSpacePosition) / -viewSpacePosition.z * 0.5 + 0.5;
}

vec3 toScreenSpace(vec3 p) {
	vec4 iProjDiag = vec4(gbufferProjectionInverse[0].x, gbufferProjectionInverse[1].y, gbufferProjectionInverse[2].zw);
    vec3 p3 = p * 2. - 1.;
    vec4 fragposition = iProjDiag * p3.xyzz + gbufferProjectionInverse[3];
    return fragposition.xyz / fragposition.w;
}

vec3 reproject(vec3 closestPos, vec2 coord, out vec2 velocity) {
    vec3 fragPos = toScreenSpace(closestPos);
	fragPos = mat3(gbufferModelViewInverse) * fragPos + gbufferModelViewInverse[3].xyz + (cameraPosition - previousCameraPosition);
	vec3 reprojectedPos = mat3(gbufferPreviousModelView) * fragPos + gbufferPreviousModelView[3].xyz;
	reprojectedPos = toClipSpace3Prev(reprojectedPos);
	velocity = reprojectedPos.xy - closestPos.xy;
	reprojectedPos.xy = coord + velocity;
    return reprojectedPos;
}

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

vec3 getDepthPointPrevious(vec2 coord, float depth) {
    vec4 pos;
    pos.xy = coord;
    pos.z = depth;
    pos.w = 1.0;
    pos.xyz = pos.xyz * 2.0 - 1.0; //convert from the 0-1 range to the -1 to +1 range
    pos = inverse(gbufferPreviousProjection) * pos;
    pos.xyz /= pos.w;
    
    return pos.xyz;
}

const ivec2 neighbours[8] = ivec2[8] ( ivec2(-1, 1),  ivec2(0, 1),  ivec2(1, 1),
                                     ivec2(-1,  0),  /* center */    ivec2(1, 0), 
                                     ivec2(-1, -1), ivec2(0, -1), ivec2(1, -1) );

vec3 nearestFrag(sampler2D tex, vec2 coord) {
	vec2 du = vec2(invRes.x*2., 0.0);
	vec2 dv = vec2(0.0, invRes.y*2.);

	vec3 dtl = vec3(coord,0.) + vec3(-invRes.x, -invRes.y, texture2D(tex, coord - dv - du).r);
	vec3 dtr = vec3(coord,0.) +  vec3( invRes.x, -invRes.y, texture2D(tex, coord - dv + du).r);
	vec3 dmc = vec3(coord,0.) + vec3( 0.0, 0.0, texture2D(tex, coord).r);
	vec3 dbl = vec3(coord,0.) + vec3(-invRes.x, invRes.y, texture2D(tex, coord + dv - du).r);
	vec3 dbr = vec3(coord,0.) + vec3( invRes.x, invRes.y, texture2D(tex, coord + dv + du).r);

	vec3 dmin = dmc;
	dmin = dmin.z > dtr.z ? dtr : dmin;
	dmin = dmin.z > dtl.z ? dtl : dmin;
	dmin = dmin.z > dbl.z ? dbl : dmin;
	dmin = dmin.z > dbr.z ? dbr : dmin;
	
	return dmin;
}