1use crate::get_bit_u16;
2use crate::FragmentFlip;
3use crate::OamShape;
4use crate::WanError;
5use anyhow::bail;
6use byteorder::WriteBytesExt;
7use byteorder::{ReadBytesExt, LE};
8use std::io::{Read, Write};
9
10#[derive(Debug, PartialEq, Eq, Clone)]
12pub struct Fragment {
13 pub unk1: u16,
14 pub unk3_4: Option<(bool, bool)>,
18 pub unk5: bool, pub fragment_bytes_index: usize,
20 pub offset_y: i8,
21 pub offset_x: i16,
22 pub flip: FragmentFlip,
23 pub is_mosaic: bool,
24 pub pal_idx: u16,
25 pub resolution: OamShape,
26}
27
28impl Fragment {
29 pub fn new_from_bytes<F: Read>(
32 file: &mut F,
33 previous_fragment_bytes: Option<usize>,
34 ) -> Result<(Fragment, bool), WanError> {
35 trace!("parsing a fragment");
36 let fragment_bytes_index = match file.read_i16::<LE>()? {
37 -1 => match previous_fragment_bytes {
38 None => return Err(WanError::FragmentBytesIDPointBackButFirstFragment),
39 Some(value) => value,
40 },
41 x => {
42 if x >= 0 {
43 x as usize
44 } else {
45 return Err(WanError::FragmentLessThanLessOne(x));
46 }
47 }
48 };
49
50 let unk1 = file.read_u16::<LE>()?;
51
52 let offset_y_data = file.read_u16::<LE>()?;
56 let size_indice_y = ((0xC000 & offset_y_data) >> (8 + 6)) as u8;
57 let is_mosaic = get_bit_u16(offset_y_data, 3).unwrap(); let unk3 = get_bit_u16(offset_y_data, 7).unwrap();
59 let unk4 = get_bit_u16(offset_y_data, 6).unwrap();
60 let offset_y = (offset_y_data & 0x00FF) as i8; #[allow(clippy::collapsible_else_if)]
63 let unk3_4 = if offset_y < 0 {
64 if unk3 && !unk4 {
65 None
66 } else {
67 Some((unk3, unk4))
68 }
69 } else {
70 if !unk3 && unk4 {
71 None
72 } else {
73 Some((unk3, unk4))
74 }
75 };
76
77 let offset_x_data = file.read_u16::<LE>()?;
78 let size_indice_x = ((0xC000 & offset_x_data) >> (8 + 6)) as u8;
79 let v_flip = get_bit_u16(offset_x_data, 2).unwrap(); let h_flip = get_bit_u16(offset_x_data, 3).unwrap();
81 let flip = FragmentFlip::from_bools(v_flip, h_flip);
82 let is_last = get_bit_u16(offset_x_data, 4).unwrap();
83 let unk5 = get_bit_u16(offset_x_data, 5).unwrap();
84 let offset_x = (offset_x_data & 0x01FF) as i16 - 256; let alloc_and_palette = file.read_u16::<LE>()?;
87 let pal_idx = (0xF000 & alloc_and_palette) >> 12;
88
89 Ok((
90 Fragment {
91 unk1,
92 unk3_4,
93 unk5,
94 fragment_bytes_index,
95 offset_x,
96 offset_y,
97 flip,
98 is_mosaic,
99 pal_idx,
100 resolution: match OamShape::new(size_indice_y, size_indice_x) {
101 Some(r) => r,
102 None => {
103 return Err(WanError::InvalidResolutionIndice(
104 size_indice_x,
105 size_indice_y,
106 ))
107 }
108 },
109 },
110 is_last,
111 ))
112 }
113
114 pub fn write<F: Write>(
115 &self,
116 file: &mut F,
117 previous_fragment_bytes: Option<usize>,
118 is_last: bool,
119 fragment_alloc_counter: u16,
120 ) -> anyhow::Result<()> {
121 let fragment_bytes_index: i16 = match previous_fragment_bytes {
123 None => self.fragment_bytes_index as i16,
124 Some(value) => {
125 if self.fragment_bytes_index == value {
126 -1
127 } else {
128 self.fragment_bytes_index as i16
129 }
130 }
131 };
132
133 file.write_i16::<LE>(fragment_bytes_index)?;
134 file.write_u16::<LE>(self.unk1)?;
135
136 let (unk3, unk4) = match self.unk3_4 {
137 Some((unk3, unk4)) => (unk3, unk4),
138 None => {
139 let unk3 = self.offset_y < 0;
140 (unk3, !unk3)
141 }
142 };
143
144 let offset_y_data: u16 = ((self.resolution.shape_indice() as u16) << (8 + 6))
145 + if self.is_mosaic { 1 << (8 + 4) } else { 0 }
146 + ((unk4 as u16) << (8 + 1))
147 + ((unk3 as u16) << 8)
148 + ((self.offset_y as u16) & 0x00FF);
149
150 let written_offset_x = self.offset_x + 256;
151 if written_offset_x >= 0x200 {
152 bail!(
153 "The x coordinate of this metaframe is more than 255 (it is {})",
154 self.offset_x
155 );
156 }
157 if written_offset_x < 0 {
158 bail!(
159 "The x coordinate of this metaframe is less than 256 (it is {})",
160 self.offset_x
161 );
162 }
163
164 let (v_flip, h_flip) = self.flip.to_bools();
165
166 let offset_x_data: u16 = ((self.resolution.size_indice() as u16) << (8 + 6))
167 + ((v_flip as u16) << (8 + 5))
168 + ((h_flip as u16) << (8 + 4))
169 + ((is_last as u16) << (8 + 3))
170 + ((self.unk5 as u16) << (8 + 2))
171 + (((written_offset_x) as u16) & 0x01FF);
172
173 file.write_u16::<LE>(offset_y_data)?;
174 file.write_u16::<LE>(offset_x_data)?;
175 file.write_u16::<LE>(
176 ((self.pal_idx & 0xF) << 12) + 0x0C00 + (fragment_alloc_counter & 0x3FF),
177 )?;
178
179 Ok(())
180 }
181}