#![no_std]
#![forbid(unsafe_code)]
use embassy_ssd1306::Ssd1306;
use embedded_hal_async::i2c::I2c;
pub struct Graphics<'a, I: I2c> {
display: &'a mut Ssd1306<I>,
}
impl<'a, I: I2c> Graphics<'a, I> {
#[inline]
pub fn new(display: &'a mut Ssd1306<I>) -> Self {
Self { display }
}
#[inline(always)]
pub fn pixel(&mut self, x: i32, y: i32, on: bool) {
if x >= 0 && y >= 0 && x < 128 && y < 64 {
self.display.draw_pixel(x as u8, y as u8, on);
}
}
}
pub fn line<I: I2c>(
gfx: &mut Graphics<'_, I>,
mut x0: i32,
mut y0: i32,
x1: i32,
y1: i32,
on: bool,
) {
let dx = (x1 - x0).abs();
let sx = if x0 < x1 { 1 } else { -1 };
let dy = -(y1 - y0).abs();
let sy = if y0 < y1 { 1 } else { -1 };
let mut err = dx + dy;
loop {
gfx.pixel(x0, y0, on);
if x0 == x1 && y0 == y1 {
break;
}
let e2 = 2 * err;
if e2 >= dy {
err += dy;
x0 += sx;
}
if e2 <= dx {
err += dx;
y0 += sy;
}
}
}
pub fn circle<I: I2c>(gfx: &mut Graphics<'_, I>, cx: i32, cy: i32, r: i32, on: bool) {
if r <= 0 {
gfx.pixel(cx, cy, on);
return;
}
let mut x = r;
let mut y = 0;
let mut err = 0;
while x >= y {
gfx.pixel(cx + x, cy + y, on);
gfx.pixel(cx + y, cy + x, on);
gfx.pixel(cx - y, cy + x, on);
gfx.pixel(cx - x, cy + y, on);
gfx.pixel(cx - x, cy - y, on);
gfx.pixel(cx - y, cy - x, on);
gfx.pixel(cx + y, cy - x, on);
gfx.pixel(cx + x, cy - y, on);
y += 1;
if err <= 0 {
err += 2 * y + 1;
} else {
x -= 1;
err += 2 * (y - x) + 1;
}
}
}
pub fn fill_circle<I: I2c>(gfx: &mut Graphics<'_, I>, cx: i32, cy: i32, r: i32, on: bool) {
if r <= 0 {
gfx.pixel(cx, cy, on);
return;
}
let mut x = r;
let mut y = 0;
let mut err = 0;
while x >= y {
for px in (cx - x)..=(cx + x) {
gfx.pixel(px, cy + y, on);
gfx.pixel(px, cy - y, on);
}
for px in (cx - y)..=(cx + y) {
gfx.pixel(px, cy + x, on);
gfx.pixel(px, cy - x, on);
}
y += 1;
if err <= 0 {
err += 2 * y + 1;
} else {
x -= 1;
err += 2 * (y - x) + 1;
}
}
}
#[inline]
pub fn triangle<I: I2c>(
gfx: &mut Graphics<'_, I>,
x0: i32, y0: i32,
x1: i32, y1: i32,
x2: i32, y2: i32,
on: bool,
) {
line(gfx, x0, y0, x1, y1, on);
line(gfx, x1, y1, x2, y2, on);
line(gfx, x2, y2, x0, y0, on);
}
pub fn ellipse<I: I2c>(gfx: &mut Graphics<'_, I>, cx: i32, cy: i32, rx: i32, ry: i32, on: bool) {
if rx <= 0 || ry <= 0 {
gfx.pixel(cx, cy, on);
return;
}
let rx2 = rx * rx;
let ry2 = ry * ry;
let mut x = 0i32;
let mut y = ry;
let mut d1 = ry2 - rx2 * ry + rx2 / 4;
let mut dx = 2 * ry2 * x;
let mut dy = 2 * rx2 * y;
while dx < dy {
gfx.pixel(cx + x, cy + y, on);
gfx.pixel(cx - x, cy + y, on);
gfx.pixel(cx + x, cy - y, on);
gfx.pixel(cx - x, cy - y, on);
x += 1;
dx += 2 * ry2;
if d1 < 0 {
d1 += dx + ry2;
} else {
y -= 1;
dy -= 2 * rx2;
d1 += dx - dy + ry2;
}
}
let mut d2 = ry2 * (x * x + x) + rx2 * (y * y - 2 * y + 1) - rx2 * ry2 + rx2;
while y >= 0 {
gfx.pixel(cx + x, cy + y, on);
gfx.pixel(cx - x, cy + y, on);
gfx.pixel(cx + x, cy - y, on);
gfx.pixel(cx - x, cy - y, on);
y -= 1;
dy -= 2 * rx2;
if d2 > 0 {
d2 += rx2 - dy;
} else {
x += 1;
dx += 2 * ry2;
d2 += dx - dy + rx2;
}
}
}
pub fn bezier_quad<I: I2c>(
gfx: &mut Graphics<'_, I>,
x0: i32, y0: i32,
x1: i32, y1: i32,
x2: i32, y2: i32,
steps: i32,
on: bool,
) {
if steps <= 0 {
return;
}
let mut px = x0;
let mut py = y0;
for i in 1..=steps {
let t = (i * 1024) / steps; let t1 = 1024 - t;
let nx = (t1 * t1 * x0 + 2 * t1 * t * x1 + t * t * x2) / (1024 * 1024);
let ny = (t1 * t1 * y0 + 2 * t1 * t * y1 + t * t * y2) / (1024 * 1024);
line(gfx, px, py, nx, ny, on);
px = nx;
py = ny;
}
}
pub fn fill_triangle<I: I2c>(
gfx: &mut Graphics<'_, I>,
x0: i32, mut y0: i32,
x1: i32, mut y1: i32,
x2: i32, mut y2: i32,
on: bool,
) {
let (mut x0, mut x1, mut x2) = (x0, x1, x2);
if y0 > y1 { core::mem::swap(&mut y0, &mut y1); core::mem::swap(&mut x0, &mut x1); }
if y1 > y2 { core::mem::swap(&mut y1, &mut y2); core::mem::swap(&mut x1, &mut x2); }
if y0 > y1 { core::mem::swap(&mut y0, &mut y1); core::mem::swap(&mut x0, &mut x1); }
let total_h = y2 - y0;
if total_h == 0 {
let xmin = x0.min(x1).min(x2);
let xmax = x0.max(x1).max(x2);
for x in xmin..=xmax {
gfx.pixel(x, y0, on);
}
return;
}
let upper_h = y1 - y0;
let lower_h = y2 - y1;
for y in y0..=y1 {
let dy = y - y0;
let xa = x0 + (x2 - x0) * dy / total_h;
let xb = if upper_h == 0 {
x1
} else {
x0 + (x1 - x0) * dy / upper_h
};
let (xmin, xmax) = if xa < xb { (xa, xb) } else { (xb, xa) };
for x in xmin..=xmax {
gfx.pixel(x, y, on);
}
}
for y in y1..=y2 {
let dy = y - y0;
let xa = x0 + (x2 - x0) * dy / total_h;
let xb = if lower_h == 0 {
x1
} else {
x1 + (x2 - x1) * (y - y1) / lower_h
};
let (xmin, xmax) = if xa < xb { (xa, xb) } else { (xb, xa) };
for x in xmin..=xmax {
gfx.pixel(x, y, on);
}
}
}