diff --git a/src/bbox.rs b/src/bbox.rs index 000432c..01e028f 100644 --- a/src/bbox.rs +++ b/src/bbox.rs @@ -58,14 +58,14 @@ impl BBox { // Creates a new BBox transformed into a different space. pub fn transformed(&self, xform: Matrix4x4) -> BBox { // BBox corners - let vs = [Point::new(self.min[0], self.min[1], self.min[2]), - Point::new(self.min[0], self.min[1], self.max[2]), - Point::new(self.min[0], self.max[1], self.min[2]), - Point::new(self.min[0], self.max[1], self.max[2]), - Point::new(self.max[0], self.min[1], self.min[2]), - Point::new(self.max[0], self.min[1], self.max[2]), - Point::new(self.max[0], self.max[1], self.min[2]), - Point::new(self.max[0], self.max[1], self.max[2])]; + let vs = [Point::new(self.min.x(), self.min.y(), self.min.z()), + Point::new(self.min.x(), self.min.y(), self.max.z()), + Point::new(self.min.x(), self.max.y(), self.min.z()), + Point::new(self.min.x(), self.max.y(), self.max.z()), + Point::new(self.max.x(), self.min.y(), self.min.z()), + Point::new(self.max.x(), self.min.y(), self.max.z()), + Point::new(self.max.x(), self.max.y(), self.min.z()), + Point::new(self.max.x(), self.max.y(), self.max.z())]; // Transform BBox corners and make new bbox let mut b = BBox::new(); @@ -79,9 +79,9 @@ impl BBox { } pub fn surface_area(&self) -> f32 { - let x = self.max[0] - self.min[0]; - let y = self.max[1] - self.min[1]; - let z = self.max[2] - self.min[2]; + let x = self.max.x() - self.min.x(); + let y = self.max.y() - self.min.y(); + let z = self.max.z() - self.min.z(); ((x * y) + (y * z) + (z * x)) * 2.0 } diff --git a/src/bvh.rs b/src/bvh.rs index d8a88d6..08080e3 100644 --- a/src/bvh.rs +++ b/src/bvh.rs @@ -145,10 +145,10 @@ impl BVH { let sah_divs = { let mut sah_divs = [[0.0f32; SAH_BIN_COUNT - 1]; 3]; for d in 0..3 { - let extent = bounds.max[d] - bounds.min[d]; + let extent = bounds.max.get_n(d) - bounds.min.get_n(d); for div in 0..(SAH_BIN_COUNT - 1) { let part = extent * ((div + 1) as f32 / SAH_BIN_COUNT as f32); - sah_divs[d][div] = bounds.min[d] + part; + sah_divs[d][div] = bounds.min.get_n(d) + part; } } sah_divs @@ -163,7 +163,7 @@ impl BVH { for d in 0..3 { for div in 0..(SAH_BIN_COUNT - 1) { - if centroid[d] <= sah_divs[d][div] { + if centroid.get_n(d) <= sah_divs[d][div] { sah_bins[d][div].0 |= tb; sah_bins[d][div].2 += 1; } else { @@ -203,7 +203,7 @@ impl BVH { // Partition let mut split_i = partition(&mut objects[..], |obj| { let tb = lerp_slice(bounder(obj), 0.5); - let centroid = (tb.min[split_axis] + tb.max[split_axis]) * 0.5; + let centroid = (tb.min.get_n(split_axis) + tb.max.get_n(split_axis)) * 0.5; centroid < div }); if split_i < 1 { @@ -219,7 +219,7 @@ impl BVH { let mut axis = 0; let mut largest = std::f32::NEG_INFINITY; for i in 0..3 { - let extent = bounds.max[i] - bounds.min[i]; + let extent = bounds.max.get_n(i) - bounds.min.get_n(i); if extent > largest { largest = extent; axis = i; @@ -234,8 +234,10 @@ impl BVH { &|a, b| { let tb_a = lerp_slice(bounder(a), 0.5); let tb_b = lerp_slice(bounder(b), 0.5); - let centroid_a = (tb_a.min[split_axis] + tb_a.max[split_axis]) * 0.5; - let centroid_b = (tb_b.min[split_axis] + tb_b.max[split_axis]) * 0.5; + let centroid_a = (tb_a.min.get_n(split_axis) + tb_a.max.get_n(split_axis)) * + 0.5; + let centroid_b = (tb_b.min.get_n(split_axis) + tb_b.max.get_n(split_axis)) * + 0.5; if centroid_a < centroid_b { Ordering::Less @@ -307,7 +309,7 @@ impl BVH { i_stack[stack_ptr + 1] = second_child_index; ray_i_stack[stack_ptr] = part; ray_i_stack[stack_ptr + 1] = part; - if rays[0].dir_inv[split_axis as usize].is_sign_positive() { + if rays[0].dir_inv.get_n(split_axis as usize).is_sign_positive() { i_stack.swap(stack_ptr, stack_ptr + 1); } stack_ptr += 1; diff --git a/src/camera.rs b/src/camera.rs index 124553f..fd40eb8 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -70,8 +70,8 @@ impl Camera { }; // Ray direction - let dir = Vector::new((x * tfov) - (orig[0] / focus_distance), - (y * tfov) - (orig[1] / focus_distance), + let dir = Vector::new((x * tfov) - (orig.x() / focus_distance), + (y * tfov) - (orig.y() / focus_distance), 1.0) .normalized(); diff --git a/src/color/mod.rs b/src/color/mod.rs index 26536df..fd4252e 100644 --- a/src/color/mod.rs +++ b/src/color/mod.rs @@ -52,7 +52,7 @@ impl SpectralSample { pub fn new(wavelength: f32) -> SpectralSample { debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX); SpectralSample { - e: Float4::new(0.0, 0.0, 0.0, 0.0), + e: Float4::splat(0.0), hero_wavelength: wavelength, } } @@ -60,7 +60,7 @@ impl SpectralSample { pub fn from_value(value: f32, wavelength: f32) -> SpectralSample { debug_assert!(wavelength >= WL_MIN && wavelength <= WL_MAX); SpectralSample { - e: Float4::new(value, value, value, value), + e: Float4::splat(value), hero_wavelength: wavelength, } } @@ -174,10 +174,10 @@ impl XYZ { } pub fn from_spectral_sample(ss: &SpectralSample) -> XYZ { - let xyz0 = XYZ::from_wavelength(ss.wl_n(0), ss.e[0]); - let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e[1]); - let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e[2]); - let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e[3]); + let xyz0 = XYZ::from_wavelength(ss.wl_n(0), ss.e.get_0()); + let xyz1 = XYZ::from_wavelength(ss.wl_n(1), ss.e.get_1()); + let xyz2 = XYZ::from_wavelength(ss.wl_n(2), ss.e.get_2()); + let xyz3 = XYZ::from_wavelength(ss.wl_n(3), ss.e.get_3()); (xyz0 + xyz1 + xyz2 + xyz3) * 0.75 } diff --git a/src/float4.rs b/src/float4.rs index 6cf34fd..825677f 100644 --- a/src/float4.rs +++ b/src/float4.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::ops::{Index, IndexMut, Add, Sub, Mul, Div}; +use std::ops::{Add, Sub, Mul, Div}; use std::cmp::PartialEq; #[cfg(feature = "simd_perf")] @@ -140,11 +140,25 @@ impl Float4 { }) } + /// Set the nth element to the given value. + #[inline] + pub fn set_n(&mut self, n: usize, v: f32) { + match n { + 0 => self.set_0(v), + 1 => self.set_1(v), + 2 => self.set_2(v), + 3 => self.set_3(v), + _ => panic!("Attempted to set element of Float4 outside of bounds."), + } + } + /// Set the 0th element to the given value. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn set_0(&mut self, n: f32) { self.data = self.data.replace(0, n); } + #[inline(always)] #[cfg(not(feature = "simd_perf"))] pub fn set_0(&mut self, n: f32) { unsafe { @@ -154,10 +168,12 @@ impl Float4 { /// Set the 1th element to the given value. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn set_1(&mut self, n: f32) { self.data = self.data.replace(1, n); } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn set_1(&mut self, n: f32) { unsafe { *self.data.get_unchecked_mut(1) = n; @@ -166,10 +182,12 @@ impl Float4 { /// Set the 2th element to the given value. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn set_2(&mut self, n: f32) { self.data = self.data.replace(2, n); } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn set_2(&mut self, n: f32) { unsafe { *self.data.get_unchecked_mut(2) = n; @@ -178,92 +196,80 @@ impl Float4 { /// Set the 3th element to the given value. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn set_3(&mut self, n: f32) { self.data = self.data.replace(3, n); } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn set_3(&mut self, n: f32) { unsafe { *self.data.get_unchecked_mut(3) = n; } } + /// Returns the value of the nth element. + #[inline] + pub fn get_n(&self, n: usize) -> f32 { + match n { + 0 => self.get_0(), + 1 => self.get_1(), + 2 => self.get_2(), + 3 => self.get_3(), + _ => panic!("Attempted to access element of Float4 outside of bounds."), + } + } + /// Returns the value of the 0th element. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn get_0(&self) -> f32 { self.data.extract(0) } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn get_0(&self) -> f32 { unsafe { *self.data.get_unchecked(0) } } /// Returns the value of the 1th element. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn get_1(&self) -> f32 { self.data.extract(1) } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn get_1(&self) -> f32 { unsafe { *self.data.get_unchecked(1) } } /// Returns the value of the 2th element. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn get_2(&self) -> f32 { self.data.extract(2) } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn get_2(&self) -> f32 { unsafe { *self.data.get_unchecked(2) } } /// Returns the value of the 3th element. #[cfg(feature = "simd_perf")] + #[inline(always)] pub fn get_3(&self) -> f32 { self.data.extract(3) } #[cfg(not(feature = "simd_perf"))] + #[inline(always)] pub fn get_3(&self) -> f32 { unsafe { *self.data.get_unchecked(3) } } } -impl Index for Float4 { - type Output = f32; - - #[cfg(feature = "simd_perf")] - fn index(&self, index: usize) -> &f32 { - // TODO: this might not be correct! It works, but need to make sure - // to do this in a way with proper defined behavior. - use std::mem::transmute; - let vs: &[f32; 4] = unsafe { transmute(&self.data) }; - &vs[index] - } - #[cfg(not(feature = "simd_perf"))] - fn index(&self, index: usize) -> &f32 { - &self.data[index] - } -} - - -impl IndexMut for Float4 { - #[cfg(feature = "simd_perf")] - fn index_mut(&mut self, index: usize) -> &mut f32 { - // TODO: this might not be correct! It works, but need to make sure - // to do this in a way with proper defined behavior. - use std::mem::transmute; - let vs: &mut [f32; 4] = unsafe { transmute(&mut self.data) }; - &mut vs[index] - } - #[cfg(not(feature = "simd_perf"))] - fn index_mut(&mut self, index: usize) -> &mut f32 { - &mut self.data[index] - } -} - - impl PartialEq for Float4 { fn eq(&self, other: &Float4) -> bool { self.get_0() == other.get_0() && self.get_1() == other.get_1() && @@ -389,27 +395,51 @@ mod tests { use super::*; #[test] - fn index() { + fn get() { let f = Float4::new(1.0, 2.0, 3.0, 4.0); - assert_eq!(f[0], 1.0); - assert_eq!(f[1], 2.0); - assert_eq!(f[2], 3.0); - assert_eq!(f[3], 4.0); + assert_eq!(f.get_0(), 1.0); + assert_eq!(f.get_1(), 2.0); + assert_eq!(f.get_2(), 3.0); + assert_eq!(f.get_3(), 4.0); } #[test] - fn index_mut() { - let mut f = Float4::new(1.0, 2.0, 3.0, 4.0); - f[0] = 5.0; - f[1] = 6.0; - f[2] = 7.0; - f[3] = 8.0; + fn get_n() { + let f = Float4::new(1.0, 2.0, 3.0, 4.0); - assert_eq!(f[0], 5.0); - assert_eq!(f[1], 6.0); - assert_eq!(f[2], 7.0); - assert_eq!(f[3], 8.0); + assert_eq!(f.get_n(0), 1.0); + assert_eq!(f.get_n(1), 2.0); + assert_eq!(f.get_n(2), 3.0); + assert_eq!(f.get_n(3), 4.0); + } + + #[test] + fn set() { + let mut f = Float4::new(1.0, 2.0, 3.0, 4.0); + f.set_0(5.0); + f.set_1(6.0); + f.set_2(7.0); + f.set_3(8.0); + + assert_eq!(f.get_0(), 5.0); + assert_eq!(f.get_1(), 6.0); + assert_eq!(f.get_2(), 7.0); + assert_eq!(f.get_3(), 8.0); + } + + #[test] + fn set_n() { + let mut f = Float4::new(1.0, 2.0, 3.0, 4.0); + f.set_n(0, 5.0); + f.set_n(1, 6.0); + f.set_n(2, 7.0); + f.set_n(3, 8.0); + + assert_eq!(f.get_0(), 5.0); + assert_eq!(f.get_1(), 6.0); + assert_eq!(f.get_2(), 7.0); + assert_eq!(f.get_3(), 8.0); } #[test] diff --git a/src/light/rectangle_light.rs b/src/light/rectangle_light.rs index b56b2d2..49fe252 100644 --- a/src/light/rectangle_light.rs +++ b/src/light/rectangle_light.rs @@ -79,11 +79,15 @@ impl LightSource for RectangleLight { // Project shadow_vec back onto the light's surface let arr_local = arr * *space; let shadow_vec_local = shadow_vec * *space; - let shadow_vec_local = shadow_vec_local * (-arr_local[2] / shadow_vec_local[2]); + let shadow_vec_local = shadow_vec_local * (-arr_local.z() / shadow_vec_local.z()); let mut sample_point_local = arr_local + shadow_vec_local; - sample_point_local[0] = sample_point_local[0].max(dim.0 * -0.5).min(dim.0 * 0.5); - sample_point_local[1] = sample_point_local[1].max(dim.1 * -0.5).min(dim.1 * 0.5); - sample_point_local[2] = 0.0; + { + let x = sample_point_local.x().max(dim.0 * -0.5).min(dim.0 * 0.5); + let y = sample_point_local.y().max(dim.1 * -0.5).min(dim.1 * 0.5); + sample_point_local.set_x(x); + sample_point_local.set_y(y); + sample_point_local.set_z(0.0); + } let sample_point = sample_point_local * space_inv; let shadow_vec = sample_point - arr; diff --git a/src/light/sphere_light.rs b/src/light/sphere_light.rs index acd39c4..6f4a90c 100644 --- a/src/light/sphere_light.rs +++ b/src/light/sphere_light.rs @@ -69,7 +69,7 @@ impl LightSource for SphereLight { // Sample the cone subtended by the sphere and calculate // useful data from that. let sample = uniform_sample_cone(u, v, cos_theta_max).normalized(); - let cos_theta: f64 = sample[2] as f64; + let cos_theta: f64 = sample.z() as f64; let cos_theta2: f64 = cos_theta * cos_theta; let sin_theta2: f64 = (1.0 - cos_theta2).max(0.0); let sin_theta: f64 = sin_theta2.sqrt(); @@ -90,7 +90,7 @@ impl LightSource for SphereLight { (d - (cos_a * radius)) as f32); // Calculate the final values and return everything. - let shadow_vec = (x * sample[0]) + (y * sample[1]) + (z * sample[2]); + let shadow_vec = (x * sample.x()) + (y * sample.y()) + (z * sample.z()); let pdf = uniform_sample_cone_pdf(cos_theta_max); let spectral_sample = (col * surface_area_inv as f32).to_spectral_sample(wavelength); return (spectral_sample, shadow_vec, pdf as f32); diff --git a/src/math/matrix.rs b/src/math/matrix.rs index ae9fd61..3e2a56c 100644 --- a/src/math/matrix.rs +++ b/src/math/matrix.rs @@ -59,9 +59,9 @@ impl Matrix4x4 { pub fn from_location(loc: Point) -> Matrix4x4 { Matrix4x4 { - values: [Float4::new(1.0, 0.0, 0.0, loc[0]), - Float4::new(0.0, 1.0, 0.0, loc[1]), - Float4::new(0.0, 0.0, 1.0, loc[2]), + values: [Float4::new(1.0, 0.0, 0.0, loc.x()), + Float4::new(0.0, 1.0, 0.0, loc.y()), + Float4::new(0.0, 0.0, 1.0, loc.z()), Float4::new(0.0, 0.0, 0.0, 1.0)], } } @@ -79,8 +79,8 @@ impl Matrix4x4 { // http://floating-point-gui.de/errors/comparison/ // It might be worth breaking this out into a separate funcion, // but I'm not entirely sure where to put it. - let a = self[y][x]; - let b = other[y][x]; + let a = self[y].get_n(x); + let b = other[y].get_n(x); let aabs = a.abs(); let babs = b.abs(); let diff = (a - b).abs(); @@ -102,10 +102,22 @@ impl Matrix4x4 { pub fn transposed(&self) -> Matrix4x4 { Matrix4x4 { values: { - [Float4::new(self[0][0], self[1][0], self[2][0], self[3][0]), - Float4::new(self[0][1], self[1][1], self[2][1], self[3][1]), - Float4::new(self[0][2], self[1][2], self[2][2], self[3][2]), - Float4::new(self[0][3], self[1][3], self[2][3], self[3][3])] + [Float4::new(self[0].get_0(), + self[1].get_0(), + self[2].get_0(), + self[3].get_0()), + Float4::new(self[0].get_1(), + self[1].get_1(), + self[2].get_1(), + self[3].get_1()), + Float4::new(self[0].get_2(), + self[1].get_2(), + self[2].get_2(), + self[3].get_2()), + Float4::new(self[0].get_3(), + self[1].get_3(), + self[2].get_3(), + self[3].get_3())] }, } } @@ -113,19 +125,19 @@ impl Matrix4x4 { /// Returns the inverse of the Matrix pub fn inverse(&self) -> Matrix4x4 { - let s0 = (self[0][0] * self[1][1]) - (self[1][0] * self[0][1]); - let s1 = (self[0][0] * self[1][2]) - (self[1][0] * self[0][2]); - let s2 = (self[0][0] * self[1][3]) - (self[1][0] * self[0][3]); - let s3 = (self[0][1] * self[1][2]) - (self[1][1] * self[0][2]); - let s4 = (self[0][1] * self[1][3]) - (self[1][1] * self[0][3]); - let s5 = (self[0][2] * self[1][3]) - (self[1][2] * self[0][3]); + 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()); + let s2 = (self[0].get_0() * self[1].get_3()) - (self[1].get_0() * self[0].get_3()); + let s3 = (self[0].get_1() * self[1].get_2()) - (self[1].get_1() * self[0].get_2()); + let s4 = (self[0].get_1() * self[1].get_3()) - (self[1].get_1() * self[0].get_3()); + let s5 = (self[0].get_2() * self[1].get_3()) - (self[1].get_2() * self[0].get_3()); - let c5 = (self[2][2] * self[3][3]) - (self[3][2] * self[2][3]); - let c4 = (self[2][1] * self[3][3]) - (self[3][1] * self[2][3]); - let c3 = (self[2][1] * self[3][2]) - (self[3][1] * self[2][2]); - let c2 = (self[2][0] * self[3][3]) - (self[3][0] * self[2][3]); - let c1 = (self[2][0] * self[3][2]) - (self[3][0] * self[2][2]); - let c0 = (self[2][0] * self[3][1]) - (self[3][0] * self[2][1]); + let c5 = (self[2].get_2() * self[3].get_3()) - (self[3].get_2() * self[2].get_3()); + let c4 = (self[2].get_1() * self[3].get_3()) - (self[3].get_1() * self[2].get_3()); + let c3 = (self[2].get_1() * self[3].get_2()) - (self[3].get_1() * self[2].get_2()); + let c2 = (self[2].get_0() * self[3].get_3()) - (self[3].get_0() * self[2].get_3()); + let c1 = (self[2].get_0() * self[3].get_2()) - (self[3].get_0() * self[2].get_2()); + let c0 = (self[2].get_0() * self[3].get_1()) - (self[3].get_0() * self[2].get_1()); // TODO: handle 0.0 determinant let det = (s0 * c5) - (s1 * c4) + (s2 * c3) + (s3 * c2) - (s4 * c1) + (s5 * c0); @@ -133,25 +145,41 @@ impl Matrix4x4 { Matrix4x4 { values: { - [Float4::new(((self[1][1] * c5) - (self[1][2] * c4) + (self[1][3] * c3)) * invdet, - ((-self[0][1] * c5) + (self[0][2] * c4) - (self[0][3] * c3)) * invdet, - ((self[3][1] * s5) - (self[3][2] * s4) + (self[3][3] * s3)) * invdet, - ((-self[2][1] * s5) + (self[2][2] * s4) - (self[2][3] * s3)) * invdet), + [Float4::new(((self[1].get_1() * c5) - (self[1].get_2() * c4) + + (self[1].get_3() * c3)) * invdet, + ((-self[0].get_1() * c5) + (self[0].get_2() * c4) - + (self[0].get_3() * c3)) * invdet, + ((self[3].get_1() * s5) - (self[3].get_2() * s4) + + (self[3].get_3() * s3)) * invdet, + ((-self[2].get_1() * s5) + (self[2].get_2() * s4) - + (self[2].get_3() * s3)) * invdet), - Float4::new(((-self[1][0] * c5) + (self[1][2] * c2) - (self[1][3] * c1)) * invdet, - ((self[0][0] * c5) - (self[0][2] * c2) + (self[0][3] * c1)) * invdet, - ((-self[3][0] * s5) + (self[3][2] * s2) - (self[3][3] * s1)) * invdet, - ((self[2][0] * s5) - (self[2][2] * s2) + (self[2][3] * s1)) * invdet), + Float4::new(((-self[1].get_0() * c5) + (self[1].get_2() * c2) - + (self[1].get_3() * c1)) * invdet, + ((self[0].get_0() * c5) - (self[0].get_2() * c2) + + (self[0].get_3() * c1)) * invdet, + ((-self[3].get_0() * s5) + (self[3].get_2() * s2) - + (self[3].get_3() * s1)) * invdet, + ((self[2].get_0() * s5) - (self[2].get_2() * s2) + + (self[2].get_3() * s1)) * invdet), - Float4::new(((self[1][0] * c4) - (self[1][1] * c2) + (self[1][3] * c0)) * invdet, - ((-self[0][0] * c4) + (self[0][1] * c2) - (self[0][3] * c0)) * invdet, - ((self[3][0] * s4) - (self[3][1] * s2) + (self[3][3] * s0)) * invdet, - ((-self[2][0] * s4) + (self[2][1] * s2) - (self[2][3] * s0)) * invdet), + Float4::new(((self[1].get_0() * c4) - (self[1].get_1() * c2) + + (self[1].get_3() * c0)) * invdet, + ((-self[0].get_0() * c4) + (self[0].get_1() * c2) - + (self[0].get_3() * c0)) * invdet, + ((self[3].get_0() * s4) - (self[3].get_1() * s2) + + (self[3].get_3() * s0)) * invdet, + ((-self[2].get_0() * s4) + (self[2].get_1() * s2) - + (self[2].get_3() * s0)) * invdet), - Float4::new(((-self[1][0] * c3) + (self[1][1] * c1) - (self[1][2] * c0)) * invdet, - ((self[0][0] * c3) - (self[0][1] * c1) + (self[0][2] * c0)) * invdet, - ((-self[3][0] * s3) + (self[3][1] * s1) - (self[3][2] * s0)) * invdet, - ((self[2][0] * s3) - (self[2][1] * s1) + (self[2][2] * s0)) * invdet)] + Float4::new(((-self[1].get_0() * c3) + (self[1].get_1() * c1) - + (self[1].get_2() * c0)) * invdet, + ((self[0].get_0() * c3) - (self[0].get_1() * c1) + + (self[0].get_2() * c0)) * invdet, + ((-self[3].get_0() * s3) + (self[3].get_1() * s1) - + (self[3].get_2() * s0)) * invdet, + ((self[2].get_0() * s3) - (self[2].get_1() * s1) + + (self[2].get_2() * s0)) * invdet)] }, } } @@ -180,7 +208,7 @@ impl PartialEq for Matrix4x4 { for y in 0..4 { for x in 0..4 { - result = result && (self[y][x] == other[y][x]); + result = result && (self[y].get_n(x) == other[y].get_n(x)); } } @@ -224,25 +252,10 @@ impl Lerp for Matrix4x4 { fn lerp(self, other: Matrix4x4, alpha: f32) -> Matrix4x4 { let alpha_minus = 1.0 - alpha; Matrix4x4 { - values: [Float4::new((self[0][0] * alpha_minus) + (other[0][0] * alpha), - (self[0][1] * alpha_minus) + (other[0][1] * alpha), - (self[0][2] * alpha_minus) + (other[0][2] * alpha), - (self[0][3] * alpha_minus) + (other[0][3] * alpha)), - - Float4::new((self[1][0] * alpha_minus) + (other[1][0] * alpha), - (self[1][1] * alpha_minus) + (other[1][1] * alpha), - (self[1][2] * alpha_minus) + (other[1][2] * alpha), - (self[1][3] * alpha_minus) + (other[1][3] * alpha)), - - Float4::new((self[2][0] * alpha_minus) + (other[2][0] * alpha), - (self[2][1] * alpha_minus) + (other[2][1] * alpha), - (self[2][2] * alpha_minus) + (other[2][2] * alpha), - (self[2][3] * alpha_minus) + (other[2][3] * alpha)), - - Float4::new((self[3][0] * alpha_minus) + (other[3][0] * alpha), - (self[3][1] * alpha_minus) + (other[3][1] * alpha), - (self[3][2] * alpha_minus) + (other[3][2] * alpha), - (self[3][3] * alpha_minus) + (other[3][3] * alpha))], + 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)], } } } diff --git a/src/math/mod.rs b/src/math/mod.rs index 6dca3c4..ca9dff1 100644 --- a/src/math/mod.rs +++ b/src/math/mod.rs @@ -134,12 +134,12 @@ pub fn log2_64(value: u64) -> u64 { /// Creates a coordinate system from a single vector. pub fn coordinate_system_from_vector(v: Vector) -> (Vector, Vector, Vector) { - let v2 = if v[0].abs() > v[1].abs() { - let invlen = 1.0 / ((v[0] * v[0]) + (v[2] * v[2])).sqrt(); - Vector::new(-v[2] * invlen, 0.0, v[0] * invlen) + let v2 = if v.x().abs() > v.y().abs() { + let invlen = 1.0 / ((v.x() * v.x()) + (v.z() * v.z())).sqrt(); + Vector::new(-v.z() * invlen, 0.0, v.x() * invlen) } else { - let invlen = 1.0 / ((v[1] * v[1]) + (v[2] * v[2])).sqrt(); - Vector::new(0.0, v[2] * invlen, -v[1] * invlen) + let invlen = 1.0 / ((v.y() * v.y()) + (v.z() * v.z())).sqrt(); + Vector::new(0.0, v.z() * invlen, -v.y() * invlen) }; let v3 = cross(v, v2); @@ -164,7 +164,7 @@ pub fn zup_to_vec(from: Vector, toz: Vector) -> Vector { // Use simple linear algebra to convert the "from" // vector to a space composed of tox, toy, and toz // as the x, y, and z axes. - (tox * from[0]) + (toy * from[1]) + (toz * from[2]) + (tox * from.x()) + (toy * from.y()) + (toz * from.z()) } /// The logit function, scaled to approximate the probit function. diff --git a/src/math/normal.rs b/src/math/normal.rs index 1d3a537..2c07876 100644 --- a/src/math/normal.rs +++ b/src/math/normal.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::ops::{Index, IndexMut, Add, Sub, Mul, Div, Neg}; +use std::ops::{Add, Sub, Mul, Div, Neg}; use std::cmp::PartialEq; use lerp::Lerp; @@ -33,26 +33,40 @@ impl Normal { } pub fn into_vector(self) -> Vector { - Vector::new(self.co[0], self.co[1], self.co[2]) + Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2()) } -} - -impl Index for Normal { - type Output = f32; - - fn index(&self, index: usize) -> &f32 { - debug_assert!(index < 3); - - &self.co[index] + pub fn get_n(&self, n: usize) -> f32 { + match n { + 0 => self.x(), + 1 => self.y(), + 2 => self.z(), + _ => panic!("Attempt to access dimension beyond z."), + } } -} -impl IndexMut for Normal { - fn index_mut(&mut self, index: usize) -> &mut f32 { - debug_assert!(index < 3); + pub fn x(&self) -> f32 { + self.co.get_0() + } - &mut self.co[index] + pub fn y(&self) -> f32 { + self.co.get_1() + } + + pub fn z(&self) -> f32 { + self.co.get_2() + } + + pub fn set_x(&mut self, x: f32) { + self.co.set_0(x); + } + + pub fn set_y(&mut self, y: f32) { + self.co.set_1(y); + } + + pub fn set_z(&mut self, z: f32) { + self.co.set_2(z); } } @@ -96,9 +110,9 @@ impl Mul for Normal { fn mul(self, other: Matrix4x4) -> Normal { let mat = other.inverse().transposed(); Normal { - co: Float4::new((self[0] * mat[0][0]) + (self[1] * mat[0][1]) + (self[2] * mat[0][2]), - (self[0] * mat[1][0]) + (self[1] * mat[1][1]) + (self[2] * mat[1][2]), - (self[0] * mat[2][0]) + (self[1] * mat[2][1]) + (self[2] * mat[2][2]), + co: Float4::new((self.co * mat[0]).h_sum(), + (self.co * mat[1]).h_sum(), + (self.co * mat[2]).h_sum(), 0.0), } } @@ -140,9 +154,12 @@ impl DotProduct for Normal { impl CrossProduct for Normal { fn cross(self, other: Normal) -> Normal { Normal { - co: Float4::new((self[1] * other[2]) - (self[2] * other[1]), - (self[2] * other[0]) - (self[0] * other[2]), - (self[0] * other[1]) - (self[1] * other[0]), + co: Float4::new((self.co.get_1() * other.co.get_2()) - + (self.co.get_2() * other.co.get_1()), + (self.co.get_2() * other.co.get_0()) - + (self.co.get_0() * other.co.get_2()), + (self.co.get_0() * other.co.get_1()) - + (self.co.get_1() * other.co.get_0()), 0.0), } } @@ -231,9 +248,9 @@ mod tests { let n1 = Normal::new(1.0, 2.0, 3.0); let n2 = Normal::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732); let n3 = n1.normalized(); - assert!((n3[0] - n2[0]).abs() < 0.000001); - assert!((n3[1] - n2[1]).abs() < 0.000001); - assert!((n3[2] - n2[2]).abs() < 0.000001); + assert!((n3.x() - n2.x()).abs() < 0.000001); + assert!((n3.y() - n2.y()).abs() < 0.000001); + assert!((n3.z() - n2.z()).abs() < 0.000001); } #[test] diff --git a/src/math/point.rs b/src/math/point.rs index 30e66dc..96d100e 100644 --- a/src/math/point.rs +++ b/src/math/point.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::ops::{Index, IndexMut, Add, Sub, Mul}; +use std::ops::{Add, Sub, Mul}; use std::cmp::PartialEq; use lerp::Lerp; @@ -23,7 +23,7 @@ impl Point { /// Returns the point in standardized coordinates, where the /// fourth homogeneous component has been normalized to 1.0. pub fn norm(&self) -> Point { - Point { co: self.co / self.co[3] } + Point { co: self.co / self.co.get_3() } } pub fn min(&self, other: Point) -> Point { @@ -41,26 +41,40 @@ impl Point { } pub fn into_vector(self) -> Vector { - Vector::new(self[0], self[1], self[2]) + Vector::new(self.co.get_0(), self.co.get_1(), self.co.get_2()) } -} - -impl Index for Point { - type Output = f32; - - fn index(&self, index: usize) -> &f32 { - debug_assert!(index < 3); - - &self.co[index] + pub fn get_n(&self, n: usize) -> f32 { + match n { + 0 => self.x(), + 1 => self.y(), + 2 => self.z(), + _ => panic!("Attempt to access dimension beyond z."), + } } -} -impl IndexMut for Point { - fn index_mut(&mut self, index: usize) -> &mut f32 { - debug_assert!(index < 3); + pub fn x(&self) -> f32 { + self.co.get_0() + } - &mut self.co[index] + pub fn y(&self) -> f32 { + self.co.get_1() + } + + pub fn z(&self) -> f32 { + self.co.get_2() + } + + pub fn set_x(&mut self, x: f32) { + self.co.set_0(x); + } + + pub fn set_y(&mut self, y: f32) { + self.co.set_1(y); + } + + pub fn set_z(&mut self, z: f32) { + self.co.set_2(z); } } @@ -130,7 +144,7 @@ mod tests { fn norm() { let mut p1 = Point::new(1.0, 2.0, 3.0); let p2 = Point::new(2.0, 4.0, 6.0); - p1.co[3] = 0.5; + p1.co.set_3(0.5); assert_eq!(p2, p1.norm()); } @@ -196,7 +210,7 @@ mod tests { 1.0, 5.0); let mut pm = Point::new(15.5, 54.0, 70.0); - pm.co[3] = 18.5; + pm.co.set_3(18.5); assert_eq!(p * m, pm); } diff --git a/src/math/vector.rs b/src/math/vector.rs index 177bea0..0dba7f4 100644 --- a/src/math/vector.rs +++ b/src/math/vector.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use std::ops::{Index, IndexMut, Add, Sub, Mul, Div, Neg}; +use std::ops::{Add, Sub, Mul, Div, Neg}; use std::cmp::PartialEq; use lerp::Lerp; @@ -33,26 +33,40 @@ impl Vector { } pub fn into_normal(self) -> Normal { - Normal::new(self.co[0], self.co[1], self.co[2]) + Normal::new(self.x(), self.y(), self.z()) } -} - -impl Index for Vector { - type Output = f32; - - fn index(&self, index: usize) -> &f32 { - debug_assert!(index < 3); - - &self.co[index] + pub fn get_n(&self, n: usize) -> f32 { + match n { + 0 => self.x(), + 1 => self.y(), + 2 => self.z(), + _ => panic!("Attempt to access dimension beyond z."), + } } -} -impl IndexMut for Vector { - fn index_mut(&mut self, index: usize) -> &mut f32 { - debug_assert!(index < 3); + pub fn x(&self) -> f32 { + self.co.get_0() + } - &mut self.co[index] + pub fn y(&self) -> f32 { + self.co.get_1() + } + + pub fn z(&self) -> f32 { + self.co.get_2() + } + + pub fn set_x(&mut self, x: f32) { + self.co.set_0(x); + } + + pub fn set_y(&mut self, y: f32) { + self.co.set_1(y); + } + + pub fn set_z(&mut self, z: f32) { + self.co.set_2(z); } } @@ -140,9 +154,12 @@ impl DotProduct for Vector { impl CrossProduct for Vector { fn cross(self, other: Vector) -> Vector { Vector { - co: Float4::new((self[1] * other[2]) - (self[2] * other[1]), - (self[2] * other[0]) - (self[0] * other[2]), - (self[0] * other[1]) - (self[1] * other[0]), + co: Float4::new((self.co.get_1() * other.co.get_2()) - + (self.co.get_2() * other.co.get_1()), + (self.co.get_2() * other.co.get_0()) - + (self.co.get_0() * other.co.get_2()), + (self.co.get_0() * other.co.get_1()) - + (self.co.get_1() * other.co.get_0()), 0.0), } } @@ -202,7 +219,7 @@ mod tests { 15.0, 3.0); let mut vm = Vector::new(14.0, 46.0, 58.0); - vm.co[3] = 90.5; + vm.co.set_3(90.5); assert_eq!(v * m, vm); } @@ -255,9 +272,9 @@ mod tests { let v1 = Vector::new(1.0, 2.0, 3.0); let v2 = Vector::new(0.2672612419124244, 0.5345224838248488, 0.8017837257372732); let v3 = v1.normalized(); - assert!((v3[0] - v2[0]).abs() < 0.000001); - assert!((v3[1] - v2[1]).abs() < 0.000001); - assert!((v3[2] - v2[2]).abs() < 0.000001); + assert!((v3.x() - v2.x()).abs() < 0.000001); + assert!((v3.y() - v2.y()).abs() < 0.000001); + assert!((v3.z() - v2.z()).abs() < 0.000001); } #[test] diff --git a/src/parse/basics.rs b/src/parse/basics.rs index d8c7c26..2722348 100644 --- a/src/parse/basics.rs +++ b/src/parse/basics.rs @@ -138,7 +138,6 @@ fn take_decimal_real(i: &[u8]) -> IResult<&[u8], &[u8]> { #[cfg(test)] mod test { - use nom::IResult; use nom::IResult::*; use super::take_decimal_real; use super::*; diff --git a/src/parse/data_tree.rs b/src/parse/data_tree.rs index 6ad9579..3c9127f 100644 --- a/src/parse/data_tree.rs +++ b/src/parse/data_tree.rs @@ -650,7 +650,7 @@ mod tests { "#) .unwrap(); - let mut i = dt.iter_children_with_type("A"); + let i = dt.iter_children_with_type("A"); assert_eq!(i.count(), 3); } @@ -665,7 +665,7 @@ mod tests { "#) .unwrap(); - let mut i = dt.iter_internal_children_with_type("A"); + let i = dt.iter_internal_children_with_type("A"); assert_eq!(i.count(), 2); } @@ -680,7 +680,7 @@ mod tests { "#) .unwrap(); - let mut i = dt.iter_leaf_children_with_type("A"); + let i = dt.iter_leaf_children_with_type("A"); assert_eq!(i.count(), 2); } } diff --git a/src/shading/surface_closure.rs b/src/shading/surface_closure.rs index ae995e1..a4b22cf 100644 --- a/src/shading/surface_closure.rs +++ b/src/shading/surface_closure.rs @@ -210,7 +210,7 @@ impl SurfaceClosure for LambertClosure { // Generate a random ray direction in the hemisphere // of the surface. let dir = cosine_sample_hemisphere(uv.0, uv.1); - let pdf = dir[2] * INV_PI; + let pdf = dir.z() * INV_PI; let out = zup_to_vec(dir, nn); let filter = self.evaluate(inc, out, nor, wavelength); diff --git a/src/tracer.rs b/src/tracer.rs index 03e5f89..057c2df 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -154,15 +154,15 @@ impl<'a> TracerInner<'a> { fn split_rays_by_direction(rays: &mut [AccelRay]) -> [&mut [AccelRay]; 8] { // | | | | | | | | | // s1 s2 s3 s4 s5 s6 s7 - let s4 = partition(&mut rays[..], |r| r.dir_inv[0].is_sign_positive()); + let s4 = partition(&mut rays[..], |r| r.dir_inv.x().is_sign_positive()); - let s2 = partition(&mut rays[..s4], |r| r.dir_inv[1].is_sign_positive()); - let s6 = s4 + partition(&mut rays[s4..], |r| r.dir_inv[1].is_sign_positive()); + let s2 = partition(&mut rays[..s4], |r| r.dir_inv.y().is_sign_positive()); + let s6 = s4 + partition(&mut rays[s4..], |r| r.dir_inv.y().is_sign_positive()); - let s1 = partition(&mut rays[..s2], |r| r.dir_inv[2].is_sign_positive()); - let s3 = s2 + partition(&mut rays[s2..s4], |r| r.dir_inv[2].is_sign_positive()); - let s5 = s4 + partition(&mut rays[s4..s6], |r| r.dir_inv[2].is_sign_positive()); - let s7 = s6 + partition(&mut rays[s6..], |r| r.dir_inv[2].is_sign_positive()); + let s1 = partition(&mut rays[..s2], |r| r.dir_inv.z().is_sign_positive()); + let s3 = s2 + partition(&mut rays[s2..s4], |r| r.dir_inv.z().is_sign_positive()); + let s5 = s4 + partition(&mut rays[s4..s6], |r| r.dir_inv.z().is_sign_positive()); + let s7 = s6 + partition(&mut rays[s6..], |r| r.dir_inv.z().is_sign_positive()); let (rest, rs7) = rays.split_at_mut(s7); let (rest, rs6) = rest.split_at_mut(s6);