diff --git a/Cargo.lock b/Cargo.lock index 1f37f78..c166610 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1290,6 +1290,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -1324,6 +1330,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "range-alloc" version = "0.1.3" @@ -1443,6 +1479,7 @@ dependencies = [ "nalgebra", "pixels", "pollster", + "rand", "rhai", "roots", "winit", diff --git a/Cargo.toml b/Cargo.toml index 5fb63bf..c128490 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,5 @@ winit = "0.27" winit_input_helper = "0.13" pixels = "0.13" error-iter = "0.4.1" -rhai = {version = "1.16.3", features=["f32_float"]} +rhai = {version = "1.16.3"} +rand = "0.8.5" diff --git a/src/camera.rs b/src/camera.rs index b14455a..4bbb4f8 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -2,32 +2,32 @@ use crate::ray::Ray; use crate::{EPSILON, INFINITY}; use nalgebra::{Matrix4, Perspective3, Point3, Unit, Vector3}; -const ZNEAR: f32 = EPSILON; -const ZFAR: f32 = INFINITY; +const ZNEAR: f64 = EPSILON; +const ZFAR: f64 = INFINITY; #[allow(dead_code)] #[derive(Clone)] pub struct Camera { - eye: Point3, - target: Point3, - up: Vector3, - fovy: f32, + eye: Point3, + target: Point3, + up: Vector3, + fovy: f64, width: u32, height: u32, - matrix: Matrix4, - inverse: Matrix4, + matrix: Matrix4, + inverse: Matrix4, pub rays: Vec, } #[allow(dead_code)] impl Camera { pub fn new( - eye: Point3, - target: Point3, - up: Vector3, + eye: Point3, + target: Point3, + up: Vector3, width: u32, height: u32, - fovy: f32, + fovy: f64, ) -> Self { let (matrix, inverse) = build_matrix_and_inverse(&eye, &target, &up, width, height, fovy); let rays = cast_rays(&eye, &target, &up, width, height, fovy); @@ -45,10 +45,10 @@ impl Camera { } pub fn new_sizeless( - eye: Point3, - target: Point3, - up: Vector3, - fovy: f32, + eye: Point3, + target: Point3, + up: Vector3, + fovy: f64, ) -> Self { Camera::new(eye, target, up, 1, 1, fovy) } @@ -71,7 +71,7 @@ impl Camera { ) } - pub fn build_matrix_and_inverse(&self) -> (Matrix4, Matrix4) { + pub fn build_matrix_and_inverse(&self) -> (Matrix4, Matrix4) { build_matrix_and_inverse( &self.eye, &self.target, @@ -92,21 +92,21 @@ impl Camera { let h_width = 2.0 * (fovh_radians / 2.0).tan(); let v_height = 2.0 * (fovy_radians / 2.0).tan(); //All good - let d_hor_vec = hor * (h_width / self.width as f64) as f32; - let d_vert_vec = vert * (v_height / self.height as f64) as f32; + let d_hor_vec = hor * (h_width / self.width as f64) as f64; + let d_vert_vec = vert * (v_height / self.height as f64) as f64; let half_w = self.width as i32 / 2; let half_h = self.height as i32 / 2; - let horizontal = (x as i32 - half_w) as f32 * (d_hor_vec); - let vertical = (-(y as i32) + half_h) as f32 * (d_vert_vec); + let horizontal = (x as i32 - half_w) as f64 * (d_hor_vec); + let vertical = (-(y as i32) + half_h) as f64 * (d_vert_vec); let direction = view_direction + horizontal + vertical; Ray::new(self.eye, Unit::new_normalize(direction)) } - pub fn set_position(&mut self, eye: Point3) { + pub fn set_position(&mut self, eye: Point3) { self.eye = eye; } @@ -119,15 +119,15 @@ impl Camera { } fn build_matrix_and_inverse( - eye: &Point3, - target: &Point3, - up: &Vector3, + eye: &Point3, + target: &Point3, + up: &Vector3, width: u32, height: u32, - fovy: f32, -) -> (Matrix4, Matrix4) { + fovy: f64, +) -> (Matrix4, Matrix4) { let view = Matrix4::look_at_lh(eye, target, up); - let aspect = width as f32 / height as f32; + let aspect = width as f64 / height as f64; let proj = Perspective3::new(aspect, fovy, ZNEAR, ZFAR); let matrix = proj.as_matrix() * view; let inverse = view.try_inverse().expect("No view") * proj.inverse(); @@ -135,12 +135,12 @@ fn build_matrix_and_inverse( } fn cast_rays( - eye: &Point3, - target: &Point3, - up: &Vector3, + eye: &Point3, + target: &Point3, + up: &Vector3, width: u32, height: u32, - fovy: f32, + fovy: f64, ) -> Vec { let aspect = width as f64 / height as f64; let fovy_radians = (fovy as f64).to_radians(); @@ -148,11 +148,11 @@ fn cast_rays( let view_direction = (target - eye).normalize(); let hor = (view_direction.cross(&up)).normalize(); let vert = (view_direction.cross(&hor)).normalize(); - let h_width = 2.0 * (fovh_radians / 2.0).tan() as f32; - let v_height = 2.0 * (fovy_radians / 2.0).tan() as f32; + let h_width = 2.0 * (fovh_radians / 2.0).tan() as f64; + let v_height = 2.0 * (fovy_radians / 2.0).tan() as f64; //All good - let d_hor_vec = hor * (h_width / width as f32); - let d_vert_vec = vert * (v_height / height as f32); + let d_hor_vec = hor * (h_width / width as f64); + let d_vert_vec = vert * (v_height / height as f64); let mut rays = Vec::with_capacity(width as usize * height as usize); @@ -161,8 +161,8 @@ fn cast_rays( for j in 0..height as i32 { for i in 0..width as i32 { - let horizontal = (i - half_w) as f32 * (d_hor_vec); - let vertical = (-j + half_h) as f32 * (d_vert_vec); + let horizontal = (i - half_w) as f64 * (d_hor_vec); + let vertical = (-j + half_h) as f64 * (d_vert_vec); let direction = view_direction + horizontal + vertical; let ray = Ray::new(eye.clone(), Unit::new_normalize(direction)); diff --git a/src/gui.rs b/src/gui.rs index 5b3d251..a888df1 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,4 +1,4 @@ -use crate::{camera::Camera, scene::Scene, state::INIT_FILE, UP_VECTOR, ZERO_VECTOR}; +use crate::{camera::Camera, scene::Scene, state::INIT_FILE, UP_VECTOR_F32, ZERO_VECTOR_F32}; use imgui::*; use nalgebra::{Point3, Vector3}; use pixels::{wgpu, PixelsContext}; @@ -102,8 +102,8 @@ impl Gui { buffer_proportion: BUFFER_PROPORTION_INIT, camera_eye: [CAMERA_INIT, CAMERA_INIT, CAMERA_INIT], - camera_target: ZERO_VECTOR.into(), - camera_up: UP_VECTOR.into(), + camera_target: ZERO_VECTOR_F32.into(), + camera_up: UP_VECTOR_F32.into(), camera_fov: 110.0, } } @@ -171,13 +171,18 @@ impl Gui { // Create three input fields for x, y, and z components if ui.button("Apply Camera") { println!("Camera changed: {:?}", self.camera_eye); + let (eye, target, up) = (&self.camera_eye, &self.camera_target, &self.camera_up); + let (ex, ey, ez) = (eye[0] as f64, eye[1] as f64, eye[2] as f64); + let (tx, ty, tz) = (target[0] as f64, target[1] as f64, target[2] as f64); + let (ux, uy, uz) = (up[0] as f64, up[1] as f64, up[2] as f64); + let camera = Camera::new( - Point3::from_slice(&self.camera_eye), - Point3::from_slice(&self.camera_target), - Vector3::from_row_slice(&self.camera_up), + Point3::new(ex, ey, ez), + Point3::new(tx, ty, tz), + Vector3::new(ux, uy, uz), 1, 1, - self.camera_fov, + self.camera_fov as f64, ); self.event = Some(GuiEvent::CameraUpdate(camera)); } diff --git a/src/light.rs b/src/light.rs index d0aaa1e..6dd8a61 100644 --- a/src/light.rs +++ b/src/light.rs @@ -2,20 +2,20 @@ use nalgebra::{Point3, Vector3}; #[derive(Clone)] pub struct Light { - pub position: Point3, - pub colour: Vector3, - pub falloff: Vector3, + pub position: Point3, + pub colour: Vector3, + pub falloff: Vector3, } impl Light { - pub fn new(position: Point3, colour: Vector3, falloff: Vector3) -> Self { + pub fn new(position: Point3, colour: Vector3, falloff: Vector3) -> Self { Light { position, colour, falloff, } } - pub fn white(position: Point3) -> Self { + pub fn white(position: Point3) -> Self { let colour = Vector3::new(1.0, 1.0, 1.0); let falloff = Vector3::new(1.0, 0.0, 0.0); Light::new(position, colour, falloff) diff --git a/src/main.rs b/src/main.rs index 69069c8..33df581 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,13 @@ use crate::state::run; use error_iter::ErrorIter; -const EPSILON: f32 = 1e-9; -const INFINITY: f32 = f32::MAX; -const EPSILON_VECTOR: Vector3 = Vector3::new(EPSILON, EPSILON, EPSILON); -static ZERO_VECTOR: Vector3 = Vector3::new(0.0, 0.0, 0.0); -static UP_VECTOR: Vector3 = Vector3::new(0.0, 1.0, 0.0); +const EPSILON: f64 = 1e-9; +const INFINITY: f64 = f64::MAX; +const EPSILON_VECTOR: Vector3 = Vector3::new(EPSILON, EPSILON, EPSILON); +static ZERO_VECTOR: Vector3 = Vector3::new(0.0, 0.0, 0.0); +static UP_VECTOR: Vector3 = Vector3::new(0.0, 1.0, 0.0); +static ZERO_VECTOR_F32: Vector3 = Vector3::new(0.0, 0.0, 0.0); +static UP_VECTOR_F32: Vector3 = Vector3::new(0.0, 1.0, 0.0); use log::error; use std::env; diff --git a/src/primitive.rs b/src/primitive.rs index e651fd4..4bc28fc 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -10,12 +10,12 @@ use std::sync::Arc; // MATERIAL ----------------------------------------------------------------- #[derive(Clone)] pub struct Material { - pub kd: Vector3, - pub ks: Vector3, - pub shininess: f32, + pub kd: Vector3, + pub ks: Vector3, + pub shininess: f64, } impl Material { - pub fn new(kd: Vector3, ks: Vector3, shininess: f32) -> Arc { + pub fn new(kd: Vector3, ks: Vector3, shininess: f64) -> Arc { Arc::new(Material { kd, ks, shininess }) } pub fn magenta() -> Arc { @@ -52,26 +52,26 @@ impl Material { // INTERSECTION ----------------------------------------------------------------- pub struct Intersection { // Information about an intersection - pub point: Point3, - pub normal: Unit>, - pub incidence: Unit>, + pub point: Point3, + pub normal: Unit>, + pub incidence: Unit>, pub material: Arc, - pub distance: f32, + pub distance: f64, } // BOUNDING BOX ----------------------------------------------------------------- #[derive(Clone)] struct BoundingBox { - bln: Point3, - trf: Point3, + bln: Point3, + trf: Point3, } impl BoundingBox { - fn new(bln: Point3, trf: Point3) -> Self { + fn new(bln: Point3, trf: Point3) -> Self { let bln = bln - EPSILON_VECTOR; let trf = trf + EPSILON_VECTOR; BoundingBox { bln, trf } } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { let t1 = (self.bln - ray.a).component_div(&ray.b); let t2 = (self.trf - ray.a).component_div(&ray.b); @@ -84,28 +84,28 @@ impl BoundingBox { None } } - fn get_centroid(&self) -> Point3 { + fn get_centroid(&self) -> Point3 { self.bln + (self.trf - self.bln) / 2.0 } } // PRIMITIVE TRAIT ----------------------------------------------------------------- pub trait Primitive: Send + Sync { fn intersect_ray(&self, ray: &Ray) -> Option; - fn intersect_bounding_box(&self, ray: &Ray) -> Option>; + fn intersect_bounding_box(&self, ray: &Ray) -> Option>; fn get_material(&self) -> Arc; } // SPHERE ----------------------------------------------------------------- #[derive(Clone)] pub struct Sphere { - position: Point3, - radius: f32, + position: Point3, + radius: f64, bounding_box: BoundingBox, material: Arc, } impl Sphere { - pub fn new(position: Point3, radius: f32, material: Arc) -> Arc { + pub fn new(position: Point3, radius: f64, material: Arc) -> Arc { let radius_vec = Vector3::new(radius, radius, radius); let bln = position - radius_vec; let trf = position + radius_vec; @@ -166,7 +166,7 @@ impl Primitive for Sphere { Arc::clone(&self.material) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { return self.bounding_box.intersect_bounding_box(ray); } } @@ -174,18 +174,18 @@ impl Primitive for Sphere { // CIRCLE ----------------------------------------------------------------- #[derive(Clone)] pub struct Circle { - position: Point3, - radius: f32, - normal: Vector3, + position: Point3, + radius: f64, + normal: Vector3, material: Arc, bounding_box: BoundingBox, } impl Circle { pub fn new( - position: Point3, - radius: f32, - normal: Vector3, + position: Point3, + radius: f64, + normal: Vector3, material: Arc, ) -> Arc { let radius_vec = Vector3::new(radius, radius, radius); @@ -249,7 +249,7 @@ impl Primitive for Circle { Arc::clone(&self.material) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } } @@ -257,9 +257,9 @@ impl Primitive for Circle { // CYLINDER ----------------------------------------------------------------- #[derive(Clone)] pub struct Cylinder { - radius: f32, - base: f32, - top: f32, + radius: f64, + base: f64, + top: f64, base_circle: Arc, top_circle: Arc, material: Arc, @@ -267,7 +267,7 @@ pub struct Cylinder { } impl Cylinder { - pub fn new(radius: f32, base: f32, top: f32, material: Arc) -> Arc { + pub fn new(radius: f64, base: f64, top: f64, material: Arc) -> Arc { let base_circle = Circle::new( Point3::new(0.0, base, 0.0), radius, @@ -377,7 +377,7 @@ impl Primitive for Cylinder { Arc::clone(&self.material) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } } @@ -385,16 +385,16 @@ impl Primitive for Cylinder { // CONE ----------------------------------------------------------------- #[derive(Clone)] pub struct Cone { - radius: f32, - base: f32, - apex: f32, + radius: f64, + base: f64, + apex: f64, circle: Arc, material: Arc, bounding_box: BoundingBox, } impl Cone { - pub fn new(radius: f32, apex: f32, base: f32, material: Arc) -> Arc { + pub fn new(radius: f64, apex: f64, base: f64, material: Arc) -> Arc { let circle = Circle::new( Point3::new(0.0, base, 0.0), radius, @@ -416,7 +416,7 @@ impl Cone { Cone::new(1.0, 2.0, -1.0, material) } - pub fn get_normal(&self, intersect: Point3) -> Vector3 { + pub fn get_normal(&self, intersect: Point3) -> Vector3 { let r = self.radius; let h = self.apex; let (x, y, z) = (intersect.x, intersect.y, intersect.z); @@ -492,7 +492,7 @@ impl Primitive for Cone { Arc::clone(&self.material) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } } @@ -500,22 +500,22 @@ impl Primitive for Cone { // RECTANGLE ----------------------------------------------------------------- #[derive(Clone)] pub struct Rectangle { - position: Point3, - normal: Vector3, - width_direction: Vector3, + position: Point3, + normal: Vector3, + width_direction: Vector3, material: Arc, - width: f32, - height: f32, + width: f64, + height: f64, bounding_box: BoundingBox, } impl Rectangle { pub fn new( - position: Point3, - normal: Vector3, - width_direction: Vector3, - width: f32, - height: f32, + position: Point3, + normal: Vector3, + width_direction: Vector3, + width: f64, + height: f64, material: Arc, ) -> Arc { let normal = normal.normalize(); @@ -580,7 +580,7 @@ impl Primitive for Rectangle { Arc::clone(&self.material) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } } @@ -588,15 +588,15 @@ impl Primitive for Rectangle { // BOX ----------------------------------------------------------------- #[derive(Clone)] pub struct Cube { - width: f32, - height: f32, - depth: f32, + width: f64, + height: f64, + depth: f64, material: Arc, bounding_box: BoundingBox, } impl Cube { - pub fn new(width: f32, height: f32, depth: f32, material: Arc) -> Arc { + pub fn new(width: f64, height: f64, depth: f64, material: Arc) -> Arc { let trf = Point3::new(width / 2.0, height / 2.0, depth / 2.0); let bln = Point3::new(-width / 2.0, -height / 2.0, -depth / 2.0); Arc::new(Cube { @@ -665,7 +665,7 @@ impl Primitive for Cube { } } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } @@ -676,19 +676,19 @@ impl Primitive for Cube { // TRIANGLE ----------------------------------------------------------------- struct Triangle { - u: Point3, - v: Point3, - w: Point3, - normal: Vector3, + u: Point3, + v: Point3, + w: Point3, + normal: Vector3, material: Arc, bounding_box: BoundingBox, } impl Triangle { fn new( - u: Point3, - v: Point3, - w: Point3, + u: Point3, + v: Point3, + w: Point3, material: Arc, ) -> Arc { let uv = v - u; @@ -759,7 +759,7 @@ impl Primitive for Triangle { Arc::clone(&self.material) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } } @@ -800,7 +800,7 @@ impl Mesh { fn from_file(filename: &str, material: Arc) -> Arc { let mut triangles: Vec> = Vec::new(); - let mut vertices: Vec> = Vec::new(); + let mut vertices: Vec> = Vec::new(); let file = File::open(filename).expect("Failed to open file"); let reader = BufReader::new(file); @@ -815,9 +815,9 @@ impl Mesh { if let (Some(x_str), Some(y_str), Some(z_str)) = (parts.next(), parts.next(), parts.next()) { - let x: f32 = x_str.parse().expect("Failed to parse vertex X"); - let y: f32 = y_str.parse().expect("Failed to parse vertex Y"); - let z: f32 = z_str.parse().expect("Failed to parse vertex Z"); + let x: f64 = x_str.parse().expect("Failed to parse vertex X"); + let y: f64 = y_str.parse().expect("Failed to parse vertex Y"); + let z: f64 = z_str.parse().expect("Failed to parse vertex Z"); vertices.push(Point3::new(x, y, z)); } } @@ -873,7 +873,7 @@ impl Primitive for Mesh { Arc::clone(&self.material) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } } @@ -968,7 +968,7 @@ impl Primitive for SteinerSurface { }) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } @@ -977,7 +977,7 @@ impl Primitive for SteinerSurface { } } -fn smallest_non_zero(arr: &[f32]) -> Option { +fn smallest_non_zero(arr: &[f64]) -> Option { for &num in arr { if num >= 0.0 { return Some(num); @@ -988,13 +988,13 @@ fn smallest_non_zero(arr: &[f32]) -> Option { #[derive(Clone)] pub struct Torus { - inner_rad: f32, - outer_rad: f32, + inner_rad: f64, + outer_rad: f64, material: Arc, bounding_box: BoundingBox, } impl Torus { - pub fn new(inner_rad: f32, outer_rad: f32, material: Arc) -> Arc { + pub fn new(inner_rad: f64, outer_rad: f64, material: Arc) -> Arc { // I need to find the bounding box for this shape let trf = Point3::new(1.0, 1.0, 1.0); let bln = Point3::new(-1.0, -1.0, -1.0); @@ -1109,7 +1109,7 @@ impl Primitive for Torus { }) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } @@ -1178,7 +1178,7 @@ impl Primitive for AdamShape { distance: t, }) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } @@ -1255,7 +1255,7 @@ impl Primitive for AdamShape2 { distance: t, }) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } @@ -1342,7 +1342,7 @@ impl Primitive for AdamShape3 { distance: t, }) } - fn intersect_bounding_box(&self, ray: &Ray) -> Option> { + fn intersect_bounding_box(&self, ray: &Ray) -> Option> { self.bounding_box.intersect_bounding_box(ray) } diff --git a/src/ray.rs b/src/ray.rs index 84a1bc0..0cfb4e6 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -8,12 +8,12 @@ use nalgebra::{Point3, Unit, Vector3}; #[derive(Clone)] pub struct Ray { - pub a: Point3, - pub b: Unit>, + pub a: Point3, + pub b: Unit>, } impl Ray { - pub fn new(a: Point3, b: Unit>) -> Ray { + pub fn new(a: Point3, b: Unit>) -> Ray { Ray { a, b } } pub fn unit() -> Ray { @@ -21,7 +21,7 @@ impl Ray { let b = Unit::new_normalize(Vector3::new(0.0, 1.0, 0.0)); Ray { a, b } } - pub fn at_t(&self, t: f32) -> Point3 { + pub fn at_t(&self, t: f64) -> Point3 { self.a + self.b.into_inner() * (t + EPSILON) } //Shade a single ray diff --git a/src/scene.rs b/src/scene.rs index c6adf30..12f2dbf 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -68,11 +68,11 @@ impl Scene { let mut engine = Engine::new(); engine - .register_type::>() - .register_fn("V", Vector3::::new); + .register_type::>() + .register_fn("V", Vector3::::new); engine - .register_type::>() - .register_fn("P", Point3::::new); + .register_type::>() + .register_fn("P", Point3::::new); engine .register_type::() .register_fn("Scene", Scene::empty) diff --git a/src/state.rs b/src/state.rs index f261004..269343a 100644 --- a/src/state.rs +++ b/src/state.rs @@ -4,6 +4,9 @@ use crate::camera::Camera; use crate::{gui::Gui, scene::Scene}; use crate::{gui::GuiEvent, log_error}; +use rand::seq::SliceRandom; +use rand::thread_rng; + use std::error::Error; use std::sync::{Arc, Mutex}; @@ -21,6 +24,146 @@ const COLOUR_CLEAR: [u8; 4] = [0x22, 0x00, 0x11, 0xff]; pub const INIT_FILE: &str = "scene.rhai"; +pub struct State { + scene: Scene, + camera: Camera, + window: Window, + + buffer_width: u32, + buffer_height: u32, + + pixels: Arc>, + gui: Gui, + + ray_queue: Vec, +} + +impl State { + pub fn new(window: Window, pixels: Pixels, gui: Gui) -> Self { + let scene = Scene::empty(); + let window_size = window.inner_size(); + let camera = Camera::unit(); + + Self { + scene, + camera, + window, + buffer_width: window_size.width as u32, + buffer_height: window_size.height as u32, + pixels: Arc::new(Mutex::new(pixels)), + gui, + ray_queue: Vec::new(), + } + } + + fn update(&mut self) -> Result<(), Box> { + if let Some(event) = self.gui.event.take() { + match event { + GuiEvent::BufferResize(proportion) => self.resize_buffer(proportion)?, + GuiEvent::CameraUpdate(camera) => self.set_camera(camera)?, + GuiEvent::SceneLoad(scene) => { + self.scene = scene; + self.clear()?; + } + } + }; + Ok(()) + } + + fn resize_buffer(&mut self, proportion: f32) -> Result<(), Box> { + let size = self.window.inner_size(); + + self.buffer_width = (size.width as f32 * proportion) as u32; + self.buffer_height = (size.height as f32 * proportion) as u32; + self.camera.set_size(self.buffer_width, self.buffer_height); + + self.clear()?; + + let mut pixels = self.pixels.lock().unwrap(); + pixels.resize_buffer(self.buffer_width, self.buffer_height)?; + Ok(()) + } + + fn resize(&mut self, size: &PhysicalSize) -> Result<(), Box> { + let mut pixels = self.pixels.lock().unwrap(); + pixels.resize_surface(size.width, size.height)?; + Ok(()) + } + + fn keyboard_input(&mut self, key: &KeyboardInput) { + if let Some(VirtualKeyCode::A) = key.virtual_keycode { + // Handle 'A' key event here + } + } + + fn mouse_input(&mut self, _button: &MouseButton) { + // Handle mouse input here + } + + fn draw(&mut self) -> Result<(), Box> { + for _ in 0..self.gui.ray_num { + //Get random index from queue + let index = self.ray_queue.pop().unwrap(); + //Shade colour for selected ray + let colour = &self.camera.rays[index].shade_ray(&self.scene); + //Assign colour to frame + let rgba = colour.map_or(COLOUR_CLEAR, |colour| [colour.x, colour.y, colour.z, 255]); + let mut pixels = self.pixels.lock().unwrap(); + let frame = pixels.frame_mut(); + frame[index * 4..(index + 1) * 4].copy_from_slice(&rgba); + + if self.ray_queue.is_empty() { + break; + }; + } + Ok(()) + } + + fn clear(&mut self) -> Result<(), Box> { + let mut pixels = self.pixels.lock().unwrap(); + let frame = pixels.frame_mut(); + for pixel in frame.chunks_exact_mut(4) { + pixel.copy_from_slice(&[0x00, 0x00, 0x00, 0xff]); + } + Ok(()) + } + + fn set_camera(&mut self, camera: Camera) -> Result<(), Box> { + self.clear()?; + self.reset_queue(); + self.camera = camera; + self.camera.set_size(self.buffer_width, self.buffer_height); + Ok(()) + } + + fn reset_queue(&mut self) { + let size = self.buffer_height as usize * self.buffer_width as usize; + let mut ray_queue: Vec = (0..size).collect(); + ray_queue.shuffle(&mut thread_rng()); + self.ray_queue = ray_queue; + } + + fn render(&mut self) -> Result<(), Box> { + self.update()?; //Update state + if !self.ray_queue.is_empty() { + self.draw()?; + } + let pixels = self.pixels.lock().unwrap(); + self.gui + .prepare(&self.window) + .expect("gui.prepare() failed"); //Prepare imgui + if let Err(e) = pixels.render_with(|encoder, render_target, context| { + context.scaling_renderer.render(encoder, render_target); // Render pixels + self.gui + .render(&self.window, encoder, render_target, context)?; + Ok(()) + }) { + log_error("pixels.render", e); + }; + Ok(()) + } +} + pub fn run() -> Result<(), Box> { let event_loop = EventLoop::new(); let window = create_window(&event_loop); @@ -83,138 +226,3 @@ fn handle_window_event( }; Ok(()) } - -pub struct State { - scene: Scene, - camera: Camera, - window: Window, - - buffer_width: u32, - buffer_height: u32, - - pixels: Arc>, - gui: Gui, - - index: usize, - finished: bool, -} - -impl State { - pub fn new(window: Window, pixels: Pixels, gui: Gui) -> Self { - let scene = Scene::empty(); - let window_size = window.inner_size(); - let camera = Camera::unit(); - - Self { - scene, - camera, - window, - buffer_width: window_size.width as u32, - buffer_height: window_size.height as u32, - pixels: Arc::new(Mutex::new(pixels)), - gui, - index: 0, - finished: false, - } - } - - fn update(&mut self) -> Result<(), Box> { - if let Some(event) = self.gui.event.take() { - match event { - GuiEvent::BufferResize(proportion) => self.resize_buffer(proportion)?, - GuiEvent::CameraUpdate(camera) => self.set_camera(camera)?, - GuiEvent::SceneLoad(scene) => { - self.scene = scene; - self.clear()?; - } - } - }; - Ok(()) - } - - fn resize_buffer(&mut self, proportion: f32) -> Result<(), Box> { - let size = self.window.inner_size(); - - self.buffer_width = (size.width as f32 * proportion) as u32; - self.buffer_height = (size.height as f32 * proportion) as u32; - self.camera.set_size(self.buffer_width, self.buffer_height); - - self.clear()?; - - let mut pixels = self.pixels.lock().unwrap(); - pixels.resize_buffer(self.buffer_width, self.buffer_height)?; - Ok(()) - } - - fn resize(&mut self, size: &PhysicalSize) -> Result<(), Box> { - let mut pixels = self.pixels.lock().unwrap(); - pixels.resize_surface(size.width, size.height)?; - Ok(()) - } - - fn keyboard_input(&mut self, key: &KeyboardInput) { - if let Some(VirtualKeyCode::A) = key.virtual_keycode { - // Handle 'A' key event here - } - } - - fn mouse_input(&mut self, _button: &MouseButton) { - // Handle mouse input here - } - - fn draw(&mut self) -> Result<(), Box> { - for _ in 0..self.gui.ray_num { - let i = self.index as usize; - let camera = &self.camera; - let colour = camera.rays[i].shade_ray(&self.scene); - let rgba = colour.map_or(COLOUR_CLEAR, |colour| [colour.x, colour.y, colour.z, 255]); - let mut pixels = self.pixels.lock().unwrap(); - let frame = pixels.frame_mut(); - frame[i * 4..(i + 1) * 4].copy_from_slice(&rgba); - self.index = self.index + 1; - if self.index >= frame.len() / 4 { - self.finished = true; - return Ok(()); - }; - } - Ok(()) - } - - fn clear(&mut self) -> Result<(), Box> { - self.index = 0; - self.finished = false; - let mut pixels = self.pixels.lock().unwrap(); - let frame = pixels.frame_mut(); - for pixel in frame.chunks_exact_mut(4) { - pixel.copy_from_slice(&[0x00, 0x00, 0x00, 0xff]); - } - Ok(()) - } - - fn set_camera(&mut self, camera: Camera) -> Result<(), Box> { - self.clear()?; - self.camera = camera; - self.camera.set_size(self.buffer_width, self.buffer_height); - Ok(()) - } - - fn render(&mut self) -> Result<(), Box> { - self.update()?; //Update state - if !self.finished { - self.draw()?; - }; //Draw to pixels - let pixels = self.pixels.lock().unwrap(); - self.gui - .prepare(&self.window) - .expect("gui.prepare() failed"); //Prepare imgui - if let Err(e) = pixels.render_with(|encoder, render_target, context| { - context.scaling_renderer.render(encoder, render_target); // Render pixels - self.gui - .render(&self.window, encoder, render_target, context)?; - Ok(()) - }) { - log_error("pixels.render", e); - }; - Ok(()) - } -}