diff --git a/src/graphics.rs b/src/graphics.rs new file mode 100644 index 0000000..1e73363 --- /dev/null +++ b/src/graphics.rs @@ -0,0 +1,121 @@ +use crate::sprite::{Sprite, SpriteAtlas}; + +pub struct GraphicsBuf { + buffer: [u8; 8192], + sprites: [Sprite; 30], + sprite_atlas: SpriteAtlas, +} + +impl GraphicsBuf { + pub fn new() -> Self { + let sprite_atlas = SpriteAtlas::new(include_bytes!("../sprites/sprites_atlas.bin")); + + let mut sprites = [Sprite::new(); 30]; + + sprites[0].sprite_index = 94; + sprites[0].x = 90; + sprites[0].y = 30; + sprites[0].visible = true; + + GraphicsBuf { + buffer: [0u8; 8192], + sprites, + sprite_atlas, + } + } + + pub fn clear(&mut self) { + self.buffer.iter_mut().for_each(|b| *b = 0); + } + + pub fn redraw(&mut self) { + let mut gfx_buf = &mut self.buffer; + + self.sprites.iter_mut().for_each(|s| { + if s.visible { + self.sprite_atlas.draw_sprite( + s.sprite_index, + s.x as u8, + s.y as u8, + s.flip, + &mut gfx_buf, + ); + } + }); + + self.sprite_atlas + .draw_string(10, 10, "Hello World!", &mut gfx_buf); + + self.sprite_atlas.draw_textfield( + 10, + 20, + 110, + 10, + "I think this font has a *lot* of 'character'! ;)", + &mut gfx_buf, + ); + + draw_bresenham_line(0, 0, 127, 0, &mut gfx_buf); + draw_bresenham_line(0, 63, 128, 63, &mut gfx_buf); + draw_bresenham_line(0, 0, 0, 63, &mut gfx_buf); + draw_bresenham_line(127, 0, 127, 63, &mut gfx_buf); + } + + pub fn get_px_buffer(&self) -> &[u8; 8192] { + &self.buffer + } +} + +fn draw_bresenham_line(x0: u8, y0: u8, x1: u8, y1: u8, gfx_buf: &mut [u8; 8192]) { + let x0 = (x0 as i32).clamp(0, 127); + let x1 = (x1 as i32).clamp(0, 127); + let y0 = (y0 as i32).clamp(0, 63); + let y1 = (y1 as i32).clamp(0, 63); + + let mut dx = x1 - x0; + let mut dy = y1 - y0; + + let mut x = x0; + let mut y = y0; + + let mut err = 0; + + let mut step_x = 1; + let mut step_y = 1; + + if dx < 0 { + dx = -dx; + step_x = -1; + } + + if dy < 0 { + dy = -dy; + step_y = -1; + } + + if dx > dy { + for _ in 0..dx { + gfx_buf[(y * 128 + x) as usize] = 1; + + x += step_x; + err += 2 * dy; + + if err > dx { + y += step_y; + err -= 2 * dx; + } + } + } else { + for _ in 0..dy { + gfx_buf[(y * 128 + x) as usize] = 1; + + y += step_y; + err += 2 * dx; + + if err > dy { + x += step_x; + err -= 2 * dy; + } + } + } +} diff --git a/src/main.rs b/src/main.rs index 3745442..c691392 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,18 +5,18 @@ #![no_main] use defmt::println; -use embedded_hal::{digital::OutputPin, i2c::I2c}; +use embedded_hal::digital::OutputPin; use hal::{fugit::RateExtU32, pac}; use rp2040_hal as hal; -use rp2040_hal::i2c::Error; -use defmt as _; +use defmt_rtt as _; use panic_probe as _; +mod graphics; mod sprite; mod ssh1106; -use crate::sprite::*; +use crate::graphics::*; use crate::ssh1106::*; #[link_section = ".boot_loader"] @@ -75,104 +75,14 @@ fn main() -> ! { let ssh1106_dev = SSH1106Dev::new(&mut delay, &mut i2c); println!("SSH1106 initialized."); - let mut gfx_buf = [0u8; 8192]; - - let sprite_atlas = SpriteAtlas::new(include_bytes!("../sprites/sprites_atlas.bin")); - - let mut sprites = [Sprite::new(); 30]; - - sprites[0].sprite_index = 94; - sprites[0].x = 90; - sprites[0].y = 30; - sprites[0].visible = true; + let mut gfx_buf = GraphicsBuf::new(); loop { - gfx_buf.iter_mut().for_each(|x| *x = 0); + gfx_buf.clear(); + gfx_buf.redraw(); - sprites.iter_mut().for_each(|s| { - if s.visible { - sprite_atlas.draw_sprite( - s.sprite_index, - s.x as u8, - s.y as u8, - s.flip, - &mut gfx_buf, - ); - } - }); - - sprite_atlas.draw_string(10, 10, "Hello World!", &mut gfx_buf); - - sprite_atlas.draw_textfield( - 10, - 20, - 110, - 10, - "I think this font has a *lot* of 'character'! ;)", - &mut gfx_buf, - ); - - draw_bresenham_line(0, 0, 127, 0, &mut gfx_buf); - draw_bresenham_line(0, 63, 128, 63, &mut gfx_buf); - draw_bresenham_line(0, 0, 0, 63, &mut gfx_buf); - draw_bresenham_line(127, 0, 127, 63, &mut gfx_buf); ssh1106_dev.blit_framebuffer(&mut i2c, &gfx_buf); - delay.delay_ms(1); - } -} - -// should probably go into some kind of graphics module -fn draw_bresenham_line(x0: u8, y0: u8, x1: u8, y1: u8, gfx_buf: &mut [u8; 8192]) { - let x0 = (x0 as i32).clamp(0, 127); - let x1 = (x1 as i32).clamp(0, 127); - let y0 = (y0 as i32).clamp(0, 63); - let y1 = (y1 as i32).clamp(0, 63); - - let mut dx = x1 - x0; - let mut dy = y1 - y0; - - let mut x = x0; - let mut y = y0; - - let mut err = 0; - - let mut step_x = 1; - let mut step_y = 1; - - if dx < 0 { - dx = -dx; - step_x = -1; - } - - if dy < 0 { - dy = -dy; - step_y = -1; - } - - if dx > dy { - for _ in 0..dx { - gfx_buf[(y * 128 + x) as usize] = 1; - - x += step_x; - err += 2 * dy; - - if err > dx { - y += step_y; - err -= 2 * dx; - } - } - } else { - for _ in 0..dy { - gfx_buf[(y * 128 + x) as usize] = 1; - - y += step_y; - err += 2 * dx; - - if err > dy { - x += step_x; - err -= 2 * dy; - } - } + delay.delay_ms(10); } } diff --git a/src/ssh1106.rs b/src/ssh1106.rs index 0d314c0..ae5edf7 100644 --- a/src/ssh1106.rs +++ b/src/ssh1106.rs @@ -2,6 +2,10 @@ use cortex_m::delay::Delay; use embedded_hal::i2c::I2c; use rp2040_hal::i2c::Error; +use defmt as _; + +use crate::graphics::GraphicsBuf; + #[allow(unused)] #[repr(u8)] #[derive(PartialEq, Copy, Clone)] @@ -37,11 +41,12 @@ impl SSH1106Dev { SSH1106Dev { ready: true } } - pub fn blit_framebuffer(&self, i2c: &mut dyn I2c, graphic: &[u8; 8192]) { + pub fn blit_framebuffer(&self, i2c: &mut dyn I2c, gfx_buf: &GraphicsBuf) { if !self.ready { panic!("Attempted to use SSH1106 before initialized."); } + let buf = gfx_buf.get_px_buffer(); // for each row of 8x8 pixels for r in 0..8 { set_page(i2c, r); @@ -60,7 +65,7 @@ impl SSH1106Dev { for y in 0..8 { let pix_x = (c as usize) * 8 + x; let pix_y = (r as usize) * 8 + y; - col_byte |= graphic[pix_y * 128 + pix_x] << y; + col_byte |= buf[pix_y * 128 + pix_x] << y; } cel[x] = col_byte;