diff --git a/src/lib.rs b/src/lib.rs index 01386db..6d38284 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,7 +176,7 @@ pub mod sdl2 { pub use crate::{ display::SimulatorDisplay, output_image::OutputImage, - output_settings::{OutputSettings, OutputSettingsBuilder}, + output_settings::{OutputSettings, OutputSettingsBuilder, PixelShape}, theme::BinaryColorTheme, window::Window, }; diff --git a/src/output_image.rs b/src/output_image.rs index ee765de..f29b7ee 100644 --- a/src/output_image.rs +++ b/src/output_image.rs @@ -6,12 +6,14 @@ use embedded_graphics::{ prelude::*, primitives::Rectangle, }; +use embedded_graphics::primitives::Circle; use image::{ codecs::png::{CompressionType, FilterType, PngEncoder}, ImageBuffer, ImageEncoder, Luma, Rgb, }; use crate::{display::SimulatorDisplay, output_settings::OutputSettings}; +use crate::output_settings::PixelShape; /// Output image. /// @@ -74,17 +76,32 @@ where let output_color = C::from(themed_color).to_be_bytes(); let output_color = output_color.as_ref(); - for p in Rectangle::new(p * pixel_pitch, pixel_size).points() { - if let Ok((x, y)) = <(u32, u32)>::try_from(p) { - let start_index = (x + y * self.size.width) as usize * output_color.len(); - self.data[start_index..start_index + output_color.len()] - .copy_from_slice(output_color) + match self.output_settings.pixel_shape { + PixelShape::Square => { + for p in Rectangle::new(p * pixel_pitch, pixel_size).points() { + if let Ok((x, y)) = <(u32, u32)>::try_from(p) { + let start_index = (x + y * self.size.width) as usize * output_color.len(); + + self.data[start_index..start_index + output_color.len()] + .copy_from_slice(output_color) + } + } + } + PixelShape::Dot => { + for p in Circle::new(p * pixel_pitch + Point::new(pixel_pitch / 2, pixel_pitch / 2), self.output_settings.scale/ 2).points() { + if let Ok((x, y)) = <(u32, u32)>::try_from(p) { + let start_index = (x + y * self.size.width) as usize * output_color.len(); + + self.data[start_index..start_index + output_color.len()] + .copy_from_slice(output_color) + } + } + } } } } } -} impl OutputImage { /// Saves the image content to a PNG file. diff --git a/src/output_settings.rs b/src/output_settings.rs index cf8381e..3858990 100644 --- a/src/output_settings.rs +++ b/src/output_settings.rs @@ -10,10 +10,23 @@ pub struct OutputSettings { pub pixel_spacing: u32, /// Binary color theme. pub theme: BinaryColorTheme, + /// Pixel shape. + pub pixel_shape: PixelShape, /// Maximum frames per second shown in the window. pub max_fps: u32, } +/// Pixel shape. +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub enum PixelShape { + /// Square pixels + #[default] + Square, + + /// Round pixels + Dot, +} + impl OutputSettings { /// Calculates the size of the framebuffer required to display the scaled display. pub(crate) fn framebuffer_size(&self, display: &SimulatorDisplay) -> Size @@ -54,6 +67,7 @@ pub struct OutputSettingsBuilder { scale: Option, pixel_spacing: Option, theme: BinaryColorTheme, + pixel_shape: Option, max_fps: Option, } @@ -112,6 +126,14 @@ impl OutputSettingsBuilder { self } + + /// Sets the pixel shape. + pub fn pixel_shape(mut self, pixel_shape: PixelShape) -> Self { + self.pixel_shape = Some(pixel_shape); + + self + } + /// Sets the FPS limit of the window. pub fn max_fps(mut self, max_fps: u32) -> Self { self.max_fps = Some(max_fps); @@ -125,6 +147,7 @@ impl OutputSettingsBuilder { scale: self.scale.unwrap_or(1), pixel_spacing: self.pixel_spacing.unwrap_or(0), theme: self.theme, + pixel_shape: self.pixel_shape.unwrap_or(PixelShape::Square), max_fps: self.max_fps.unwrap_or(60), } } diff --git a/src/theme.rs b/src/theme.rs index fdd8a22..1e22a4d 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -24,8 +24,12 @@ pub enum BinaryColorTheme { /// An on/off OLED-like display with a dark blue background and light blue pixels OledBlue, + + /// An on/off OLED-like display with a black background and orange pixels + OledOrange, } + fn map_color(color: Rgb888, color_off: Rgb888, color_on: Rgb888) -> Rgb888 { match color { Rgb888::BLACK => color_off, @@ -54,6 +58,9 @@ impl BinaryColorTheme { map_color(color, Rgb888::new(0, 20, 40), Rgb888::new(0, 210, 255)) } BinaryColorTheme::OledWhite => map_color(color, Rgb888::new(20, 20, 20), Rgb888::WHITE), + BinaryColorTheme::OledOrange => { + map_color(color, Rgb888::new(0, 0, 0), Rgb888::new(255, 100, 0)) + } } } }