Skip to content

Commit

Permalink
- added 4x3 matrix for column major transposes and fixed 3x4 transpose
Browse files Browse the repository at this point in the history
  • Loading branch information
polymonster committed Mar 22, 2023
1 parent 119e424 commit 088fcc3
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 18 deletions.
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod num;
pub mod vec;

/// multi dimensional row-major matrix with generic mat2, mat3, mat34 and mat4 implementations
/// there is a column-major mat43 type which can be transposed from mat34 but it does not support the full functionality
pub mod mat;

/// generic quaternion for varying floating point precision
Expand Down Expand Up @@ -35,10 +36,12 @@ pub type Vec4u = Vec4<u32>;
pub type Mat2f = Mat2<f32>;
pub type Mat3f = Mat3<f32>;
pub type Mat34f = Mat34<f32>;
pub type Mat43f = Mat43<f32>;
pub type Mat4f = Mat4<f32>;
pub type Mat2d = Mat2<f64>;
pub type Mat3d = Mat3<f64>;
pub type Mat34d = Mat34<f64>;
pub type Mat43d = Mat43<f64>;
pub type Mat4d = Mat4<f64>;
pub type Quatf = Quat<f32>;
pub type Quatd = Quat<f64>;
Expand Down
149 changes: 135 additions & 14 deletions src/mat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ use std::fmt::Formatter;
/// 08 09 10 11
/// 12 13 14 15
macro_rules! mat_impl {
/// Create a partial matrix class, this is the concreate matrix struct and indexing operations.
/// the partial implementation allows data only (no arithmetic or traits) to be created
/// to facilitate 3x4 to 4x3 trasposes for interoperation with other API's and shaders
macro_rules! mat_partial_impl {
($MatN:ident, $rows:expr, $cols:expr, $elems:expr,
$RowVecN:ident { $($row_field:ident, $row_field_index:expr),* },
$ColVecN:ident { $($col_field:ident, $col_field_index:expr),* } ) => {
Expand Down Expand Up @@ -81,14 +84,18 @@ macro_rules! mat_impl {
impl<T> Deref for $MatN<T> where T: Number {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
unsafe {
std::slice::from_raw_parts(&self.m[0], $elems)
}
}
}

/// mutably deref matrix as a slice of T
impl<T> DerefMut for $MatN<T> where T: Number {
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
unsafe {
std::slice::from_raw_parts_mut(&mut self.m[0], $elems)
}
}
}

Expand Down Expand Up @@ -140,7 +147,14 @@ macro_rules! mat_impl {
true
}
}
}
}

/// creates the basic generic traits for row-major matrices
macro_rules! mat_impl {
($MatN:ident, $rows:expr, $cols:expr, $elems:expr,
$RowVecN:ident { $($row_field:ident, $row_field_index:expr),* },
$ColVecN:ident { $($col_field:ident, $col_field_index:expr),* } ) => {
impl<T> $MatN<T> where T: Number {
/// initialise matrix to all zero's
pub fn zero() -> $MatN<T> {
Expand All @@ -164,6 +178,14 @@ macro_rules! mat_impl {
}
}

pub const fn get_num_rows(&self) -> usize {
$rows
}

pub const fn get_num_columns(&self) -> usize {
$cols
}

/// get single element from the matrix at row, column index
pub fn at(self, row: u32, column: u32) -> T {
let urow = row as usize;
Expand Down Expand Up @@ -226,17 +248,6 @@ macro_rules! mat_impl {
std::slice::from_raw_parts((&self.m[0] as *const T) as *const u8, std::mem::size_of::<$MatN<T>>())
}
}

/// returns a transposed matrix so rows become columns and columns become rows
pub fn transpose(&self) -> $MatN<T> {
let mut t = *self;
for r in 0..$rows {
for c in 0..$cols {
t.set(c, r, self.at(r, c));
}
}
t
}
}
}
}
Expand Down Expand Up @@ -1275,6 +1286,78 @@ impl<T> MatInverse<T> for Mat4<T> where T: SignedNumber {
}
}

/// trait for matrix transpose
pub trait MatTranspose<T, Other> {
fn transpose(&self) -> Other;
}

impl<T> MatTranspose<T, Self> for Mat2<T> where T: Number {
fn transpose(&self) -> Self {
let mut t = *self;
for r in 0..t.get_num_rows() as u32 {
for c in 0..t.get_num_columns() as u32 {
t.set(c, r, self.at(r, c));
}
}
t
}
}

impl<T> MatTranspose<T, Self> for Mat3<T> where T: Number {
fn transpose(&self) -> Self {
let mut t = *self;
for r in 0..t.get_num_rows() as u32 {
for c in 0..t.get_num_columns() as u32 {
t.set(c, r, self.at(r, c));
}
}
t
}
}

impl<T> MatTranspose<T, Self> for Mat4<T> where T: Number {
fn transpose(&self) -> Self {
let mut t = *self;
for r in 0..t.get_num_rows() as u32 {
for c in 0..t.get_num_columns() as u32 {
t.set(c, r, self.at(r, c));
}
}
t
}
}

impl<T> MatTranspose<T, Mat43<T>> for Mat34<T> where T: Number {
fn transpose(&self) -> Mat43<T> {
let mut t = Mat43 {
m: [T::zero(); 12]
};
for r in 0..3 {
for c in 0..4 {
let i = c * 3 + r;
let v = self.at(r as u32, c as u32);
t.m[i] = v;
}
}
t
}
}

