Refactor: improve naming & types
* renamed display traits to Draw* * renamed Send to SendBits to differentiate from the standard trait * introduced the Paint trait * changed type of coordinate to u8 instead of usize * use generic constant when performing moodulo operation based on screen size
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
mod thumbv6m;
|
||||
|
||||
pub trait Sender {
|
||||
fn send(&self, value: u32);
|
||||
pub trait SendBits {
|
||||
fn send_bits(&self, value: u32);
|
||||
}
|
||||
|
||||
pub use thumbv6m::Msb2LsbSender;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::Sender;
|
||||
use super::SendBits;
|
||||
use core::arch::asm;
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -52,7 +52,7 @@ impl<
|
||||
const T0B: u32,
|
||||
const T1A: u32,
|
||||
const T1B: u32,
|
||||
> Sender
|
||||
> SendBits
|
||||
for Msb2LsbSender<
|
||||
BITS,
|
||||
SHIFT,
|
||||
@@ -72,7 +72,7 @@ impl<
|
||||
// T0A, T0B, T1A, T1B are the number of cycles to wait after writing to A START, and B STOP address.
|
||||
// At a minimum there is always a 3cycle-delay, and due to rounding there might be a +/- 1 cycle
|
||||
// difference for non-multiple of 3.
|
||||
fn send(&self, value: u32) {
|
||||
fn send_bits(&self, value: u32) {
|
||||
unsafe {
|
||||
let mut primask: u32;
|
||||
asm!(
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
pub trait DisplayRectangles<Position, Color> {
|
||||
fn fill_rectangle(&mut self, a: Position, b: Position, color: Color);
|
||||
pub trait DrawRectangles<Position, Color> {
|
||||
fn draw_filled_rectangle(&mut self, a: Position, b: Position, color: Color);
|
||||
|
||||
fn rectangle(&mut self, bottom_left: Position, upper_right: Position, color: Color);
|
||||
fn draw_rectangle(&mut self, bottom_left: Position, upper_right: Position, color: Color);
|
||||
}
|
||||
|
||||
pub trait DisplayCircles<Position, Color> {
|
||||
fn fill_circle(&mut self, origin: Position, radius: usize, color: Color);
|
||||
pub trait DrawCircles<Position, Color> {
|
||||
fn draw_filled_circle(&mut self, origin: Position, radius: usize, color: Color);
|
||||
|
||||
fn circle(&mut self, origin: Position, radius: usize, color: Color);
|
||||
fn draw_circle(&mut self, origin: Position, radius: usize, color: Color);
|
||||
}
|
||||
|
||||
pub type Sprite<Color, const X: usize, const Y: usize> = [[Color; X]; Y];
|
||||
|
||||
pub trait DisplaySprites<Position, Color> {
|
||||
fn copy<const SPRITE_X: usize, const SPRITE_Y: usize>(
|
||||
pub trait DrawSprites<Position, Color> {
|
||||
fn draw_sprite<const SPRITE_X: usize, const SPRITE_Y: usize>(
|
||||
&mut self,
|
||||
origin: Position,
|
||||
data: &Sprite<Color, SPRITE_X, SPRITE_Y>,
|
||||
|
||||
@@ -2,12 +2,12 @@ mod draw;
|
||||
|
||||
pub use draw::*;
|
||||
|
||||
pub trait Screen<Position, Color> {
|
||||
pub trait Display<Position, Color> {
|
||||
fn show(&self);
|
||||
|
||||
fn clear(&mut self);
|
||||
|
||||
fn fill(&mut self, color: Color);
|
||||
|
||||
fn point(&mut self, position: Position, color: Color);
|
||||
fn draw_dot(&mut self, position: Position, color: Color);
|
||||
}
|
||||
|
||||
123
src/lib.rs
123
src/lib.rs
@@ -5,14 +5,14 @@ pub mod bit_string;
|
||||
pub mod led_display;
|
||||
pub mod neo_pixel;
|
||||
|
||||
use crate::led_display::{DisplaySprites, Screen, Sprite};
|
||||
use crate::neo_pixel::{Color, CompositeNeoPixelDisplay, DisplayCircles, DisplayRectangles};
|
||||
use crate::led_display::{Display, DrawSprites, Sprite};
|
||||
use crate::neo_pixel::{Color, DrawCircles, DrawRectangles, NeoPixelScreen};
|
||||
use cortex_m::asm::delay;
|
||||
use rand::rngs::SmallRng;
|
||||
use rand::{RngCore, SeedableRng};
|
||||
|
||||
mod hardware {
|
||||
use super::neo_pixel::{CompositeNeoPixelDisplay, NeoPixelSender};
|
||||
use super::neo_pixel::{NeoPixelScreen, NeoPixelSender};
|
||||
use cortex_m::asm::delay;
|
||||
use microbit::hal::gpio::Level::Low;
|
||||
use microbit::Board;
|
||||
@@ -21,13 +21,12 @@ mod hardware {
|
||||
const T0H_NS: u32 = 250; // 350+/-150 [ns]
|
||||
const T1H_NS: u32 = 900; // 700+/-150 [ns]
|
||||
|
||||
// Latch reset delay
|
||||
const TLL_NS: u32 = 250_000; // 6_000 [ns] min, newer pixels require ~250_000 [ns]
|
||||
|
||||
const T0L_NS: u32 = 900; // 800+/-150 [ns]
|
||||
const T1L_NS: u32 = 600; // 600+/-150 [ns]
|
||||
|
||||
// Rounded down, from 20.8333
|
||||
// Latch reset delay
|
||||
const TLL_NS: u32 = 250_000; // 6_000 [ns] min, newer pixels require ~250_000 [ns]
|
||||
|
||||
pub const NS_PER_CYCLE: u32 = 114; // empirically measured to be about 114ns
|
||||
|
||||
const T0H: u32 = T0H_NS / NS_PER_CYCLE;
|
||||
@@ -41,7 +40,7 @@ mod hardware {
|
||||
const EDGE_PAD0_SET_ADDRESS: u32 = 0x5000_0508; // Address of the SET register
|
||||
const EDGE_PAD0_CLEAR_ADDRESS: u32 = 0x5000_050c; // Address of the toggle register
|
||||
|
||||
pub fn setup() -> CompositeNeoPixelDisplay<
|
||||
pub fn setup() -> NeoPixelScreen<
|
||||
NeoPixelSender<
|
||||
EDGE_PAD0_MASK,
|
||||
EDGE_PAD0_SET_ADDRESS,
|
||||
@@ -71,26 +70,47 @@ mod hardware {
|
||||
T1L,
|
||||
>::new();
|
||||
|
||||
CompositeNeoPixelDisplay::<_, TLL, 8, 8, 4 /*NX*/, 1 /*NY*/>::new(sender)
|
||||
NeoPixelScreen::<_, TLL, 8, 8, 4 /*NX*/, 1 /*NY*/>::new(sender)
|
||||
}
|
||||
}
|
||||
|
||||
// const BLANK: Option<Color> = None;
|
||||
trait Paint {
|
||||
fn dx(frame: i32, fps: i32, speed: i32) -> i32;
|
||||
|
||||
fn dy(frame: i32, fps: i32, speed: i32) -> i32;
|
||||
|
||||
fn paint_with_color<const SPRITE_X: usize, const SPRITE_Y: usize>(
|
||||
&mut self,
|
||||
x0: usize,
|
||||
y0: usize,
|
||||
sprite: &[[bool; SPRITE_Y]; SPRITE_X],
|
||||
color: u32,
|
||||
);
|
||||
|
||||
fn paint_list<const S: usize, const ELEM_X: usize, const ELEM_Y: usize>(
|
||||
&mut self,
|
||||
list: &[Option<(u8, u8, Color)>; S],
|
||||
dx: u8,
|
||||
dy: u8,
|
||||
tree: &[[bool; ELEM_X]; ELEM_Y],
|
||||
);
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: neo_pixel::Sender,
|
||||
Sender: neo_pixel::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> CompositeNeoPixelDisplay<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
> Paint for NeoPixelScreen<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
fn dx(frame: i32, fps: i32, speed: i32) -> i32 {
|
||||
((speed * frame / fps) / 512) % 32
|
||||
((speed * frame / fps) / 512) % { (X * NX) as i32 }
|
||||
}
|
||||
|
||||
fn dy(frame: i32, fps: i32, speed: i32) -> i32 {
|
||||
((speed * frame / fps) / 512) % 8
|
||||
((speed * frame / fps) / 512) % { (Y * NY) as i32 }
|
||||
}
|
||||
|
||||
fn paint_with_color<const SPRITE_X: usize, const SPRITE_Y: usize>(
|
||||
@@ -103,7 +123,10 @@ impl<
|
||||
for (x, line) in sprite.iter().enumerate() {
|
||||
for (y, paint) in line.iter().enumerate() {
|
||||
if *paint {
|
||||
self.point(self.position((x0 + x) % 32, (y0 + y) % 8), color);
|
||||
self.draw_dot(
|
||||
self.position(((x0 + x) % { X * NX }) as u8, ((y0 + y) % Y) as u8),
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,7 +143,17 @@ impl<
|
||||
self.paint_with_color((*x0 + dx) as usize, (*y0 + dy) as usize, tree, *color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: neo_pixel::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> NeoPixelScreen<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
fn stars_far(&mut self, frame: i32, fps: i32, rng: &mut SmallRng) {
|
||||
// We repeat the same 2-screen pseudo-random pattern. We have an area of (3 * 8 * 2 =) 48
|
||||
// pixels we want to cover with some stars. so we arbitrarily decided 6 stars was enough.
|
||||
@@ -149,24 +182,21 @@ impl<
|
||||
STAR_COLOR[i + NB_STARS] = COLORS[(rng.next_u32() % 10) as usize];
|
||||
}
|
||||
// Screens 1 & 2
|
||||
self.point(self.position(*x as usize, *y as usize), STAR_COLOR[i]);
|
||||
self.draw_dot(self.position(*x, *y), STAR_COLOR[i]);
|
||||
|
||||
// Screens 3 & 4
|
||||
self.point(
|
||||
self.position((*x + 16) as usize, *y as usize),
|
||||
STAR_COLOR[i + NB_STARS],
|
||||
);
|
||||
self.draw_dot(self.position(*x + 16, *y), STAR_COLOR[i + NB_STARS]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn moon(&mut self, frame: i32, fps: i32) {
|
||||
const COLOR: Option<u32> = Some(0x1b1a1a);
|
||||
let x = Self::dx(frame, fps, 256);
|
||||
let dy = Self::dy(frame, fps, 128);
|
||||
let x = Self::dx(frame, fps, 256) as u8;
|
||||
let dy = Self::dy(frame, fps, 128) as u8;
|
||||
let y = if dy < 4 { dy + 2 } else { 11 - dy };
|
||||
let origin = self.position(x as usize, y as usize);
|
||||
self.fill_circle(origin, 2, COLOR);
|
||||
let origin = self.position(x, y);
|
||||
self.draw_filled_circle(origin, 2, COLOR);
|
||||
}
|
||||
|
||||
fn stars_close(&mut self, frame: i32, fps: i32) {
|
||||
@@ -191,14 +221,14 @@ impl<
|
||||
];
|
||||
|
||||
for (i, (x, y)) in STAR_POSITIONS.iter().enumerate() {
|
||||
let x = ((*x as i32 + Self::dx(frame, fps, 64)) % 32) as usize;
|
||||
let x = ((*x as i32 + Self::dx(frame, fps, 64)) % { (X * NX) as i32 }) as usize;
|
||||
let y = *y as usize;
|
||||
self.paint_with_color(x, y, &STAR, COLORS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fn snow(&mut self) {
|
||||
self.fill_rectangle(self.position(0, 0), self.position(31, 2), Some(0x0a0a0a));
|
||||
self.draw_filled_rectangle(self.position(0, 0), self.position(31, 2), Some(0x0a0a0a));
|
||||
}
|
||||
|
||||
fn trees(&mut self, frame: i32, fps: i32) {
|
||||
@@ -244,13 +274,16 @@ impl<
|
||||
}
|
||||
|
||||
fn houses(&mut self, frame: i32, fps: i32) {
|
||||
let max_x: i32 = { (X * NX) as i32 };
|
||||
|
||||
const BLANK_: Option<Color> = None;
|
||||
const RED___: Option<Color> = Some(0x003300);
|
||||
const BLUE__: Option<Color> = Some(0x000033);
|
||||
const PURPLE: Option<Color> = Some(0x004433);
|
||||
const YELLOW: Option<Color> = Some(0x444400);
|
||||
const ORANGE: Option<Color> = Some(0x448800);
|
||||
const BROWN_: Option<Color> = Some(0x8b4513);
|
||||
//const BROWN_: Option<Color> = Some(0x8b4513);
|
||||
|
||||
const HOUSE1: Sprite<Option<Color>, 5, 5> = [
|
||||
[BLANK_, BLANK_, RED___, BLANK_, BLANK_],
|
||||
[PURPLE, PURPLE, PURPLE, RED___, BLANK_],
|
||||
@@ -267,30 +300,27 @@ impl<
|
||||
[BLANK_, BLANK_, RED___, BLANK_, BLANK_],
|
||||
];
|
||||
|
||||
self.copy(
|
||||
self.position((3 + Self::dx(frame, fps, 1024)) as usize % 32, 0),
|
||||
self.draw_sprite(
|
||||
self.position(((3 + Self::dx(frame, fps, 1024)) % max_x) as u8, 0),
|
||||
&HOUSE2,
|
||||
);
|
||||
self.copy(
|
||||
self.position((7 + Self::dx(frame, fps, 1024)) as usize % 32, 2),
|
||||
self.draw_sprite(
|
||||
self.position(((7 + Self::dx(frame, fps, 1024)) % max_x) as u8, 2),
|
||||
&HOUSE1,
|
||||
);
|
||||
self.copy(
|
||||
self.position((14 + Self::dx(frame, fps, 1024)) as usize % 32, 1),
|
||||
self.draw_sprite(
|
||||
self.position(((14 + Self::dx(frame, fps, 1024)) % max_x) as u8, 1),
|
||||
&HOUSE2,
|
||||
);
|
||||
self.copy(
|
||||
self.position((20 + Self::dx(frame, fps, 1024)) as usize % 32, 0),
|
||||
self.draw_sprite(
|
||||
self.position(((20 + Self::dx(frame, fps, 1024)) % max_x) as u8, 0),
|
||||
&HOUSE2,
|
||||
);
|
||||
self.copy(
|
||||
self.position((27 + Self::dx(frame, fps, 1024)) as usize % 32, 1),
|
||||
self.draw_sprite(
|
||||
self.position(((27 + Self::dx(frame, fps, 1024)) % max_x) as u8, 1),
|
||||
&HOUSE2,
|
||||
);
|
||||
}
|
||||
fn sled(&self, _frame: usize) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
@@ -304,16 +334,13 @@ pub fn main() {
|
||||
loop {
|
||||
display.clear();
|
||||
|
||||
// 10 Background
|
||||
display.stars_far(frame, FRAME_PER_S, &mut rng); // OK
|
||||
display.stars_close(frame, FRAME_PER_S); // OK
|
||||
display.moon(frame, FRAME_PER_S); // OK
|
||||
display.snow(); // OK
|
||||
display.stars_far(frame, FRAME_PER_S, &mut rng);
|
||||
display.stars_close(frame, FRAME_PER_S);
|
||||
display.moon(frame, FRAME_PER_S);
|
||||
display.snow();
|
||||
|
||||
display.trees(frame, FRAME_PER_S); // OK
|
||||
display.trees(frame, FRAME_PER_S);
|
||||
display.houses(frame, FRAME_PER_S);
|
||||
//
|
||||
// display.sled(frame);
|
||||
|
||||
display.show();
|
||||
frame += 1;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
mod screen;
|
||||
|
||||
pub use crate::bit_string::{self, Sender};
|
||||
pub use crate::led_display::{DisplayCircles, DisplayRectangles, DisplaySprites, Screen, Sprite};
|
||||
pub use crate::bit_string::{self, SendBits};
|
||||
pub use crate::led_display::{Display, DrawCircles, DrawRectangles, DrawSprites, Sprite};
|
||||
use defmt::Format;
|
||||
pub use screen::CompositeNeoPixelDisplay;
|
||||
pub use screen::CompositeNeoPixelScreen as NeoPixelScreen;
|
||||
|
||||
pub type Color = u32;
|
||||
|
||||
@@ -29,12 +29,12 @@ pub type NeoPixelSender<
|
||||
|
||||
#[derive(Eq, Format, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Position {
|
||||
x: usize,
|
||||
y: usize,
|
||||
x: u8,
|
||||
y: u8,
|
||||
}
|
||||
|
||||
impl Position {
|
||||
fn new(x: usize, y: usize) -> Self {
|
||||
pub(crate) fn new(x: u8, y: u8) -> Self {
|
||||
Self { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use cortex_m::asm::delay;
|
||||
use defmt::warn;
|
||||
|
||||
use super::{Color, DisplayCircles, DisplayRectangles, DisplaySprites, Position, Screen, Sprite};
|
||||
use super::{Color, Display, DrawCircles, DrawRectangles, DrawSprites, Position, Sprite};
|
||||
|
||||
struct BufferPosition<const X: usize, const Y: usize, const NX: usize, const NY: usize> {
|
||||
row: usize,
|
||||
@@ -30,27 +30,24 @@ impl<const X: usize, const Y: usize, const NX: usize, const NY: usize> TryFrom<P
|
||||
type Error = ();
|
||||
|
||||
fn try_from(position: Position) -> Result<Self, Self::Error> {
|
||||
let col = position.x / X;
|
||||
let row = position.y / Y;
|
||||
let px = position.x as usize;
|
||||
let py = position.y as usize;
|
||||
|
||||
if col > NX && row > NY {
|
||||
return Err(());
|
||||
}
|
||||
if col > NX {
|
||||
return Err(());
|
||||
}
|
||||
if row > NY {
|
||||
return Err(());
|
||||
}
|
||||
let col = px / X;
|
||||
let row = py / Y;
|
||||
let x = px % X;
|
||||
let y = py % Y;
|
||||
|
||||
let x = position.x % X;
|
||||
let y = position.y % Y;
|
||||
Ok(BufferPosition { row, col, y, x })
|
||||
if col > NX || row > NY {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(BufferPosition { row, col, y, x })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CompositeNeoPixelDisplay<
|
||||
Sender: super::Sender,
|
||||
pub struct CompositeNeoPixelScreen<
|
||||
Sender: super::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
@@ -62,13 +59,13 @@ pub struct CompositeNeoPixelDisplay<
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: super::Sender,
|
||||
Sender: super::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> CompositeNeoPixelDisplay<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
> CompositeNeoPixelScreen<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
pub fn new(sender: Sender) -> Self {
|
||||
let display = Self {
|
||||
@@ -80,8 +77,8 @@ impl<
|
||||
display
|
||||
}
|
||||
|
||||
pub fn position(&self, x: usize, y: usize) -> Option<Position> {
|
||||
if (x < { X * NX }) && (y < { Y * NY }) {
|
||||
pub fn position(&self, x: u8, y: u8) -> Option<Position> {
|
||||
if ((x as usize) < { X * NX }) && ((y as usize) < { Y * NY }) {
|
||||
Some(Position::new(x, y))
|
||||
} else {
|
||||
warn!(
|
||||
@@ -94,24 +91,54 @@ impl<
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rectangle_parameters(
|
||||
a: Option<Position>,
|
||||
b: Option<Position>,
|
||||
color: Option<Color>,
|
||||
) -> Option<(Position, Position, Color)> {
|
||||
let color = color?;
|
||||
let a = a?;
|
||||
let b = b?;
|
||||
|
||||
if b > a {
|
||||
Some((a, b, color))
|
||||
} else {
|
||||
Some((b, a, color))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_circle_parameters(
|
||||
origin: Option<Position>,
|
||||
radius: u8,
|
||||
color: Option<Color>,
|
||||
) -> Option<(u8, u8, u8, u8, Color)> {
|
||||
let color = color?;
|
||||
let Position { x: cx, y: cy } = origin?;
|
||||
|
||||
let y0 = if cy < radius { 0 } else { cy - radius };
|
||||
let x0 = if cx < radius { 0 } else { cx - radius };
|
||||
|
||||
Some((cx, cy, x0, y0, color))
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: super::Sender,
|
||||
Sender: super::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> Screen<Option<Position>, Color>
|
||||
for CompositeNeoPixelDisplay<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
> Display<Option<Position>, Color>
|
||||
for CompositeNeoPixelScreen<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
fn show(&self) {
|
||||
for r in 0..NY {
|
||||
for c in 0..NX {
|
||||
for y in 0..Y {
|
||||
for x in 0..X {
|
||||
self.sender.send(self.buffer[r][c][y][x]);
|
||||
self.sender.send_bits(self.buffer[r][c][y][x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,14 +151,14 @@ impl<
|
||||
}
|
||||
|
||||
fn fill(&mut self, color: Color) {
|
||||
self.fill_rectangle(
|
||||
self.draw_filled_rectangle(
|
||||
self.position(0, 0),
|
||||
self.position(X * NX - 1, Y * NY - 1),
|
||||
self.position((X * NX - 1) as u8, (Y * NY - 1) as u8),
|
||||
Some(color),
|
||||
);
|
||||
}
|
||||
|
||||
fn point(&mut self, position: Option<Position>, color: Color) {
|
||||
fn draw_dot(&mut self, position: Option<Position>, color: Color) {
|
||||
if let Ok(BufferPosition::<X, Y, NX, NY> { row, col, y, x }) = position.try_into() {
|
||||
self.buffer[row][col][y][x] = color;
|
||||
}
|
||||
@@ -139,67 +166,104 @@ impl<
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: super::Sender,
|
||||
Sender: super::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> DisplayRectangles<Option<Position>, Option<Color>>
|
||||
for CompositeNeoPixelDisplay<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
> DrawRectangles<Option<Position>, Option<Color>>
|
||||
for CompositeNeoPixelScreen<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
fn fill_rectangle(&mut self, a: Option<Position>, b: Option<Position>, color: Option<Color>) {
|
||||
let color = if let Some(c) = color { c } else { return };
|
||||
fn draw_filled_rectangle(
|
||||
&mut self,
|
||||
a: Option<Position>,
|
||||
b: Option<Position>,
|
||||
color: Option<Color>,
|
||||
) {
|
||||
if let Some((bottom_left, upper_right, color)) = Self::get_rectangle_parameters(a, b, color)
|
||||
{
|
||||
let Position { x: x0, y: y0 } = bottom_left;
|
||||
let Position { x: x1, y: y1 } = upper_right;
|
||||
|
||||
if let Some(a) = a {
|
||||
if let Some(b) = b {
|
||||
let bottom_left;
|
||||
let upper_right;
|
||||
if a < b {
|
||||
bottom_left = a;
|
||||
upper_right = b;
|
||||
} else {
|
||||
bottom_left = b;
|
||||
upper_right = a;
|
||||
for y in y0..=y1 {
|
||||
for x in x0..=x1 {
|
||||
self.draw_dot(self.position(x, y), color)
|
||||
}
|
||||
let Position { x: x0, y: y0 } = bottom_left;
|
||||
let Position { x: x1, y: y1 } = upper_right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for y in y0..=y1 {
|
||||
for x in x0..=x1 {
|
||||
self.point(self.position(x, y), color)
|
||||
fn draw_rectangle(&mut self, a: Option<Position>, b: Option<Position>, color: Option<Color>) {
|
||||
if let Some((bottom_left, upper_right, color)) = Self::get_rectangle_parameters(a, b, color)
|
||||
{
|
||||
let Position { x: x0, y: y0 } = bottom_left;
|
||||
let Position { x: x1, y: y1 } = upper_right;
|
||||
|
||||
for y in y0..=y1 {
|
||||
if (y != y0) && (y != y1) {
|
||||
continue;
|
||||
}
|
||||
for x in x0..=x1 {
|
||||
if (x != x0) && (x != x1) {
|
||||
continue;
|
||||
}
|
||||
self.draw_dot(self.position(x, y), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: super::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> DrawCircles<Option<Position>, Option<Color>>
|
||||
for CompositeNeoPixelScreen<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
fn draw_filled_circle(
|
||||
&mut self,
|
||||
origin: Option<Position>,
|
||||
radius: usize,
|
||||
color: Option<Color>,
|
||||
) {
|
||||
let radius = radius as u8;
|
||||
|
||||
if let Some((cx, cy, x0, y0, color)) = Self::get_circle_parameters(origin, radius, color) {
|
||||
for y in y0..=(cy + radius) {
|
||||
for x in x0..=(cx + radius) {
|
||||
let dx = if x < cx { cx - x } else { x - cx };
|
||||
let dy = if y < cy { cy - y } else { y - cy };
|
||||
let h = dx * dx + dy * dy;
|
||||
let epsilon = (radius * 2) + 1 / radius + 1; // todo simplify or tune some more
|
||||
if h <= radius + epsilon {
|
||||
self.draw_dot(self.position(x, y), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rectangle(&mut self, a: Option<Position>, b: Option<Position>, color: Option<Color>) {
|
||||
if let Some(color) = color {
|
||||
if let Some(a) = a {
|
||||
if let Some(b) = b {
|
||||
let bottom_left;
|
||||
let upper_right;
|
||||
if a < b {
|
||||
bottom_left = a;
|
||||
upper_right = b;
|
||||
} else {
|
||||
bottom_left = b;
|
||||
upper_right = a;
|
||||
}
|
||||
let Position { x: x0, y: y0 } = bottom_left;
|
||||
let Position { x: x1, y: y1 } = upper_right;
|
||||
fn draw_circle(&mut self, origin: Option<Position>, radius: usize, color: Option<Color>) {
|
||||
let radius = radius as u8;
|
||||
|
||||
for y in y0..=y1 {
|
||||
if (y != y0) && (y != y1) {
|
||||
continue;
|
||||
}
|
||||
for x in x0..=x1 {
|
||||
if (x != x0) && (x != x1) {
|
||||
continue;
|
||||
}
|
||||
self.point(self.position(x, y), color);
|
||||
}
|
||||
if let Some((cx, cy, x0, y0, color)) = Self::get_circle_parameters(origin, radius, color) {
|
||||
for y in y0..=(cy + radius) {
|
||||
for x in x0..=(cx + radius) {
|
||||
let dx = if x < cx { cx - x } else { x - cx };
|
||||
let dy = if y < cy { cy - y } else { y - cy };
|
||||
let r2 = radius * radius;
|
||||
let h = dx * dx + dy * dy;
|
||||
let d = if r2 < h { h - r2 } else { r2 - h };
|
||||
let epsilon = (radius * 2 + 1) / radius + 1;
|
||||
|
||||
if d < epsilon {
|
||||
// we use a larger epsilon to have a full line
|
||||
self.draw_dot(self.position(x, y), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,74 +272,16 @@ impl<
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: super::Sender,
|
||||
Sender: super::SendBits,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> DisplayCircles<Option<Position>, Option<Color>>
|
||||
for CompositeNeoPixelDisplay<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
> DrawSprites<Option<Position>, Option<Color>>
|
||||
for CompositeNeoPixelScreen<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
fn fill_circle(&mut self, origin: Option<Position>, radius: usize, color: Option<Color>) {
|
||||
if let Some(color) = color {
|
||||
if let Some(origin) = origin {
|
||||
let Position { x: cx, y: cy } = origin;
|
||||
let y0 = if cy < radius { 0 } else { cy - radius };
|
||||
let x0 = if cx < radius { 0 } else { cx - radius };
|
||||
|
||||
for y in y0..=(cy + radius) {
|
||||
for x in x0..=(cx + radius) {
|
||||
let dx = if x < cx { cx - x } else { x - cx };
|
||||
let dy = if y < cy { cy - y } else { y - cy };
|
||||
let h = dx * dx + dy * dy;
|
||||
let epsilon = (radius * 2) + 1 / radius + 1; // todo simplify or tune some more
|
||||
if h <= radius + epsilon {
|
||||
self.point(self.position(x, y), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn circle(&mut self, origin: Option<Position>, radius: usize, color: Option<Color>) {
|
||||
if let Some(color) = color {
|
||||
if let Some(origin) = origin {
|
||||
let Position { x: cx, y: cy } = origin;
|
||||
let y0 = if cy < radius { 0 } else { cy - radius };
|
||||
let x0 = if cx < radius { 0 } else { cx - radius };
|
||||
|
||||
for y in y0..=(cy + radius) {
|
||||
for x in x0..=(cx + radius) {
|
||||
let dx = if x < cx { cx - x } else { x - cx };
|
||||
let dy = if y < cy { cy - y } else { y - cy };
|
||||
let r2 = radius * radius;
|
||||
let h = dx * dx + dy * dy;
|
||||
let d = if r2 < h { h - r2 } else { r2 - h };
|
||||
let epsilon = (radius * 2 + 1) / radius + 1;
|
||||
if d < epsilon {
|
||||
// we use a larger epsilon to have a full line
|
||||
self.point(self.position(x, y), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
Sender: super::Sender,
|
||||
const DELAY_RESET: u32,
|
||||
const X: usize,
|
||||
const Y: usize,
|
||||
const NX: usize,
|
||||
const NY: usize,
|
||||
> DisplaySprites<Option<Position>, Option<Color>>
|
||||
for CompositeNeoPixelDisplay<Sender, DELAY_RESET, X, Y, NX, NY>
|
||||
{
|
||||
fn copy<const SW: usize, const SH: usize>(
|
||||
fn draw_sprite<const SW: usize, const SH: usize>(
|
||||
&mut self,
|
||||
origin: Option<Position>,
|
||||
sprite: &Sprite<Option<Color>, SW, SH>,
|
||||
@@ -284,7 +290,7 @@ impl<
|
||||
for (x, line) in sprite.iter().enumerate() {
|
||||
for (y, color) in line.iter().enumerate() {
|
||||
if let &Some(color) = color {
|
||||
self.point(self.position(x0 + x, y0 + y), color);
|
||||
self.draw_dot(self.position(x0 + x as u8, y0 + y as u8), color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user