diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 99 |
1 files changed, 98 insertions, 1 deletions
@@ -2,7 +2,8 @@ use std::{convert::TryFrom, fmt, io::{self, BufWriter, Error, Write}, os::unix::io::{AsRawFd, RawFd}, - path::{Path, PathBuf}}; + path::{Path, PathBuf}, + time::{Duration, Instant}}; trait IsMinusOne { @@ -776,3 +777,99 @@ impl fmt::Display for Console write!(f, "Console(fd={})", self.0) } } + +/* Use doubles for fractional scaling. */ +struct FadePalette([f64; PALETTE_SIZE * 3]); + +impl FadePalette +{ + fn new() -> Self { Self([0f64; PALETTE_SIZE * 3]) } + + /** Linear interpolation between self and ``goal``. + + We scale each byte individually so there can be a maximum + of 256 interpolation steps. + */ + fn towards(&self, goal: &FadePalette, progress: f64) -> FadePalette + { + let mut res = FadePalette::new(); + + for (i, (a, b)) in self.0.iter().zip(goal.0.iter()).enumerate() { + res.0[i] = a + (b - a) * progress; + } + + res + } +} + +impl From<&Palette> for FadePalette +{ + fn from(pal: &Palette) -> Self + { + let mut fpal = Self::new(); + pal.0.iter().enumerate().for_each(|(i, &b)| { + fpal.0[i] = b as f64; + }); + fpal + } +} + +impl From<&FadePalette> for Palette +{ + fn from(fpal: &FadePalette) -> Self + { + let mut pal = Self::new(); + fpal.0.iter().enumerate().for_each(|(i, &b)| { + let b = if b < 0f64 { + 0 + } else if 256f64 <= b { + 255 + } else { + b.round() as u8 + }; + pal.0[i] = b; + }); + pal + } +} + +pub struct Fade +{ + from: Palette, + to: Palette, + hz: u8, + duration: Duration, +} + +impl Fade +{ + pub fn new(from: Palette, to: Palette, duration: Duration, hz: u8) -> Self + { + let hz = if hz == 0 { 1 } else { hz }; + Self { from, to, hz, duration } + } + + pub fn commence(self, con: &Console) -> io::Result<()> + { + let Self { from, to, hz, duration } = self; + con.apply_palette(&from)?; + + let fade = FadePalette::from(&con.current_palette()?); + let fade_to = FadePalette::from(&to); + let t_0 = Instant::now(); + let tick = Duration::from_millis(1_000u64 / hz as u64); + let iters = (duration.as_millis() / tick.as_millis()) as u32; + + let mut i = 0; + while i < iters { + i += 1; + let progress = f64::from(i) / f64::from(iters); + let pal = Palette::from(&fade.towards(&fade_to, progress)); + con.apply_palette(&pal)?; + let next = i * tick; + std::thread::sleep(next.saturating_sub(t_0.elapsed())); + } + + Ok(()) + } +} |