#version 450

layout(binding = 0) uniform UniformBufferObject {
    mat4 model;
    mat4 geom_rot;
    mat4 view;
    mat4 proj;
    vec3 camera_pos;
    bool[16] use_geom_shader;
} ubo;

layout(binding = 3) readonly buffer CompoundBuffer {
   uint compounds[];
};

layout(binding = 4) readonly buffer ColorBuffer {
   uint grid_in[];
};

layout(binding = 9) readonly buffer TransparentBuffer {
   bool transparent_grid[];
};

layout(binding = 7) readonly buffer SizeBuffer2D {
   uint grid_size_in[];
};

layout(binding = 8) buffer SizeBuffer3D {
   uint grid_out[];
};

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

void main() {
    uint index = gl_GlobalInvocationID.x;
    uint output_offset = 0;
    uint compound_start = 0;
    // iterate over the compounds and find the work index inside of it
    while (index > compounds[compound_start] * compounds[compound_start]) {
        output_offset += compounds[compound_start] * compounds[compound_start] * compounds[compound_start] * 2;
        index -= compounds[compound_start] * compounds[compound_start];
        compound_start = compounds[compound_start + 2];
    }
    // grid pos in the task
    uint compound_grid_size = compounds[compound_start];
    float compound_scale = uintBitsToFloat(compounds[compound_start + 1]);
    vec3 mid_offset = vec3(compound_scale * 0.5, compound_scale * 0.5, compound_scale * 0.5);
    uint x = index % compound_grid_size;
    uint y = (index - x) / compound_grid_size;
    vec3 compound_pos = vec3(uintBitsToFloat(compounds[compound_start + 5]), uintBitsToFloat(compounds[compound_start + 6]), uintBitsToFloat(compounds[compound_start + 7]));
    // iterate upwards along the x axis
    bool seen_empty = false;
    uint start = 0;
    uint start_x_size = 0;
    uint start_y_size = 0;
    uint last_col = 0;
    for (uint z=0; z < compound_grid_size; z++) {
        uint color_val = grid_in[output_offset + x * compound_grid_size * compound_grid_size + y * compound_grid_size + z];
        bool transparent = transparent_grid[output_offset + x * compound_grid_size * compound_grid_size + y * compound_grid_size + z];
        uint current_x_size = grid_size_in[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + z) * 2];
        uint current_y_size = grid_size_in[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + z) * 2 + 1];
        
        grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + z) * 3] = 0;
        grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + z) * 3 + 1] = 0;
        grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + z) * 3 + 2] = 0;
        // check if we need to stop a volume
        if (color_val != 0 && !transparent) {
            // check if we are in a volume right now
            if (seen_empty) {
                // close the current volume
                grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3] = start_x_size;
                grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3 + 1] = start_y_size;
                grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3 + 2] = z - start;
                seen_empty = false;
                last_col = 0;
            }
        } else {
            // check if transparency changed
            if (seen_empty && ((transparent && last_col != color_val) || (start_x_size != current_x_size) || (start_y_size != current_y_size))) {
                // if we switch colors or size close the current volume and prepare for a new one
                grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3] = start_x_size;
                grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3 + 1] = start_y_size;
                grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3 + 2] = z - start;
                seen_empty = false;
            }
            // start a new volume if we are not in one right now
            if (!seen_empty && current_x_size != 0 && current_y_size != 0) {
                seen_empty = true;
                start = z;
                start_x_size = current_x_size;
                start_y_size = current_y_size;
                last_col = color_val;
            }
        }
    }
    if (seen_empty) {
        grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3] = start_x_size;
        grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3 + 1] = start_y_size;
        grid_out[output_offset + (x * compound_grid_size * compound_grid_size + y * compound_grid_size + start) * 3 + 2] = compound_grid_size - start;
    }
}