import { assert } from "../../../core/assert.js";

/**
 * BVH leaves will contain `face_id` and their bounds will be set from the corresponding face bounds.
 * @param {BVH} bvh
 * @param {BinaryTopology} mesh
 */
export function bvh_build_from_bt_mesh(bvh, mesh) {
    assert.defined(bvh, 'bvh');
    assert.defined(mesh, 'mesh');
    assert.equal(mesh.isBinaryTopology, true, 'mesh.isBinaryTopology !== true');

    // clear out the BVH
    bvh.release_all();

    // NOTE: we assume there are no holes in the allocation, data must be packed
    const face_count = mesh.faces.size;

    const vertex_position = new Float32Array(3);

    for (let face_id = 0; face_id < face_count; face_id++) {
        let bounds_x0 = Infinity;
        let bounds_y0 = Infinity;
        let bounds_z0 = Infinity;

        let bounds_x1 = -Infinity;
        let bounds_y1 = -Infinity;
        let bounds_z1 = -Infinity;

        let loop = mesh.face_read_loop(face_id);
        const loop_start = loop;

        do {
            const vertex = mesh.loop_read_vertex(loop);

            mesh.vertex_read_coordinate(vertex_position, 0, vertex);

            const px = vertex_position[0];
            const py = vertex_position[1];
            const pz = vertex_position[2];

            bounds_x0 = Math.min(bounds_x0, px);
            bounds_y0 = Math.min(bounds_y0, py);
            bounds_z0 = Math.min(bounds_z0, pz);

            bounds_x1 = Math.max(bounds_x1, px);
            bounds_y1 = Math.max(bounds_y1, py);
            bounds_z1 = Math.max(bounds_z1, pz);

            loop = mesh.loop_read_next(loop);

        } while (loop !== loop_start)

        const node = bvh.allocate_node();

        bvh.node_set_user_data(node, face_id);
        bvh.node_set_aabb_primitive(node,
            bounds_x0, bounds_y0, bounds_z0,
            bounds_x1, bounds_y1, bounds_z1
        );

        bvh.insert_leaf(node);
    }
}