use crate::Framebuffer;
use crate::{Button, LightDir, Lights, color};
mod coordinates;
pub use {coordinates::BUTTON_LOCATIONS, coordinates::LIGHT_LOCATIONS};
pub fn draw_light_circle_with_mask(
c: color::RGB,
x: f32,
y: f32,
radius: f32,
fb: &mut Framebuffer,
mask: Lights,
) {
const FALL_OFF_DISTANCE: f32 = 0.7;
let dist_within_squared = radius * radius;
for idx in mask.indices() {
let (x2, y2) = LIGHT_LOCATIONS[idx];
let dx = x - x2;
let dy = y - y2;
let dist_squared = dx * dx + dy * dy;
let within = dist_squared < dist_within_squared;
if within {
let dist = dist_squared.sqrt();
let relative_dist = dist / radius;
let percent_colored = if relative_dist < FALL_OFF_DISTANCE {
1.0
} else {
1. - ((relative_dist - FALL_OFF_DISTANCE) / (1.0 - FALL_OFF_DISTANCE))
};
let this_color = color::dim_to(c, percent_colored);
fb.set_color(Lights::from_index(idx), this_color);
}
}
}
pub fn draw_light_circle_no_fall_off(
c: color::RGB,
x: f32,
y: f32,
radius: f32,
fb: &mut Framebuffer,
mask: Lights,
) {
let dist_within_squared = radius * radius;
for idx in mask.indices() {
let (x2, y2) = LIGHT_LOCATIONS[idx];
let dx = x - x2;
let dy = y - y2;
let dist_squared = dx * dx + dy * dy;
let within = dist_squared < dist_within_squared;
if within {
fb.set_color(Lights::from_index(idx), c);
}
}
}
pub fn draw_light_rectangle_with_mask(
color: color::RGB,
x: f32,
y: f32,
width: f32,
height: f32,
fb: &mut Framebuffer,
mask: Lights,
) {
for idx in mask.indices() {
const FALL_OFF_DISTANCE: f32 = 0.2;
let (l_x, l_y) = coordinates_for_light_index(idx);
let distance_to_nearest_border = distance_within_rectangle(l_x, l_y, x, y, width, height);
let alpha = (distance_to_nearest_border / FALL_OFF_DISTANCE).clamp(0., 1.);
fb.set_color(Lights::from_index(idx), color::dim_to(color, alpha));
}
}
pub fn draw_light_circle(c: color::RGB, x: f32, y: f32, radius: f32, fb: &mut Framebuffer) {
draw_light_circle_with_mask(c, x, y, radius, fb, Lights::all());
}
pub fn draw_light_rectangle(
color: color::RGB,
x: f32,
y: f32,
width: f32,
height: f32,
fb: &mut Framebuffer,
) {
draw_light_rectangle_with_mask(color, x, y, width, height, fb, Lights::all());
}
#[must_use]
pub fn x_val_for_col(col: crate::Column) -> f32 {
match col {
crate::Column::C0 => -4.0,
crate::Column::C1 => -2.0,
crate::Column::C2 => 0.0,
crate::Column::C3 => 2.0,
crate::Column::C4 => 4.0,
}
}
#[must_use]
pub fn y_val_for_row(row: crate::Row) -> f32 {
match row {
crate::Row::Top => 1.0,
crate::Row::Bottom => -1.0,
}
}
#[must_use]
pub const fn coordinates_for_button(button: Button) -> (f32, f32) {
BUTTON_LOCATIONS[button.index()]
}
#[must_use]
pub fn coordinates_for_light(button: Button, dir: LightDir) -> (f32, f32) {
LIGHT_LOCATIONS[button.index() * 4 + dir as usize]
}
#[must_use]
pub fn coordinates_for_light_index(index: usize) -> (f32, f32) {
LIGHT_LOCATIONS[index]
}
fn distance_within_rectangle(
p_x: f32,
p_y: f32,
rect_x: f32,
rect_y: f32,
rect_width: f32,
rect_height: f32,
) -> f32 {
if p_x > rect_x && p_x < rect_x + rect_width && p_y > rect_y && p_y < rect_y + rect_height {
f32::min(
f32::min((p_y - rect_y - rect_height).abs(), (p_y - rect_y).abs()),
f32::min((p_x - rect_x - rect_width).abs(), (p_x - rect_x).abs()),
)
} else {
0.0
}
}