added canvas sizes

This commit is contained in:
Jon Janzen
2021-03-05 17:14:06 -07:00
parent 1fc84c7d1f
commit aa4e01d3f7
2 changed files with 144 additions and 2 deletions

View File

@@ -1,13 +1,13 @@
use color::Color;
struct Canvas {
pub struct Canvas {
width: usize,
height: usize,
pixels: Vec<Vec<Color>>,
}
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::<Vec<&str>>().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::<Vec<&str>>().join("\n");
assert_eq!(line4_7, four_to_seven);
}
}

View File

@@ -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 {