unity_asset_decode/sprite/
parser.rs1use super::types::*;
6use crate::error::Result;
7use crate::object::UnityObject;
8use crate::reader::BinaryReader;
9use crate::unity_version::UnityVersion;
10use indexmap::IndexMap;
11use unity_asset_core::UnityValue;
12
13pub struct SpriteParser {
18 version: UnityVersion,
19}
20
21impl SpriteParser {
22 pub fn new(version: UnityVersion) -> Self {
24 Self { version }
25 }
26
27 pub fn parse_from_unity_object(&self, obj: &UnityObject) -> Result<SpriteResult> {
29 let sprite = self
30 .parse_from_typetree(obj.class.properties())
31 .or_else(|_| self.parse_from_binary_data(obj.raw_data()))?;
32
33 Ok(SpriteResult::new(sprite))
34 }
35
36 pub fn parse_from_typetree(&self, properties: &IndexMap<String, UnityValue>) -> Result<Sprite> {
38 let mut sprite = Sprite::default();
39
40 if let Some(UnityValue::String(name)) = properties.get("m_Name") {
42 sprite.name = name.clone();
43 }
44
45 if let Some(rect_value) = properties.get("m_Rect") {
47 self.extract_rect(&mut sprite, rect_value)?;
48 }
49
50 if let Some(offset_value) = properties.get("m_Offset") {
52 self.extract_offset(&mut sprite, offset_value)?;
53 }
54
55 if let Some(border_value) = properties.get("m_Border") {
57 self.extract_border(&mut sprite, border_value)?;
58 }
59
60 if let Some(UnityValue::Float(pixels_to_units)) = properties.get("m_PixelsToUnits") {
62 sprite.pixels_to_units = *pixels_to_units as f32;
63 }
64
65 if let Some(pivot_value) = properties.get("m_Pivot") {
67 self.extract_pivot(&mut sprite, pivot_value)?;
68 }
69
70 if let Some(UnityValue::Integer(extrude)) = properties.get("m_Extrude") {
72 sprite.extrude = *extrude as u8;
73 }
74
75 if let Some(UnityValue::Bool(is_polygon)) = properties.get("m_IsPolygon") {
77 sprite.is_polygon = *is_polygon;
78 }
79
80 if let Some(render_data_value) = properties.get("m_RD") {
82 self.extract_render_data(&mut sprite, render_data_value)?;
83 }
84
85 if let Some(atlas_tags_value) = properties.get("m_AtlasTags") {
87 self.extract_atlas_tags(&mut sprite, atlas_tags_value)?;
88 }
89
90 if let Some(sprite_atlas_value) = properties.get("m_SpriteAtlas") {
92 self.extract_sprite_atlas(&mut sprite, sprite_atlas_value)?;
93 }
94
95 Ok(sprite)
96 }
97
98 #[allow(clippy::field_reassign_with_default)]
100 pub fn parse_from_binary_data(&self, data: &[u8]) -> Result<Sprite> {
101 let mut reader = BinaryReader::new(data, crate::reader::ByteOrder::Little);
102 let mut sprite = Sprite::default();
103
104 sprite.name = reader.read_aligned_string()?;
106
107 sprite.rect_x = reader.read_f32()?;
109 sprite.rect_y = reader.read_f32()?;
110 sprite.rect_width = reader.read_f32()?;
111 sprite.rect_height = reader.read_f32()?;
112
113 sprite.offset_x = reader.read_f32()?;
115 sprite.offset_y = reader.read_f32()?;
116
117 sprite.border_x = reader.read_f32()?;
119 sprite.border_y = reader.read_f32()?;
120 sprite.border_z = reader.read_f32()?;
121 sprite.border_w = reader.read_f32()?;
122
123 sprite.pixels_to_units = reader.read_f32()?;
125
126 sprite.pivot_x = reader.read_f32()?;
128 sprite.pivot_y = reader.read_f32()?;
129
130 sprite.extrude = reader.read_u8()?;
132 reader.align_to(4)?; sprite.is_polygon = reader.read_bool()?;
136 reader.align_to(4)?; if reader.remaining() > 0 {
140 self.read_render_data_binary(&mut sprite, &mut reader)?;
141 }
142
143 Ok(sprite)
144 }
145
146 fn extract_rect(&self, sprite: &mut Sprite, rect_value: &UnityValue) -> Result<()> {
148 if let UnityValue::Object(rect_obj) = rect_value {
149 if let Some(UnityValue::Float(x)) = rect_obj.get("x") {
150 sprite.rect_x = *x as f32;
151 }
152 if let Some(UnityValue::Float(y)) = rect_obj.get("y") {
153 sprite.rect_y = *y as f32;
154 }
155 if let Some(UnityValue::Float(width)) = rect_obj.get("width") {
156 sprite.rect_width = *width as f32;
157 }
158 if let Some(UnityValue::Float(height)) = rect_obj.get("height") {
159 sprite.rect_height = *height as f32;
160 }
161 }
162 Ok(())
163 }
164
165 fn extract_offset(&self, sprite: &mut Sprite, offset_value: &UnityValue) -> Result<()> {
167 if let UnityValue::Object(offset_obj) = offset_value {
168 if let Some(UnityValue::Float(x)) = offset_obj.get("x") {
169 sprite.offset_x = *x as f32;
170 }
171 if let Some(UnityValue::Float(y)) = offset_obj.get("y") {
172 sprite.offset_y = *y as f32;
173 }
174 }
175 Ok(())
176 }
177
178 fn extract_border(&self, sprite: &mut Sprite, border_value: &UnityValue) -> Result<()> {
180 if let UnityValue::Object(border_obj) = border_value {
181 if let Some(UnityValue::Float(x)) = border_obj.get("x") {
182 sprite.border_x = *x as f32;
183 }
184 if let Some(UnityValue::Float(y)) = border_obj.get("y") {
185 sprite.border_y = *y as f32;
186 }
187 if let Some(UnityValue::Float(z)) = border_obj.get("z") {
188 sprite.border_z = *z as f32;
189 }
190 if let Some(UnityValue::Float(w)) = border_obj.get("w") {
191 sprite.border_w = *w as f32;
192 }
193 }
194 Ok(())
195 }
196
197 fn extract_pivot(&self, sprite: &mut Sprite, pivot_value: &UnityValue) -> Result<()> {
199 if let UnityValue::Object(pivot_obj) = pivot_value {
200 if let Some(UnityValue::Float(x)) = pivot_obj.get("x") {
201 sprite.pivot_x = *x as f32;
202 }
203 if let Some(UnityValue::Float(y)) = pivot_obj.get("y") {
204 sprite.pivot_y = *y as f32;
205 }
206 }
207 Ok(())
208 }
209
210 fn extract_render_data(
212 &self,
213 sprite: &mut Sprite,
214 render_data_value: &UnityValue,
215 ) -> Result<()> {
216 if let UnityValue::Object(rd_obj) = render_data_value {
217 if let Some(UnityValue::Object(texture_obj)) = rd_obj.get("texture") {
219 if let Some(UnityValue::Integer(path_id)) = texture_obj.get("m_PathID") {
220 sprite.render_data.texture_path_id = *path_id;
221 }
222 }
223
224 if let Some(UnityValue::Object(rect_obj)) = rd_obj.get("textureRect") {
226 if let Some(UnityValue::Float(x)) = rect_obj.get("x") {
227 sprite.render_data.texture_rect_x = *x as f32;
228 }
229 if let Some(UnityValue::Float(y)) = rect_obj.get("y") {
230 sprite.render_data.texture_rect_y = *y as f32;
231 }
232 if let Some(UnityValue::Float(width)) = rect_obj.get("width") {
233 sprite.render_data.texture_rect_width = *width as f32;
234 }
235 if let Some(UnityValue::Float(height)) = rect_obj.get("height") {
236 sprite.render_data.texture_rect_height = *height as f32;
237 }
238 }
239
240 if let Some(UnityValue::Float(downscale)) = rd_obj.get("downscaleMultiplier") {
242 sprite.render_data.downscale_multiplier = *downscale as f32;
243 }
244 }
245 Ok(())
246 }
247
248 fn extract_atlas_tags(&self, sprite: &mut Sprite, atlas_tags_value: &UnityValue) -> Result<()> {
250 if let UnityValue::Array(tags_array) = atlas_tags_value {
251 sprite.atlas_tags.clear();
252 for tag_value in tags_array {
253 if let UnityValue::String(tag) = tag_value {
254 sprite.atlas_tags.push(tag.clone());
255 }
256 }
257 }
258 Ok(())
259 }
260
261 fn extract_sprite_atlas(
263 &self,
264 sprite: &mut Sprite,
265 sprite_atlas_value: &UnityValue,
266 ) -> Result<()> {
267 if let UnityValue::Object(atlas_obj) = sprite_atlas_value {
268 if let Some(UnityValue::Integer(path_id)) = atlas_obj.get("m_PathID") {
269 sprite.sprite_atlas_path_id = Some(*path_id);
270 }
271 }
272 Ok(())
273 }
274
275 fn read_render_data_binary(
277 &self,
278 sprite: &mut Sprite,
279 reader: &mut BinaryReader,
280 ) -> Result<()> {
281 if reader.remaining() >= 4 {
284 sprite.render_data.texture_path_id = reader.read_i64().unwrap_or(0);
285 }
286
287 if reader.remaining() >= 16 {
288 sprite.render_data.texture_rect_x = reader.read_f32().unwrap_or(0.0);
289 sprite.render_data.texture_rect_y = reader.read_f32().unwrap_or(0.0);
290 sprite.render_data.texture_rect_width = reader.read_f32().unwrap_or(0.0);
291 sprite.render_data.texture_rect_height = reader.read_f32().unwrap_or(0.0);
292 }
293
294 Ok(())
295 }
296
297 pub fn version(&self) -> &UnityVersion {
299 &self.version
300 }
301
302 pub fn set_version(&mut self, version: UnityVersion) {
304 self.version = version;
305 }
306}
307
308impl Default for SpriteParser {
309 fn default() -> Self {
310 Self::new(UnityVersion::default())
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 #[test]
319 fn test_parser_creation() {
320 let parser = SpriteParser::new(UnityVersion::default());
321 assert_eq!(parser.version(), &UnityVersion::default());
322 }
323
324 #[test]
325 fn test_extract_rect() {
326 let parser = SpriteParser::default();
327 let mut sprite = Sprite::default();
328
329 let mut rect_obj = IndexMap::new();
330 rect_obj.insert("x".to_string(), UnityValue::Float(10.0));
331 rect_obj.insert("y".to_string(), UnityValue::Float(20.0));
332 rect_obj.insert("width".to_string(), UnityValue::Float(100.0));
333 rect_obj.insert("height".to_string(), UnityValue::Float(200.0));
334
335 let rect_value = UnityValue::Object(rect_obj);
336 parser.extract_rect(&mut sprite, &rect_value).unwrap();
337
338 assert_eq!(sprite.rect_x, 10.0);
339 assert_eq!(sprite.rect_y, 20.0);
340 assert_eq!(sprite.rect_width, 100.0);
341 assert_eq!(sprite.rect_height, 200.0);
342 }
343}