#![doc = include_str!("../../examples/shapes_stage.rs")]
mod cells;
pub mod font;
mod pixels;
pub use font::{GLYPH_ADVANCE, GLYPH_HEIGHT, GLYPH_WIDTH};
pub use pixels::Image;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct Area {
pub x: i32,
pub y: i32,
pub w: u32,
pub h: u32,
}
impl Area {
pub const fn new(x: i32, y: i32, w: u32, h: u32) -> Self {
Self { x, y, w, h }
}
pub(crate) fn left(&self) -> i64 {
i64::from(self.x)
}
pub(crate) fn top(&self) -> i64 {
i64::from(self.y)
}
pub(crate) fn right(&self) -> i64 {
i64::from(self.x) + i64::from(self.w)
}
pub(crate) fn bottom(&self) -> i64 {
i64::from(self.y) + i64::from(self.h)
}
}
impl From<crate::Rect> for Area {
fn from(rect: crate::Rect) -> Self {
Self {
x: rect.x.min(i32::MAX as u32) as i32,
y: rect.y.min(i32::MAX as u32) as i32,
w: rect.w,
h: rect.h,
}
}
}
pub trait Shapes {
type Ink: Copy;
fn stroke_rect(&mut self, area: Area, ink: Self::Ink);
fn fill_rect(&mut self, area: Area, ink: Self::Ink);
fn line(&mut self, from: (i32, i32), to: (i32, i32), ink: Self::Ink);
fn bar(&mut self, area: Area, fraction: f32, fill: Self::Ink, track: Self::Ink);
fn rounded_rect(&mut self, area: Area, radius: u32, ink: Self::Ink);
fn fill_rounded_rect(&mut self, area: Area, radius: u32, ink: Self::Ink);
fn circle(&mut self, centre: (f32, f32), radius: f32, ink: Self::Ink);
fn fill_circle(&mut self, centre: (f32, f32), radius: f32, ink: Self::Ink);
fn label(&mut self, x: i32, y: i32, text: &str, ink: Self::Ink) -> u32;
}
pub(crate) fn unit(fraction: f32) -> f32 {
if fraction.is_nan() {
0.0
} else {
fraction.clamp(0.0, 1.0)
}
}
pub(crate) fn clip_segment(
from: (i64, i64),
to: (i64, i64),
width: u32,
height: u32,
) -> Option<((i64, i64), (i64, i64))> {
let (x0, y0) = (from.0 as f64, from.1 as f64);
let (dx, dy) = ((to.0 - from.0) as f64, (to.1 - from.1) as f64);
let (min_x, max_x) = (-1.0, f64::from(width));
let (min_y, max_y) = (-1.0, f64::from(height));
let (mut enter, mut leave) = (0.0f64, 1.0f64);
for (p, q) in [
(-dx, x0 - min_x),
(dx, max_x - x0),
(-dy, y0 - min_y),
(dy, max_y - y0),
] {
if p == 0.0 {
if q < 0.0 {
return None;
}
continue;
}
let t = q / p;
if p < 0.0 {
enter = enter.max(t);
} else {
leave = leave.min(t);
}
if enter > leave {
return None;
}
}
let point = |t: f64| {
(
libm::round(x0 + t * dx) as i64,
libm::round(y0 + t * dy) as i64,
)
};
Some((point(enter), point(leave)))
}