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