dvd_render/
sequence.rs

1use crate::grid::Grid;
2use std::collections::{HashMap, VecDeque, HashSet};
3use core::num::NonZeroU8;
4
5#[derive(Clone)]
6pub struct Frame<const W: usize, const H: usize> {
7	grid: Grid<W, H>,
8	pub frame_hold: NonZeroU8
9}
10
11impl<const W: usize, const H: usize> Frame<W, H> {
12	/// display a grid for a single frame
13	pub fn single(grid: Grid<W, H>) -> Self {
14		Self { grid, frame_hold: NonZeroU8::MIN }
15	}
16
17	/// hold on a grid for some amount of frames
18	pub fn variable(grid: Grid<W, H>, frame_hold: NonZeroU8) -> Self {
19		Self { grid, frame_hold }
20	}
21
22	pub(crate) fn serialize(self, lut: &HashMap<char, u32>) -> Vec<u8> {
23		self.grid.cells().iter().flat_map(|row| {
24			row.iter().map(|cell| {
25				*lut.get(&cell.character()).expect("invariant upheld by type system")
26			}).flat_map(u32::to_ne_bytes)
27		}).collect()
28	}
29
30	pub(crate) fn serialize_colors(&self) -> Vec<u8> {
31		self.grid.cells().iter().flat_map(|row| {
32			row.iter().flat_map(|cell| {
33				[cell.fg_color().0, cell.bg_color().0]
34			}).flatten()
35		}).collect()
36	}
37}
38
39pub enum FontSize {
40	Pixel(f32),
41	PixelXY { x: f32, y: f32 },
42	Point(f32)
43}
44
45pub struct Px(pub f32);
46
47impl From<Px> for FontSize {
48	fn from(s: Px) -> FontSize {
49		FontSize::Pixel(s.0)
50	}
51}
52
53impl From<(Px, Px)> for FontSize {
54	fn from(xy: (Px, Px)) -> FontSize {
55		FontSize::PixelXY { x: xy.0.0, y: xy.1.0 }
56	}
57}
58
59impl From<[Px; 2]> for FontSize {
60	fn from(xy: [Px; 2]) -> FontSize {
61		FontSize::PixelXY { x: xy[0].0, y: xy[1].0 }
62	}
63}
64
65pub struct Pt(pub f32);
66
67impl From<Pt> for FontSize {
68	fn from(pt: Pt) -> FontSize {
69		FontSize::Point(pt.0)
70	}
71}
72
73pub struct GridSequence<const W: usize, const H: usize> {
74	pub framerate: NonZeroU8,
75	frames: VecDeque<Frame<W, H>>,
76	pub font_scale: FontSize,
77	glyph_set: HashSet<char>
78}
79
80impl<const W: usize, const H: usize> GridSequence<W, H> {
81	pub fn new(s: impl Into<FontSize>) -> Self {
82		Self {
83			framerate: NonZeroU8::MIN,
84			frames: VecDeque::new(),
85			font_scale: s.into(),
86			glyph_set: HashSet::new()
87		}
88	}
89
90	/// push a frame to the beginning of the sequence
91	pub fn prepend(&mut self, frame: Frame<W, H>) {
92		for c in frame.grid.chars() {
93			self.glyph_set.insert(c);
94		}
95
96		self.frames.push_front(frame);
97	}
98
99	/// push a frame to the end of the sequence
100	pub fn append(&mut self, frame: Frame<W, H>) {
101		for c in frame.grid.chars() {
102			self.glyph_set.insert(c);
103		}
104
105		self.frames.push_back(frame);
106	}
107
108	#[inline]
109	pub fn glyph_set(&self) -> &HashSet<char> {
110		&self.glyph_set
111	}
112
113	#[inline]
114	pub(crate) fn pop(&mut self) -> Option<Frame<W, H>> {
115		self.frames.pop_front()
116	}
117
118	pub(crate) fn resolve_px_scale<F: ab_glyph::Font>(&self, font: F) -> ab_glyph::PxScale {
119		match self.font_scale {
120			FontSize::Pixel(s) => ab_glyph::PxScale::from(s),
121			FontSize::PixelXY { x, y } => ab_glyph::PxScale { x, y },
122			FontSize::Point(pt) => font.pt_to_px_scale(pt).expect("not sure why this would fail?")
123		}
124	}
125}