#version 330 core
const float Nsamples = 14.0;

// inputz
in vec2 UV;
in vec2 ray;
uniform sampler2D colors;
uniform sampler2D normals;
uniform sampler2D dbuffer;
uniform mat4 projection;
uniform vec3 eyepos;
uniform vec2 iResolution;
uniform float steplength;   // Ray step length = steplength pixels

// outputz
out vec4 color;

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

vec3 getPos(vec2 uv) {
  float z = 2.0 * texture(dbuffer, uv).x - 1.0;
  vec4 clipSpace = vec4(2.0*UV-1.0, z, 1.0);
  vec4 homogLoc = inverse(projection) * clipSpace;
  return homogLoc.xyz / homogLoc.w;
}

const float ERR = 1e2;
void main() {
    float origz = texture(dbuffer, UV).x;
    vec3 origin = getPos(UV);
    vec3 normal = normalize(texture(normals, UV).xyz);
    vec4 reflvec = vec4(reflect(normalize(origin - eyepos), normalize(normal)), 1.0);
    if (texture(colors, UV).a < 0.1 || dot(reflvec.xyz, origin - eyepos) < 0.0) {
        color = vec4(UV,ERR,1.0);
        return;
    }
    vec4 reflproj = projection * reflvec;
    float rfpl = length(reflproj.xyz);
    vec2 ssref = normalize(reflproj.xy / reflproj.z) / iResolution; // [-1, 1] to "pixel length"

    //vec2 pos = UV;
    vec3 posT = origin;
    color = vec4(UV,ERR,1.0);
    for (float i = 0.0; i < Nsamples; i += 1.0) {
        posT += (steplength / rfpl) * reflvec.xyz;
        vec4 posproj = projection * vec4(posT, 1.0);
        vec2 pos = 0.5 * posproj.xy / posproj.z + vec2(0.5); // [-1, 1] to "pixel length"
        //pos += steplength * ssref;


        // Out of range
        if (pos.x < 0.0 || pos.y < 0.0 || pos.x > 1.0 || pos.y > 1.0) {
            return;
        }
        // Depth test
        if (length(posT - eyepos) > length(getPos(pos) - eyepos)) {
            vec3 posA = posT - (steplength / rfpl) * reflvec.xyz;
            vec3 posB = posT;
            float sl = steplength;
            vec2 miduv = pos;
            vec3 mid = 0.5 * (posA + posB);

            // Bisect refinement for the intersection guesstimate
            for (float idx = 0.0; idx < 4.0; idx += 1.0) {
                vec4 midproj = projection * vec4(mid, 1.0);
                vec2 miduv = 0.5 * midproj.xy / midproj.z + vec2(0.5); // [-1, 1] to "pixel length"
                vec3 midpos = getPos(miduv);

                if (length(mid - eyepos) > length(getPos(miduv) - eyepos)) {
                    posB = mix(posA, posB, vec3(0.4));
                } else {
                    posA = mix(posA, posB, vec3(0.6));
                }
                mid = 0.5 * (posA + posB);
            }
            color = vec4(miduv, length(mid - origin), 1.0);
            return;
        }
    }
}
