struct PushConstants
{
    view_projection: mat4x4<f32>,
    transform: mat4x4<f32>,
    eye_position: vec3<f32>,
    root_color: vec4<f32>,
    root_subdivided: u32,
}

var<push_constant> constants: PushConstants;

struct VertexOutput
{
    @builtin(position) pos: vec4<f32>,
    @location(0) eye_pos: vec3<f32>,
    @location(1) world_pos: vec3<f32>,
    @location(2) cube_pos: vec3<f32>,
    @location(3) root_color: vec4<f32>,
    @location(4) root_subdivided: u32
}

@vertex
fn vertex_main(@builtin(vertex_index) index: u32, @builtin(instance_index) instance_index: u32) -> VertexOutput
{
    let side_length = u32(100);
    let offset = vec3<f32>(vec3<u32>(
        instance_index % side_length,
        (instance_index / side_length) % side_length,
        instance_index / (side_length * side_length)
    ));

    let cube_vertices = array<vec3<f32>, 8>(
        vec3<f32>(0., 0., 0.),
        vec3<f32>(0., 0., 1.),
        vec3<f32>(1., 0., 1.),
        vec3<f32>(1., 0., 0.),

        vec3<f32>(0., 1., 0.),
        vec3<f32>(0., 1., 1.),
        vec3<f32>(1., 1., 1.),
        vec3<f32>(1., 1., 0.),
    );

    let cube_faces = array<u32, 24>(
        // Bottom face
        1, 0, 2, 3,

        // Top face
        4, 5, 7, 6,

        // Side faces
        0, 1, 4, 5,
        1, 2, 5, 6,
        2, 3, 6, 7,
        3, 0, 7, 4,
    );

    let quad_index = index / (3 * 2);
    let triangle_index = index % (3 * 2);
    let triangle_map = array<u32, 6>(
        0, 1, 2, 1, 3, 2
    );

    let vertex = cube_vertices[cube_faces[quad_index * 4 + triangle_map[triangle_index]]];

    var output: VertexOutput;
    output.pos = constants.view_projection * constants.transform * vec4<f32>(vertex + offset, 1.);
    output.eye_pos = constants.eye_position;
    output.world_pos = (constants.transform * vec4<f32>(vertex + offset, 1.)).xyz;
    output.cube_pos = offset;

    output.root_color = constants.root_color;
    output.root_subdivided = constants.root_subdivided;
    return output;
}

@fragment
fn fragment_main() -> @location(0) vec4<f32>
{
    return vec4(1.);
}
