summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs99
1 files changed, 98 insertions, 1 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 213d58c..5952517 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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(())
+ }
+}