ceratophrys 0.0.3

Library to draw pixel art as code
Documentation
use crate::{filters::Filter, Image, Size};
use std::{num::NonZeroU8, time::Duration};

#[derive(Debug, Clone)]
pub struct Animation {
    pub frames: Vec<Image>,
    pub fps: NonZeroU8,
}

impl Animation {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn still_frame(frame: Image) -> Self {
        Self {
            frames: vec![frame],
            fps: NonZeroU8::MAX,
        }
    }

    pub fn frame(mut self, frame: Image) -> Self {
        self.frames.push(frame);
        self
    }

    pub fn frames(mut self, frames: impl IntoIterator<Item = Image>) -> Self {
        self.frames.extend(frames);
        self
    }

    pub fn fps(mut self, fps: NonZeroU8) -> Self {
        self.fps = fps;
        self
    }

    pub fn fps4(self) -> Self {
        self.fps(NonZeroU8::new(4).expect("unreachable"))
    }

    pub fn fps5(self) -> Self {
        self.fps(NonZeroU8::new(5).expect("unreachable"))
    }

    pub fn fps10(self) -> Self {
        self.fps(NonZeroU8::new(10).expect("unreachable"))
    }

    pub fn fps12(self) -> Self {
        self.fps(NonZeroU8::new(12).expect("unreachable"))
    }

    pub fn fps15(self) -> Self {
        self.fps(NonZeroU8::new(15).expect("unreachable"))
    }

    pub fn fps20(self) -> Self {
        self.fps(NonZeroU8::new(20).expect("unreachable"))
    }

    pub fn fps24(self) -> Self {
        self.fps(NonZeroU8::new(24).expect("unreachable"))
    }

    pub fn fps30(self) -> Self {
        self.fps(NonZeroU8::new(30).expect("unreachable"))
    }

    pub fn fps60(self) -> Self {
        self.fps(NonZeroU8::new(60).expect("unreachable"))
    }

    pub fn get_frame_duration(&self) -> Duration {
        Duration::from_secs(1) / u32::from(self.fps.get())
    }

    pub fn get_duration(&self) -> Duration {
        Duration::from_secs(self.frames.len() as u64) / u32::from(self.fps.get())
    }

    pub fn get_max_frame_size(&self) -> Size {
        let mut size = Size::EMPTY;
        for frame in &self.frames {
            size = size.max(frame.iter().map(|p| p.position).collect());
        }
        size
    }

    pub fn get_nth_frame_time(&self, n: usize) -> Duration {
        Duration::from_secs(n as u64) / u32::from(self.fps.get())
    }

    pub fn map_frame<F>(self, f: F) -> Animation
    where
        F: FnMut(Image) -> Image,
    {
        Animation {
            frames: self.frames.into_iter().map(f).collect(),
            fps: self.fps,
        }
    }

    pub fn filter<F: Filter>(self, f: F) -> Animation {
        self.map_frame(|mut frame| {
            f.filter(&mut frame);
            frame
        })
    }
}

impl Default for Animation {
    fn default() -> Self {
        Self {
            frames: Vec::new(),
            fps: NonZeroU8::new(1).expect("unreachable"),
        }
    }
}