diff --git a/src/main.rs b/src/main.rs index 5d5e534..d396cc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ use crate::camera::Camera; use crate::hittable::{Hittable, Sphere}; +use crate::output::{Output, P3}; use crate::ray::Ray; use crate::vec3::{Color, Point3, Vec3}; use rand::distributions::{Distribution, Uniform}; @@ -10,6 +11,7 @@ mod ray; mod hittable; mod material; mod camera; +mod output; fn random_scene() -> Vec> { let mut world:Vec> = Vec::new(); @@ -52,15 +54,35 @@ fn random_scene() -> Vec> { world.push(sphere); } } + + let material1 = Material::Dielectric(Dielectric::new(1.5)); + world.push(Box::new(Sphere { + center: Point3::new(0.0, 1.0, 0.0), + radius: 1.0, + material: material1 + })); + let material2 = Material::Lambertian(Lambertian::new(Color::new(0.4, 0.2, 0.1))); + world.push(Box::new(Sphere { + center: Point3::new(-4.0, 1.0, 0.0), + radius: 1.0, + material: material2 + })); + let material3 = Material::Metal(Metal::new(Color::new(0.7, 0.6, 0.5), 0.0)); + world.push(Box::new(Sphere { + center: Point3::new(4.0, 1.0, 0.0), + radius: 1.0, + material: material3 + })); + world } fn main() { // Image const ASPECT_RATIO: f64 = 3.0 / 2.0; - const IMAGE_WIDTH: i32 = 1200; - const IMAGE_HEIGHT: i32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as i32; - const SAMPLES_PER_PIXEL: i32 = 10; + const IMAGE_WIDTH: usize = 1200; + const IMAGE_HEIGHT: usize = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as usize; + const SAMPLES_PER_PIXEL: i32 = 100; const MAX_DEPTH: i32 = 50; let look_from = Point3::new(13.0, 2.0, 3.0); @@ -79,26 +101,27 @@ fn main() { // World let world= random_scene(); - println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT); + //println!("P3\n{} {}\n255", IMAGE_WIDTH, IMAGE_HEIGHT); let between = Uniform::from(0.0..1.0); + let mut pixels = Vec::::new(); let mut rng = rand::thread_rng(); for j in (0..IMAGE_HEIGHT).rev() { eprint!("\rScanlines remaining: {} ", j); for i in 0..IMAGE_WIDTH { let mut color = Color::default(); - for s in 0..SAMPLES_PER_PIXEL { + (0..SAMPLES_PER_PIXEL).for_each(|_s| { let random_number = between.sample(&mut rng); let u = (i as f64 + random_number) / (IMAGE_WIDTH - 1) as f64; let v = (j as f64 + random_number) / (IMAGE_HEIGHT - 1) as f64; let ray = cam.get_ray(u, v); - if i == 200 && (j == 112 || j == 113) { - let tt = 0; - } color += ray.pixel_color(&world, MAX_DEPTH); - } - color.write_color(SAMPLES_PER_PIXEL); + }); + pixels.append(&mut color.into_bytes(SAMPLES_PER_PIXEL)); + + //color.write_color(SAMPLES_PER_PIXEL); } } + P3::write("i.ppm", &pixels, IMAGE_WIDTH, IMAGE_HEIGHT).expect("Error writing image: {}"); eprintln!("\nDone"); } diff --git a/src/output.rs b/src/output.rs new file mode 100644 index 0000000..dee1f6c --- /dev/null +++ b/src/output.rs @@ -0,0 +1,19 @@ +use std::{fs::File, io::{Error, Write}}; + +pub trait Output { + fn write(filename: &str, pixels: &Vec, width: usize, height: usize) -> Result; +} + +pub struct P3 {} +impl Output for P3 { + fn write(filename: &str, pixels: &Vec, width: usize, height: usize) -> Result { + let mut file = File::create(filename)?; + file.write(format!("P3\n{} {}\n255\n", width, height).as_bytes())?; + let lines: Result, Error> = pixels + .chunks(3) + .map(|chunk| format!("{} {} {}\n", chunk[0], chunk[1], chunk[2])) + .map(|line| file.write(line.as_bytes())) + .collect(); + lines.map(|_v| file) + } +} \ No newline at end of file diff --git a/src/vec3.rs b/src/vec3.rs index 3788ba6..9e1c96b 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -105,12 +105,12 @@ fn test_refract() { let n = Point3::new(-1.0, 0.0, 0.0); let etai_over_etat = 1.0; let expected = Point3::new(0.0, 1.0, 0.0); - let actual = uv.refract_orig( &n, etai_over_etat); + let actual = uv.refract( &n, etai_over_etat); assert_eq!(actual, expected); } impl Color { - pub fn write_color(self: Color, samples_per_pixel: i32) { + fn tone_map(self: &Color, samples_per_pixel: i32) -> (f64, f64, f64) { let scale = 1.0 / samples_per_pixel as f64; let r = f64::sqrt(scale * self.x); let g = f64::sqrt(scale * self.y); @@ -118,8 +118,16 @@ impl Color { let r = 256.0 * f64::clamp(r, 0.0, 0.999); let g = 256.0 * f64::clamp(g, 0.0, 0.999); let b = 256.0 * f64::clamp(b, 0.0, 0.999); + (r, g, b) + } + pub fn write_color(self: &Color, samples_per_pixel: i32) { + let (r, g, b) = self.tone_map(samples_per_pixel); println!("{} {} {}", r as i32, g as i32, b as i32); } + pub fn into_bytes(self: &Color, samples_per_pixel: i32) -> Vec { + let (r, g, b) = self.tone_map(samples_per_pixel); + vec![r as u8, g as u8, b as u8] + } } impl Default for Vec3 {