import { v3_dot } from "../../vec3/v3_dot.js";

/**
 * Compute barycentric coordinates for triangle intersection
 * Operates on edges, this is optimized for raytracing, as same edges are required to reconstruct various attributes later on
 * NOTE:  most of the code is inlined for speed to avoid allocation and function calls
 * @see https://github.com/erich666/jgt-code/blob/master/Volume_02/Number_1/Moller1997a/raytri.c
 * @source https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm (Möller and Trumbore, « Fast, Minimum Storage Ray-Triangle Intersection », Journal of Graphics Tools, vol. 2,‎ 1997, p. 21–28)
 * @param {number[]} result
 * @param {number} origin_x
 * @param {number} origin_y
 * @param {number} origin_z
 * @param {number} direction_x
 * @param {number} direction_y
 * @param {number} direction_z
 * @param {number} ax
 * @param {number} ay
 * @param {number} az
 * @param {number} edge1_x
 * @param {number} edge1_y
 * @param {number} edge1_z
 * @param {number} edge2_x
 * @param {number} edge2_y
 * @param {number} edge2_z
 * @return {boolean}
 */
export function computeTriangleRayIntersectionBarycentricEdge(
    result,
    origin_x, origin_y, origin_z,
    direction_x, direction_y, direction_z,
    ax, ay, az,
    edge1_x, edge1_y, edge1_z,
    edge2_x, edge2_y, edge2_z
) {

    // begin calculating determinant - also used to calculate U parameter

    // CROSS(pvec, dir, edge2)
    const pvec_x = direction_y * edge2_z - direction_z * edge2_y;
    const pvec_y = direction_z * edge2_x - direction_x * edge2_z;
    const pvec_z = direction_x * edge2_y - direction_y * edge2_x;

    //if determinant is near zero, ray lies in plane of triangle
    const det = v3_dot(edge1_x, edge1_y, edge1_z, pvec_x, pvec_y, pvec_z);

    if(det === 0){
        // ray is parallel to the plane of the triange, no intersection possible
        return false;
    }

    if (det <= 0) {
        // back-face culling
        // return false;
    }

    const inv_det = 1 / det;

    // calculate distance from vert0 to ray origin (not really, but okay)
    const tvec_x = origin_x - ax;
    const tvec_y = origin_y - ay;
    const tvec_z = origin_z - az;

    // calculate u
    const u = v3_dot(tvec_x, tvec_y, tvec_z, pvec_x, pvec_y, pvec_z)*inv_det;

    if (u < 0 || u > 1) {
        // outside of bounds of the triangle
        return false;
    }

    // prepare to test V parameter
    // CROSS(qvec, tvec, edge1)
    const qvec_x = tvec_y * edge1_z - tvec_z * edge1_y;
    const qvec_y = tvec_z * edge1_x - tvec_x * edge1_z;
    const qvec_z = tvec_x * edge1_y - tvec_y * edge1_x;

    // calculate V parameter
    const v = v3_dot(direction_x, direction_y, direction_z, qvec_x, qvec_y, qvec_z)*inv_det;

    if (v < 0 || u + v > 1) {
        // out of bounds
        return false;
    }



    // calculate t, scale parameter, ray intersects triangle
    const t = v3_dot(edge2_x, edge2_y, edge2_z, qvec_x, qvec_y, qvec_z) * inv_det;

    result[0] = t;
    result[1] = u ;
    result[2] = v ;

    return true;
}
