use core::ops::{Add, Div, Mul, Neg, Sub};
use num_traits::{One, Zero};
use super::inv;
#[inline]
pub fn mul<'out, T>(out: &'out mut [T; 16], a: &[T; 16], b: &[T; 16]) -> &'out mut [T; 16]
where
T: Add<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let a00 = &a[0];
let a01 = &a[1];
let a02 = &a[2];
let a03 = &a[3];
let a10 = &a[4];
let a11 = &a[5];
let a12 = &a[6];
let a13 = &a[7];
let a20 = &a[8];
let a21 = &a[9];
let a22 = &a[10];
let a23 = &a[11];
let a30 = &a[12];
let a31 = &a[13];
let a32 = &a[14];
let a33 = &a[15];
let mut b0;
let mut b1;
let mut b2;
let mut b3;
b0 = &b[0];
b1 = &b[1];
b2 = &b[2];
b3 = &b[3];
out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = &b[4];
b1 = &b[5];
b2 = &b[6];
b3 = &b[7];
out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = &b[8];
b1 = &b[9];
b2 = &b[10];
b3 = &b[11];
out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
b0 = &b[12];
b1 = &b[13];
b2 = &b[14];
b3 = &b[15];
out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
out
}
#[inline]
pub fn rmul_mut<'out, T>(out: &'out mut [T; 16], m: &[T; 16]) -> &'out mut [T; 16]
where
T: Clone + Add<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let tmp = out.clone();
mul(out, m, &tmp)
}
#[inline]
pub fn lmul_mut<'out, T>(out: &'out mut [T; 16], m: &[T; 16]) -> &'out mut [T; 16]
where
T: Clone + Add<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let tmp = out.clone();
mul(out, &tmp, m)
}
#[inline]
pub fn smul<'out, T>(out: &'out mut [T; 16], m: &[T; 16], s: &T) -> &'out mut [T; 16]
where
T: Add<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
out[0] = &m[0] * s;
out[1] = &m[1] * s;
out[2] = &m[2] * s;
out[3] = &m[3] * s;
out[4] = &m[4] * s;
out[5] = &m[5] * s;
out[6] = &m[6] * s;
out[7] = &m[7] * s;
out[8] = &m[8] * s;
out[9] = &m[9] * s;
out[10] = &m[10] * s;
out[11] = &m[11] * s;
out[12] = &m[12] * s;
out[13] = &m[13] * s;
out[14] = &m[14] * s;
out[15] = &m[15] * s;
out
}
#[inline]
pub fn smul_mut<'out, T>(out: &'out mut [T; 16], s: &T) -> &'out mut [T; 16]
where
T: Clone + Add<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let tmp = out.clone();
smul(out, &tmp, s)
}
#[inline]
pub fn div<'out, T>(out: &'out mut [T; 16], a: &[T; 16], b: &[T; 16]) -> &'out mut [T; 16]
where
T: Clone + One + Zero + Sub<T, Output = T>,
for<'a, 'b> &'a T: Neg<Output = T> + Mul<&'b T, Output = T> + Div<&'b T, Output = T>,
{
let mut inv_b = b.clone();
inv(&mut inv_b, b);
mul(out, a, &inv_b)
}
#[inline]
pub fn rdiv_mut<'out, T>(out: &'out mut [T; 16], m: &[T; 16]) -> &'out mut [T; 16]
where
T: Clone + One + Zero + Sub<T, Output = T>,
for<'a, 'b> &'a T: Neg<Output = T> + Mul<&'b T, Output = T> + Div<&'b T, Output = T>,
{
let tmp = out.clone();
div(out, m, &tmp)
}
#[inline]
pub fn ldiv_mut<'out, T>(out: &'out mut [T; 16], m: &[T; 16]) -> &'out mut [T; 16]
where
T: Clone + One + Zero + Sub<T, Output = T>,
for<'a, 'b> &'a T: Neg<Output = T> + Mul<&'b T, Output = T> + Div<&'b T, Output = T>,
{
let tmp = out.clone();
div(out, &tmp, m)
}
#[inline]
pub fn sdiv<'out, T>(out: &'out mut [T; 16], m: &[T; 16], s: &T) -> &'out mut [T; 16]
where
T: One + Zero + Add<T, Output = T>,
for<'a, 'b> &'a T: Div<&'b T, Output = T> + Mul<&'b T, Output = T>,
{
let inv_s = if s.is_zero() {
T::zero()
} else {
&T::one() / s
};
smul(out, m, &inv_s)
}
#[inline]
pub fn sdiv_mut<'out, T>(out: &'out mut [T; 16], s: &T) -> &'out mut [T; 16]
where
T: Clone + One + Zero + Add<T, Output = T>,
for<'a, 'b> &'a T: Div<&'b T, Output = T> + Mul<&'b T, Output = T>,
{
let tmp = out.clone();
sdiv(out, &tmp, s)
}