graphics_rs/
simple_canvas.rs

1use std::{fs::File, io::Write};
2
3use crate::color;
4use crate::{
5    color::Color,
6    traits::{
7        canvas::Canvas, handles_draw_request::HandlesDrawRequest, is_color::IsColor,
8        requests_draw::RequestDraw, shape::Shape,
9    },
10};
11
12pub struct SimpleCanvas<'a> {
13    buffer: Vec<Color>,
14    width: usize,
15    height: usize,
16    color: Color,
17    antialiasing: bool,
18    antialiasing_resolution: usize,
19    draw_request_handler: Option<&'a dyn HandlesDrawRequest>,
20}
21
22impl<'a> SimpleCanvas<'a> {
23    pub fn new(
24        width: usize,
25        height: usize,
26        fill_color: Option<Color>,
27        antialiasing: bool,
28        antialiasing_resolution: usize,
29    ) -> Self {
30        let antialiasing_resolution = antialiasing_resolution.clamp(1, usize::MAX);
31        let fill_color = fill_color.unwrap_or(color::BLACK);
32
33        Self {
34            buffer: vec![fill_color; width * height],
35            width,
36            height,
37            color: fill_color,
38            antialiasing,
39            draw_request_handler: None,
40            antialiasing_resolution: antialiasing_resolution,
41        }
42    }
43
44    pub fn size(&self) -> usize {
45        self.width * self.height
46    }
47
48    pub fn save(&mut self, path: &str) -> std::io::Result<()> {
49        let mut file = File::create(path)?;
50        File::write(
51            &mut file,
52            format!("P6\n{} {} 255\n", self.width, self.height).as_bytes(),
53        )?;
54
55        for i in 0..self.size() {
56            let pixel = self.color_at(i);
57            let red = pixel.red();
58            let green = pixel.green();
59            let blue = pixel.blue();
60
61            File::write(&mut file, &[red, green, blue])?;
62        }
63
64        Ok(())
65    }
66}
67
68impl<'a> Canvas for SimpleCanvas<'a> {
69    fn draw_shape(&mut self, shape: &mut impl Shape) {
70        shape.draw_to(self);
71    }
72
73    fn change_color(&mut self, color: Color) {
74        self.color = color
75    }
76
77    fn clamp_row(&self, row: i64) -> i64 {
78        row.clamp(0, (self.height - 1) as i64)
79    }
80
81    fn clamp_col(&self, col: i64) -> i64 {
82        col.clamp(0, (self.width - 1) as i64)
83    }
84
85    fn color_at(&self, index: usize) -> Color {
86        return self.buffer[index];
87    }
88
89    fn width(&self) -> usize {
90        self.width
91    }
92
93    fn height(&self) -> usize {
94        self.height
95    }
96
97    fn fits_inside(&self, row: i64, col: i64) -> bool {
98        return row < self.height as i64 && col < self.width as i64;
99    }
100
101    fn fill(&mut self) {
102        for row in 0..self.height {
103            for col in 0..self.width {
104                self.set_pixel_color(row, col, self.color);
105            }
106        }
107    }
108
109    fn antialiasing(&self) -> bool {
110        self.antialiasing
111    }
112
113    fn resolution(&self) -> usize {
114        self.antialiasing_resolution
115    }
116
117    fn color(&self) -> Color {
118        self.color
119    }
120
121    fn set_pixel(&mut self, row: usize, col: usize) {
122        self.set_pixel_color(row, col, self.color);
123    }
124
125    fn set_pixel_color(&mut self, row: usize, col: usize, color: Color) {
126        if self.fits_inside(row as i64, col as i64) {
127            let index = self.width * row + col;
128            let old_color = self.color_at(index);
129
130            self.buffer[index] = old_color.mix(color);
131        }
132    }
133
134    fn buffer_mut_slice(&mut self) -> &mut [Color] {
135        self.buffer.as_mut_slice()
136    }
137}
138
139impl<'a> RequestDraw<'a> for SimpleCanvas<'a> {
140    fn set_draw_request_handler<T: HandlesDrawRequest>(&mut self, handler: &'a T) {
141        self.draw_request_handler = Some(handler)
142    }
143
144    fn request_draw(&self) {
145        if let Some(draw_handler) = self.draw_request_handler {
146            draw_handler.draw();
147        }
148    }
149}