From a9d797e82e612bc2013f84bfbe54bb0f8983d4cb Mon Sep 17 00:00:00 2001 From: Joshua Simmons Date: Thu, 8 Sep 2022 22:46:38 +0200 Subject: [PATCH] Fill out `Mat2` and `Mat3` some more --- narcissus-maths/src/affine2.rs | 1 + narcissus-maths/src/affine3.rs | 1 + narcissus-maths/src/mat2.rs | 35 +++++++++++++++ narcissus-maths/src/mat3.rs | 79 ++++++++++++++++++++++++++++++++++ narcissus-maths/src/mat4.rs | 17 ++++++++ 5 files changed, 133 insertions(+) diff --git a/narcissus-maths/src/affine2.rs b/narcissus-maths/src/affine2.rs index 42a0a2c..0d10b17 100644 --- a/narcissus-maths/src/affine2.rs +++ b/narcissus-maths/src/affine2.rs @@ -1,5 +1,6 @@ use crate::{Mat2, Vec2}; +/// Matrix and translation vector which together represent a 2d affine transformation. #[derive(Clone, Copy, PartialEq)] #[repr(C)] pub struct Affine2 { diff --git a/narcissus-maths/src/affine3.rs b/narcissus-maths/src/affine3.rs index f13a653..39c924e 100644 --- a/narcissus-maths/src/affine3.rs +++ b/narcissus-maths/src/affine3.rs @@ -1,5 +1,6 @@ use crate::{Mat3, Vec3}; +/// Matrix and translation vector which together represent a 3d affine transformation. #[derive(Clone, Copy, PartialEq)] #[repr(C)] pub struct Affine3 { diff --git a/narcissus-maths/src/mat2.rs b/narcissus-maths/src/mat2.rs index 8b21e7b..e36669f 100644 --- a/narcissus-maths/src/mat2.rs +++ b/narcissus-maths/src/mat2.rs @@ -1,3 +1,38 @@ +/// 2x2 matrix. #[derive(Clone, Copy, PartialEq)] #[repr(C)] pub struct Mat2(pub [f32; 4]); + +impl std::fmt::Debug for Mat2 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + writeln!(f, "Mat2 [")?; + for row in self.as_rows() { + writeln!(f, "\t{:?}", row)?; + } + writeln!(f, "]") + } else { + writeln!(f, "Mat2 {:?}", self.as_rows()) + } + } +} + +impl Mat2 { + pub const ZERO: Mat2 = Mat2::from_rows([[0.0, 0.0], [0.0, 0.0]]); + pub const IDENTITY: Mat2 = Mat2::from_rows([[1.0, 0.0], [0.0, 1.0]]); + + #[inline(always)] + pub fn as_rows(&self) -> &[[f32; 2]; 2] { + unsafe { std::mem::transmute(&self.0) } + } + + #[inline(always)] + pub fn as_rows_mut(&mut self) -> &mut [[f32; 2]; 2] { + unsafe { std::mem::transmute(&mut self.0) } + } + + #[inline(always)] + pub const fn from_rows(rows: [[f32; 2]; 2]) -> Self { + unsafe { std::mem::transmute(rows) } + } +} diff --git a/narcissus-maths/src/mat3.rs b/narcissus-maths/src/mat3.rs index 93a772a..33741fc 100644 --- a/narcissus-maths/src/mat3.rs +++ b/narcissus-maths/src/mat3.rs @@ -1,3 +1,82 @@ +use crate::{Rad, Vec3}; + +/// 3x3 matrix. #[derive(Clone, Copy, PartialEq)] #[repr(C)] pub struct Mat3(pub [f32; 9]); + +impl std::fmt::Debug for Mat3 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + writeln!(f, "Mat3 [")?; + for row in self.as_rows() { + writeln!(f, "\t{:?}", row)?; + } + writeln!(f, "]") + } else { + writeln!(f, "Mat3 {:?}", self.as_rows()) + } + } +} + +impl Mat3 { + pub const ZERO: Mat3 = Mat3::from_rows([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]); + pub const IDENTITY: Mat3 = Mat3::from_rows([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]); + + #[inline(always)] + pub fn as_rows(&self) -> &[[f32; 3]; 3] { + unsafe { std::mem::transmute(&self.0) } + } + + #[inline(always)] + pub fn as_rows_mut(&mut self) -> &mut [[f32; 3]; 3] { + unsafe { std::mem::transmute(&mut self.0) } + } + + #[inline(always)] + pub const fn from_rows(rows: [[f32; 3]; 3]) -> Self { + unsafe { std::mem::transmute(rows) } + } + + /// Construct a matrix with the provided `diagonal` and all other values set to `0.0`. + pub const fn from_diagonal(diagonal: Vec3) -> Mat3 { + Mat3::from_rows([ + [diagonal.x, 0.0, 0.0], + [0.0, diagonal.y, 0.0], + [0.0, 0.0, diagonal.z], + ]) + } + + /// Construct a transformation matrix which scales along the coordinate axis by the values given in `scale`. + pub const fn from_scale(scale: Vec3) -> Mat3 { + Mat3::from_diagonal(scale) + } + + /// Constructs a transformation matrix which rotates around the given `axis` by `angle`. + pub fn from_axis_angle(axis: Vec3, angle: Rad) -> Mat3 { + let (sin, cos) = angle.as_f32().sin_cos(); + let axis_sin = axis * sin; + let axis_sq = axis * axis; + let one_minus_cos = 1.0 - cos; + let xy = axis.x * axis.y * one_minus_cos; + let xz = axis.x * axis.z * one_minus_cos; + let yz = axis.y * axis.z * one_minus_cos; + Mat3::from_rows([ + [ + axis_sq.x * one_minus_cos + cos, + xy - axis_sin.z, + xz + axis_sin.y, + ], + [ + xy + axis_sin.z, + axis_sq.y * one_minus_cos + cos, + yz - axis_sin.x, + ], + [ + xz - axis_sin.y, + yz + axis_sin.x, + axis_sq.z * one_minus_cos + cos, + ], + ]) + } +} diff --git a/narcissus-maths/src/mat4.rs b/narcissus-maths/src/mat4.rs index 40260b4..ae7615b 100644 --- a/narcissus-maths/src/mat4.rs +++ b/narcissus-maths/src/mat4.rs @@ -1,5 +1,8 @@ use crate::{Point2, Point3, Rad, Vec2, Vec3, Vec4}; +/// 4x4 matrix. +/// +/// Supports affine transformations. #[derive(Clone, Copy, PartialEq)] #[repr(C)] pub struct Mat4(pub [f32; 16]); @@ -77,6 +80,7 @@ impl Mat4 { result } + /// Construct a matrix with the provided `diagonal` and all other values set to `0.0`. pub const fn from_diagonal(diagonal: Vec4) -> Mat4 { Mat4::from_rows([ [diagonal.x, 0.0, 0.0, 0.0], @@ -86,6 +90,7 @@ impl Mat4 { ]) } + /// Construct a transformation matrix which scales along the coordinate axis by the values given in `scale`. pub const fn from_scale(scale: Vec3) -> Mat4 { Mat4::from_rows([ [scale.x, 0.0, 0.0, 0.0], @@ -95,6 +100,7 @@ impl Mat4 { ]) } + /// Construct an affine transformation matrix with the given `translation` along the coordinate axis. pub const fn from_translation(translation: Vec3) -> Mat4 { Mat4::from_rows([ [1.0, 0.0, 0.0, translation.x], @@ -104,6 +110,7 @@ impl Mat4 { ]) } + /// Constructs a transformation matrix which rotates around the given `axis` by `angle`. pub fn from_axis_angle(axis: Vec3, angle: Rad) -> Mat4 { let (sin, cos) = angle.as_f32().sin_cos(); let axis_sin = axis * sin; @@ -147,6 +154,7 @@ impl Mat4 { ]) } + // Safety: Requires SSE2. #[inline] #[target_feature(enable = "sse2")] unsafe fn transpose_sse2(self) -> Mat4 { @@ -156,6 +164,7 @@ impl Mat4 { Mat4::from_m128_array([row0, row1, row2, row3]) } + /// Returns the transpose of `self`. #[must_use] #[inline(always)] pub fn transpose(self) -> Mat4 { @@ -169,6 +178,7 @@ impl Mat4 { } } + /// Transforms the given [`Vec2`] `vec` by `self`. #[must_use] #[inline] pub fn mul_vec2(&self, vec: Vec2) -> Vec2 { @@ -177,6 +187,7 @@ impl Mat4 { Vec2::new(vec.x, vec.y) } + /// Transforms the given [`Point2`] `point` by `self`. #[must_use] #[inline] pub fn mul_point2(&self, point: Point2) -> Point2 { @@ -185,6 +196,7 @@ impl Mat4 { Point2::new(vec.x, vec.y) } + /// Transforms the given [`Vec3`] `vec` by `self`. #[must_use] #[inline] pub fn mul_vec3(&self, vec: Vec3) -> Vec3 { @@ -193,6 +205,7 @@ impl Mat4 { [vec.x, vec.y, vec.z].into() } + /// Transforms the given [`Point3`] `point` by `self`. #[must_use] #[inline] pub fn mul_point3(&self, point: Point3) -> Point3 { @@ -212,6 +225,7 @@ impl Mat4 { ) } + // Safety: Requires SSE4.1. #[allow(dead_code)] #[inline] #[target_feature(enable = "sse4.1")] @@ -229,6 +243,7 @@ impl Mat4 { values.into() } + /// Transforms the given [`Vec4`] `vec` by `self`. #[must_use] #[inline(always)] pub fn mul_vec4(&self, vec: Vec4) -> Vec4 { @@ -263,6 +278,7 @@ impl Mat4 { result } + // Safety: Requires SSE2. #[allow(dead_code)] #[inline] #[target_feature(enable = "sse2")] @@ -290,6 +306,7 @@ impl Mat4 { Mat4::from_m128_array([x0, x1, x2, x3]) } + // Safety: Requires AVX2. #[allow(dead_code)] #[inline] #[target_feature(enable = "avx2")] -- 2.49.0