#version 430 core

layout  (local_size_x  = 1, local_size_y = 1)  in;

struct Vertex {
    vec3 pos;
    vec3 norm;
    vec2 uv;
};

layout(std430, binding=0) buffer Vertices {
    Vertex vb[];
};

layout(std430, binding=1) buffer Index {
    unsigned int ib[];
};

layout(std430, binding=2) buffer Offset {
    unsigned int offset_in;
    unsigned int offset_search;
};

layout(std430, binding=3) buffer Output {
    int neighbors[][3];
};

int shared_edge(vec3 u, vec3 v, vec3 w, vec3 a, vec3 b, vec3 c) {
    if (u == a && v == c) {
        return 0;
    } else if (u == a && w == b) {
        return 2;
    } else if (v == a && w == c) {
        return 1;
    }
    return -1;
}

void main() {
    if (3 * (gl_GlobalInvocationID.x + offset_in) + 2 >= ib.length()) {
        return;
    }

    int found = 0;
    found += (neighbors[gl_GlobalInvocationID.x + offset_in][0] > 0) ? 1 : 0;
    found += (neighbors[gl_GlobalInvocationID.x + offset_in][1] > 0) ? 1 : 0;
    found += (neighbors[gl_GlobalInvocationID.x + offset_in][2] > 0) ? 1 : 0;

    vec3 u = vb[ib[3 * (gl_GlobalInvocationID.x + offset_in) + 0]].pos;
    vec3 v = vb[ib[3 * (gl_GlobalInvocationID.x + offset_in) + 1]].pos;
    vec3 w = vb[ib[3 * (gl_GlobalInvocationID.x + offset_in) + 2]].pos;

    for (int i = 0; found < 3 && i < 128 && (3 * gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 2 < ib.length(); i++) {
        vec3 a = vb[ib[3 * (gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 0]].pos;
        vec3 b = vb[ib[3 * (gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 1]].pos;
        vec3 c = vb[ib[3 * (gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i) + 2]].pos;

        int edge;
        edge = shared_edge(u, v, w, a, b, c);
        if (edge < 0) {
            edge = shared_edge(u, v, w, b, c, a);
        }
        if (edge < 0) {
            edge = shared_edge(u, v, w, c, a, b);
        }
        if (edge >= 0) {
            neighbors[gl_GlobalInvocationID.x + offset_in][edge] = int(gl_GlobalInvocationID.y + offset_search + gl_NumWorkGroups.y * i);
            found++;
        }
    }
}