use core::ops::{Add, Div, Mul, Neg, Sub};
use num_traits::{Float, FromPrimitive, One, Zero};
use super::new_identity;
#[inline]
pub fn look_at<'out, T>(
out: &'out mut [T; 16],
eye: &[T; 3],
target: &[T; 3],
up: &[T; 3],
) -> &'out mut [T; 16]
where
T: Clone + Zero + One + Float + Add<T, Output = T> + Sub<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>
+ Div<&'b T, Output = T>
+ Add<&'b T, Output = T>
+ Sub<&'b T, Output = T>,
{
let eyex = &eye[0];
let eyey = &eye[1];
let eyez = &eye[2];
let upx = &up[0];
let upy = &up[1];
let upz = &up[2];
let targetx = &target[0];
let targety = &target[1];
let targetz = &target[2];
let mut z0 = eyex - targetx;
let mut z1 = eyey - targety;
let mut z2 = eyez - targetz;
let mut len = &z0 * &z0 + &z1 * &z1 + &z2 * &z2;
if len.is_zero() {
z0 = T::zero();
z1 = T::zero();
z2 = T::one();
} else {
len = &T::one() / &len.sqrt();
z0 = &z0 * &len;
z1 = &z1 * &len;
z2 = &z2 * &len;
}
let mut x0 = upy * &z2 - upz * &z1;
let mut x1 = upz * &z0 - upx * &z2;
let mut x2 = upx * &z1 - upy * &z0;
len = &x0 * &x0 + &x1 * &x1 + &x2 * &x2;
if len.is_zero() {
x0 = T::zero();
x1 = T::zero();
x2 = T::zero();
} else {
len = &T::one() / &len.sqrt();
x0 = &x0 * &len;
x1 = &x1 * &len;
x2 = &x2 * &len;
}
let mut y0 = &z1 * &x2 - &z2 * &x1;
let mut y1 = &z2 * &x0 - &z0 * &x2;
let mut y2 = &z0 * &x1 - &z1 * &x0;
len = &y0 * &y0 + &y1 * &y1 + &y2 * &y2;
if len.is_zero() {
y0 = T::zero();
y1 = T::zero();
y2 = T::zero();
} else {
len = &T::one() / &len.sqrt();
y0 = &y0 * &len;
y1 = &y1 * &len;
y2 = &y2 * &len;
}
out[0] = x0.clone();
out[1] = x1.clone();
out[2] = x2.clone();
out[3] = T::zero();
out[4] = y0.clone();
out[5] = y1.clone();
out[6] = y2.clone();
out[7] = T::zero();
out[8] = z0.clone();
out[9] = z1.clone();
out[10] = z2.clone();
out[11] = T::zero();
out[12] = -(&x0 * eyex + &x1 * eyey + &x2 * eyez);
out[13] = -(&y0 * eyex + &y1 * eyey + &y2 * eyez);
out[14] = -(&z0 * eyex + &z1 * eyey + &z2 * eyez);
out[15] = T::one();
out
}
#[inline]
pub fn translate<'out, T>(out: &'out mut [T; 16], a: &[T; 16], v: &[T; 3]) -> &'out mut [T; 16]
where
T: Clone + Add<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let x = &v[0];
let y = &v[1];
let z = &v[2];
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];
out[0] = a00.clone();
out[1] = a01.clone();
out[2] = a02.clone();
out[3] = a03.clone();
out[4] = a10.clone();
out[5] = a11.clone();
out[6] = a12.clone();
out[7] = a13.clone();
out[8] = a20.clone();
out[9] = a21.clone();
out[10] = a22.clone();
out[11] = a23.clone();
out[12] = a00 * x + a10 * y + a20 * z + a[12].clone();
out[13] = a01 * x + a11 * y + a21 * z + a[13].clone();
out[14] = a02 * x + a12 * y + a22 * z + a[14].clone();
out[15] = a03 * x + a13 * y + a23 * z + a[15].clone();
out
}
#[inline]
pub fn scale<'out, T>(out: &'out mut [T; 16], a: &[T; 16], v: &[T; 3]) -> &'out mut [T; 16]
where
T: Clone,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let x = &v[0];
let y = &v[1];
let z = &v[2];
out[0] = &a[0] * x;
out[1] = &a[1] * x;
out[2] = &a[2] * x;
out[3] = &a[3] * x;
out[4] = &a[4] * y;
out[5] = &a[5] * y;
out[6] = &a[6] * y;
out[7] = &a[7] * y;
out[8] = &a[8] * z;
out[9] = &a[9] * z;
out[10] = &a[10] * z;
out[11] = &a[11] * z;
out[12] = a[12].clone();
out[13] = a[13].clone();
out[14] = a[14].clone();
out[15] = a[15].clone();
out
}
#[inline]
pub fn rotate_x<'out, T>(out: &'out mut [T; 16], a: &[T; 16], angle: &T) -> &'out mut [T; 16]
where
T: Clone + Float + Add<T, Output = T> + Sub<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let s = angle.sin();
let c = angle.cos();
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];
out[0] = a[0].clone();
out[1] = a[1].clone();
out[2] = a[2].clone();
out[3] = a[3].clone();
out[12] = a[12].clone();
out[13] = a[13].clone();
out[14] = a[14].clone();
out[15] = a[15].clone();
out[4] = a10 * &c + a20 * &s;
out[5] = a11 * &c + a21 * &s;
out[6] = a12 * &c + a22 * &s;
out[7] = a13 * &c + a23 * &s;
out[8] = a20 * &c - a10 * &s;
out[9] = a21 * &c - a11 * &s;
out[10] = a22 * &c - a12 * &s;
out[11] = a23 * &c - a13 * &s;
out
}
#[inline]
pub fn rotate_y<'out, T>(out: &'out mut [T; 16], a: &[T; 16], angle: &T) -> &'out mut [T; 16]
where
T: Clone + Float + Add<T, Output = T> + Sub<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let s = angle.sin();
let c = angle.cos();
let a00 = &a[0];
let a01 = &a[1];
let a02 = &a[2];
let a03 = &a[3];
let a20 = &a[8];
let a21 = &a[9];
let a22 = &a[10];
let a23 = &a[11];
out[4] = a[4].clone();
out[5] = a[5].clone();
out[6] = a[6].clone();
out[7] = a[7].clone();
out[12] = a[12].clone();
out[13] = a[13].clone();
out[14] = a[14].clone();
out[15] = a[15].clone();
out[0] = a00 * &c - a20 * &s;
out[1] = a01 * &c - a21 * &s;
out[2] = a02 * &c - a22 * &s;
out[3] = a03 * &c - a23 * &s;
out[8] = a00 * &s + a20 * &c;
out[9] = a01 * &s + a21 * &c;
out[10] = a02 * &s + a22 * &c;
out[11] = a03 * &s + a23 * &c;
out
}
#[inline]
pub fn rotate_z<'out, T>(out: &'out mut [T; 16], a: &[T; 16], angle: &T) -> &'out mut [T; 16]
where
T: Clone + Float + Add<T, Output = T> + Sub<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let s = angle.sin();
let c = angle.cos();
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];
out[8] = a[8].clone();
out[9] = a[9].clone();
out[10] = a[10].clone();
out[11] = a[11].clone();
out[12] = a[12].clone();
out[13] = a[13].clone();
out[14] = a[14].clone();
out[15] = a[15].clone();
out[0] = a00 * &c + a10 * &s;
out[1] = a01 * &c + a11 * &s;
out[2] = a02 * &c + a12 * &s;
out[3] = a03 * &c + a13 * &s;
out[4] = a10 * &c - a00 * &s;
out[5] = a11 * &c - a01 * &s;
out[6] = a12 * &c - a02 * &s;
out[7] = a13 * &c - a03 * &s;
out
}
#[inline]
pub fn rotate<'out, T>(
out: &'out mut [T; 16],
a: &[T; 16],
x: &T,
y: &T,
z: &T,
) -> &'out mut [T; 16]
where
T: Clone + Float + Add<T, Output = T> + Sub<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
let mut tmp_a = a.clone();
let mut tmp_b = new_identity();
rotate_z(&mut tmp_a, a, z);
rotate_x(&mut tmp_b, &tmp_a, x);
rotate_y(out, &tmp_b, y);
out
}
#[inline]
pub fn frustum<'out, T>(
out: &'out mut [T; 16],
top: &T,
right: &T,
bottom: &T,
left: &T,
near: &T,
far: &T,
) -> &'out mut [T; 16]
where
T: One + Zero + FromPrimitive + Neg<Output = T>,
for<'a, 'b> &'a T: Neg<Output = T>
+ Mul<&'b T, Output = T>
+ Div<&'b T, Output = T>
+ Add<&'b T, Output = T>
+ Sub<&'b T, Output = T>,
{
let x = &(&T::from_isize(2).unwrap() * near) / &(right - left);
let y = &(&T::from_isize(2).unwrap() * near) / &(top - bottom);
let a = &(right + left) / &(right - left);
let b = &(top + bottom) / &(top - bottom);
let c = &-&(far + near) / &(far - near);
let d = &(&(&T::from_isize(-2).unwrap() * far) * near) / &(far - near);
out[0] = x;
out[4] = T::zero();
out[8] = a;
out[12] = T::zero();
out[1] = T::zero();
out[5] = y;
out[9] = b;
out[13] = T::zero();
out[2] = T::zero();
out[6] = T::zero();
out[10] = c;
out[14] = d;
out[3] = T::zero();
out[7] = T::zero();
out[11] = -T::one();
out[15] = T::zero();
out
}
#[inline]
pub fn perspective<'out, T>(
out: &'out mut [T; 16],
fov: &T,
aspect: &T,
near: &T,
far: &T,
) -> &'out mut [T; 16]
where
T: One + Zero + Float + FromPrimitive + Neg<Output = T>,
for<'a, 'b> &'a T: Neg<Output = T>
+ Mul<&'b T, Output = T>
+ Div<&'b T, Output = T>
+ Add<&'b T, Output = T>
+ Sub<&'b T, Output = T>,
{
let ymax = near * &(fov / &T::from_isize(2).unwrap()).tan();
let ymin = -ymax;
let xmin = &ymin * aspect;
let xmax = &ymax * aspect;
frustum(out, &ymax, &xmax, &ymin, &xmin, near, far)
}
#[inline]
pub fn orthographic<'out, T>(
out: &'out mut [T; 16],
top: &T,
right: &T,
bottom: &T,
left: &T,
near: &T,
far: &T,
) -> &'out mut [T; 16]
where
T: One + Zero + FromPrimitive + Neg<Output = T>,
for<'a, 'b> &'a T: Neg<Output = T>
+ Mul<&'b T, Output = T>
+ Div<&'b T, Output = T>
+ Add<&'b T, Output = T>
+ Sub<&'b T, Output = T>,
{
let w = right - left;
let h = top - bottom;
let p = far - near;
let x = &(right + left) / &w;
let y = &(top + bottom) / &h;
let z = &(far + near) / &p;
out[0] = &T::from_isize(2).unwrap() / &w;
out[1] = T::zero();
out[2] = T::zero();
out[3] = T::zero();
out[4] = T::zero();
out[5] = &T::from_isize(2).unwrap() / &h;
out[6] = T::zero();
out[7] = T::zero();
out[8] = T::zero();
out[9] = T::zero();
out[10] = &T::from_isize(-2).unwrap() / &p;
out[11] = T::zero();
out[12] = -x;
out[13] = -y;
out[14] = -z;
out[15] = T::one();
out
}