snes_bitplanes/
bitplanes_4bpp.rs

1use core::slice::Chunks;
2use tile::Tile;
3
4/// An iterator over 4-bits-per-pixel bitplanes.
5///
6/// Accepts a slice of bytes encoded in bitplanes and decoded `u8`s.
7/// The length of input bytes must be evenly divisible by 32. For every
8/// 32 bytes consumed, this iterator yields 64 decoded bytes.
9/// (Conceptually, it's an 8x8 tile.)
10///
11/// The 4 most significant bits of each decoded byte will always be 0.
12#[derive(Debug)]
13pub struct Bitplanes<'a> {
14    chunks: Chunks<'a, u8>,
15}
16
17impl<'a> Iterator for Bitplanes<'a> {
18    type Item = Tile;
19
20    fn next(&mut self) -> Option<Self::Item> {
21        self.chunks.next()
22            .map(|chunk| {
23                let (planes01, planes23) = chunk.split_at(16);
24                let mut result = [0; 64];
25                let mut cursor = 0;
26                for (bytes01, bytes23) in planes01.chunks(2).zip(planes23.chunks(2)) {
27                    for n in (0..8).rev() {
28                        let mask = 1 << n;
29                        let mut px = 0;
30
31                        if bytes23[1] & mask > 0 {
32                            px += 1;
33                        }
34                        px <<= 1;
35                        if bytes23[0] & mask > 0 {
36                            px += 1;
37                        }
38                        px <<= 1;
39                        if bytes01[1] & mask > 0 {
40                            px += 1;
41                        }
42                        px <<= 1;
43                        if bytes01[0] & mask > 0 {
44                            px += 1;
45                        }
46                        result[cursor] = px;
47                        cursor += 1;
48                    }
49                }
50                Tile(result)
51            })
52    }
53
54    fn size_hint(&self) -> (usize, Option<usize>) {
55        self.chunks.size_hint()
56    }
57}
58
59impl<'a> Bitplanes<'a> {
60    /// Constructs a new `Bitplanes` from a slice of bytes.
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// # use snes_bitplanes::Bitplanes;
66    /// # fn main() {
67    ///
68    /// let bytes = [0u8; 128];
69    ///
70    /// let tiles: Vec<_> = Bitplanes::new(&bytes[0..64]).collect();
71    /// # }
72    /// ```
73    ///
74    /// # Panics
75    ///
76    /// Panics if the length of the slice is not evenly divisible by 32.
77    pub fn new(bytes: &'a [u8]) -> Bitplanes<'a> {
78        assert!(bytes.len() % 32 == 0, "Byte slice doesn't fit into 32-byte tiles");
79        Bitplanes {
80            chunks: bytes.chunks(32),
81        }
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::{Bitplanes, Tile};
88
89    #[test]
90    fn snes_mode_4_4bpp() {
91        let encoded: &[u8] = &[
92            0b00101110, // Bitplane 0
93            0b00100000, // Bitplane 1
94            0b11101001, // Bitplane 0
95            0b10010101, // Bitplane 1
96            0b11111101, // ...
97            0b10101011,
98            0b01000111,
99            0b00010101,
100            0b00110000,
101            0b01011100,
102            0b10011111,
103            0b00011101,
104            0b10010110,
105            0b01011010,
106            0b00010101,
107            0b00101110,
108
109            0b01000000, // Bitplane 2
110            0b00001111, // Bitplane 3
111            0b00010001, // Bitplane 2
112            0b11111011, // Bitplane 3
113            0b01000001, // ...
114            0b10011100,
115            0b10000100,
116            0b11110110,
117            0b10110000,
118            0b00011000,
119            0b00100111,
120            0b00001001,
121            0b11101000,
122            0b00101010,
123            0b00010001,
124            0b10000011,
125        ];
126
127        let expected = Tile([
128            0b0000, 0b0100, 0b0011, 0b0000, 0b1001, 0b1001, 0b1001, 0b1000,
129            0b1011, 0b1001, 0b1001, 0b1110, 0b1001, 0b0010, 0b1000, 0b1111,
130            0b1011, 0b0101, 0b0011, 0b1001, 0b1011, 0b1001, 0b0010, 0b0111,
131            0b1100, 0b1001, 0b1000, 0b1010, 0b0000, 0b1111, 0b1001, 0b0011,
132            0b0100, 0b0010, 0b0101, 0b1111, 0b1010, 0b0010, 0b0000, 0b0000,
133            0b0001, 0b0000, 0b0100, 0b0011, 0b1011, 0b0111, 0b0101, 0b1111,
134            0b0101, 0b0110, 0b1100, 0b0011, 0b1110, 0b0001, 0b1011, 0b0000,
135            0b1000, 0b0000, 0b0010, 0b0101, 0b0010, 0b0011, 0b1010, 0b1101,                                     
136        ]);
137
138        let mut decoded = Bitplanes::new(encoded);
139
140        assert_eq!(decoded.next(), Some(expected));
141        assert!(decoded.next().is_none());
142    }
143}