use std::f64::consts::TAU;
use crate::kit::ease;
use crate::paint::{Palette, Rgb};
use crate::shimmer::Spell;
use crate::stage::{Canvas, Stage};
pub(crate) const DRAG: u32 = 4;
pub(crate) const TEMPO: f64 = 1.0 / DRAG as f64;
pub(crate) const LULL: f64 = 5.0 * TEMPO;
const GREY: f64 = 0.6;
const KEEP: f64 = 0.3;
const SHADE: f64 = 0.35;
const TINT: f64 = 0.16;
const SWAY: f64 = 0.04;
const BREATH: f64 = 0.35;
const BREATH_SECS: f64 = 8.0;
const SETTLE_SECS: f64 = 2.0;
pub(crate) fn settle(canvas: &mut Canvas, stage: &Stage, palette: Palette) {
if stage.spell != Spell::Idle {
return;
}
let rested = stage.spell_t / TEMPO;
let depth = ease((rested / SETTLE_SECS).min(1.0));
let breath = 1.0 + BREATH * (TAU * rested / BREATH_SECS).sin();
let grey = palette.grey(GREY);
let ink = |color: Rgb| {
trace(color, grey, KEEP * breath, TINT * breath, SWAY * breath).blend(color, depth)
};
let shade = |color: Rgb| {
trace(
color,
palette.bg,
SHADE * breath,
TINT * breath,
f64::INFINITY,
)
.blend(color, depth)
};
for paint in canvas
.mark
.iter_mut()
.chain(&mut canvas.letters)
.chain(&mut canvas.tail)
{
paint.fg = Some(ink(paint.fg.unwrap_or(palette.fg)));
paint.bg = paint.bg.map(shade);
paint.underline = paint.underline.map(ink);
paint.bold &= depth < 0.5;
}
for color in &mut canvas.backdrop {
*color = shade(*color);
}
}
fn trace(color: Rgb, home: Rgb, share: f64, tint: f64, sway: f64) -> Rgb {
let kept = color.blend(home, share);
let stray = kept.luma() - home.luma();
let lift = 255.0 * (stray.clamp(-sway, sway) - stray);
let Rgb(r, g, b) = kept;
let lifted = Rgb(r + lift, g + lift, b + lift);
let top = r.max(g).max(b) + lift;
let spread = r.max(g).max(b) - r.min(g).min(b);
if spread <= tint * top {
return lifted;
}
let grey = 255.0 * lifted.luma();
lifted.blend(
Rgb(grey, grey, grey),
tint * grey / (spread - tint * (top - grey)),
)
}