import { m4_multiply } from "../../../../core/geom/3d/mat4/m4_multiply.js";
import { mat4x4_transpose_copy_to_mat4x3 } from "../../../../core/math/matrix/mat4x4_transpose_copy_to_mat4x3.js";
import { mesh_apply_skeletal_vertex_skinning } from "./mesh_apply_skeletal_vertex_skinning.js";

/**
 * NOTE: the method is completely inlined for better performance. 0 function calls within the skinning loop
 * @param {Float32Array} destination Skinned vertex positions
 * @param {SkinnedMesh} mesh
 * @param {number} [destination_offset=0]
 */
export function computeSkinnedMeshVertices(
    destination,
    mesh,
    destination_offset = 0
) {

    const geometry = mesh.geometry;
    const skeleton = mesh.skeleton;

    const tempMatrix = new Float32Array(16);

    const attributes = geometry.attributes;

    const positions = attributes.position.array;
    const skin_indices_array = attributes.skinIndex.array;
    const skin_weights_array = attributes.skinWeight.array;

    const vertex_count = attributes.position.count;

    const bones = skeleton.bones;
    const boneCount = bones.length;

    //pre-build transform matrices for bones
    const boneMatrixData = new Float32Array(boneCount * 12);

    for (let boneIndex = 0; boneIndex < boneCount; boneIndex++) {
        const targetIndex = boneIndex * 12;

        m4_multiply(tempMatrix, bones[boneIndex].matrixWorld.elements, skeleton.boneInverses[boneIndex].elements);

        // write matrix data in transposed form, to conform to access order when applied to Vector3 transformation
        mat4x4_transpose_copy_to_mat4x3(
            boneMatrixData, targetIndex,
            tempMatrix, 0
        );
    }

    const m4_bind = mesh.bindMatrix.elements;

    // inverse of bind matrix
    const m4_bind_inv = mesh.bindMatrixInverse.elements;

    mesh_apply_skeletal_vertex_skinning(destination, destination_offset, positions, vertex_count, skin_weights_array, skin_indices_array, boneMatrixData, m4_bind, m4_bind_inv);
}
