diff --git a/Cargo.toml b/Cargo.toml index 656513f..b8d533c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,13 @@ version = "0.1.0" authors = ["ishanjain28 "] edition = "2018" + +[features] +gui = ["sdl2"] +avx2 = ["packed_simd"] + [dependencies] sdl2 = { version = "0.33.0", optional = true } rand = { version = "0.7.3", features = ["small_rng"] } rayon = "1.3.0" -packed_simd = "0.3.3" +packed_simd = { version = "0.3.3", optional = true } diff --git a/src/demos/final_scene.rs b/src/demos/final_scene.rs index a1e41b7..22ae034 100644 --- a/src/demos/final_scene.rs +++ b/src/demos/final_scene.rs @@ -159,7 +159,7 @@ impl Demo for FinalScene { fn calc_color(ray: Ray, world: &HitableList, depth: u32, rng: &mut SmallRng) -> Vec3 { if let Some(hit_rec) = world.hit(&ray, 0.001, std::f64::MAX) { - if depth >= 10 { + if depth >= 50 { Vec3::new(0.0, 0.0, 0.0) } else { let material = hit_rec.material.as_ref(); diff --git a/src/main.rs b/src/main.rs index 0cce323..007f533 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,7 +52,7 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> { //println!("{:?} {:?} {:?}", texture.query(), texture.color_mod(), texture.alpha_mod()); - let active_demo: &dyn Demo = &demos::MotionBlur; + let mut active_demo: &dyn Demo = &demos::SimpleRectangle; // TODO: Should update when window is unfocus since the project window retains // data from overlapped window // TODO: Maybe consider using condition variable to make loop {} not run at full @@ -121,6 +121,7 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> { active_demo = &demos::FinalScene; should_update = true; } + _ => (), }; } Event::Window { diff --git a/src/types/sphere.rs b/src/types/sphere.rs index efa2e9b..bb286b6 100644 --- a/src/types/sphere.rs +++ b/src/types/sphere.rs @@ -38,9 +38,9 @@ impl Hitable for Sphere { // Check this for detailed proof // https://vchizhov.github.io/resources/ray%20tracing/ray%20tracing%20tutorial%20series%20vchizhov/ray_casting/part1/intersecting_a_sphere.md.html#appendix let discriminant = b * b - a * c; - let discriminant_root = discriminant.sqrt(); let a_d = 1.0 / a; if discriminant > 0.0 { + let discriminant_root = discriminant.sqrt(); let root = (-b - discriminant_root) * a_d; if root < t_max && root > t_min { let p = ray.point_at_parameter(root); diff --git a/src/types/vec3.rs b/src/types/vec3.rs index b541199..85dad59 100644 --- a/src/types/vec3.rs +++ b/src/types/vec3.rs @@ -1,205 +1,418 @@ -use { - packed_simd::f64x4, - std::{ +#[cfg(feature = "avx2")] +pub use avx2::*; + +#[cfg(not(feature = "avx2"))] +pub use scalar::*; + +#[cfg(feature = "avx2")] +mod avx2 { + #[cfg(feature = "avx2")] + use packed_simd::f64x4; + + use std::{ fmt::{Display, Formatter, Result as FmtResult}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, - }, -}; + }; + #[derive(Debug, PartialEq, Copy, Clone)] + pub struct Vec3(f64x4); -// x,y,z,t -// r,g,b,_ -#[derive(Debug, PartialEq, Copy, Clone)] -pub struct Vec3(f64x4); + impl Vec3 { + #[inline] + pub const fn new(a: f64, b: f64, c: f64) -> Vec3 { + Vec3(f64x4::new(a, b, c, 0.0)) + } -impl Vec3 { - #[inline] - pub const fn new(a: f64, b: f64, c: f64) -> Vec3 { - Vec3(f64x4::new(a, b, c, 0.0)) + #[inline] + pub fn x(&self) -> f64 { + self.0.extract(0) + } + #[inline] + pub fn y(&self) -> f64 { + self.0.extract(1) + } + #[inline] + pub fn z(&self) -> f64 { + self.0.extract(2) + } + #[inline] + pub fn r(&self) -> f64 { + self.0.extract(0) + } + #[inline] + pub fn g(&self) -> f64 { + self.0.extract(1) + } + #[inline] + pub fn b(&self) -> f64 { + self.0.extract(2) + } + + #[inline] + pub fn length(&self) -> f64 { + self.sq_len().sqrt() + } + + #[inline] + pub fn sq_len(&self) -> f64 { + let p = self.0.powf(f64x4::new(2.0, 2.0, 2.0, 2.0)); + p.sum() + } + + #[inline] + pub fn dot(&self, v: &Vec3) -> f64 { + let p = self.0 * v.0; + p.sum() + } + + #[inline] + pub fn cross(&self, v: &Vec3) -> Vec3 { + let p1 = self.0 * f64x4::new(v.0.extract(1), v.0.extract(2), v.0.extract(0), 0.0); + let p2 = self.0 * f64x4::new(v.0.extract(2), v.0.extract(0), v.0.extract(1), 0.0); + + Vec3(f64x4::new( + p1.extract(1) - p2.extract(2), + p1.extract(2) - p2.extract(0), + p1.extract(0) - p2.extract(1), + 0.0, + )) + } + + #[inline] + pub fn unit_vector(&self) -> Vec3 { + let length = self.length(); + Vec3(self.0 / length) + } } - #[inline] - pub fn x(&self) -> f64 { - self.0.extract(0) - } - #[inline] - pub fn y(&self) -> f64 { - self.0.extract(1) - } - #[inline] - pub fn z(&self) -> f64 { - self.0.extract(2) - } - #[inline] - pub fn r(&self) -> f64 { - self.0.extract(0) - } - #[inline] - pub fn g(&self) -> f64 { - self.0.extract(1) - } - #[inline] - pub fn b(&self) -> f64 { - self.0.extract(2) + impl Add for Vec3 { + type Output = Vec3; + + fn add(self, o: Vec3) -> Vec3 { + Vec3(self.0 + o.0) + } } - #[inline] - pub fn length(&self) -> f64 { - self.sq_len().sqrt() + impl AddAssign for Vec3 { + fn add_assign(&mut self, o: Vec3) { + self.0 += o.0 + } } - #[inline] - pub fn sq_len(&self) -> f64 { - let p = self.0.powf(f64x4::new(2.0, 2.0, 2.0, 2.0)); - p.sum() + impl Sub for Vec3 { + type Output = Vec3; + + fn sub(self, o: Vec3) -> Vec3 { + Vec3(self.0 - o.0) + } } - #[inline] - pub fn dot(&self, v: &Vec3) -> f64 { - let p = self.0 * v.0; - p.sum() + impl SubAssign for Vec3 { + fn sub_assign(&mut self, o: Vec3) { + self.0 -= o.0 + } } - #[inline] - pub fn cross(&self, v: &Vec3) -> Vec3 { - let p1 = self.0 * f64x4::new(v.0.extract(1), v.0.extract(2), v.0.extract(0), 0.0); - let p2 = self.0 * f64x4::new(v.0.extract(2), v.0.extract(0), v.0.extract(1), 0.0); + impl Neg for Vec3 { + type Output = Vec3; - Vec3(f64x4::new( - p1.extract(1) - p2.extract(2), - p1.extract(2) - p2.extract(0), - p1.extract(0) - p2.extract(1), - 0.0, - )) + fn neg(self) -> Vec3 { + Vec3(-self.0) + } } - #[inline] - pub fn unit_vector(&self) -> Vec3 { - let length = self.length(); - Vec3(self.0 / length) + impl MulAssign for Vec3 { + fn mul_assign(&mut self, o: Vec3) { + self.0 *= o.0 + } + } + + impl MulAssign for Vec3 { + fn mul_assign(&mut self, o: f64) { + self.0 *= o + } + } + + impl Mul for Vec3 { + type Output = Vec3; + fn mul(self, o: f64) -> Vec3 { + Vec3(self.0 * o) + } + } + + impl Mul for Vec3 { + type Output = Vec3; + fn mul(self, o: Vec3) -> Vec3 { + Vec3(self.0 * o.0) + } + } + + impl Div for Vec3 { + type Output = Vec3; + + fn div(self, o: Vec3) -> Vec3 { + Vec3(self.0 / o.0) + } + } + + impl Div for Vec3 { + type Output = Vec3; + + fn div(self, o: f64) -> Vec3 { + let o = 1.0 / o; + self * o + } + } + + impl DivAssign for Vec3 { + fn div_assign(&mut self, o: f64) { + let o = 1.0 / o; + *self *= o; + } + } + + impl Display for Vec3 { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_fmt(format_args!( + "{} {} {}", + self.0.extract(0), + self.0.extract(1), + self.0.extract(2) + )) + } + } + + #[test] + fn vec3_test() { + let v = Vec3::new(0.5, 0.6, 0.8); + let q = Vec3::new(0.4, 0.2, 0.1); + let cross = Vec3::new( + -0.10000000000000003, + 0.2700000000000001, + -0.13999999999999999, + ); + let unit_vector = Vec3::new(0.4472135954999579, 0.5366563145999494, 0.7155417527999327); + let add = Vec3::new(0.9, 0.8, 0.9); + let sub = Vec3::new(0.09999999999999998, 0.39999999999999997, 0.7000000000000001); + let mul = Vec3::new(0.2, 0.12, 0.08000000000000002); + let div = Vec3::new(1.25, 2.9999999999999996, 8.0); + + assert_eq!(v.x(), 0.5); + assert_eq!(v.y(), 0.6); + assert_eq!(v.z(), 0.8); + assert_eq!(v.r(), 0.5); + assert_eq!(v.g(), 0.6); + assert_eq!(v.b(), 0.8); + assert_eq!(v.length(), 1.118033988749895); + assert_eq!(v.sq_len(), 1.25); + assert_eq!(v.dot(&q), 0.4); + assert_eq!(v.cross(&q), cross); + assert_eq!(v.unit_vector(), unit_vector); + assert_eq!(v + q, add); + assert_eq!(v - q, sub); + assert_eq!(v * q, mul); + assert_eq!(v / q, div); } } -impl Add for Vec3 { - type Output = Vec3; +mod scalar { + use std::{ + fmt::{Display, Formatter, Result as FmtResult}, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, + }; + #[derive(Debug, PartialEq, Copy, Clone)] + pub struct Vec3(f64, f64, f64); - fn add(self, o: Vec3) -> Vec3 { - Vec3(self.0 + o.0) + impl Vec3 { + #[inline] + pub const fn new(a: f64, b: f64, c: f64) -> Vec3 { + Vec3(a, b, c) + } + + #[inline] + pub fn x(&self) -> f64 { + self.0 + } + #[inline] + pub fn y(&self) -> f64 { + self.1 + } + #[inline] + pub fn z(&self) -> f64 { + self.2 + } + #[inline] + pub fn r(&self) -> f64 { + self.0 + } + #[inline] + pub fn g(&self) -> f64 { + self.1 + } + #[inline] + pub fn b(&self) -> f64 { + self.2 + } + + #[inline] + pub fn length(&self) -> f64 { + self.sq_len().sqrt() + } + + #[inline] + pub fn sq_len(&self) -> f64 { + self.0 * self.0 + self.1 * self.1 + self.2 * self.2 + } + + #[inline] + pub fn dot(&self, v: &Vec3) -> f64 { + self.0 * v.0 + self.1 * v.1 + self.2 * v.2 + } + + #[inline] + pub fn cross(&self, v: &Vec3) -> Vec3 { + Vec3( + self.1 * v.2 - self.2 * v.1, + self.2 * v.0 - self.0 * v.2, + self.0 * v.1 - self.1 * v.0, + ) + } + + #[inline] + pub fn unit_vector(&self) -> Vec3 { + let length = self.length(); + Vec3(self.0 / length, self.1 / length, self.2 / length) + } + } + + impl Add for Vec3 { + type Output = Vec3; + + fn add(self, o: Vec3) -> Vec3 { + Vec3::new(self.0 + o.0, self.1 + o.1, self.2 + o.2) + } + } + + impl AddAssign for Vec3 { + fn add_assign(&mut self, o: Vec3) { + self.0 += o.0; + self.1 += o.1; + self.2 += o.2; + } + } + + impl Sub for Vec3 { + type Output = Vec3; + + fn sub(self, o: Vec3) -> Vec3 { + Vec3::new(self.0 - o.0, self.1 - o.1, self.2 - o.2) + } + } + + impl SubAssign for Vec3 { + fn sub_assign(&mut self, o: Vec3) { + self.0 -= o.0; + self.1 -= o.1; + self.2 -= o.2; + } + } + + impl Neg for Vec3 { + type Output = Vec3; + + fn neg(self) -> Vec3 { + Vec3(-self.0, -self.1, -self.2) + } + } + + impl MulAssign for Vec3 { + fn mul_assign(&mut self, o: Vec3) { + self.0 *= o.0; + self.1 *= o.1; + self.2 *= o.2; + } + } + + impl MulAssign for Vec3 { + fn mul_assign(&mut self, o: f64) { + self.0 *= o; + self.1 *= o; + self.2 *= o; + } + } + + impl Mul for Vec3 { + type Output = Vec3; + fn mul(self, o: f64) -> Vec3 { + Vec3::new(self.0 * o, self.1 * o, self.2 * o) + } + } + + impl Mul for Vec3 { + type Output = Vec3; + fn mul(self, o: Vec3) -> Vec3 { + Vec3::new(self.0 * o.0, self.1 * o.1, self.2 * o.2) + } + } + + impl Div for Vec3 { + type Output = Vec3; + + fn div(self, o: Vec3) -> Vec3 { + Vec3::new(self.0 / o.0, self.1 / o.1, self.2 / o.2) + } + } + + impl Div for Vec3 { + type Output = Vec3; + + fn div(self, o: f64) -> Vec3 { + let o = 1.0 / o; + self * o + } + } + + impl DivAssign for Vec3 { + fn div_assign(&mut self, o: f64) { + let o = 1.0 / o; + *self *= o; + } + } + + impl Display for Vec3 { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + f.write_fmt(format_args!("{} {} {}", self.0, self.1, self.2)) + } + } + + #[test] + fn vec3_test() { + let v = Vec3::new(0.5, 0.6, 0.8); + let q = Vec3::new(0.4, 0.2, 0.1); + let cross = Vec3::new( + -0.10000000000000003, + 0.2700000000000001, + -0.13999999999999999, + ); + let unit_vector = Vec3::new(0.4472135954999579, 0.5366563145999494, 0.7155417527999327); + let add = Vec3::new(0.9, 0.8, 0.9); + let sub = Vec3::new(0.09999999999999998, 0.39999999999999997, 0.7000000000000001); + let mul = Vec3::new(0.2, 0.12, 0.08000000000000002); + let div = Vec3::new(1.25, 2.9999999999999996, 8.0); + + assert_eq!(v.x(), 0.5); + assert_eq!(v.y(), 0.6); + assert_eq!(v.z(), 0.8); + assert_eq!(v.r(), 0.5); + assert_eq!(v.g(), 0.6); + assert_eq!(v.b(), 0.8); + assert_eq!(v.length(), 1.118033988749895); + assert_eq!(v.sq_len(), 1.25); + assert_eq!(v.dot(&q), 0.4); + assert_eq!(v.cross(&q), cross); + assert_eq!(v.unit_vector(), unit_vector); + assert_eq!(v + q, add); + assert_eq!(v - q, sub); + assert_eq!(v * q, mul); + assert_eq!(v / q, div); } } - -impl AddAssign for Vec3 { - fn add_assign(&mut self, o: Vec3) { - self.0 += o.0 - } -} - -impl Sub for Vec3 { - type Output = Vec3; - - fn sub(self, o: Vec3) -> Vec3 { - Vec3(self.0 - o.0) - } -} - -impl SubAssign for Vec3 { - fn sub_assign(&mut self, o: Vec3) { - self.0 -= o.0 - } -} - -impl Neg for Vec3 { - type Output = Vec3; - - fn neg(self) -> Vec3 { - Vec3(-self.0) - } -} - -impl MulAssign for Vec3 { - fn mul_assign(&mut self, o: Vec3) { - self.0 *= o.0 - } -} - -impl MulAssign for Vec3 { - fn mul_assign(&mut self, o: f64) { - self.0 *= o - } -} - -impl Mul for Vec3 { - type Output = Vec3; - fn mul(self, o: f64) -> Vec3 { - Vec3(self.0 * o) - } -} - -impl Mul for Vec3 { - type Output = Vec3; - fn mul(self, o: Vec3) -> Vec3 { - Vec3(self.0 * o.0) - } -} - -impl Div for Vec3 { - type Output = Vec3; - - fn div(self, o: Vec3) -> Vec3 { - Vec3(self.0 / o.0) - } -} - -impl Div for Vec3 { - type Output = Vec3; - - fn div(self, o: f64) -> Vec3 { - let o = 1.0 / o; - self * o - } -} - -impl DivAssign for Vec3 { - fn div_assign(&mut self, o: f64) { - let o = 1.0 / o; - *self *= o; - } -} - -impl Display for Vec3 { - fn fmt(&self, f: &mut Formatter) -> FmtResult { - //f.write_fmt(format_args!("{} {} {}", self[0], self[1], self[2])) - Ok(()) - } -} - -#[test] -fn vec3_test() { - let v = Vec3::new(0.5, 0.6, 0.8); - let q = Vec3::new(0.4, 0.2, 0.1); - let cross = Vec3::new( - -0.10000000000000003, - 0.2700000000000001, - -0.13999999999999999, - ); - let unit_vector = Vec3::new(0.4472135954999579, 0.5366563145999494, 0.7155417527999327); - let add = Vec3::new(0.9, 0.8, 0.9); - let sub = Vec3::new(0.09999999999999998, 0.39999999999999997, 0.7000000000000001); - let mul = Vec3::new(0.2, 0.12, 0.08000000000000002); - let div = Vec3::new(1.25, 2.9999999999999996, 8.0); - - assert_eq!(v.x(), 0.5); - assert_eq!(v.y(), 0.6); - assert_eq!(v.z(), 0.8); - assert_eq!(v.r(), 0.5); - assert_eq!(v.g(), 0.6); - assert_eq!(v.b(), 0.8); - assert_eq!(v.length(), 1.118033988749895); - assert_eq!(v.sq_len(), 1.25); - assert_eq!(v.dot(&q), 0.4); - assert_eq!(v.cross(&q), cross); - assert_eq!(v.unit_vector(), unit_vector); - assert_eq!(v + q, add); - assert_eq!(v - q, sub); - assert_eq!(v * q, mul); - assert_eq!(v / q, div); -}