sar_core/renderer/
resource.rs1use std::collections::HashMap;
2
3use crate::core::result::Result;
4use image::{imageops, DynamicImage, SubImage};
5
6use crate::core::symbol::SymbolId;
7
8const SYMBOLS_R: &[u8] = include_bytes!("../../assets/symbols_r.png");
9const SYMBOLS_G: &[u8] = include_bytes!("../../assets/symbols_g.png");
10const SYMBOLS_B: &[u8] = include_bytes!("../../assets/symbols_b.png");
11const SYMBOLS_COLOR: &[u8] = include_bytes!("../../assets/symbols_color.png");
12
13const SYMBOL_PIXELS: u32 = 64;
14const SYMBOL_WIDTH_NUM: u32 = 16;
15
16#[derive(Eq, Hash, PartialEq)]
17enum ImageSheet {
18 R,
19 G,
20 B,
21 Color,
22}
23
24pub struct Resource {
30 sheets: HashMap<ImageSheet, DynamicImage>,
32 pub symbol_pixels: u32,
34}
35
36impl Resource {
37 pub fn new() -> Result<Self> {
38 let r = image::load_from_memory(SYMBOLS_R)?;
39 let g = image::load_from_memory(SYMBOLS_G)?;
40 let b = image::load_from_memory(SYMBOLS_B)?;
41 let color = image::load_from_memory(SYMBOLS_COLOR)?;
42
43 let mut sheets = HashMap::new();
44 sheets.insert(ImageSheet::R, r);
45 sheets.insert(ImageSheet::G, g);
46 sheets.insert(ImageSheet::B, b);
47 sheets.insert(ImageSheet::Color, color);
48
49 Ok(Self {
50 sheets,
51 symbol_pixels: SYMBOL_PIXELS,
52 })
53 }
54
55 pub(crate) fn get_image(&self, id: SymbolId) -> Option<Image> {
56 let index = ImageIndex::get(id)?;
57 let sheet = self.sheets.get(&index.sheet)?;
58 let (x, y) = Self::get_coordinates(&index);
59 let image = imageops::crop_imm(sheet, x, y, SYMBOL_PIXELS, SYMBOL_PIXELS);
60 Some(Image::new_with_sheet(image, index))
61 }
62
63 fn get_coordinates(index: &ImageIndex) -> (u32, u32) {
64 let x = index.index % SYMBOL_WIDTH_NUM * SYMBOL_PIXELS;
65 let y = index.index / SYMBOL_WIDTH_NUM * SYMBOL_PIXELS;
66 (x, y)
67 }
68}
69
70pub(crate) enum Image<'a> {
71 R(SubImage<&'a DynamicImage>),
72 G(SubImage<&'a DynamicImage>),
73 B(SubImage<&'a DynamicImage>),
74 Color(SubImage<&'a DynamicImage>),
75}
76
77impl<'a> Image<'a> {
78 pub(crate) fn inner(&self) -> &SubImage<&'a DynamicImage> {
79 match self {
80 Image::R(image) => image,
81 Image::G(image) => image,
82 Image::B(image) => image,
83 Image::Color(image) => image,
84 }
85 }
86}
87
88impl std::fmt::Debug for Image<'_> {
89 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90 match self {
91 Image::R(_) => write!(f, "R"),
92 Image::G(_) => write!(f, "G"),
93 Image::B(_) => write!(f, "B"),
94 Image::Color(_) => write!(f, "Color"),
95 }
96 }
97}
98
99impl<'a> Image<'a> {
100 fn new_with_sheet(image: SubImage<&'a DynamicImage>, index: ImageIndex) -> Self {
101 match index.sheet {
102 ImageSheet::R => Self::R(image),
103 ImageSheet::G => Self::G(image),
104 ImageSheet::B => Self::B(image),
105 ImageSheet::Color => Self::Color(image),
106 }
107 }
108}
109
110struct ImageIndex {
111 sheet: ImageSheet,
112 index: u32,
113}
114
115impl ImageIndex {
116 fn get(id: SymbolId) -> Option<Self> {
117 match id.id() {
118 id @ 1..=80 => Some(Self {
119 sheet: ImageSheet::R,
120 index: id,
121 }),
122 id @ 240..=480 => {
123 let offset = match id {
124 305..400 => 240 + 16,
125 _ if id > 400 => 240 + 16 * 2,
126 _ => 240,
127 };
128 Some(Self {
129 sheet: ImageSheet::G,
130 index: id - offset,
131 })
132 }
133 id @ 481..=720 => {
134 let offset = match id {
135 561..641 => 480 + 16,
136 _ if id > 641 => 480 + 16 * 2,
137 _ => 480,
138 };
139 Some(Self {
140 sheet: ImageSheet::B,
141 index: id - offset,
142 })
143 }
144 id @ 721..=768 => Some(Self {
145 sheet: ImageSheet::Color,
146 index: id - 720,
147 }),
148 _ => None,
149 }
150 }
151}
152
153#[cfg(test)]
154mod test {
155 use image::GenericImageView;
156
157 use super::*;
158
159 #[test]
160 fn test_get_image_index() {
161 let index = ImageIndex::get(SymbolId::new(1));
162 assert!(index.is_some());
163 }
164
165 #[test]
166 fn test_get_image() {
167 let resource = Resource::new().unwrap();
168 let image = resource.get_image(SymbolId::new(40)).unwrap();
169 let image2 = resource.get_image(SymbolId::new(41)).unwrap();
170 if let Image::R(image) = image {
171 assert_eq!(image.width(), SYMBOL_PIXELS);
172 } else {
173 panic!("image is not R");
174 }
175 if let Image::R(image) = image2 {
176 assert_eq!(image.width(), SYMBOL_PIXELS);
177 } else {
178 panic!("image2 is not R");
179 }
180 }
181}