|
- #![allow(dead_code)]
-
- use std::borrow::Borrow;
- use std::convert::{AsMut, AsRef};
- use std::fmt::{Debug, Formatter, Result as FmtResult};
- use std::ops::{Deref, DerefMut, Mul};
-
- use super::vector::{Element, Vector2, Vector3, Vector4};
-
- macro_rules! first_ptr {
- ($this:ident, $first:ident $(,$other:ident)*) => {
- unsafe { $this.$first.as_ptr() }
- };
- }
-
- macro_rules! define_mat {
- ($Name:ident, $Vector:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => {
- #[repr(C, packed)]
- pub struct $Name<T> {
- $(pub $f: $Vector<T>,)+
- }
-
- impl<T> $Name<T> {
- #[inline]
- pub fn new($($f: $Vector<T>,)+) -> Self {
- Self { $($f,)+ }
- }
-
- pub fn as_ptr(&self) -> * const T {
- first_ptr!(self $(,$f)+)
- }
- }
-
- impl<T> Default for $Name<T>
- where
- T: Element
- {
- #[inline]
- fn default() -> Self {
- Self::identity()
- }
- }
-
- impl<T> Debug for $Name<T>
- where
- T: Debug
- {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
- fmt.debug_list().entries(self.as_ref().iter()).finish()
- }
- }
-
- impl<T, S> PartialEq<$Name<S>> for $Name<T>
- where
- $Vector<S>: PartialEq<$Vector<T>>,
- {
- fn eq(&self, other: &$Name<S>) -> bool {
- unsafe { true $(&& other.$f.eq(&self.$f))+ }
- }
- }
-
- impl<T> Eq for $Name<T>
- where
- T: Eq
- { }
-
- impl<T> Deref for $Name<T> {
- type Target = [$Vector<T>; $size];
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- self.as_ref()
- }
- }
-
- impl<T> DerefMut for $Name<T> {
- #[inline]
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.as_mut()
- }
- }
-
- impl<T> AsRef<[$Vector<T>; $size]> for $Name<T> {
- #[inline]
- fn as_ref(&self) -> &[$Vector<T>; $size] {
- unsafe {
- let raw: * const _ = self;
- let raw = raw as * const [$Vector<T>; $size];
-
- &*raw
- }
- }
- }
-
- impl<T> AsMut<[$Vector<T>; $size]> for $Name<T> {
- #[inline]
- fn as_mut(&mut self) -> &mut [$Vector<T>; $size] {
- unsafe {
- let raw: * mut _ = self;
- let raw = raw as * mut [$Vector<T>; $size];
-
- &mut *raw
- }
- }
- }
-
- impl<T> Clone for $Name<T>
- where
- T: Clone
- {
- #[inline]
- fn clone(&self) -> Self {
- unsafe {
- Self {
- $($f: self.$f.clone(),)+
- }
- }
- }
- }
-
- impl<T> Copy for $Name<T>
- where
- T: Copy
- { }
-
- impl<T> From<[$Vector<T>; $size]> for $Name<T>
- where
- T: Copy,
- {
- #[inline]
- fn from(arr: [$Vector<T>; $size]) -> Self {
- Self {
- $($f: arr[$i],)+
- }
- }
- }
-
- impl<T> From<($($Vector<$T>,)+)> for $Name<T> {
- #[inline]
- fn from(($($f,)+): ($($Vector<$T>,)+)) -> Self {
- Self {
- $($f,)+
- }
- }
- }
- };
- }
-
- define_mat!(Matrix2, Vector2, 2, T => 0 => axis_x, T => 1 => axis_y);
- define_mat!(Matrix3, Vector3, 3, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z);
- define_mat!(Matrix4, Vector4, 4, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z, T => 3 => position);
-
- pub type Matrix2f = Matrix2<gl::GLfloat>;
- pub type Matrix3f = Matrix3<gl::GLfloat>;
- pub type Matrix4f = Matrix4<gl::GLfloat>;
-
- pub type Matrix2d = Matrix2<gl::GLdouble>;
- pub type Matrix3d = Matrix3<gl::GLdouble>;
- pub type Matrix4d = Matrix4<gl::GLdouble>;
-
- pub type Matrix2i = Matrix2<gl::GLint>;
- pub type Matrix3i = Matrix3<gl::GLint>;
- pub type Matrix4i = Matrix4<gl::GLint>;
-
- /* Matrix2 */
-
- impl<T> Matrix2<T>
- where
- T: Element,
- {
- #[inline]
- pub fn identity() -> Self {
- let one = T::one();
- let zero = T::zero();
-
- Self::new(Vector2::new(one, zero), Vector2::new(zero, one))
- }
- }
-
- /* Matrix3 */
-
- impl<T> Matrix3<T>
- where
- T: Element,
- {
- #[inline]
- pub fn identity() -> Self {
- let one = T::one();
- let zero = T::zero();
-
- Self::new(
- Vector3::new(one, zero, zero),
- Vector3::new(zero, one, zero),
- Vector3::new(zero, zero, one),
- )
- }
-
- #[inline]
- pub fn determinant(&self) -> T {
- let m = self;
-
- m[0][0] * m[1][1] * m[2][2] + m[1][0] * m[2][1] * m[0][2] + m[2][0] * m[0][1] * m[1][2]
- - m[2][0] * m[1][1] * m[0][2]
- - m[1][0] * m[0][1] * m[2][2]
- - m[0][0] * m[2][1] * m[1][2]
- }
- }
-
- /* Matrix4 */
-
- impl<T> Matrix4<T>
- where
- T: Element,
- {
- #[inline]
- pub fn identity() -> Self {
- let one = T::one();
- let zero = T::zero();
-
- Self::new(
- Vector4::new(one, zero, zero, zero),
- Vector4::new(zero, one, zero, zero),
- Vector4::new(zero, zero, one, zero),
- Vector4::new(zero, zero, zero, one),
- )
- }
-
- #[inline]
- pub fn translate(v: Vector3<T>) -> Self {
- let one = T::one();
- let zero = T::zero();
-
- Self::new(
- Vector4::new(one, zero, zero, zero),
- Vector4::new(zero, one, zero, zero),
- Vector4::new(zero, zero, one, zero),
- Vector4::new(v.x, v.y, v.z, one),
- )
- }
-
- #[inline]
- pub fn scale(v: Vector3<T>) -> Self {
- let one = T::one();
- let zero = T::zero();
-
- Self::new(
- Vector4::new(v.x, zero, zero, zero),
- Vector4::new(zero, v.y, zero, zero),
- Vector4::new(zero, zero, v.z, zero),
- Vector4::new(zero, zero, zero, one),
- )
- }
-
- #[inline]
- #[allow(clippy::many_single_char_names)]
- pub fn rotate(axis: Vector3<T>, angle: Angle<T>) -> Self {
- let axis = axis.normalize();
- let x = axis.x;
- let y = axis.y;
- let z = axis.z;
- let angle = angle.into_rad().into_inner();
- let s = T::sin(angle);
- let c = T::cos(angle);
- let one = T::one();
- let zero = T::zero();
-
- Self::new(
- Vector4::new(
- x * x + (one - y * y) * c,
- x * y * (one - c) + z * s,
- x * z * (one - c) - y * s,
- zero,
- ),
- Vector4::new(
- x * y * (one - c) - z * s,
- y * y + (one - y * y) * c,
- y * z * (one - c) + x * s,
- zero,
- ),
- Vector4::new(
- x * z * (one - c) + y * s,
- y * z * (one - c) - x * s,
- z * z + (one - z * z) * c,
- zero,
- ),
- Vector4::new(zero, zero, zero, one),
- )
- }
-
- #[inline]
- pub fn multiply(&self, other: &Self) -> Self {
- let m1 = self;
- let m2 = other;
-
- macro_rules! mul {
- ($x:tt, $y:tt) => {
- m1[0][$y] * m2[$x][0]
- + m1[1][$y] * m2[$x][1]
- + m1[2][$y] * m2[$x][2]
- + m1[3][$y] * m2[$x][3]
- };
- }
-
- Self::new(
- Vector4::new(mul!(0, 0), mul!(0, 1), mul!(0, 2), mul!(0, 3)),
- Vector4::new(mul!(1, 0), mul!(1, 1), mul!(1, 2), mul!(1, 3)),
- Vector4::new(mul!(2, 0), mul!(2, 1), mul!(2, 2), mul!(2, 3)),
- Vector4::new(mul!(3, 0), mul!(3, 1), mul!(3, 2), mul!(3, 3)),
- )
- }
-
- #[inline]
- pub fn transform(&self, v: &Vector4<T>) -> Vector4<T> {
- let m = self;
-
- macro_rules! mul {
- ($i:tt) => {
- m[0][$i] * v[0] + m[1][$i] * v[1] + m[2][$i] * v[2] + m[3][$i] * v[3]
- };
- }
-
- Vector4::new(mul!(0), mul!(1), mul!(2), mul!(3))
- }
-
- #[inline]
- pub fn transpose(&self) -> Self {
- let m = self;
-
- Self::new(
- Vector4::new(m[0][0], m[1][0], m[2][0], m[3][0]),
- Vector4::new(m[0][1], m[1][1], m[2][1], m[3][1]),
- Vector4::new(m[0][2], m[1][2], m[2][2], m[3][2]),
- Vector4::new(m[0][3], m[1][3], m[2][3], m[3][3]),
- )
- }
-
- #[inline]
- pub fn submatrix(&self, s: usize, z: usize) -> Matrix3<T> {
- let mut ret = Matrix3::identity();
-
- for i in 0..=2 {
- for j in 0..=2 {
- let x = if i >= s { i + 1 } else { i };
- let y = if j >= z { j + 1 } else { j };
-
- ret[i][j] = self[x][y];
- }
- }
-
- ret
- }
-
- #[inline]
- pub fn determinant(&self) -> T {
- let m = self;
-
- m[0][0] * m.submatrix(0, 0).determinant() - m[1][0] * m.submatrix(1, 0).determinant()
- + m[2][0] * m.submatrix(2, 0).determinant()
- + m[3][0] * m.submatrix(3, 0).determinant()
- }
-
- #[inline]
- pub fn adjoint(&self) -> Self {
- let m = self;
-
- Self::new(
- Vector4::new(
- m.submatrix(0, 0).determinant(),
- -m.submatrix(1, 0).determinant(),
- m.submatrix(2, 0).determinant(),
- -m.submatrix(3, 0).determinant(),
- ),
- Vector4::new(
- -m.submatrix(0, 1).determinant(),
- m.submatrix(1, 1).determinant(),
- -m.submatrix(2, 1).determinant(),
- m.submatrix(3, 1).determinant(),
- ),
- Vector4::new(
- m.submatrix(0, 2).determinant(),
- -m.submatrix(1, 2).determinant(),
- m.submatrix(2, 2).determinant(),
- -m.submatrix(3, 2).determinant(),
- ),
- Vector4::new(
- -m.submatrix(0, 3).determinant(),
- m.submatrix(1, 3).determinant(),
- -m.submatrix(2, 3).determinant(),
- m.submatrix(3, 3).determinant(),
- ),
- )
- }
-
- #[inline]
- pub fn invert(&self) -> Self {
- let d = self.determinant();
- let mut ret = self.adjoint();
-
- ret[0][0] = ret[0][0] / d;
- ret[0][1] = ret[0][1] / d;
- ret[0][2] = ret[0][2] / d;
- ret[0][3] = ret[0][3] / d;
-
- ret[1][0] = ret[1][0] / d;
- ret[1][1] = ret[1][1] / d;
- ret[1][2] = ret[1][2] / d;
- ret[1][3] = ret[1][3] / d;
-
- ret[2][0] = ret[2][0] / d;
- ret[2][1] = ret[2][1] / d;
- ret[2][2] = ret[2][2] / d;
- ret[2][3] = ret[2][3] / d;
-
- ret[3][0] = ret[3][0] / d;
- ret[3][1] = ret[3][1] / d;
- ret[3][2] = ret[3][2] / d;
- ret[3][3] = ret[3][3] / d;
-
- ret
- }
- }
-
- impl<T> Matrix4<T>
- where
- T: Element<AsFloat = T>,
- {
- #[inline]
- pub fn ortho(left: T, right: T, bottom: T, top: T, near: T, far: T) -> Self {
- let one = T::one();
- let two = one + one;
- let zero = T::zero();
-
- Matrix4::new(
- Vector4::new(two / (right - left), zero, zero, zero),
- Vector4::new(zero, two / (top - bottom), zero, zero),
- Vector4::new(zero, zero, -two / (far - near), zero),
- Vector4::new(
- -(right + left) / (right - left),
- -(top + bottom) / (top - bottom),
- -(far + near) / (far - near),
- one,
- ),
- )
- }
-
- #[inline]
- pub fn perspective(fov: Angle<T>, ratio: T, near: T, far: T) -> Self {
- let one = T::one();
- let two = one + one;
- let zero = T::zero();
-
- let top = near * fov.into_rad().into_inner().tan();
- let bottom = -top;
- let right = ratio * top;
- let left = -right;
-
- Matrix4::new(
- Vector4::new(two * near / (right - left), zero, zero, zero),
- Vector4::new(zero, two * near / (top - bottom), zero, zero),
- Vector4::new(
- (right + left) / (right - left),
- (top + bottom) / (top - bottom),
- -(far + near) / (far - near),
- -one,
- ),
- Vector4::new(zero, zero, -two * far * near / (far - near), zero),
- )
- }
- }
-
- impl<T, M> Mul<M> for Matrix4<T>
- where
- T: Element,
- M: Borrow<Matrix4<T>>,
- {
- type Output = Self;
-
- fn mul(self, rhs: M) -> Self::Output {
- self.multiply(rhs.borrow())
- }
- }
-
- /* Angle */
-
- pub enum Angle<T> {
- Deg(T),
- Rad(T),
- }
-
- impl<T> Angle<T>
- where
- T: Element,
- {
- pub fn into_inner(self) -> T {
- match self {
- Self::Deg(v) => v,
- Self::Rad(v) => v,
- }
- }
-
- pub fn into_deg(self) -> Self {
- match self {
- Self::Deg(v) => Self::Deg(v),
- Self::Rad(v) => Self::Rad(T::to_degrees(v)),
- }
- }
-
- pub fn into_rad(self) -> Self {
- match self {
- Self::Deg(v) => Self::Deg(T::to_radians(v)),
- Self::Rad(v) => Self::Rad(v),
- }
- }
- }
-
- #[cfg(test)]
- mod tests {
- use super::*;
-
- #[test]
- fn invert() {
- let m = Matrix4d::identity()
- * Matrix4::translate(Vector3::new(1.0, 2.0, 3.0))
- * Matrix4::scale(Vector3::new(30.0, 20.0, 10.0))
- * Matrix4::rotate(Vector3::new(1.0, 0.0, 0.0), Angle::Deg(45.0));
- let m = m.invert();
-
- let e = Matrix4d::new(
- Vector4::new(
- 0.019526214587563498,
- -0.000000000000000000,
- 0.000000000000000000,
- -0.000000000000000000,
- ),
- Vector4::new(
- -0.000000000000000000,
- 0.035355339059327376,
- -0.035355339059327376,
- 0.000000000000000000,
- ),
- Vector4::new(
- 0.00000000000000000,
- 0.07071067811865475,
- 0.07071067811865475,
- -0.00000000000000000,
- ),
- Vector4::new(
- -0.019526214587563498,
- -0.282842712474619000,
- -0.141421356237309560,
- 1.000000000000000000,
- ),
- );
-
- assert_eq!(e, m);
- }
- }
|