use num_traits::{One, Zero};
use crate::basenum::BaseFloat;
use crate::builtin::{cross, dot, normalize};
use crate::mat::mat::{Matrix3, Matrix4};
use crate::traits::GenFloat;
use crate::vec::vec::{Vector3, Vector4};
#[inline]
pub fn translate<T>(m: &Matrix4<T>, v: Vector3<T>) -> Matrix4<T>
where
T: BaseFloat,
{
Matrix4::new(
m.c0,
m.c1,
m.c2,
m.c0 * v.x + m.c1 * v.y + m.c2 * v.z + m.c3,
)
}
#[inline]
pub fn perspective<T>(fov_y: T, aspect: T, z_near: T, z_far: T) -> Matrix4<T>
where
T: BaseFloat,
{
perspective_rh(fov_y, aspect, z_near, z_far)
}
#[inline]
pub fn perspective_rh<T>(fov_y: T, aspect: T, z_near: T, z_far: T) -> Matrix4<T>
where
T: BaseFloat,
{
let zero = num_traits::zero::<T>();
let one = num_traits::one::<T>();
let two = one + one;
let q = one / (fov_y / two).tan();
let a = q / aspect;
let b = (z_near + z_far) / (z_near - z_far);
let c = (two * z_near * z_far) / (z_near - z_far);
Matrix4::new(
Vector4::new(a, zero, zero, zero),
Vector4::new(zero, q, zero, zero),
Vector4::new(zero, zero, b, zero - one),
Vector4::new(zero, zero, c, zero),
)
}
#[inline]
pub fn rotate<T>(m: &Matrix4<T>, angle: T, v: Vector3<T>) -> Matrix4<T>
where
T: BaseFloat + GenFloat<T>,
{
let zero = num_traits::zero::<T>();
let one = num_traits::one::<T>();
let a = angle;
let (s, c) = a.sin_cos();
let axis = normalize(v);
let temp = axis * (one - c);
let rotate = Matrix3::new(
Vector3::new(
c + temp.x * axis.x,
temp.x * axis.y + s * axis.z,
temp.x * axis.z - s * axis.y,
),
Vector3::new(
temp.y * axis.x - s * axis.z,
c + temp.y * axis.y,
temp.y * axis.z + s * axis.x,
),
Vector3::new(
temp.z * axis.x + s * axis.y,
temp.z * axis.y - s * axis.x,
c + temp.z * axis.z,
),
);
Matrix4::new(
m.c0 * rotate.c0.x + m.c1 * rotate.c0.y + m.c2 * rotate.c0.z,
m.c0 * rotate.c1.x + m.c1 * rotate.c1.y + m.c2 * rotate.c1.z,
m.c0 * rotate.c2.x + m.c1 * rotate.c2.y + m.c2 * rotate.c2.z,
m.c3,
)
}
#[inline]
pub fn scale<T>(m: &Matrix4<T>, v: Vector3<T>) -> Matrix4<T>
where
T: BaseFloat + GenFloat<T>,
{
Matrix4::new(m.c0 * v.x, m.c1 * v.y, m.c2 * v.z, m.c3)
}
#[inline]
pub fn look_at<T>(eye: Vector3<T>, center: Vector3<T>, up: Vector3<T>) -> Matrix4<T>
where
T: BaseFloat + GenFloat<T>,
{
look_at_rh::<T>(eye, center, up)
}
#[inline]
pub fn look_at_rh<T>(eye: Vector3<T>, center: Vector3<T>, up: Vector3<T>) -> Matrix4<T>
where
T: BaseFloat + GenFloat<T>,
{
let zero = <T as Zero>::zero();
let one = <T as One>::one();
let f = normalize(center - eye);
let s = normalize(cross(f, up));
let u = cross(s, f);
Matrix4::new(
Vector4::new(s.x, u.x, -f.x, zero),
Vector4::new(s.y, u.y, -f.y, zero),
Vector4::new(s.z, u.z, -f.z, zero),
Vector4::new(-dot(s, eye), -dot(u, eye), dot(f, eye), one),
)
}
#[cfg(test)]
mod test {
use crate::ext::{perspective, translate, Consts};
use crate::vec::vec::{vec3, vec4};
#[test]
fn test_translate() {
let v = vec3(1.0, 3.0, 2.0);
let m = num_traits::one();
let t = translate(&m, v);
assert_eq!(t[0], vec4(1., 0., 0., 0.));
assert_eq!(t[1], vec4(0., 1., 0., 0.));
assert_eq!(t[2], vec4(0., 0., 1., 0.));
assert_eq!(t[3], v.extend(1.));
}
#[test]
fn test_perspective() {
let p = perspective(f32::pi() * 2.0 * 45.0 / 360.0, 1920.0 / 1080.0, 0.1, 100.0);
}
}