import { v3_length } from "../../../../../core/geom/vec3/v3_length.js";
import { PI2 } from "../../../../../core/math/PI2.js";

/**
 * @see 2003 "Global Illumination Compendium" by Philip Dutré (equation 36)
 * @see http://blog.hvidtfeldts.net/index.php/2015/01/path-tracing-3d-fractals/
 * @param {number[]} out
 * @param {number} out_offset
 * @param {number[]} normal
 * @param {number} normal_offset
 * @param {number} power
 * @param {function():number} random
 */
export function getBiasedNormalSample(
    out,
    out_offset,
    normal,
    normal_offset,
    power,
    random
) {

    const dir_x = normal[normal_offset];
    const dir_y = normal[normal_offset + 1];
    const dir_z = normal[normal_offset + 2];

    // we build orthonormal vectors with respect to the direction vector
    let o1_x, o1_y, o1_z;

    if (Math.abs(dir_x) > Math.abs(dir_z)) {
        o1_x = -dir_y;
        o1_y = dir_x;
        o1_z = 0;
    } else {
        o1_x = 0;
        o1_y = -dir_z;
        o1_z = dir_y;
    }

    // normalize orthonormal vector
    const o1_norm = 1 / v3_length(o1_x, o1_y, o1_z);

    o1_x *= o1_norm;
    o1_y *= o1_norm;
    o1_z *= o1_norm;

    const o2_x = dir_y * o1_z - dir_z * o1_y;
    const o2_y = dir_z * o1_x - dir_x * o1_z;
    const o2_z = dir_x * o1_y - dir_y * o1_x;

    // we can skip normalizing second orthonormal vector, as it will be guaranteed to be unit length already
    // for explanation, see https://math.stackexchange.com/questions/23259/is-the-cross-product-of-two-unit-vectors-itself-a-unit-vector#:~:text=If%20you%20know%20that%20the,(a%20length%20of%20one).

    const r_x = random() * PI2;
    const r_y = Math.pow(random(), 1 / (power + 1));

    const oneminus = Math.sqrt(1.0 - r_y * r_y);

    const k0 = Math.cos(r_x) * oneminus;
    const k1 = Math.sin(r_x) * oneminus;


    out[out_offset] = k0 * o1_x + k1 * o2_x + r_y * dir_x;
    out[out_offset + 1] = k0 * o1_y + k1 * o2_y + r_y * dir_y;
    out[out_offset + 2] = k0 * o1_z + k1 * o2_z + r_y * dir_z;
}

