import { assert } from "../../../../../../assert.js";
import { v3_compute_triangle_normal } from "../../../../triangle/v3_compute_triangle_normal.js";
import { NULL_POINTER } from "../BinaryTopology.js";

const scratch_normal = new Float32Array(3);
const scratch_coord_a = new Float32Array(3);
const scratch_coord_b = new Float32Array(3);
const scratch_coord_c = new Float32Array(3);

/**
 * Compute face normals for all allocated triangular faces, overwriting any previous value.
 * Non-triangular faces are left untouched.
 *
 * @param {BinaryTopology} mesh
 */
export function bt_mesh_compute_face_normals(mesh) {
    assert.defined(mesh, "mesh");
    assert.notNull(mesh, "mesh");
    assert.equal(mesh.isBinaryTopology, true, "mesh.isBinaryTopology !== true");

    const face_pool = mesh.faces;
    const face_count = face_pool.size;

    for (let face_id = 0; face_id < face_count; face_id++) {
        if (!face_pool.is_allocated(face_id)) {
            continue;
        }

        const loop_a = mesh.face_read_loop(face_id);

        if (loop_a === NULL_POINTER) {
            continue;
        }

        const loop_b = mesh.loop_read_next(loop_a);
        const loop_c = mesh.loop_read_next(loop_b);

        // must be a triangle
        if (mesh.loop_read_next(loop_c) !== loop_a) {
            continue;
        }

        mesh.vertex_read_coordinate(scratch_coord_a, 0, mesh.loop_read_vertex(loop_a));
        mesh.vertex_read_coordinate(scratch_coord_b, 0, mesh.loop_read_vertex(loop_b));
        mesh.vertex_read_coordinate(scratch_coord_c, 0, mesh.loop_read_vertex(loop_c));

        v3_compute_triangle_normal(
            scratch_normal, 0,
            scratch_coord_a[0], scratch_coord_a[1], scratch_coord_a[2],
            scratch_coord_b[0], scratch_coord_b[1], scratch_coord_b[2],
            scratch_coord_c[0], scratch_coord_c[1], scratch_coord_c[2]
        );

        mesh.face_write_normal(face_id, scratch_normal, 0);
    }
}
