import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
import { aabb3_intersects_ray } from "../../../geom/3d/aabb/aabb3_intersects_ray.js";
import { COLUMN_CHILD_1, COLUMN_CHILD_2, ELEMENT_WORD_COUNT, NULL_NODE } from "../BVH.js";

const stack = SCRATCH_UINT32_TRAVERSAL_STACK;


/**
 *
 * @param {BVH} bvh
 * @param {number} root
 * @param {number[]} result
 * @param {number} result_offset
 * @param {number} origin_x
 * @param {number} origin_y
 * @param {number} origin_z
 * @param {number} direction_x
 * @param {number} direction_y
 * @param {number} direction_z
 * @returns {number}
 */
export function bvh_query_leaves_ray(
    bvh, root,
    result, result_offset,
    origin_x, origin_y, origin_z,
    direction_x, direction_y, direction_z
) {

    if (root === NULL_NODE) {
        return 0;
    }


    /**
     *
     * @type {number}
     */
    const stack_top = stack.pointer++;

    stack[stack_top] = root;

    let result_cursor = result_offset;

    /*
     For performance, we bind data directly to avoid extra copies required to read out AABB
     */
    const float32 = bvh.__data_float32;
    const uint32 = bvh.__data_uint32;

    do {
        stack.pointer--;

        /**
         *
         * @type {number}
         */
        const node = stack[stack.pointer];

        const address = node * ELEMENT_WORD_COUNT;

        // test node against the ray
        const intersects = aabb3_intersects_ray(
            float32[address], float32[address + 1], float32[address + 2],
            float32[address + 3], float32[address + 4], float32[address + 5],
            origin_x, origin_y, origin_z,
            direction_x, direction_y, direction_z
        );

        if (!intersects) {
            continue;
        }

        // get fist child to check if this is a leaf node or not
        const child_1 = uint32[address + COLUMN_CHILD_1];

        if (child_1 !== NULL_NODE) {

            // this is not a leaf node, push children onto traversal stack
            stack[stack.pointer++] = uint32[address + COLUMN_CHILD_2];
            stack[stack.pointer++] = child_1;

        } else {
            // leaf node

            result[result_cursor++] = node;
        }
    } while (stack.pointer > stack_top);

    return result_cursor - result_offset;
}
