boundschecker/
boundschecker.rs

1//! A visual tool to check the functionality of `Bounds::union` and `Bounds::subtract`
2
3use std::io;
4use std::io::stdout;
5use std::time::Instant;
6use teng::components::Component;
7use teng::rendering::pixel::Pixel;
8use teng::rendering::renderer::Renderer;
9use teng::util::planarvec::Bounds;
10use teng::{
11    install_panic_handler, terminal_cleanup, terminal_setup, Game, SharedState, UpdateInfo,
12};
13
14fn main() -> io::Result<()> {
15    terminal_setup()?;
16    install_panic_handler();
17
18    let mut game = Game::new(stdout());
19    game.install_recommended_components();
20    game.add_component(Box::new(BoundsCheckerComponent::new()));
21    game.run()?;
22
23    terminal_cleanup()?;
24
25    Ok(())
26}
27
28pub struct BoundsCheckerComponent {
29    first_loc: Option<(usize, usize)>,
30    second_loc: Option<(usize, usize)>,
31    sub_first_loc: Option<(usize, usize)>,
32    sub_second_loc: Option<(usize, usize)>,
33    union_instead_of_subtract: bool,
34}
35
36impl BoundsCheckerComponent {
37    pub fn new() -> Self {
38        Self {
39            first_loc: None,
40            second_loc: None,
41            sub_first_loc: None,
42            sub_second_loc: None,
43            union_instead_of_subtract: false,
44        }
45    }
46}
47
48impl Component for BoundsCheckerComponent {
49    fn update(&mut self, _update_info: UpdateInfo, shared_state: &mut SharedState) {
50        // was there a mouse down event?
51        let pressed = shared_state.mouse_pressed.left;
52        if pressed {
53            self.first_loc = None;
54            self.second_loc = None;
55
56            self.first_loc = Some(shared_state.mouse_info.last_mouse_pos);
57        }
58
59        // was there a mouse up event?
60        if !shared_state.mouse_info.left_mouse_down
61            && self.first_loc.is_some()
62            && self.second_loc.is_none()
63        {
64            // set the second location
65            self.second_loc = Some(shared_state.mouse_info.last_mouse_pos);
66        }
67
68        // was there a mouse down event for right?
69        let pressed = shared_state.mouse_pressed.right;
70        if pressed {
71            self.sub_first_loc = None;
72            self.sub_second_loc = None;
73
74            self.sub_first_loc = Some(shared_state.mouse_info.last_mouse_pos);
75        }
76
77        // was there a mouse up event for right?
78        if !shared_state.mouse_info.right_mouse_down
79            && self.sub_first_loc.is_some()
80            && self.sub_second_loc.is_none()
81        {
82            // set the second location
83            self.sub_second_loc = Some(shared_state.mouse_info.last_mouse_pos);
84        }
85
86        if shared_state.pressed_keys.did_press_char_ignore_case(' ') {
87            self.union_instead_of_subtract = !self.union_instead_of_subtract;
88        }
89    }
90
91    fn render(&self, renderer: &mut dyn Renderer, shared_state: &SharedState, depth_base: i32) {
92        let depth_base = i32::MAX - 1;
93
94        let mut min_x = 0;
95        let mut max_x = 0;
96        let mut min_y = 0;
97        let mut max_y = 0;
98
99        let mut first_bounds = None;
100
101        if let Some((x, y)) = self.first_loc {
102            let first_pos = (x, y);
103
104            let second_pos = if let Some((x, y)) = self.second_loc {
105                (x, y)
106            } else {
107                // must be still pressing, so just take this for rendering
108                shared_state.mouse_info.last_mouse_pos
109            };
110
111            min_x = first_pos.0.min(second_pos.0);
112            max_x = first_pos.0.max(second_pos.0);
113            min_y = first_pos.1.min(second_pos.1);
114            max_y = first_pos.1.max(second_pos.1);
115
116            let bounds = Bounds {
117                min_x: min_x as i64,
118                max_x: max_x as i64,
119                min_y: min_y as i64,
120                max_y: max_y as i64,
121            };
122
123            first_bounds = Some(bounds);
124        }
125
126        let mut sub_bounds = None;
127
128        if let Some((x, y)) = self.sub_first_loc {
129            let first_pos = (x, y);
130
131            let second_pos = if let Some((x, y)) = self.sub_second_loc {
132                (x, y)
133            } else {
134                // must be still pressing, so just take this for rendering
135                shared_state.mouse_info.last_mouse_pos
136            };
137
138            min_x = first_pos.0.min(second_pos.0);
139            max_x = first_pos.0.max(second_pos.0);
140            min_y = first_pos.1.min(second_pos.1);
141            max_y = first_pos.1.max(second_pos.1);
142
143            let bounds = Bounds {
144                min_x: min_x as i64,
145                max_x: max_x as i64,
146                min_y: min_y as i64,
147                max_y: max_y as i64,
148            };
149
150            sub_bounds = Some(bounds);
151        }
152
153        if self.union_instead_of_subtract {
154            // render the union
155            match (first_bounds, sub_bounds) {
156                (Some(b1), Some(b2)) => {
157                    let bound = b1.union(b2);
158                    for x in bound.min_x..=bound.max_x {
159                        for y in bound.min_y..=bound.max_y {
160                            renderer.render_pixel(
161                                x as usize,
162                                y as usize,
163                                Pixel::new('█'),
164                                depth_base,
165                            );
166                        }
167                    }
168                }
169                _ => {}
170            }
171        } else {
172            // render the difference
173            if let Some(bounds) = first_bounds {
174                let the_bounds = bounds.subtract(sub_bounds.unwrap_or(Bounds::empty()));
175
176                for bound in the_bounds.iter() {
177                    for x in bound.min_x..=bound.max_x {
178                        for y in bound.min_y..=bound.max_y {
179                            renderer.render_pixel(
180                                x as usize,
181                                y as usize,
182                                Pixel::new('█'),
183                                depth_base,
184                            );
185                        }
186                    }
187                }
188            }
189        }
190    }
191}