use crate::color::Color;
use crate::grid::Grid;
#[derive(Clone, Copy, Debug)]
pub enum SweepDirection {
Horizontal,
Vertical,
DiagonalDown,
DiagonalUp,
}
#[derive(Clone, Copy, Debug)]
pub struct LightSweep {
pub center: f32,
pub width: f32,
pub intensity: f32,
pub softness: f32,
pub direction: SweepDirection,
}
impl LightSweep {
pub fn new(direction: SweepDirection) -> Self {
Self {
center: 0.5,
width: 0.25,
intensity: 0.8,
softness: 2.0,
direction,
}
}
pub fn center(mut self, center: f32) -> Self {
self.center = center;
self
}
pub fn width(mut self, width: f32) -> Self {
self.width = width;
self
}
pub fn intensity(mut self, intensity: f32) -> Self {
self.intensity = intensity;
self
}
pub fn softness(mut self, softness: f32) -> Self {
self.softness = softness;
self
}
}
pub fn apply_light_sweep(grid: &mut Grid, sweep: LightSweep) {
apply_light_sweep_tint(grid, sweep, Color::Rgb(255, 255, 255));
}
pub fn apply_light_sweep_tint(grid: &mut Grid, sweep: LightSweep, highlight: Color) {
let height = grid.height().max(1);
let width = grid.width().max(1);
let intensity = sweep.intensity.clamp(0.0, 1.0);
let band = sweep.width.max(0.0);
if intensity <= 0.0 || band <= 0.0 {
return;
}
let half = band / 2.0;
let softness = sweep.softness.max(1.0);
for r in 0..height {
for c in 0..width {
let Some(cell) = grid.cell_mut(r, c) else {
continue;
};
if !cell.visible {
continue;
}
let t = axis_t(sweep.direction, r, c, width, height);
let dist = (t - sweep.center).abs();
if dist > half {
continue;
}
let falloff = 1.0 - (dist / half);
let strength = falloff.powf(softness);
let amount = (intensity * strength).clamp(0.0, 1.0);
if amount <= 0.0 {
continue;
}
if let Some(color) = cell.fg {
cell.fg = Some(blend_to(color, highlight, amount));
}
}
}
}
fn axis_t(direction: SweepDirection, row: usize, col: usize, width: usize, height: usize) -> f32 {
match direction {
SweepDirection::Horizontal => {
if width <= 1 {
0.0
} else {
col as f32 / (width - 1) as f32
}
}
SweepDirection::Vertical => {
if height <= 1 {
0.0
} else {
row as f32 / (height - 1) as f32
}
}
SweepDirection::DiagonalDown => {
if width + height <= 2 {
0.0
} else {
(row + col) as f32 / (width + height - 2) as f32
}
}
SweepDirection::DiagonalUp => {
if width + height <= 2 {
0.0
} else {
(row + (width - 1 - col)) as f32 / (width + height - 2) as f32
}
}
}
}
fn blend_to(color: Color, target: Color, amount: f32) -> Color {
color.lerp(target, amount)
}