embedded_graphics_simulator/window/
mod.rs1use std::{
2 env,
3 fs::File,
4 io::BufReader,
5 ops::Deref,
6 process, thread,
7 time::{Duration, Instant},
8};
9
10use embedded_graphics::{pixelcolor::Rgb888, prelude::*};
11
12use crate::{
13 display::SimulatorDisplay, output_image::OutputImage, output_settings::OutputSettings,
14};
15
16#[cfg(feature = "with-sdl")]
17mod sdl_window;
18
19#[cfg(feature = "with-sdl")]
20pub use sdl_window::{SdlWindow, SimulatorEvent};
21
22#[allow(dead_code)]
24pub struct Window {
25 framebuffer: Option<OutputImage<Rgb888>>,
26 #[cfg(feature = "with-sdl")]
27 sdl_window: Option<SdlWindow>,
28 title: String,
29 output_settings: OutputSettings,
30 desired_loop_duration: Duration,
31 frame_start: Instant,
32}
33
34impl Window {
35 pub fn new(title: &str, output_settings: &OutputSettings) -> Self {
37 Self {
38 framebuffer: None,
39 #[cfg(feature = "with-sdl")]
40 sdl_window: None,
41 title: String::from(title),
42 output_settings: output_settings.clone(),
43 desired_loop_duration: Duration::from_millis(1000 / output_settings.max_fps as u64),
44 frame_start: Instant::now(),
45 }
46 }
47
48 pub fn update<C>(&mut self, display: &SimulatorDisplay<C>)
50 where
51 C: PixelColor + Into<Rgb888> + From<Rgb888>,
52 {
53 if let Ok(path) = env::var("EG_SIMULATOR_CHECK") {
54 let output = display.to_rgb_output_image(&self.output_settings);
55
56 let png_file = BufReader::new(File::open(path).unwrap());
57 let expected = image::load(png_file, image::ImageFormat::Png)
58 .unwrap()
59 .to_rgb8();
60
61 let png_size = Size::new(expected.width(), expected.height());
62
63 assert!(
64 output.size().eq(&png_size),
65 "display dimensions don't match PNG dimensions (display: {}x{}, PNG: {}x{})",
66 output.size().width,
67 output.size().height,
68 png_size.width,
69 png_size.height
70 );
71
72 assert!(
73 output
74 .as_image_buffer()
75 .as_raw()
76 .eq(&expected.as_raw().deref()),
77 "display content doesn't match PNG file",
78 );
79
80 process::exit(0);
81 }
82
83 if let Ok(path) = env::var("EG_SIMULATOR_CHECK_RAW") {
84 let expected = SimulatorDisplay::load_png(path).unwrap();
85
86 assert!(
87 display.size().eq(&expected.size()),
88 "display dimensions don't match PNG dimensions (display: {}x{}, PNG: {}x{})",
89 display.size().width,
90 display.size().height,
91 expected.size().width,
92 expected.size().height
93 );
94
95 assert!(
96 display.pixels.eq(&expected.pixels),
97 "display content doesn't match PNG file",
98 );
99
100 process::exit(0);
101 }
102
103 if let Ok(path) = env::var("EG_SIMULATOR_DUMP") {
104 display
105 .to_rgb_output_image(&self.output_settings)
106 .save_png(path)
107 .unwrap();
108 process::exit(0);
109 }
110
111 if let Ok(path) = env::var("EG_SIMULATOR_DUMP_RAW") {
112 display
113 .to_rgb_output_image(&OutputSettings::default())
114 .save_png(path)
115 .unwrap();
116 process::exit(0);
117 }
118
119 #[cfg(feature = "with-sdl")]
120 {
121 if self.framebuffer.is_none() {
122 self.framebuffer = Some(OutputImage::new(display, &self.output_settings));
123 }
124
125 if self.sdl_window.is_none() {
126 self.sdl_window = Some(SdlWindow::new(display, &self.title, &self.output_settings));
127 }
128
129 let framebuffer = self.framebuffer.as_mut().unwrap();
130 let sdl_window = self.sdl_window.as_mut().unwrap();
131
132 framebuffer.update(display);
133 sdl_window.update(framebuffer);
134 }
135
136 thread::sleep(
137 (self.frame_start + self.desired_loop_duration)
138 .saturating_duration_since(Instant::now()),
139 );
140
141 self.frame_start = Instant::now();
142 }
143
144 pub fn show_static<C>(&mut self, display: &SimulatorDisplay<C>)
149 where
150 C: PixelColor + Into<Rgb888> + From<Rgb888>,
151 {
152 self.update(display);
153
154 #[cfg(feature = "with-sdl")]
155 'running: loop {
156 if self.events().any(|e| e == SimulatorEvent::Quit) {
157 break 'running;
158 }
159 thread::sleep(Duration::from_millis(20));
160 }
161 }
162
163 #[cfg(feature = "with-sdl")]
169 pub fn events(&mut self) -> impl Iterator<Item = SimulatorEvent> + '_ {
170 self.sdl_window
171 .as_mut()
172 .unwrap()
173 .events(&self.output_settings)
174 }
175}