impl<T> MatTranspose<T, Mat34<T>> for Mat43<T> where T: Number {
fn transpose(&self) -> Mat34<T> {
let mut t = Mat34 {
m: [T::zero(); 12]
};
for r in 0..4 {
for c in 0..3 {
let i = r * 3 + c;
t.set(c, r, self.m[i as usize]);
}
}
t
}
}

/// trait for 4x4 projection matrices
pub trait MatProjection<T> {
/// returns 6 frustum planes as `Vec4`'s in the form `.xyz = normal, .w = plane distance`
Expand Down Expand Up @@ -1485,6 +1568,35 @@ impl<T> MatNew34<T> for Mat34<T> where T: Number {
}
}

#[allow(clippy::too_many_arguments)]
/// trait to construct matrix from 12 scalars
pub trait MatNew43<T> {
fn new(
m00: T, m01: T, m02: T,
m03: T, m10: T, m11: T,
m12: T, m13: T, m20: T,
m21: T, m22: T, m23: T,
) -> Self;
}

impl<T> MatNew43<T> for Mat43<T> where T: Number {
fn new(
m00: T, m01: T, m02: T,
m03: T, m10: T, m11: T,
m12: T, m13: T, m20: T,
m21: T, m22: T, m23: T,
) -> Self {
Self {
m: [
m00, m01, m02,
m03, m10, m11,
m12, m13, m20,
m21, m22, m23
]
}
}
}

#[allow(clippy::too_many_arguments)]
/// trait to construct matrix from 16 scalars
pub trait MatNew4<T> {
Expand Down Expand Up @@ -1514,7 +1626,16 @@ impl<T> MatNew4<T> for Mat4<T> where T: Number {
}
}

mat_partial_impl!(Mat2, 2, 2, 4, Vec2 {x, 0, y, 1}, Vec2 {x, 0, y, 1});
mat_impl!(Mat2, 2, 2, 4, Vec2 {x, 0, y, 1}, Vec2 {x, 0, y, 1});

mat_partial_impl!(Mat3, 3, 3, 9, Vec3 {x, 0, y, 1, z, 2}, Vec3 {x, 0, y, 1, z, 2});
mat_impl!(Mat3, 3, 3, 9, Vec3 {x, 0, y, 1, z, 2}, Vec3 {x, 0, y, 1, z, 2});

mat_partial_impl!(Mat4, 4, 4, 16, Vec4 {x, 0, y, 1, z, 2, w, 3}, Vec4 {x, 0, y, 1, z, 2, w, 3});
mat_impl!(Mat4, 4, 4, 16, Vec4 {x, 0, y, 1, z, 2, w, 3}, Vec4 {x, 0, y, 1, z, 2, w, 3});

mat_partial_impl!(Mat34, 3, 4, 12, Vec4 {x, 0, y, 1, z, 2, w, 3}, Vec3 {x, 0, y, 1, z, 2});
mat_impl!(Mat34, 3, 4, 12, Vec4 {x, 0, y, 1, z, 2, w, 3}, Vec3 {x, 0, y, 1, z, 2});

mat_partial_impl!(Mat43, 4, 3, 12, Vec4 {x, 0, y, 1, z, 2}, Vec3 {x, 0, y, 1, z, 2, w, 3});
6 changes: 2 additions & 4 deletions src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub trait Lerp<T: Float> {
fn lerp(e0: Self, e1: Self, t: T) -> Self;
}

pub trait Cast<T: Number> {
pub trait Cast<T: Number> where Self: Sized {
fn from_f32(v: f32) -> Self;
fn from_f64(v: f64) -> Self;
fn from_u32(v: u32) -> Self;
Expand Down Expand Up @@ -547,6 +547,4 @@ float_trait_impl!(
floor, ceil, round, sqrt, recip,
cos, sin, tan, acos, asin, atan, cosh, sinh, tanh,
exp, exp2, log2, log10
);

// num_cast!(f32, f64);
);
18 changes: 18 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,7 @@ fn matrix_transpose() {
1.0, 3.0
);
assert_eq!(m2.transpose(),t2);
assert_eq!(t2.transpose(),m2);

// 3x3
let m3 = Mat3f::new(
Expand All @@ -961,6 +962,7 @@ fn matrix_transpose() {
2.0, 5.0, 8.0
);
assert_eq!(m3.transpose(),t3);
assert_eq!(t3.transpose(),m3);

// 4x4
let m4 = Mat4f::new(
Expand All @@ -976,6 +978,22 @@ fn matrix_transpose() {
3.0, 7.0, 11.0, 15.0
);
assert_eq!(m4.transpose(),t4);
assert_eq!(t4.transpose(),m4);

// 3x4 to 4x3
let m34 = Mat34f::new(
0.0, 1.0, 2.0, 3.0,
4.0, 5.0, 6.0, 7.0,
8.0, 9.0, 10.0, 11.0
);
let t43 = Mat43f::new(
0.0, 4.0, 8.0,
1.0, 5.0, 9.0,
2.0, 6.0, 10.0,
3.0, 7.0, 11.0
);
assert_eq!(m34.transpose(), t43);
assert_eq!(t43.transpose(), m34);
}

#[test]
Expand Down

0 comments on commit 088fcc3

Please sign in to comment.