import { Matrix4InOut, Vector3 as Vec3 } from './mat4' /** * Set the components of a vec3 to the given values * @ignore * @param out the receiving vector * @param x X component * @param y Y component * @param z Z component * @returns out */ export function set(out: Vec3, x: number, y: number, z: number) { out[0] = x; out[1] = y; out[2] = z; return out; } /** * Adds two vec3's * @ignore * @param out the receiving vector * @param a the first operand * @param b the second operand * @returns out */ export function add(out: Vec3, a: Vec3, b: Vec3) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; return out; } /** * Subtracts vector b from vector a * @ignore * @param out the receiving vector * @param a the first operand * @param b the second operand * @returns out */ export function subtract(out: Vec3, a: Vec3, b: Vec3) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; return out; } export function sub(out: Vec3, a: Vec3, b: Vec3) { return subtract(out, a, b); } export function copy(out: Vec3, a: Vec3) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; } /** * Calculates the length of a vec3 * @ignore * @param a vector to calculate length of * @returns length of a */ export function length(a: Vec3) { const x = a[0], y = a[1], z = a[2]; return Math.sqrt(x * x + y * y + z * z); } /** * Normalize a vec3 * @ignore * @param out the receiving vector * @param a vector to normalize * @returns out */ export function normalize(out: Vec3, a: Vec3) { const x = a[0], y = a[1], z = a[2]; let len = x * x + y * y + z * z; if (len > 0) { //TODO: evaluate use of glm_invsqrt here? len = 1 / Math.sqrt(len); out[0] = a[0] * len; out[1] = a[1] * len; out[2] = a[2] * len; } return out; } /** * Calculates the dot product of two vec3's * @ignore * @param a the first operand * @param b the second operand * @returns dot product of a and b */ export function dot(a: Vec3, b: Vec3) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } /** * Scales a vec3 by a scalar number * @ignore * @param out the receiving vector * @param a the vector to scale * @param b amount to scale the vector by * @returns out */ export function scale(out: Vec3, a: Vec3, b: number) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; return out; } /** * Computes the cross product of two vec3's * @ignore * @param out the receiving vector * @param a the first operand * @param b the second operand * @returns out */ export function cross(out: Vec3, a: Vec3, b: Vec3) { const ax = a[0], ay = a[1], az = a[2], bx = b[0], by = b[1], bz = b[2]; out[0] = ay * bz - az * by; out[1] = az * bx - ax * bz; out[2] = ax * by - ay * bx; return out; } /** * Calculates the euclidian distance between two vec3's * @ignore * @param a the first operand * @param b the second operand * @returns distance between a and b */ export function distance(a: Vec3, b: Vec3) { const x = b[0] - a[0]; const y = b[1] - a[1]; const z = b[2] - a[2]; return Math.hypot ? Math.hypot(x, y, z) : hypot(x, y, z); } /** * Transforms the vec3 with a mat4. * 4th vector component is implicitly '1' * @ignore * @param out the receiving vector * @param a the vector to transform * @param m matrix to transform with * @returns out */ export function transformMat4(out: Vec3, a: Vec3, m: Matrix4InOut) { const x = a[0], y = a[1], z = a[2]; let w = m[3] * x + m[7] * y + m[11] * z + m[15]; w = w || 1.0; out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; return out; } function hypot(...args: number[]) { let y = 0; let i = args.length; while (i--) y += args[i] * args[i]; return Math.sqrt(y); } export function angle(a: Vec3, b: Vec3) { normalize(a, a); normalize(b, b); const cosine = dot(a, b); if (cosine > 1.0) { return 0; } else if (cosine < -1.0) { return Math.PI; } else { return Math.acos(cosine); } }