1#[cfg(feature = "image")]
23use crate::color::Color;
24use crate::color::Color16;
25use crate::error::{MEMWRITER_ERROR, MulReaderError, MulReaderResult};
26use crate::mul::MulReader;
27use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
28use std::fs::File;
29use std::io::{Cursor, Read, Seek, SeekFrom, Write};
30use std::path::Path;
31
32#[cfg(feature = "image")]
33use image::{Rgba, RgbaImage};
34
35pub trait Art {
37 fn serialize(&self) -> Vec<u8>;
39
40 #[cfg(feature = "image")]
42 fn to_image(&self) -> RgbaImage;
43}
44
45pub const TILE_SIZE: u32 = 2048;
46pub const STATIC_OFFSET: u32 = 0x4000;
47
48#[derive(Debug, PartialEq, Eq, Clone)]
51pub struct RunPair {
52 pub offset: u16,
53 pub run: Vec<Color16>,
54}
55
56impl RunPair {
57 fn serialize(&self) -> Vec<u8> {
58 let mut writer = vec![];
59
60 writer
61 .write_u16::<LittleEndian>(self.offset)
62 .expect(MEMWRITER_ERROR);
63 writer
64 .write_u16::<LittleEndian>(self.run.len() as u16)
65 .expect(MEMWRITER_ERROR);
66 for &color in self.run.iter() {
67 writer
68 .write_u16::<LittleEndian>(color)
69 .expect(MEMWRITER_ERROR);
70 }
71 writer
72 }
73}
74
75pub type StaticRow = Vec<RunPair>;
76
77#[derive(Debug, PartialEq, Eq, Clone)]
79pub struct Tile {
80 pub header: u32,
82 pub image_data: [Color16; 1022],
85}
86
87impl Art for Tile {
88 fn serialize(&self) -> Vec<u8> {
89 let mut writer = vec![];
90 writer
91 .write_u32::<LittleEndian>(self.header)
92 .expect(MEMWRITER_ERROR);
93 for &pixel in self.image_data.iter() {
94 writer
95 .write_u16::<LittleEndian>(pixel)
96 .expect(MEMWRITER_ERROR);
97 }
98 writer
99 }
100
101 #[cfg(feature = "image")]
102 fn to_image(&self) -> RgbaImage {
103 let mut buffer = RgbaImage::new(44, 44);
104 let mut read_idx = 0;
105
106 for y in 0..44 {
107 let slice_size = if y >= 22 { (44 - y) * 2 } else { (y + 1) * 2 };
108
109 let indent = 22 - (slice_size / 2);
110
111 for x in 0..slice_size {
112 let (r, g, b, a) = self.image_data[read_idx].to_rgba();
113 buffer.put_pixel(indent + x, y, Rgba([r, g, b, a]));
114 read_idx += 1;
115 }
116 }
117 buffer
118 }
119}
120
121impl Art for Static {
122 fn serialize(&self) -> Vec<u8> {
123 let mut writer = vec![];
124 writer
125 .write_u16::<LittleEndian>(self.size)
126 .expect(MEMWRITER_ERROR);
127 writer
128 .write_u16::<LittleEndian>(self.trigger)
129 .expect(MEMWRITER_ERROR);
130 writer
131 .write_u16::<LittleEndian>(self.width)
132 .expect(MEMWRITER_ERROR);
133 writer
134 .write_u16::<LittleEndian>(self.height)
135 .expect(MEMWRITER_ERROR);
136
137 let mut rows = vec![];
138
139 for row in self.rows.iter() {
141 let mut out = vec![];
142 for pair in row.iter() {
143 out.write_all(pair.serialize().as_slice())
144 .expect(MEMWRITER_ERROR);
145 }
146 out.write_u16::<LittleEndian>(0).expect(MEMWRITER_ERROR);
148 out.write_u16::<LittleEndian>(0).expect(MEMWRITER_ERROR);
149 rows.push(out);
150 }
151
152 let mut lookup_table = vec![];
153 let mut last_position = 0;
154 for row in rows.iter() {
156 lookup_table
157 .write_u16::<LittleEndian>(last_position)
158 .expect(MEMWRITER_ERROR);
159 last_position += (row.len() / 2) as u16;
160 }
161 writer
162 .write_all(lookup_table.as_slice())
163 .expect(MEMWRITER_ERROR);
164 for row in rows.iter() {
165 writer.write_all(row.as_slice()).expect(MEMWRITER_ERROR);
166 }
167
168 writer
169 }
170
171 #[cfg(feature = "image")]
172 fn to_image(&self) -> RgbaImage {
173 let mut buffer = RgbaImage::new(self.width as u32, self.height as u32);
174 for (y, row) in self.rows.iter().enumerate() {
175 let mut x: u32 = 0;
176 for run_pair in row.iter() {
177 x += run_pair.offset as u32;
178 for pixel in run_pair.run.iter() {
179 let (r, g, b, a) = pixel.to_rgba();
180 buffer.put_pixel(x, y as u32, Rgba([r, g, b, a]));
181 x += 1;
182 }
183 }
184 }
185 buffer
186 }
187}
188
189#[derive(Debug, PartialEq, Eq, Clone)]
191pub struct Static {
192 pub size: u16,
194 pub trigger: u16,
196 pub width: u16,
198 pub height: u16,
200 pub rows: Vec<StaticRow>,
202}
203
204#[derive(Debug)]
206pub struct ArtReader<T: Read + Seek> {
207 mul_reader: MulReader<T>,
208}
209
210impl ArtReader<File> {
211 pub fn new(index_path: &Path, mul_path: &Path) -> MulReaderResult<ArtReader<File>> {
213 let mul_reader = MulReader::new(index_path, mul_path)?;
214 Ok(ArtReader { mul_reader })
215 }
216}
217
218impl<T: Read + Seek> ArtReader<T> {
219 pub fn from_mul(reader: MulReader<T>) -> ArtReader<T> {
221 ArtReader { mul_reader: reader }
222 }
223
224 pub fn read_tile(&mut self, id: u32) -> MulReaderResult<Tile> {
226 if id >= STATIC_OFFSET {
227 return Err(MulReaderError::IndexOutOfBounds(id));
228 }
229
230 let raw = self.mul_reader.read(id)?;
231 let mut reader = Cursor::new(raw.data);
232
233 if raw.length > TILE_SIZE {
234 return Err(MulReaderError::UnexpectedSize {
235 found: raw.length,
236 expected: TILE_SIZE,
237 });
238 }
239
240 let header = reader.read_u32::<LittleEndian>()?;
241 let mut body = [0; 1022];
242 for cell in &mut body {
243 *cell = reader.read_u16::<LittleEndian>().unwrap_or(0);
244 }
245 Ok(Tile {
246 header,
247 image_data: body,
248 })
249 }
250
251 pub fn read_static(&mut self, id: u32) -> MulReaderResult<Static> {
255 let offset_id = id + STATIC_OFFSET;
256
257 let raw = self.mul_reader.read(offset_id)?;
258 let mut reader = Cursor::new(raw.data);
259
260 let size = reader.read_u16::<LittleEndian>()?;
261 let trigger = reader.read_u16::<LittleEndian>()?;
262 let width = reader.read_u16::<LittleEndian>()?;
263 let height = reader.read_u16::<LittleEndian>()?;
264
265 if width == 0 || width >= 1024 || height == 0 || height >= 1024 {
266 return Err(MulReaderError::FailedParse(format!(
267 "Got invalid width and height of {}, {}",
268 width, height
269 )));
270 }
271
272 let mut offset_table = vec![];
274 for _index in 0..height {
275 offset_table.push(reader.read_u16::<LittleEndian>()?);
276 }
277
278 let data_start_pos = reader.position();
279 let mut rows = vec![];
280
281 for &offset in offset_table.iter() {
282 reader.seek(SeekFrom::Start(data_start_pos + offset as u64 * 2))?;
283 let mut row = vec![];
284
285 loop {
286 let x_offset = reader.read_u16::<LittleEndian>()?;
287 let run_length = reader.read_u16::<LittleEndian>()?;
288 if x_offset + run_length == 0 {
289 break;
290 } else {
291 let mut run = vec![];
292 for _index in 0..run_length {
293 run.push(reader.read_u16::<LittleEndian>()?);
294 }
295
296 row.push(RunPair {
297 offset: x_offset,
298 run,
299 });
300 }
301 }
302 rows.push(row);
303 }
304
305 Ok(Static {
306 size,
307 trigger,
308 width,
309 height,
310 rows,
311 })
312 }
313}