From c0fc3926e06acddcc02ef086fbda688d4709e5ba Mon Sep 17 00:00:00 2001 From: lamp Date: Sun, 21 Jan 2024 13:44:51 +0000 Subject: refactor display backends, add pixelflut backend --- src/display/image.rs | 68 ++++++++++++++++++++++++++++++++++++++++++ src/display/mod.rs | 17 +++++++++++ src/display/pixel.rs | 14 +++++++++ src/display/pixelflut.rs | 69 +++++++++++++++++++++++++++++++++++++++++++ src/image.rs | 77 ------------------------------------------------ src/main.rs | 14 +++++---- 6 files changed, 177 insertions(+), 82 deletions(-) create mode 100644 src/display/image.rs create mode 100644 src/display/mod.rs create mode 100644 src/display/pixel.rs create mode 100644 src/display/pixelflut.rs delete mode 100644 src/image.rs (limited to 'src') diff --git a/src/display/image.rs b/src/display/image.rs new file mode 100644 index 0000000..77d8c83 --- /dev/null +++ b/src/display/image.rs @@ -0,0 +1,68 @@ +use std::io::Write; + +use crate::vec3::Color; +use crate::display::{Display, Pixel}; + +pub struct Image { + width: usize, + height: usize, + data: Vec, +} + +impl Image { + pub fn new(width: usize, height: usize) -> Image { + let data = vec![ + Pixel { + color: Color { + x: 0.0, + y: 0.0, + z: 0.0 + }, + sample_count: 0 + }; + width * height + ]; + Image { + width, + height, + data, + } + } +} + +impl Display for Image { + fn add_sample(&mut self, x: usize, y: usize, color: Color) { + self.data + .get_mut((y * self.width) + x) + .unwrap() + .update(color); + } + + fn maybe_write(&self, output: &mut impl Write) { + output.write_fmt(format_args!("P3\n{} {}\n255\n", self.width, self.height)).unwrap(); + for y in (0..self.height).rev() { + for x in 0..self.width { + let pixel = self.data.get((y * self.width) + x).unwrap(); + let mut r = pixel.color.x; + let mut g = pixel.color.y; + let mut b = pixel.color.z; + + // Divide by the number of samples and perform gamma correction for gamma 2 + let scale = 1.0 / pixel.sample_count as f64; + r = (r * scale).sqrt(); + g = (g * scale).sqrt(); + b = (b * scale).sqrt(); + + output + .write_fmt(format_args!( + "{} {} {}\n", + (256.0 * r.clamp(0.0, 0.999)) as u32, + (256.0 * g.clamp(0.0, 0.999)) as u32, + (256.0 * b.clamp(0.0, 0.999)) as u32, + )) + .unwrap(); + } + } + } + fn maybe_update(&mut self) {} +} diff --git a/src/display/mod.rs b/src/display/mod.rs new file mode 100644 index 0000000..0a18e48 --- /dev/null +++ b/src/display/mod.rs @@ -0,0 +1,17 @@ +mod image; +pub use image::Image; +mod pixelflut; +pub use pixelflut::Pixelflut; + +mod pixel; +use pixel::Pixel; + +use std::io::Write; + +use crate::vec3::Color; + +pub trait Display { + fn add_sample(&mut self, x: usize, y: usize, color: Color); + fn maybe_write(&self, output: &mut impl Write); + fn maybe_update(&mut self); +} diff --git a/src/display/pixel.rs b/src/display/pixel.rs new file mode 100644 index 0000000..c9113d9 --- /dev/null +++ b/src/display/pixel.rs @@ -0,0 +1,14 @@ +use crate::vec3::Color; + +#[derive(Clone)] +pub struct Pixel { + pub color: Color, + pub sample_count: u32, +} + +impl Pixel { + pub fn update(&mut self, color: Color) { + self.color += color; + self.sample_count += 1; + } +} diff --git a/src/display/pixelflut.rs b/src/display/pixelflut.rs new file mode 100644 index 0000000..3a62f8d --- /dev/null +++ b/src/display/pixelflut.rs @@ -0,0 +1,69 @@ +use std::io::Write; +use std::net::{TcpStream}; + +use crate::vec3::Color; +use crate::display::{Display, Pixel}; + +pub struct Pixelflut { + socket: TcpStream, + x: usize, + y: usize, + width: usize, + height: usize, + data: Vec, +} + +impl Pixelflut { + pub fn new(addr: &str, x: usize, y: usize, width: usize, height: usize) -> Self { + let data = vec![ + Pixel { + color: Color { + x: 0.0, + y: 0.0, + z: 0.0 + }, + sample_count: 0 + }; + width * height + ]; + let mut ret = Self { + socket: TcpStream::connect(addr).expect("Could not connect to Pixelflut!"), + x, + y, + width, + height, + data, + }; + ret.maybe_update(); + ret + } +} + +impl Display for Pixelflut { + fn add_sample(&mut self, x: usize, y: usize, color: crate::vec3::Color) { + self.data + .get_mut((y * self.width) + x) + .unwrap() + .update(color); + } + + fn maybe_write(&self, _: &mut impl std::io::prelude::Write) {} + + fn maybe_update(&mut self) { + for y in 0..self.height { + for x in 0..self.width { + let pixel = self.data.get((y * self.width) + x).unwrap(); + let scale = 1.0 / pixel.sample_count as f64; + let mut r = (pixel.color.x * scale).sqrt(); + let mut g = (pixel.color.y * scale).sqrt(); + let mut b = (pixel.color.z * scale).sqrt(); + self.socket.write(format!("PX {} {} {:02x}{:02x}{:02x}\n", + self.x + x, + self.y + self.height - y, + (256.0 * r.clamp(0.0, 0.999)) as u32, + (256.0 * g.clamp(0.0, 0.999)) as u32, + (256.0 * b.clamp(0.0, 0.999)) as u32).as_bytes()); + } + } + } +} diff --git a/src/image.rs b/src/image.rs deleted file mode 100644 index e24c14b..0000000 --- a/src/image.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::io::Write; - -use crate::vec3::Color; - -pub struct Image { - width: usize, - height: usize, - data: Vec, -} - -#[derive(Clone)] -struct Pixel { - color: Color, - sample_count: u32, -} - -impl Image { - pub fn new(width: usize, height: usize) -> Image { - let data = vec![ - Pixel { - color: Color { - x: 0.0, - y: 0.0, - z: 0.0 - }, - sample_count: 0 - }; - width * height - ]; - Image { - width, - height, - data, - } - } - - pub fn add_sample(&mut self, x: usize, y: usize, color: Color) { - self.data - .get_mut((y * self.width) + x) - .unwrap() - .update(color); - } - - pub fn write(&self, output: &mut impl Write) { - output.write_fmt(format_args!("P3\n{} {}\n255\n", self.width, self.height)).unwrap(); - for y in (0..self.height).rev() { - for x in 0..self.width { - let pixel = self.data.get((y * self.width) + x).unwrap(); - let mut r = pixel.color.x; - let mut g = pixel.color.y; - let mut b = pixel.color.z; - - // Divide by the number of samples and perform gamma correction for gamma 2 - let scale = 1.0 / pixel.sample_count as f64; - r = (r * scale).sqrt(); - g = (g * scale).sqrt(); - b = (b * scale).sqrt(); - - output - .write_fmt(format_args!( - "{} {} {}\n", - (256.0 * r.clamp(0.0, 0.999)) as u32, - (256.0 * g.clamp(0.0, 0.999)) as u32, - (256.0 * b.clamp(0.0, 0.999)) as u32, - )) - .unwrap(); - } - } - } -} - -impl Pixel { - pub fn update(&mut self, color: Color) { - self.color += color; - self.sample_count += 1; - } -} diff --git a/src/main.rs b/src/main.rs index 7ec82e6..c99ca58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ mod material; mod ray; mod util; mod vec3; -mod image; +mod display; mod texture; mod scenes; @@ -12,7 +12,7 @@ use std::{sync::{Arc, mpsc}, thread}; use camera::Camera; use hittable::Hittable; -use image::Image; +use display::{Display, Image, Pixelflut}; use ray::Ray; use vec3::{Vec3, Color}; use scenes::get_scene; @@ -70,7 +70,7 @@ fn main() { //const ASPECT_RATIO: f64 = 1.0; const IMAGE_WIDTH: u32 = 600; const IMAGE_HEIGHT: u32 = (IMAGE_WIDTH as f64 / ASPECT_RATIO) as u32; - const SAMPLES_PER_PIXEL: u32 = 30; + const SAMPLES_PER_PIXEL: u32 = 500; const MAX_DEPTH: u32 = 50; const THREAD_COUNT: u32 = 8; const TIME_START: f64 = 0.0; @@ -83,7 +83,8 @@ fn main() { let dist_to_focus = 10.0; let cam = Arc::new(Camera::new(lookfrom, lookat, vup, vfov, ASPECT_RATIO, aperture, dist_to_focus, TIME_START, TIME_END)); // Render - let mut final_image = Image::new(IMAGE_WIDTH as usize, IMAGE_HEIGHT as usize); + // let mut final_image = Image::new(IMAGE_WIDTH as usize, IMAGE_HEIGHT as usize); + let mut final_image = Pixelflut::new("192.168.0.38:1337", 0, 0, IMAGE_WIDTH as usize, IMAGE_HEIGHT as usize); let (tx, rx) = mpsc::channel::(); for _ in 0..THREAD_COUNT { let sender = tx.clone(); @@ -96,12 +97,14 @@ fn main() { } let expected_updates: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_HEIGHT as u64 * IMAGE_WIDTH as u64; let print_frequency: u64 = (SAMPLES_PER_PIXEL / THREAD_COUNT) as u64 * THREAD_COUNT as u64 * IMAGE_WIDTH as u64; + let print_frequency = print_frequency * 3; let mut update_count: u64 = 0; loop { if let Ok(update) = rx.try_recv() { update_count += 1; final_image.add_sample(update.x, update.y, update.color); if update_count % print_frequency == 0 { + final_image.maybe_update(); eprint!("\rCurrent completion: {:.2}%", (update_count as f64 / expected_updates as f64) * 100.0) } } else { @@ -110,6 +113,7 @@ fn main() { } } } - final_image.write(&mut std::io::stdout()); + final_image.maybe_update(); + final_image.maybe_write(&mut std::io::stdout()); eprintln!("\nDone."); } -- cgit v1.2.3