diff --git a/sub_crates/rmath/src/normal.rs b/sub_crates/rmath/src/normal.rs index 8ae05fe..b4c6508 100644 --- a/sub_crates/rmath/src/normal.rs +++ b/sub_crates/rmath/src/normal.rs @@ -3,13 +3,14 @@ use std::ops::{Add, Div, Mul, Neg, Sub}; use crate::wide4::Float4; +use crate::xform::XformFull; use crate::DotProduct; use crate::Vector; /// A surface normal in 3D space. #[derive(Debug, Copy, Clone)] #[repr(transparent)] -pub struct Normal(pub(crate) Float4); +pub struct Normal(pub Float4); impl Normal { #[inline(always)] @@ -71,6 +72,25 @@ impl Normal { pub fn set_z(self, z: f32) -> Self { Self(self.0.set_c(z)) } + + //------------- + // Transforms. + + pub fn xform(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3(&Float4::transpose_3x3(xform.m_inv))) + } + + pub fn xform_inv(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3(&Float4::transpose_3x3(xform.m))) + } + + pub fn xform_fast(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3_fast(&Float4::transpose_3x3(xform.m_inv))) + } + + pub fn xform_inv_fast(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3_fast(&Float4::transpose_3x3(xform.m))) + } } impl Add for Normal { diff --git a/sub_crates/rmath/src/point.rs b/sub_crates/rmath/src/point.rs index 0af5900..9b94811 100644 --- a/sub_crates/rmath/src/point.rs +++ b/sub_crates/rmath/src/point.rs @@ -3,11 +3,12 @@ use std::ops::{Add, Sub}; use crate::vector::Vector; use crate::wide4::Float4; +use crate::xform::XformFull; /// A position in 3D space. #[derive(Debug, Copy, Clone)] #[repr(transparent)] -pub struct Point(pub(crate) Float4); +pub struct Point(pub Float4); impl Point { #[inline(always)] @@ -62,6 +63,25 @@ impl Point { pub fn set_z(self, z: f32) -> Self { Self(self.0.set_c(z)) } + + //------------- + // Transforms. + + pub fn xform(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_affine(&xform.m, xform.t)) + } + + pub fn xform_inv(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_affine_rev(&xform.m_inv, -xform.t)) + } + + pub fn xform_fast(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_affine_fast(&xform.m, xform.t)) + } + + pub fn xform_inv_fast(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_affine_rev_fast(&xform.m_inv, -xform.t)) + } } impl Add for Point { diff --git a/sub_crates/rmath/src/vector.rs b/sub_crates/rmath/src/vector.rs index 0e37c6e..04beb1d 100644 --- a/sub_crates/rmath/src/vector.rs +++ b/sub_crates/rmath/src/vector.rs @@ -5,12 +5,13 @@ use std::ops::{Add, Div, Mul, Neg, Sub}; use crate::normal::Normal; use crate::point::Point; use crate::wide4::Float4; +use crate::xform::XformFull; use crate::DotProduct; /// A direction vector in 3D space. #[derive(Debug, Copy, Clone)] #[repr(transparent)] -pub struct Vector(pub(crate) Float4); +pub struct Vector(pub Float4); impl Vector { #[inline(always)] @@ -77,6 +78,25 @@ impl Vector { pub fn set_z(self, z: f32) -> Self { Self(self.0.set_c(z)) } + + //------------- + // Transforms. + + pub fn xform(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3(&xform.m)) + } + + pub fn xform_inv(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3(&xform.m_inv)) + } + + pub fn xform_fast(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3_fast(&xform.m)) + } + + pub fn xform_inv_fast(self, xform: &XformFull) -> Self { + Self(self.0.vec_mul_3x3_fast(&xform.m_inv)) + } } impl Add for Vector { diff --git a/sub_crates/rmath/src/wide4.rs b/sub_crates/rmath/src/wide4.rs index 466c9fd..5962109 100644 --- a/sub_crates/rmath/src/wide4.rs +++ b/sub_crates/rmath/src/wide4.rs @@ -10,7 +10,6 @@ mod fallback { use crate::FMulAdd; - #[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone)] #[repr(C, align(16))] pub struct Float4 { @@ -463,6 +462,18 @@ impl Float4 { s3 + err3 } + /// Transforms a 3d point by an affine transform. + /// + /// Faster but less precise version. + #[inline] + pub fn vec_mul_affine_fast(self, m: &[Self; 3], t: Self) -> Self { + let x = self.aaaa(); + let y = self.bbbb(); + let z = self.cccc(); + + (x * m[0]) + (y * m[1]) + (z * m[2]) + t + } + /// Transforms a 3d point by an affine transform, except it applies /// the translation part before the 3x3 part. /// @@ -499,6 +510,21 @@ impl Float4 { s3 + err3 } + /// Transforms a 3d point by an affine transform, except it applies + /// the translation part before the 3x3 part. + /// + /// Faster but less precise version. + #[inline] + pub fn vec_mul_affine_rev_fast(self, m: &[Self; 3], t: Self) -> Self { + let v = self + t; + + let x = v.aaaa(); + let y = v.bbbb(); + let z = v.cccc(); + + (x * m[0]) + (y * m[1]) + (z * m[2]) + } + /// Returns whether the `Float4`s are approximately equal to each /// other. /// diff --git a/sub_crates/rmath/src/xform.rs b/sub_crates/rmath/src/xform.rs index 6d4e186..bd071d4 100644 --- a/sub_crates/rmath/src/xform.rs +++ b/sub_crates/rmath/src/xform.rs @@ -9,8 +9,8 @@ use crate::wide4::Float4; #[derive(Debug, Copy, Clone)] #[repr(C)] pub struct Xform { - pub(crate) m: [Float4; 3], // Linear matrix. - pub(crate) t: Float4, // Translation. + pub m: [Float4; 3], // Linear matrix. + pub t: Float4, // Translation. } impl Xform { @@ -170,9 +170,9 @@ impl Add for Xform { #[derive(Debug, Copy, Clone)] #[repr(C)] pub struct XformFull { - pub(crate) m: [Float4; 3], // Linear matrix. - pub(crate) m_inv: [Float4; 3], // Inverse of linear matrix. - pub(crate) t: Float4, // Forward translation. + pub m: [Float4; 3], // Forward linear matrix. + pub m_inv: [Float4; 3], // Inverse linear matrix. + pub t: Float4, // Forward translation. } //-------------------------------------------------------------