#version 460 core
layout(local_size_x = 1) in;

struct mesh_data {
    mat4 model;
};

struct meshlet_data {
    vec4 bounds; // xyz, radius
    vec4 cone_apex; // xyz, unused
    vec4 cone_axis_cutoff; // xyz, cutoff = w
    uint mesh_index;
    uint first_index;
    uint base_vertex;
    uint index_count;
};

struct draw_indirect_command {
    uint count;
    uint instance_count;
    uint first_index;
    int base_vertex;
    uint base_instance;
};

layout(std430, binding = 1) readonly buffer meshletsSSBO {
    meshlet_data meshlets[];
};
layout(std430, binding = 2) writeonly buffer drawSSBO {
    draw_indirect_command draw_commands[];
};
layout(std430, binding = 3) buffer outputSSBO {
    uint draw_count;
};
layout(std430, binding = 4) readonly buffer meshSSBO {
    mesh_data meshes[];
};

// World space camera position
layout(location = 0) uniform vec3 camera_pos;

void main() {
    uint meshlet_idx     = gl_GlobalInvocationID.x;
    meshlet_data meshlet = meshlets[meshlet_idx];
    mesh_data mesh       = meshes[meshlet.mesh_index];

    vec3 cone_axis    = (mesh.model * vec4(meshlet.cone_axis_cutoff.xyz, 0)).xyz;
    vec3 cone_apex    = (mesh.model * vec4(meshlet.cone_apex.xyz, 1)).xyz;
    float cone_cutoff = meshlet.cone_axis_cutoff.w;

    
    if (dot(normalize(cone_apex - camera_pos), cone_axis) < cone_cutoff) {
        uint draw_idx                          = atomicAdd(draw_count, 1);
        draw_commands[draw_idx].count          = meshlet.index_count;
        draw_commands[draw_idx].instance_count = 1;
        draw_commands[draw_idx].first_index    = meshlet.first_index;
        draw_commands[draw_idx].base_vertex    = int(meshlet.base_vertex);
        draw_commands[draw_idx].base_instance  = 0;
    }
}