diff --git a/Cargo.lock b/Cargo.lock index 3463705..5c113ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,6 +55,13 @@ name = "crossbeam" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "float4" +version = "0.1.0" +dependencies = [ + "simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gcc" version = "0.3.45" @@ -93,6 +100,13 @@ dependencies = [ "rgb 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "math3d" +version = "0.1.0" +dependencies = [ + "float4 0.1.0", +] + [[package]] name = "mem_arena" version = "0.1.0" @@ -141,16 +155,17 @@ version = "0.1.0" dependencies = [ "clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "float4 0.1.0", "halton 0.1.0", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lodepng 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "math3d 0.1.0", "mem_arena 0.1.0", "nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "openexr 0.1.0 (git+https://github.com/cessen/openexr-rs?rev=612fc6c81c031970ffddcab15509236711613de8)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sobol 0.1.0", "spectra_xyz 0.1.0", "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 9a11ca9..eb4233f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,9 @@ [workspace] members = [ - "sub_crates/mem_arena", + "sub_crates/float4", "sub_crates/halton", + "sub_crates/math3d", + "sub_crates/mem_arena", "sub_crates/sobol", "sub_crates/spectra_xyz" ] @@ -12,7 +14,7 @@ version = "0.1.0" authors = ["Nathan Vegdahl "] [features] -simd_perf = ["simd"] +simd_perf = ["float4/simd_perf", "math3d/simd_perf"] [profile.release] debug = true @@ -28,15 +30,21 @@ crossbeam = "0.2" num_cpus = "1.0" lodepng = "0.8" lazy_static = "0.2" -simd = { version = "0.2.0", optional = true } + # Github dependencies openexr = { git = "https://github.com/cessen/openexr-rs", rev = "612fc6c81c031970ffddcab15509236711613de8" } # Local crate dependencies +[dependencies.float4] +path = "sub_crates/float4" + [dependencies.halton] path = "sub_crates/halton" +[dependencies.math3d] +path = "sub_crates/math3d" + [dependencies.mem_arena] path = "sub_crates/mem_arena" diff --git a/src/lerp.rs b/src/lerp.rs index 6793ee9..46c227d 100644 --- a/src/lerp.rs +++ b/src/lerp.rs @@ -1,5 +1,8 @@ #![allow(dead_code)] +use float4; +use math3d::{Matrix4x4, Normal, Point, Vector}; + /// Trait for allowing a type to be linearly interpolated. pub trait Lerp { fn lerp(self, other: Self, alpha: f32) -> Self; @@ -73,6 +76,46 @@ impl Lerp for (T, T) { } } +impl Lerp for float4::Float4 { + fn lerp(self, other: float4::Float4, alpha: f32) -> float4::Float4 { + (self * (1.0 - alpha)) + (other * alpha) + } +} + +impl Lerp for Matrix4x4 { + fn lerp(self, other: Matrix4x4, alpha: f32) -> Matrix4x4 { + let alpha_minus = 1.0 - alpha; + Matrix4x4 { + values: [(self[0] * alpha_minus) + (other[0] * alpha), + (self[1] * alpha_minus) + (other[1] * alpha), + (self[2] * alpha_minus) + (other[2] * alpha), + (self[3] * alpha_minus) + (other[3] * alpha)], + } + } +} + +impl Lerp for Normal { + fn lerp(self, other: Normal, alpha: f32) -> Normal { + (self * (1.0 - alpha)) + (other * alpha) + } +} + + +impl Lerp for Point { + fn lerp(self, other: Point, alpha: f32) -> Point { + let s = self.norm(); + let o = other.norm(); + Point { co: (s.co * (1.0 - alpha)) + (o.co * alpha) } + } +} + + +impl Lerp for Vector { + fn lerp(self, other: Vector, alpha: f32) -> Vector { + (self * (1.0 - alpha)) + (other * alpha) + } +} + #[cfg(test)] mod tests { @@ -152,4 +195,176 @@ mod tests { assert_eq!(2.5, lerp_slice(&s[..], alpha)); } + + #[test] + fn lerp_matrix() { + let a = Matrix4x4::new_from_values(0.0, + 2.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 7.0, + 8.0, + 9.0, + 10.0, + 11.0, + 12.0, + 13.0, + 14.0, + 15.0); + let b = Matrix4x4::new_from_values(-1.0, + 1.0, + 3.0, + 4.0, + 5.0, + 6.0, + 7.0, + 8.0, + 9.0, + 10.0, + 11.0, + 12.0, + 13.0, + 14.0, + 15.0, + 16.0); + + let c1 = Matrix4x4::new_from_values(-0.25, + 1.75, + 2.25, + 3.25, + 4.25, + 5.25, + 6.25, + 7.25, + 8.25, + 9.25, + 10.25, + 11.25, + 12.25, + 13.25, + 14.25, + 15.25); + let c2 = Matrix4x4::new_from_values(-0.5, + 1.5, + 2.5, + 3.5, + 4.5, + 5.5, + 6.5, + 7.5, + 8.5, + 9.5, + 10.5, + 11.5, + 12.5, + 13.5, + 14.5, + 15.5); + let c3 = Matrix4x4::new_from_values(-0.75, + 1.25, + 2.75, + 3.75, + 4.75, + 5.75, + 6.75, + 7.75, + 8.75, + 9.75, + 10.75, + 11.75, + 12.75, + 13.75, + 14.75, + 15.75); + + assert_eq!(a.lerp(b, 0.0), a); + assert_eq!(a.lerp(b, 0.25), c1); + assert_eq!(a.lerp(b, 0.5), c2); + assert_eq!(a.lerp(b, 0.75), c3); + assert_eq!(a.lerp(b, 1.0), b); + } + + #[test] + fn lerp_point_1() { + let p1 = Point::new(1.0, 2.0, 1.0); + let p2 = Point::new(-2.0, 1.0, -1.0); + let p3 = Point::new(1.0, 2.0, 1.0); + + assert_eq!(p3, p1.lerp(p2, 0.0)); + } + + #[test] + fn lerp_point_2() { + let p1 = Point::new(1.0, 2.0, 1.0); + let p2 = Point::new(-2.0, 1.0, -1.0); + let p3 = Point::new(-2.0, 1.0, -1.0); + + assert_eq!(p3, p1.lerp(p2, 1.0)); + } + + #[test] + fn lerp_point_3() { + let p1 = Point::new(1.0, 2.0, 1.0); + let p2 = Point::new(-2.0, 1.0, -1.0); + let p3 = Point::new(-0.5, 1.5, 0.0); + + assert_eq!(p3, p1.lerp(p2, 0.5)); + } + + #[test] + fn lerp_normal_1() { + let n1 = Normal::new(1.0, 2.0, 1.0); + let n2 = Normal::new(-2.0, 1.0, -1.0); + let n3 = Normal::new(1.0, 2.0, 1.0); + + assert_eq!(n3, n1.lerp(n2, 0.0)); + } + + #[test] + fn lerp_normal_2() { + let n1 = Normal::new(1.0, 2.0, 1.0); + let n2 = Normal::new(-2.0, 1.0, -1.0); + let n3 = Normal::new(-2.0, 1.0, -1.0); + + assert_eq!(n3, n1.lerp(n2, 1.0)); + } + + #[test] + fn lerp_normal_3() { + let n1 = Normal::new(1.0, 2.0, 1.0); + let n2 = Normal::new(-2.0, 1.0, -1.0); + let n3 = Normal::new(-0.5, 1.5, 0.0); + + assert_eq!(n3, n1.lerp(n2, 0.5)); + } + + #[test] + fn lerp_vector_1() { + let v1 = Vector::new(1.0, 2.0, 1.0); + let v2 = Vector::new(-2.0, 1.0, -1.0); + let v3 = Vector::new(1.0, 2.0, 1.0); + + assert_eq!(v3, v1.lerp(v2, 0.0)); + } + + #[test] + fn lerp_vector_2() { + let v1 = Vector::new(1.0, 2.0, 1.0); + let v2 = Vector::new(-2.0, 1.0, -1.0); + let v3 = Vector::new(-2.0, 1.0, -1.0); + + assert_eq!(v3, v1.lerp(v2, 1.0)); + } + + #[test] + fn lerp_vector_3() { + let v1 = Vector::new(1.0, 2.0, 1.0); + let v2 = Vector::new(-2.0, 1.0, -1.0); + let v3 = Vector::new(-0.5, 1.5, 0.0); + + assert_eq!(v3, v1.lerp(v2, 0.5)); + } } diff --git a/src/main.rs b/src/main.rs index b424f10..24d3377 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,7 @@ + +extern crate float4; extern crate halton; +extern crate math3d; extern crate mem_arena; extern crate spectra_xyz; @@ -17,9 +20,6 @@ extern crate nom; #[macro_use] extern crate lazy_static; -#[cfg(feature = "simd_perf")] -extern crate simd; - mod accel; mod algorithm; mod bbox; @@ -28,7 +28,6 @@ mod bitstack; mod boundable; mod camera; mod color; -mod float4; mod hash; mod hilbert; mod image; diff --git a/src/math/mod.rs b/src/math.rs similarity index 89% rename from src/math/mod.rs rename to src/math.rs index ec009d2..0e11168 100644 --- a/src/math/mod.rs +++ b/src/math.rs @@ -1,35 +1,5 @@ #![allow(dead_code)] - -mod matrix; -mod normal; -mod point; -mod vector; - -pub use self::matrix::Matrix4x4; -pub use self::normal::Normal; -pub use self::point::Point; -pub use self::vector::Vector; - - -/// Trait for calculating dot products. -pub trait DotProduct { - fn dot(self, other: Self) -> f32; -} - -pub fn dot(a: T, b: T) -> f32 { - a.dot(b) -} - - -/// Trait for calculating cross products. -pub trait CrossProduct { - fn cross(self, other: Self) -> Self; -} - -pub fn cross(a: T, b: T) -> T { - a.cross(b) -} - +pub use math3d::{Matrix4x4, Normal, Point, Vector, DotProduct, dot, CrossProduct, cross}; /// Clamps a value between a min and max. pub fn clamp(v: T, lower: T, upper: T) -> T { diff --git a/sub_crates/float4/Cargo.toml b/sub_crates/float4/Cargo.toml new file mode 100644 index 0000000..38f1264 --- /dev/null +++ b/sub_crates/float4/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "float4" +version = "0.1.0" +authors = ["Nathan Vegdahl "] +license = "MIT" + +[lib] +name = "float4" +path = "src/lib.rs" + +[features] +simd_perf = ["simd"] + +[dependencies] +# Crates.io dependencies +simd = { version = "0.2.0", optional = true } \ No newline at end of file diff --git a/src/float4.rs b/sub_crates/float4/src/lib.rs similarity index 95% rename from src/float4.rs rename to sub_crates/float4/src/lib.rs index 23f2214..eb1592a 100644 --- a/src/float4.rs +++ b/sub_crates/float4/src/lib.rs @@ -1,13 +1,14 @@ #![allow(dead_code)] +#[cfg(feature = "simd_perf")] +extern crate simd; + use std::cmp::PartialEq; use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, BitAnd}; #[cfg(feature = "simd_perf")] use simd::{f32x4, bool32fx4}; -use lerp::Lerp; - /// Essentially a tuple of four floats, which will use SIMD operations /// where possible on a platform. #[cfg(feature = "simd_perf")] @@ -24,31 +25,38 @@ pub struct Float4 { impl Float4 { #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn new(a: f32, b: f32, c: f32, d: f32) -> Float4 { Float4 { data: f32x4::new(a, b, c, d) } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn new(a: f32, b: f32, c: f32, d: f32) -> Float4 { Float4 { data: [a, b, c, d] } } #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn splat(n: f32) -> Float4 { Float4 { data: f32x4::splat(n) } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn splat(n: f32) -> Float4 { Float4 { data: [n, n, n, n] } } + #[inline] pub fn h_sum(&self) -> f32 { (self.get_0() + self.get_1()) + (self.get_2() + self.get_3()) } + #[inline] pub fn h_product(&self) -> f32 { (self.get_0() * self.get_1()) * (self.get_2() * self.get_3()) } + #[inline] pub fn h_min(&self) -> f32 { let n1 = if self.get_0() < self.get_1() { self.get_0() @@ -63,6 +71,7 @@ impl Float4 { if n1 < n2 { n1 } else { n2 } } + #[inline] pub fn h_max(&self) -> f32 { let n1 = if self.get_0() > self.get_1() { self.get_0() @@ -78,10 +87,12 @@ impl Float4 { } #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn v_min(&self, other: Float4) -> Float4 { Float4 { data: self.data.min(other.data) } } #[cfg(not(feature = "simd_perf"))] + #[inline] pub fn v_min(&self, other: Float4) -> Float4 { Float4::new(if self.get_0() < other.get_0() { self.get_0() @@ -107,10 +118,12 @@ impl Float4 { } #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn v_max(&self, other: Float4) -> Float4 { Float4 { data: self.data.max(other.data) } } #[cfg(not(feature = "simd_perf"))] + #[inline] pub fn v_max(&self, other: Float4) -> Float4 { Float4::new(if self.get_0() > other.get_0() { self.get_0() @@ -135,10 +148,12 @@ impl Float4 { } #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn lt(&self, other: Float4) -> Bool4 { Bool4 { data: self.data.lt(other.data) } } #[cfg(not(feature = "simd_perf"))] + #[inline] pub fn lt(&self, other: Float4) -> Bool4 { Bool4 { data: [self.data[0] < other.data[0], @@ -149,10 +164,12 @@ impl Float4 { } #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn lte(&self, other: Float4) -> Bool4 { Bool4 { data: self.data.le(other.data) } } #[cfg(not(feature = "simd_perf"))] + #[inline] pub fn lte(&self, other: Float4) -> Bool4 { Bool4 { data: [self.data[0] <= other.data[0], @@ -163,10 +180,12 @@ impl Float4 { } #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn gt(&self, other: Float4) -> Bool4 { Bool4 { data: self.data.gt(other.data) } } #[cfg(not(feature = "simd_perf"))] + #[inline] pub fn gt(&self, other: Float4) -> Bool4 { Bool4 { data: [self.data[0] > other.data[0], @@ -177,10 +196,12 @@ impl Float4 { } #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn gte(&self, other: Float4) -> Bool4 { Bool4 { data: self.data.ge(other.data) } } #[cfg(not(feature = "simd_perf"))] + #[inline] pub fn gte(&self, other: Float4) -> Bool4 { Bool4 { data: [self.data[0] >= other.data[0], @@ -208,8 +229,8 @@ impl Float4 { pub fn set_0(&mut self, n: f32) { self.data = self.data.replace(0, n); } - #[inline(always)] #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn set_0(&mut self, n: f32) { unsafe { *self.data.get_unchecked_mut(0) = n; @@ -321,6 +342,7 @@ impl Float4 { impl PartialEq for Float4 { + #[inline] fn eq(&self, other: &Float4) -> bool { self.get_0() == other.get_0() && self.get_1() == other.get_1() && self.get_2() == other.get_2() && self.get_3() == other.get_3() @@ -332,10 +354,12 @@ impl Add for Float4 { type Output = Float4; #[cfg(feature = "simd_perf")] + #[inline(always)] fn add(self, other: Float4) -> Float4 { Float4 { data: self.data + other.data } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] fn add(self, other: Float4) -> Float4 { Float4 { data: [self.get_0() + other.get_0(), @@ -348,6 +372,7 @@ impl Add for Float4 { impl AddAssign for Float4 { + #[inline(always)] fn add_assign(&mut self, rhs: Float4) { *self = *self + rhs; } @@ -358,10 +383,12 @@ impl Sub for Float4 { type Output = Float4; #[cfg(feature = "simd_perf")] + #[inline(always)] fn sub(self, other: Float4) -> Float4 { Float4 { data: self.data - other.data } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] fn sub(self, other: Float4) -> Float4 { Float4 { data: [self.get_0() - other.get_0(), @@ -374,6 +401,7 @@ impl Sub for Float4 { impl SubAssign for Float4 { + #[inline(always)] fn sub_assign(&mut self, rhs: Float4) { *self = *self - rhs; } @@ -384,10 +412,12 @@ impl Mul for Float4 { type Output = Float4; #[cfg(feature = "simd_perf")] + #[inline(always)] fn mul(self, other: Float4) -> Float4 { Float4 { data: self.data * other.data } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] fn mul(self, other: Float4) -> Float4 { Float4 { data: [self.get_0() * other.get_0(), @@ -402,10 +432,12 @@ impl Mul for Float4 { type Output = Float4; #[cfg(feature = "simd_perf")] + #[inline(always)] fn mul(self, other: f32) -> Float4 { Float4 { data: self.data * f32x4::splat(other) } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] fn mul(self, other: f32) -> Float4 { Float4 { data: [self.get_0() * other, @@ -418,12 +450,14 @@ impl Mul for Float4 { impl MulAssign for Float4 { + #[inline(always)] fn mul_assign(&mut self, rhs: Float4) { *self = *self * rhs; } } impl MulAssign for Float4 { + #[inline(always)] fn mul_assign(&mut self, rhs: f32) { *self = *self * rhs; } @@ -434,10 +468,12 @@ impl Div for Float4 { type Output = Float4; #[cfg(feature = "simd_perf")] + #[inline(always)] fn div(self, other: Float4) -> Float4 { Float4 { data: self.data / other.data } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] fn div(self, other: Float4) -> Float4 { Float4 { data: [self.get_0() / other.get_0(), @@ -452,10 +488,12 @@ impl Div for Float4 { type Output = Float4; #[cfg(feature = "simd_perf")] + #[inline(always)] fn div(self, other: f32) -> Float4 { Float4 { data: self.data / f32x4::splat(other) } } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] fn div(self, other: f32) -> Float4 { Float4 { data: [self.get_0() / other, @@ -468,24 +506,19 @@ impl Div for Float4 { impl DivAssign for Float4 { + #[inline(always)] fn div_assign(&mut self, rhs: Float4) { *self = *self / rhs; } } impl DivAssign for Float4 { + #[inline(always)] fn div_assign(&mut self, rhs: f32) { *self = *self / rhs; } } - -impl Lerp for Float4 { - fn lerp(self, other: Float4, alpha: f32) -> Float4 { - (self * (1.0 - alpha)) + (other * alpha) - } -} - #[inline(always)] pub fn v_min(a: Float4, b: Float4) -> Float4 { a.v_min(b) @@ -560,6 +593,7 @@ impl Bool4 { unsafe { *self.data.get_unchecked(3) } } + #[inline] pub fn to_bitmask(&self) -> u8 { (self.get_0() as u8) | ((self.get_1() as u8) << 1) | ((self.get_2() as u8) << 2) | ((self.get_3() as u8) << 3) @@ -570,10 +604,12 @@ impl BitAnd for Bool4 { type Output = Bool4; #[cfg(feature = "simd_perf")] + #[inline(always)] fn bitand(self, rhs: Bool4) -> Bool4 { Bool4 { data: self.data & rhs.data } } #[cfg(not(feature = "simd_perf"))] + #[inline] fn bitand(self, rhs: Bool4) -> Bool4 { Bool4 { data: [self.data[0] && rhs.data[0], diff --git a/sub_crates/math3d/Cargo.toml b/sub_crates/math3d/Cargo.toml new file mode 100644 index 0000000..de115e4 --- /dev/null +++ b/sub_crates/math3d/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "math3d" +version = "0.1.0" +authors = ["Nathan Vegdahl "] +license = "MIT" + +[lib] +name = "math3d" +path = "src/lib.rs" + +[features] +simd_perf = ["float4/simd_perf"] + +# Local crate dependencies +[dependencies.float4] +path = "../float4" \ No newline at end of file diff --git a/sub_crates/math3d/src/lib.rs b/sub_crates/math3d/src/lib.rs new file mode 100644 index 0000000..9757cc8 --- /dev/null +++ b/sub_crates/math3d/src/lib.rs @@ -0,0 +1,36 @@ +#![allow(dead_code)] + +extern crate float4; + +mod matrix; +mod normal; +mod point; +mod vector; + +pub use self::matrix::Matrix4x4; +pub use self::normal::Normal; +pub use self::point::Point; +pub use self::vector::Vector; + +/// Trait for calculating dot products. +pub trait DotProduct { + #[inline] + fn dot(self, other: Self) -> f32; +} + +#[inline] +pub fn dot(a: T, b: T) -> f32 { + a.dot(b) +} + + +/// Trait for calculating cross products. +pub trait CrossProduct { + #[inline] + fn cross(self, other: Self) -> Self; +} + +#[inline] +pub fn cross(a: T, b: T) -> T { + a.cross(b) +} diff --git a/src/math/matrix.rs b/sub_crates/math3d/src/matrix.rs similarity index 79% rename from src/math/matrix.rs rename to sub_crates/math3d/src/matrix.rs index 3e2a56c..c247b84 100644 --- a/src/math/matrix.rs +++ b/sub_crates/math3d/src/matrix.rs @@ -4,7 +4,6 @@ use std; use std::ops::{Index, IndexMut, Mul}; use float4::Float4; -use lerp::Lerp; use super::Point; @@ -12,12 +11,13 @@ use super::Point; /// A 4x4 matrix, used for transforms #[derive(Debug, Copy, Clone)] pub struct Matrix4x4 { - values: [Float4; 4], + pub values: [Float4; 4], } impl Matrix4x4 { /// Creates a new identity matrix + #[inline] pub fn new() -> Matrix4x4 { Matrix4x4 { values: [Float4::new(1.0, 0.0, 0.0, 0.0), @@ -32,6 +32,7 @@ impl Matrix4x4 { /// e f g h /// i j k l /// m n o p + #[inline] pub fn new_from_values(a: f32, b: f32, c: f32, @@ -57,6 +58,7 @@ impl Matrix4x4 { } } + #[inline] pub fn from_location(loc: Point) -> Matrix4x4 { Matrix4x4 { values: [Float4::new(1.0, 0.0, 0.0, loc.x()), @@ -69,6 +71,7 @@ impl Matrix4x4 { /// Returns whether the matrices are approximately equal to each other. /// Each corresponding element in the matrices cannot have a relative error /// exceeding `epsilon`. + #[inline] pub fn aprx_eq(&self, other: Matrix4x4, epsilon: f32) -> bool { let mut result = true; @@ -99,6 +102,7 @@ impl Matrix4x4 { } /// Returns the transpose of the matrix + #[inline] pub fn transposed(&self) -> Matrix4x4 { Matrix4x4 { values: { @@ -124,6 +128,7 @@ impl Matrix4x4 { /// Returns the inverse of the Matrix + #[inline] pub fn inverse(&self) -> Matrix4x4 { let s0 = (self[0].get_0() * self[1].get_1()) - (self[1].get_0() * self[0].get_1()); let s1 = (self[0].get_0() * self[1].get_2()) - (self[1].get_0() * self[0].get_2()); @@ -189,6 +194,7 @@ impl Matrix4x4 { impl Index for Matrix4x4 { type Output = Float4; + #[inline(always)] fn index<'a>(&'a self, _index: usize) -> &'a Float4 { &self.values[_index] } @@ -196,6 +202,7 @@ impl Index for Matrix4x4 { impl IndexMut for Matrix4x4 { + #[inline(always)] fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Float4 { &mut self.values[_index] } @@ -203,6 +210,7 @@ impl IndexMut for Matrix4x4 { impl PartialEq for Matrix4x4 { + #[inline] fn eq(&self, other: &Matrix4x4) -> bool { let mut result = true; @@ -221,6 +229,7 @@ impl PartialEq for Matrix4x4 { impl Mul for Matrix4x4 { type Output = Matrix4x4; + #[inline] fn mul(self, other: Matrix4x4) -> Matrix4x4 { let m = self.transposed(); Matrix4x4 { @@ -248,23 +257,12 @@ impl Mul for Matrix4x4 { } -impl Lerp for Matrix4x4 { - fn lerp(self, other: Matrix4x4, alpha: f32) -> Matrix4x4 { - let alpha_minus = 1.0 - alpha; - Matrix4x4 { - values: [(self[0] * alpha_minus) + (other[0] * alpha), - (self[1] * alpha_minus) + (other[1] * alpha), - (self[2] * alpha_minus) + (other[2] * alpha), - (self[3] * alpha_minus) + (other[3] * alpha)], - } - } -} + #[cfg(test)] mod tests { use super::*; - use lerp::Lerp; #[test] fn equality_test() { @@ -464,95 +462,4 @@ mod tests { assert_eq!(b, c); } - - #[test] - fn lerp_test() { - let a = Matrix4x4::new_from_values(0.0, - 2.0, - 2.0, - 3.0, - 4.0, - 5.0, - 6.0, - 7.0, - 8.0, - 9.0, - 10.0, - 11.0, - 12.0, - 13.0, - 14.0, - 15.0); - let b = Matrix4x4::new_from_values(-1.0, - 1.0, - 3.0, - 4.0, - 5.0, - 6.0, - 7.0, - 8.0, - 9.0, - 10.0, - 11.0, - 12.0, - 13.0, - 14.0, - 15.0, - 16.0); - - let c1 = Matrix4x4::new_from_values(-0.25, - 1.75, - 2.25, - 3.25, - 4.25, - 5.25, - 6.25, - 7.25, - 8.25, - 9.25, - 10.25, - 11.25, - 12.25, - 13.25, - 14.25, - 15.25); - let c2 = Matrix4x4::new_from_values(-0.5, - 1.5, - 2.5, - 3.5, - 4.5, - 5.5, - 6.5, - 7.5, - 8.5, - 9.5, - 10.5, - 11.5, - 12.5, - 13.5, - 14.5, - 15.5); - let c3 = Matrix4x4::new_from_values(-0.75, - 1.25, - 2.75, - 3.75, - 4.75, - 5.75, - 6.75, - 7.75, - 8.75, - 9.75, - 10.75, - 11.75, - 12.75, - 13.75, - 14.75, - 15.75); - - assert_eq!(a.lerp(b, 0.0), a); - assert_eq!(a.lerp(b, 0.25), c1); - assert_eq!(a.lerp(b, 0.5), c2); - assert_eq!(a.lerp(b, 0.75), c3); - assert_eq!(a.lerp(b, 1.0), b); - } } diff --git a/src/math/normal.rs b/sub_crates/math3d/src/normal.rs similarity index 85% rename from src/math/normal.rs rename to sub_crates/math3d/src/normal.rs index 2cc68d7..7d12980 100644 --- a/src/math/normal.rs +++ b/sub_crates/math3d/src/normal.rs @@ -4,7 +4,6 @@ use std::cmp::PartialEq; use std::ops::{Add, Sub, Mul, Div, Neg}; use float4::Float4; -use lerp::Lerp; use super::{DotProduct, CrossProduct}; use super::{Matrix4x4, Vector}; @@ -17,26 +16,32 @@ pub struct Normal { } impl Normal { + #[inline(always)] pub fn new(x: f32, y: f32, z: f32) -> Normal { Normal { co: Float4::new(x, y, z, 0.0) } } + #[inline(always)] pub fn length(&self) -> f32 { (self.co * self.co).h_sum().sqrt() } + #[inline(always)] pub fn length2(&self) -> f32 { (self.co * self.co).h_sum() } + #[inline(always)] pub fn normalized(&self) -> Normal { *self / self.length() } + #[inline(always)] pub fn into_vector(self) -> Vector { Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2()) } + #[inline(always)] pub fn get_n(&self, n: usize) -> f32 { match n { 0 => self.x(), @@ -46,26 +51,32 @@ impl Normal { } } + #[inline(always)] pub fn x(&self) -> f32 { self.co.get_0() } + #[inline(always)] pub fn y(&self) -> f32 { self.co.get_1() } + #[inline(always)] pub fn z(&self) -> f32 { self.co.get_2() } + #[inline(always)] pub fn set_x(&mut self, x: f32) { self.co.set_0(x); } + #[inline(always)] pub fn set_y(&mut self, y: f32) { self.co.set_1(y); } + #[inline(always)] pub fn set_z(&mut self, z: f32) { self.co.set_2(z); } @@ -73,6 +84,7 @@ impl Normal { impl PartialEq for Normal { + #[inline(always)] fn eq(&self, other: &Normal) -> bool { self.co == other.co } @@ -82,6 +94,7 @@ impl PartialEq for Normal { impl Add for Normal { type Output = Normal; + #[inline(always)] fn add(self, other: Normal) -> Normal { Normal { co: self.co + other.co } } @@ -91,6 +104,7 @@ impl Add for Normal { impl Sub for Normal { type Output = Normal; + #[inline(always)] fn sub(self, other: Normal) -> Normal { Normal { co: self.co - other.co } } @@ -100,6 +114,7 @@ impl Sub for Normal { impl Mul for Normal { type Output = Normal; + #[inline(always)] fn mul(self, other: f32) -> Normal { Normal { co: self.co * other } } @@ -108,12 +123,13 @@ impl Mul for Normal { impl Mul for Normal { type Output = Normal; + #[inline] fn mul(self, other: Matrix4x4) -> Normal { let mat = other.inverse().transposed(); Normal { - co: Float4::new((self.co * mat[0]).h_sum(), - (self.co * mat[1]).h_sum(), - (self.co * mat[2]).h_sum(), + co: Float4::new((self.co * mat.values[0]).h_sum(), + (self.co * mat.values[1]).h_sum(), + (self.co * mat.values[2]).h_sum(), 0.0), } } @@ -123,6 +139,7 @@ impl Mul for Normal { impl Div for Normal { type Output = Normal; + #[inline(always)] fn div(self, other: f32) -> Normal { Normal { co: self.co / other } } @@ -132,20 +149,15 @@ impl Div for Normal { impl Neg for Normal { type Output = Normal; + #[inline(always)] fn neg(self) -> Normal { Normal { co: self.co * -1.0 } } } -impl Lerp for Normal { - fn lerp(self, other: Normal, alpha: f32) -> Normal { - (self * (1.0 - alpha)) + (other * alpha) - } -} - - impl DotProduct for Normal { + #[inline(always)] fn dot(self, other: Normal) -> f32 { (self.co * other.co).h_sum() } @@ -153,6 +165,7 @@ impl DotProduct for Normal { impl CrossProduct for Normal { + #[inline] fn cross(self, other: Normal) -> Normal { Normal { co: Float4::new((self.co.get_1() * other.co.get_2()) - @@ -171,7 +184,6 @@ impl CrossProduct for Normal { mod tests { use super::*; use super::super::{Matrix4x4, CrossProduct, DotProduct}; - use lerp::Lerp; #[test] fn add() { @@ -271,31 +283,4 @@ mod tests { assert_eq!(v3, v1.cross(v2)); } - - #[test] - fn lerp1() { - let n1 = Normal::new(1.0, 2.0, 1.0); - let n2 = Normal::new(-2.0, 1.0, -1.0); - let n3 = Normal::new(1.0, 2.0, 1.0); - - assert_eq!(n3, n1.lerp(n2, 0.0)); - } - - #[test] - fn lerp2() { - let n1 = Normal::new(1.0, 2.0, 1.0); - let n2 = Normal::new(-2.0, 1.0, -1.0); - let n3 = Normal::new(-2.0, 1.0, -1.0); - - assert_eq!(n3, n1.lerp(n2, 1.0)); - } - - #[test] - fn lerp3() { - let n1 = Normal::new(1.0, 2.0, 1.0); - let n2 = Normal::new(-2.0, 1.0, -1.0); - let n3 = Normal::new(-0.5, 1.5, 0.0); - - assert_eq!(n3, n1.lerp(n2, 0.5)); - } } diff --git a/src/math/point.rs b/sub_crates/math3d/src/point.rs similarity index 86% rename from src/math/point.rs rename to sub_crates/math3d/src/point.rs index 36b0f65..ba47310 100644 --- a/src/math/point.rs +++ b/sub_crates/math3d/src/point.rs @@ -4,7 +4,6 @@ use std::cmp::PartialEq; use std::ops::{Add, Sub, Mul}; use float4::Float4; -use lerp::Lerp; use super::Matrix4x4; use super::Vector; @@ -17,16 +16,19 @@ pub struct Point { } impl Point { + #[inline(always)] pub fn new(x: f32, y: f32, z: f32) -> Point { Point { co: Float4::new(x, y, z, 1.0) } } /// Returns the point in standardized coordinates, where the /// fourth homogeneous component has been normalized to 1.0. + #[inline(always)] pub fn norm(&self) -> Point { Point { co: self.co / self.co.get_3() } } + #[inline(always)] pub fn min(&self, other: Point) -> Point { let n1 = self.norm(); let n2 = other.norm(); @@ -34,6 +36,7 @@ impl Point { Point { co: n1.co.v_min(n2.co) } } + #[inline(always)] pub fn max(&self, other: Point) -> Point { let n1 = self.norm(); let n2 = other.norm(); @@ -41,10 +44,12 @@ impl Point { Point { co: n1.co.v_max(n2.co) } } + #[inline(always)] pub fn into_vector(self) -> Vector { Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2()) } + #[inline(always)] pub fn get_n(&self, n: usize) -> f32 { match n { 0 => self.x(), @@ -54,26 +59,32 @@ impl Point { } } + #[inline(always)] pub fn x(&self) -> f32 { self.co.get_0() } + #[inline(always)] pub fn y(&self) -> f32 { self.co.get_1() } + #[inline(always)] pub fn z(&self) -> f32 { self.co.get_2() } + #[inline(always)] pub fn set_x(&mut self, x: f32) { self.co.set_0(x); } + #[inline(always)] pub fn set_y(&mut self, y: f32) { self.co.set_1(y); } + #[inline(always)] pub fn set_z(&mut self, z: f32) { self.co.set_2(z); } @@ -81,6 +92,7 @@ impl Point { impl PartialEq for Point { + #[inline(always)] fn eq(&self, other: &Point) -> bool { self.co == other.co } @@ -90,6 +102,7 @@ impl PartialEq for Point { impl Add for Point { type Output = Point; + #[inline(always)] fn add(self, other: Vector) -> Point { Point { co: self.co + other.co } } @@ -99,6 +112,7 @@ impl Add for Point { impl Sub for Point { type Output = Vector; + #[inline(always)] fn sub(self, other: Point) -> Vector { Vector { co: self.norm().co - other.norm().co } } @@ -107,6 +121,7 @@ impl Sub for Point { impl Sub for Point { type Output = Point; + #[inline(always)] fn sub(self, other: Vector) -> Point { Point { co: self.co - other.co } } @@ -115,31 +130,22 @@ impl Sub for Point { impl Mul for Point { type Output = Point; + #[inline] fn mul(self, other: Matrix4x4) -> Point { Point { - co: Float4::new((self.co * other[0]).h_sum(), - (self.co * other[1]).h_sum(), - (self.co * other[2]).h_sum(), - (self.co * other[3]).h_sum()), + co: Float4::new((self.co * other.values[0]).h_sum(), + (self.co * other.values[1]).h_sum(), + (self.co * other.values[2]).h_sum(), + (self.co * other.values[3]).h_sum()), } } } -impl Lerp for Point { - fn lerp(self, other: Point, alpha: f32) -> Point { - let s = self.norm(); - let o = other.norm(); - Point { co: (s.co * (1.0 - alpha)) + (o.co * alpha) } - } -} - - #[cfg(test)] mod tests { use super::*; use super::super::{Vector, Matrix4x4}; - use lerp::Lerp; #[test] fn norm() { @@ -258,31 +264,4 @@ mod tests { assert!((pmm1 - pmm2).length2() <= 0.00001); // Assert pmm1 and pmm2 are roughly equal } - - #[test] - fn lerp1() { - let p1 = Point::new(1.0, 2.0, 1.0); - let p2 = Point::new(-2.0, 1.0, -1.0); - let p3 = Point::new(1.0, 2.0, 1.0); - - assert_eq!(p3, p1.lerp(p2, 0.0)); - } - - #[test] - fn lerp2() { - let p1 = Point::new(1.0, 2.0, 1.0); - let p2 = Point::new(-2.0, 1.0, -1.0); - let p3 = Point::new(-2.0, 1.0, -1.0); - - assert_eq!(p3, p1.lerp(p2, 1.0)); - } - - #[test] - fn lerp3() { - let p1 = Point::new(1.0, 2.0, 1.0); - let p2 = Point::new(-2.0, 1.0, -1.0); - let p3 = Point::new(-0.5, 1.5, 0.0); - - assert_eq!(p3, p1.lerp(p2, 0.5)); - } } diff --git a/src/math/vector.rs b/sub_crates/math3d/src/vector.rs similarity index 86% rename from src/math/vector.rs rename to sub_crates/math3d/src/vector.rs index 31b7ba1..ee54307 100644 --- a/src/math/vector.rs +++ b/sub_crates/math3d/src/vector.rs @@ -4,7 +4,6 @@ use std::cmp::PartialEq; use std::ops::{Add, Sub, Mul, Div, Neg}; use float4::Float4; -use lerp::Lerp; use super::{DotProduct, CrossProduct}; use super::{Matrix4x4, Normal}; @@ -17,26 +16,32 @@ pub struct Vector { } impl Vector { + #[inline(always)] pub fn new(x: f32, y: f32, z: f32) -> Vector { Vector { co: Float4::new(x, y, z, 0.0) } } + #[inline(always)] pub fn length(&self) -> f32 { (self.co * self.co).h_sum().sqrt() } + #[inline(always)] pub fn length2(&self) -> f32 { (self.co * self.co).h_sum() } + #[inline(always)] pub fn normalized(&self) -> Vector { *self / self.length() } + #[inline(always)] pub fn into_normal(self) -> Normal { Normal::new(self.x(), self.y(), self.z()) } + #[inline(always)] pub fn get_n(&self, n: usize) -> f32 { match n { 0 => self.x(), @@ -46,26 +51,32 @@ impl Vector { } } + #[inline(always)] pub fn x(&self) -> f32 { self.co.get_0() } + #[inline(always)] pub fn y(&self) -> f32 { self.co.get_1() } + #[inline(always)] pub fn z(&self) -> f32 { self.co.get_2() } + #[inline(always)] pub fn set_x(&mut self, x: f32) { self.co.set_0(x); } + #[inline(always)] pub fn set_y(&mut self, y: f32) { self.co.set_1(y); } + #[inline(always)] pub fn set_z(&mut self, z: f32) { self.co.set_2(z); } @@ -73,6 +84,7 @@ impl Vector { impl PartialEq for Vector { + #[inline(always)] fn eq(&self, other: &Vector) -> bool { self.co == other.co } @@ -82,6 +94,7 @@ impl PartialEq for Vector { impl Add for Vector { type Output = Vector; + #[inline(always)] fn add(self, other: Vector) -> Vector { Vector { co: self.co + other.co } } @@ -91,6 +104,7 @@ impl Add for Vector { impl Sub for Vector { type Output = Vector; + #[inline(always)] fn sub(self, other: Vector) -> Vector { Vector { co: self.co - other.co } } @@ -100,6 +114,7 @@ impl Sub for Vector { impl Mul for Vector { type Output = Vector; + #[inline(always)] fn mul(self, other: f32) -> Vector { Vector { co: self.co * other } } @@ -109,12 +124,13 @@ impl Mul for Vector { impl Mul for Vector { type Output = Vector; + #[inline] fn mul(self, other: Matrix4x4) -> Vector { Vector { - co: Float4::new((self.co * other[0]).h_sum(), - (self.co * other[1]).h_sum(), - (self.co * other[2]).h_sum(), - (self.co * other[3]).h_sum()), + co: Float4::new((self.co * other.values[0]).h_sum(), + (self.co * other.values[1]).h_sum(), + (self.co * other.values[2]).h_sum(), + (self.co * other.values[3]).h_sum()), } } } @@ -123,6 +139,7 @@ impl Mul for Vector { impl Div for Vector { type Output = Vector; + #[inline(always)] fn div(self, other: f32) -> Vector { Vector { co: self.co / other } } @@ -132,20 +149,15 @@ impl Div for Vector { impl Neg for Vector { type Output = Vector; + #[inline(always)] fn neg(self) -> Vector { Vector { co: self.co * -1.0 } } } -impl Lerp for Vector { - fn lerp(self, other: Vector, alpha: f32) -> Vector { - (self * (1.0 - alpha)) + (other * alpha) - } -} - - impl DotProduct for Vector { + #[inline(always)] fn dot(self, other: Vector) -> f32 { (self.co * other.co).h_sum() } @@ -153,6 +165,7 @@ impl DotProduct for Vector { impl CrossProduct for Vector { + #[inline] fn cross(self, other: Vector) -> Vector { Vector { co: Float4::new((self.co.get_1() * other.co.get_2()) - @@ -171,7 +184,6 @@ impl CrossProduct for Vector { mod tests { use super::*; use super::super::{Matrix4x4, CrossProduct, DotProduct}; - use lerp::Lerp; #[test] fn add() { @@ -295,31 +307,4 @@ mod tests { assert_eq!(v3, v1.cross(v2)); } - - #[test] - fn lerp1() { - let v1 = Vector::new(1.0, 2.0, 1.0); - let v2 = Vector::new(-2.0, 1.0, -1.0); - let v3 = Vector::new(1.0, 2.0, 1.0); - - assert_eq!(v3, v1.lerp(v2, 0.0)); - } - - #[test] - fn lerp2() { - let v1 = Vector::new(1.0, 2.0, 1.0); - let v2 = Vector::new(-2.0, 1.0, -1.0); - let v3 = Vector::new(-2.0, 1.0, -1.0); - - assert_eq!(v3, v1.lerp(v2, 1.0)); - } - - #[test] - fn lerp3() { - let v1 = Vector::new(1.0, 2.0, 1.0); - let v2 = Vector::new(-2.0, 1.0, -1.0); - let v3 = Vector::new(-0.5, 1.5, 0.0); - - assert_eq!(v3, v1.lerp(v2, 0.5)); - } }