import morton from "../../geom/3d/morton/v3_morton_encode.js";

/**
 * Compute morton codes for each triangle
 * @param {number[]|Uint32Array} morton_codes output where the morton codes are to be written to, matching order in {@link index_array}
 * @param {number} tri_count
 * @param {number[]|Uint8Array|Uint16Array|Uint32Array} index_array
 * @param {number[]|Float32Array} position_array
 * @param {number} aabb_x0
 * @param {number} aabb_y0
 * @param {number} aabb_z0
 * @param {number} aabb_x1
 * @param {number} aabb_y1
 * @param {number} aabb_z1
 */
export function build_triangle_morton_codes(
    morton_codes,
    tri_count,
    index_array,
    position_array,
    aabb_x0, aabb_y0, aabb_z0,
    aabb_x1, aabb_y1, aabb_z1
) {
    // TODO use adaptive number of bits per axis (see "Extended Morton Codes for High Performance Bounding Volume Hierarchy Construction" by Marek Vinkler et al, 2017,  Proceedings of HPG

    const aabb_size_x = aabb_x1 - aabb_x0;
    const aabb_size_y = aabb_y1 - aabb_y0;
    const aabb_size_z = aabb_z1 - aabb_z0;

    /*
    NOTE: to avoid division by 3 when computing triangle center, we instead add that factor into our morton scale
     */

    const aabb_3_x0 = aabb_x0 * 3;
    const aabb_3_y0 = aabb_y0 * 3;
    const aabb_3_z0 = aabb_z0 * 3;

    // compute multipliers to bring normalized values in range of 10bit unsigned integer each
    const morton_scale_x = aabb_size_x === 0 ? 0 : 1023 / (aabb_size_x * 3);
    const morton_scale_y = aabb_size_y === 0 ? 0 : 1023 / (aabb_size_y * 3);
    const morton_scale_z = aabb_size_z === 0 ? 0 : 1023 / (aabb_size_z * 3);

    // compute morton codes
    for (let i = 0; i < tri_count; i++) {

        const i3 = i * 3;

        // read indices
        const a = index_array[i3];
        const b = index_array[i3 + 1];
        const c = index_array[i3 + 2];

        // read vertex positions
        const a_address = a * 3;
        const c_address = c * 3;
        const b_address = b * 3;

        const ax = position_array[a_address];
        const ay = position_array[a_address + 1];
        const az = position_array[a_address + 2];

        const bx = position_array[b_address];
        const by = position_array[b_address + 1];
        const bz = position_array[b_address + 2];

        const cx = position_array[c_address];
        const cy = position_array[c_address + 1];
        const cz = position_array[c_address + 2];

        // compute centroid coordinate
        const center_x = (ax + bx + cx);
        const center_y = (ay + by + cy);
        const center_z = (az + bz + cz);

        // normalize to 10bit range
        const ncx = (center_x - aabb_3_x0) * morton_scale_x;
        const ncy = (center_y - aabb_3_y0) * morton_scale_y;
        const ncz = (center_z - aabb_3_z0) * morton_scale_z;

        morton_codes[i] = morton(
            Math.round(ncx),
            Math.round(ncy),
            Math.round(ncz),
        );
    }
}