From aa4e01d3f7dfa1e8820f06b59a4065b435080c59 Mon Sep 17 00:00:00 2001 From: Jon Janzen Date: Fri, 5 Mar 2021 17:14:06 -0700 Subject: [PATCH] added canvas sizes --- canvas/src/lib.rs | 125 +++++++++++++++++++++++++++++++++++++++++++++- color/src/lib.rs | 21 ++++++++ 2 files changed, 144 insertions(+), 2 deletions(-) diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index e3d6ed5..eaa1403 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -1,13 +1,13 @@ use color::Color; -struct Canvas { +pub struct Canvas { width: usize, height: usize, pixels: Vec>, } impl Canvas { - fn new(width: usize, height: usize) -> Canvas { + pub fn new(width: usize, height: usize) -> Canvas { Canvas { width, height, @@ -16,6 +16,58 @@ impl Canvas { } } +impl Canvas { + pub fn write_pixel(&mut self, x: usize, y: usize, color: Color) { + self.pixels[y][x] = color; + } + + pub fn pixel(&self, x: usize, y: usize) -> Color { + self.pixels[y][x] + } + + fn header(&self) -> String { + let mut ppm = String::new(); + ppm.push_str("P3\n"); + ppm.push_str(self.width.to_string().as_str()); + ppm.push(' '); + ppm.push_str(self.height.to_string().as_str()); + ppm.push('\n'); + ppm.push_str("255"); + ppm.push('\n'); + ppm + } + + pub fn to_ppm(&self) -> String { + let mut ppm = self.header(); + for row in &self.pixels { + let mut ppm_row = String::new(); + for pixel in row { + let pixel_str = pixel.ppm_str(); + if pixel_str.len() + ppm_row.len() > 70 { + let components: Vec<&str> = pixel_str.split(" ").collect(); + for component in components { + if ppm_row.len() + component.len() > 70 { + ppm_row.pop(); + ppm.push_str(&ppm_row); + ppm.push_str("\n"); + ppm_row = String::new(); + } + ppm_row.push_str(component); + ppm_row.push_str(" "); + } + } else { + ppm_row.push_str(&pixel_str); + ppm_row.push_str(" "); + } + } + ppm_row.pop(); + ppm.push_str(&ppm_row); + ppm.push('\n'); + } + ppm + } +} + #[cfg(test)] mod tests { use super::*; @@ -33,4 +85,73 @@ mod tests { } } } + + #[test] + fn write_pixels_to_canvas() { + let mut c = Canvas::new(10, 20); + let red = Color::new(1.0, 0.0, 0.0); + c.write_pixel(2, 3, red); + assert_eq!(red, c.pixel(2, 3)); + } + + #[test] + fn constructing_ppm_header() { + let c = Canvas::new(5, 3); + let ppm = c.to_ppm(); + + let expected = "P3 +5 3 +255"; + + let header = ppm.split("\n").take(3).collect::>().join("\n"); + + assert_eq!(expected, header); + } + + #[test] + fn constructing_the_ppm_pixel_data() { + let mut c = Canvas::new(5, 3); + let c1 = Color::new(1.5, 0.0, 0.0); + let c2 = Color::new(0.0, 0.5, 0.0); + let c3 = Color::new(-0.5, 0.0, 1.0); + + c.write_pixel(0, 0, c1); + c.write_pixel(2, 1, c2); + c.write_pixel(4, 2, c3); + + let ppm = c.to_ppm(); + + + let line_4 = "255 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; + let line_5 = "0 0 0 0 0 0 0 127 0 0 0 0 0 0 0"; + let line_6 = "0 0 0 0 0 0 0 0 0 0 0 0 0 0 255"; + + let v : Vec<&str> = ppm.split("\n").collect(); + + print!("{}", ppm); + + assert_eq!(line_4, *v.get(3).expect("must exist")); + assert_eq!(line_5, *v.get(4).expect("must exist")); + assert_eq!(line_6, *v.get(5).expect("must exist")); + } + + #[test] + fn test_split_long_lines() { + let mut c = Canvas::new(10, 2); + for row in &mut c.pixels { + for pix in row { + *pix = Color::new(1.0, 0.8, 0.6); + } + } + + let line4_7 = r#"255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204 +153 255 204 153 255 204 153 255 204 153 255 204 153 +255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204 +153 255 204 153 255 204 153 255 204 153 255 204 153 +"#; + + let ppm = c.to_ppm(); + let four_to_seven = ppm.split("\n").skip(3).collect::>().join("\n"); + assert_eq!(line4_7, four_to_seven); + } } diff --git a/color/src/lib.rs b/color/src/lib.rs index 0ccb87d..9944061 100644 --- a/color/src/lib.rs +++ b/color/src/lib.rs @@ -18,6 +18,27 @@ impl Color { blue, } } + + pub fn red(&self) -> f32 { + self.red + } + + pub fn green(&self) -> f32 { + self.green + } + + pub fn blue(&self) -> f32 { + self.blue + } + + pub fn ppm_str(&self) -> String { + // need to scale 0 - 1 -> 0 - 255 + let r = (self.red * 255.0) as u8; + let g = (self.green * 255.0) as u8; + let b = (self.blue * 255.0) as u8; + + format!("{} {} {}", r, g, b) + } } impl PartialEq for Color {