|
1 use png::{ColorType, Decoder, DecodingError}; |
1 use std::{ |
2 use std::{ |
2 slice::{ |
3 fs::{read_dir, File}, |
3 from_raw_parts, |
|
4 from_raw_parts_mut |
|
5 }, |
|
6 io, |
4 io, |
7 io::BufReader, |
5 io::BufReader, |
8 fs::{File, read_dir}, |
6 path::Path, |
9 path::Path |
7 slice::{from_raw_parts, from_raw_parts_mut}, |
10 }; |
|
11 use png::{ |
|
12 ColorType, |
|
13 Decoder, |
|
14 DecodingError |
|
15 }; |
8 }; |
16 |
9 |
17 use integral_geometry::Size; |
10 use integral_geometry::Size; |
18 use vec2d::Vec2D; |
11 use vec2d::Vec2D; |
19 |
12 |
20 pub struct ThemeSprite { |
13 pub struct ThemeSprite { |
21 pixels: Vec2D<u32> |
14 pixels: Vec2D<u32>, |
22 } |
15 } |
23 |
16 |
24 impl ThemeSprite { |
17 impl ThemeSprite { |
25 #[inline] |
18 #[inline] |
26 pub fn size(&self) -> Size { |
19 pub fn size(&self) -> Size { |
73 for (x, v) in row.iter().enumerate() { |
66 for (x, v) in row.iter().enumerate() { |
74 pixels[get_tiled_index(x, y, tile_width_shift)] = *v; |
67 pixels[get_tiled_index(x, y, tile_width_shift)] = *v; |
75 } |
68 } |
76 } |
69 } |
77 |
70 |
78 TiledSprite { tile_width_shift, size, pixels } |
71 TiledSprite { |
|
72 tile_width_shift, |
|
73 size, |
|
74 pixels, |
|
75 } |
79 } |
76 } |
80 } |
77 } |
81 |
78 |
82 #[inline] |
79 #[inline] |
83 fn get_tiled_index(x: usize, y: usize, tile_width_shift: usize) -> usize { |
80 fn get_tiled_index(x: usize, y: usize, tile_width_shift: usize) -> usize { |
129 |
126 |
130 #[derive(Debug)] |
127 #[derive(Debug)] |
131 pub enum ThemeLoadError { |
128 pub enum ThemeLoadError { |
132 File(io::Error), |
129 File(io::Error), |
133 Decoding(DecodingError), |
130 Decoding(DecodingError), |
134 Format(String) |
131 Format(String), |
135 } |
132 } |
136 |
133 |
137 impl From<io::Error> for ThemeLoadError { |
134 impl From<io::Error> for ThemeLoadError { |
138 fn from(e: io::Error) -> Self { |
135 fn from(e: io::Error) -> Self { |
139 ThemeLoadError::File(e) |
136 ThemeLoadError::File(e) |
169 Ok(theme) |
166 Ok(theme) |
170 } |
167 } |
171 } |
168 } |
172 |
169 |
173 fn load_sprite(path: &Path) -> Result<ThemeSprite, ThemeLoadError> { |
170 fn load_sprite(path: &Path) -> Result<ThemeSprite, ThemeLoadError> { |
174 let decoder = Decoder::new( |
171 let decoder = Decoder::new(BufReader::new(File::open(path)?)); |
175 BufReader::new(File::open(path)?)); |
|
176 let (info, mut reader) = decoder.read_info()?; |
172 let (info, mut reader) = decoder.read_info()?; |
177 |
173 |
178 if info.color_type != ColorType::RGBA { |
174 if info.color_type != ColorType::RGBA { |
179 return Err(ThemeLoadError::Format( |
175 return Err(ThemeLoadError::Format(format!( |
180 format!("Unexpected format: {:?}", info.color_type))); |
176 "Unexpected format: {:?}", |
|
177 info.color_type |
|
178 ))); |
181 } |
179 } |
182 let size = Size::new(info.width as usize, info.height as usize); |
180 let size = Size::new(info.width as usize, info.height as usize); |
183 |
181 |
184 let mut pixels: Vec2D<u32> = Vec2D::new(size, 0); |
182 let mut pixels: Vec2D<u32> = Vec2D::new(size, 0); |
185 reader.next_frame(slice_u32_to_u8_mut(pixels.as_mut_slice()))?; |
183 reader.next_frame(slice_u32_to_u8_mut(pixels.as_mut_slice()))?; |
186 |
184 |
187 Ok(ThemeSprite { pixels }) |
185 Ok(ThemeSprite { pixels }) |
188 } |
186 } |
189 |
187 |
190 pub fn slice_u32_to_u8(slice_u32: &[u32]) -> &[u8] { |
188 pub fn slice_u32_to_u8(slice_u32: &[u32]) -> &[u8] { |
191 unsafe { |
189 unsafe { from_raw_parts::<u8>(slice_u32.as_ptr() as *const u8, slice_u32.len() * 4) } |
192 from_raw_parts::<u8>( |
|
193 slice_u32.as_ptr() as *const u8, |
|
194 slice_u32.len() * 4 |
|
195 ) |
|
196 } |
|
197 } |
190 } |
198 |
191 |
199 pub fn slice_u32_to_u8_mut(slice_u32: &mut [u32]) -> &mut [u8] { |
192 pub fn slice_u32_to_u8_mut(slice_u32: &mut [u32]) -> &mut [u8] { |
200 unsafe { |
193 unsafe { from_raw_parts_mut::<u8>(slice_u32.as_mut_ptr() as *mut u8, slice_u32.len() * 4) } |
201 from_raw_parts_mut::<u8>( |
|
202 slice_u32.as_mut_ptr() as *mut u8, |
|
203 slice_u32.len() * 4 |
|
204 ) |
|
205 } |
|
206 } |
194 } |
207 |
|