Skip to main content

inkling/
rank.rs

1//! [`RankMap`]: the reveal schedule.
2//!
3//! Every ink cell carries a rank in `0..=1`; a cell is visible when
4//! `rank <= progress`. Background cells carry no rank and never appear.
5
6/// A per-cell reveal schedule produced by an [`crate::Ordering`].
7#[derive(Clone, Debug)]
8pub struct RankMap {
9    width: u16,
10    height: u16,
11    /// `ranks[index] == Some(r)` for ink cells, `None` for background.
12    ranks: Vec<Option<f32>>,
13}
14
15impl RankMap {
16    /// An all-background map of the given size; fill it in via [`set`](Self::set).
17    pub fn new(width: u16, height: u16) -> Self {
18        RankMap {
19            width,
20            height,
21            ranks: vec![None; width as usize * height as usize],
22        }
23    }
24
25    pub fn width(&self) -> u16 {
26        self.width
27    }
28
29    pub fn height(&self) -> u16 {
30        self.height
31    }
32
33    #[inline]
34    fn index(&self, x: u16, y: u16) -> usize {
35        y as usize * self.width as usize + x as usize
36    }
37
38    /// Assign `rank` to the cell at `(x, y)`.
39    pub fn set(&mut self, x: u16, y: u16, rank: f32) {
40        let i = self.index(x, y);
41        self.ranks[i] = Some(rank);
42    }
43
44    /// The rank of `(x, y)`, or `None` if it is background / out of bounds.
45    #[inline]
46    pub fn rank_at(&self, x: u16, y: u16) -> Option<f32> {
47        self.ranks.get(self.index(x, y)).copied().flatten()
48    }
49
50    /// True when `(x, y)` is ink and revealed at `progress`.
51    #[inline]
52    pub fn visible_at(&self, x: u16, y: u16, progress: f32) -> bool {
53        matches!(self.rank_at(x, y), Some(r) if r <= progress)
54    }
55
56    /// Number of ranked (ink) cells.
57    pub fn ink_count(&self) -> usize {
58        self.ranks.iter().filter(|r| r.is_some()).count()
59    }
60}