maikor_vm_file/
palette.rs

1use crate::file_utils::{convert_vec, ReaderExt};
2use crate::read_write_impl::{FileReadable, Readable, Writeable};
3use crate::GameFileError;
4use crate::GameFileError::{FileAccessError, InvalidPalette};
5use std::path::Path;
6
7const PALETTE_HEADER: [u8; 2] = [0xFD, 0xA2];
8pub const PALETTE_EXT: &str = "mpal";
9
10#[derive(Clone, Eq, PartialEq, Debug)]
11pub struct Palette {
12    pub filepath: Option<String>,
13    pub colors: [Color; 16],
14}
15
16impl Palette {
17    pub fn new(filepath: Option<String>, palette: [Color; 16]) -> Self {
18        Self {
19            filepath,
20            colors: palette,
21        }
22    }
23}
24
25impl Palette {
26    pub fn filename(&self) -> Option<String> {
27        self.filepath.as_ref().and_then(|path| {
28            Path::new(&path)
29                .file_name()
30                .map(|name| name.to_string_lossy().to_string())
31        })
32    }
33}
34
35#[derive(Copy, Clone, Eq, PartialEq, Debug)]
36pub struct Color {
37    pub r: u8,
38    pub g: u8,
39    pub b: u8,
40}
41
42impl Color {
43    pub fn new(r: u8, g: u8, b: u8) -> Self {
44        Self { r, g, b }
45    }
46
47    pub fn from_bytes(rgb: [u8; 3]) -> Color {
48        Color::new(rgb[0], rgb[1], rgb[2])
49    }
50}
51
52impl Color {
53    pub fn as_bytes(&self) -> [u8; 3] {
54        [self.r, self.g, self.b]
55    }
56}
57
58impl Writeable for Palette {
59    fn as_bytes(&self) -> Result<Vec<u8>, GameFileError> {
60        let mut output = vec![];
61        output.extend_from_slice(&PALETTE_HEADER);
62        for color in self.colors {
63            output.extend_from_slice(&color.as_bytes());
64        }
65        Ok(output)
66    }
67}
68
69impl Readable for Palette {
70    fn from_reader<R: ReaderExt>(reader: &mut R) -> Result<Self, GameFileError>
71    where
72        Self: Sized,
73    {
74        let mut header = [0; 2];
75        reader
76            .read_exact(&mut header)
77            .map_err(|e| FileAccessError(e, "reading palette header data"))?;
78        if header != PALETTE_HEADER {
79            return Err(InvalidPalette(String::from("Not a palette file")));
80        }
81        let blocks = reader
82            .read_multiple_blocks(3, 16)
83            .map_err(|e| FileAccessError(e, "reading palette data"))?;
84        let colours: Vec<Color> = blocks
85            .into_iter()
86            .map(|rgb| Color::from_bytes(convert_vec(rgb)))
87            .collect();
88        Ok(Palette::new(None, convert_vec(colours)))
89    }
90}
91
92impl FileReadable for Palette {}
93
94#[cfg(test)]
95mod test {
96    use super::*;
97    use std::io::BufReader;
98
99    #[test]
100    fn header_check() {
101        let data: Vec<u8> = vec![0, 0];
102        let palette = Palette::from_reader(&mut BufReader::new(&*data));
103        assert!(palette.is_err());
104        assert_eq!(
105            palette.err().unwrap().to_string(),
106            String::from("Invalid Palette file: Not a palette file")
107        )
108    }
109
110    #[test]
111    fn read() {
112        let data: Vec<u8> = vec![
113            PALETTE_HEADER[0],
114            PALETTE_HEADER[1],
115            0,
116            0,
117            0,
118            255,
119            255,
120            255,
121            100,
122            100,
123            100,
124            101,
125            101,
126            101,
127            102,
128            102,
129            102,
130            103,
131            104,
132            105,
133            99,
134            88,
135            77,
136            1,
137            2,
138            3,
139            4,
140            5,
141            6,
142            7,
143            8,
144            9,
145            11,
146            22,
147            33,
148            66,
149            55,
150            44,
151            88,
152            77,
153            99,
154            1,
155            10,
156            100,
157            2,
158            20,
159            200,
160            158,
161            158,
162            158,
163        ];
164        let palette = Palette::from_reader(&mut BufReader::new(&*data)).unwrap();
165        assert_eq!(palette.filepath, None);
166        assert_eq!(palette.colors[0], Color::new(0, 0, 0));
167        assert_eq!(palette.colors[1], Color::new(255, 255, 255));
168        assert_eq!(palette.colors[2], Color::new(100, 100, 100));
169        assert_eq!(palette.colors[3], Color::new(101, 101, 101));
170        assert_eq!(palette.colors[4], Color::new(102, 102, 102));
171        assert_eq!(palette.colors[5], Color::new(103, 104, 105));
172        assert_eq!(palette.colors[6], Color::new(99, 88, 77));
173        assert_eq!(palette.colors[7], Color::new(1, 2, 3));
174        assert_eq!(palette.colors[8], Color::new(4, 5, 6));
175        assert_eq!(palette.colors[9], Color::new(7, 8, 9));
176        assert_eq!(palette.colors[10], Color::new(11, 22, 33));
177        assert_eq!(palette.colors[11], Color::new(66, 55, 44));
178        assert_eq!(palette.colors[12], Color::new(88, 77, 99));
179        assert_eq!(palette.colors[13], Color::new(1, 10, 100));
180        assert_eq!(palette.colors[14], Color::new(2, 20, 200));
181        assert_eq!(palette.colors[15], Color::new(158, 158, 158));
182    }
183}