unity_asset_binary/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 = if let Some(type_tree) = &obj.info.type_tree {
30 let properties = obj.parse_with_typetree(type_tree)?;
31 self.parse_from_typetree(&properties)?
32 } else {
33 self.parse_from_binary_data(&obj.info.data)?
34 };
35
36 Ok(SpriteResult::new(sprite))
37 }
38
39 pub fn parse_from_typetree(&self, properties: &IndexMap<String, UnityValue>) -> Result<Sprite> {
41 let mut sprite = Sprite::default();
42
43 if let Some(UnityValue::String(name)) = properties.get("m_Name") {
45 sprite.name = name.clone();
46 }
47
48 if let Some(rect_value) = properties.get("m_Rect") {
50 self.extract_rect(&mut sprite, rect_value)?;
51 }
52
53 if let Some(offset_value) = properties.get("m_Offset") {
55 self.extract_offset(&mut sprite, offset_value)?;
56 }
57
58 if let Some(border_value) = properties.get("m_Border") {
60 self.extract_border(&mut sprite, border_value)?;
61 }
62
63 if let Some(UnityValue::Float(pixels_to_units)) = properties.get("m_PixelsToUnits") {
65 sprite.pixels_to_units = *pixels_to_units as f32;
66 }
67
68 if let Some(pivot_value) = properties.get("m_Pivot") {
70 self.extract_pivot(&mut sprite, pivot_value)?;
71 }
72
73 if let Some(UnityValue::Integer(extrude)) = properties.get("m_Extrude") {
75 sprite.extrude = *extrude as u8;
76 }
77
78 if let Some(UnityValue::Bool(is_polygon)) = properties.get("m_IsPolygon") {
80 sprite.is_polygon = *is_polygon;
81 }
82
83 if let Some(render_data_value) = properties.get("m_RD") {
85 self.extract_render_data(&mut sprite, render_data_value)?;
86 }
87
88 if let Some(atlas_tags_value) = properties.get("m_AtlasTags") {
90 self.extract_atlas_tags(&mut sprite, atlas_tags_value)?;
91 }
92
93 if let Some(sprite_atlas_value) = properties.get("m_SpriteAtlas") {
95 self.extract_sprite_atlas(&mut sprite, sprite_atlas_value)?;
96 }
97
98 Ok(sprite)
99 }
100
101 #[allow(clippy::field_reassign_with_default)]
103 pub fn parse_from_binary_data(&self, data: &[u8]) -> Result<Sprite> {
104 let mut reader = BinaryReader::new(data, crate::reader::ByteOrder::Little);
105 let mut sprite = Sprite::default();
106
107 sprite.name = reader.read_aligned_string()?;
109
110 sprite.rect_x = reader.read_f32()?;
112 sprite.rect_y = reader.read_f32()?;
113 sprite.rect_width = reader.read_f32()?;
114 sprite.rect_height = reader.read_f32()?;
115
116 sprite.offset_x = reader.read_f32()?;
118 sprite.offset_y = reader.read_f32()?;
119
120 sprite.border_x = reader.read_f32()?;
122 sprite.border_y = reader.read_f32()?;
123 sprite.border_z = reader.read_f32()?;
124 sprite.border_w = reader.read_f32()?;
125
126 sprite.pixels_to_units = reader.read_f32()?;
128
129 sprite.pivot_x = reader.read_f32()?;
131 sprite.pivot_y = reader.read_f32()?;
132
133 sprite.extrude = reader.read_u8()?;
135 reader.align_to(4)?; sprite.is_polygon = reader.read_bool()?;
139 reader.align_to(4)?; if reader.remaining() > 0 {
143 self.read_render_data_binary(&mut sprite, &mut reader)?;
144 }
145
146 Ok(sprite)
147 }
148
149 fn extract_rect(&self, sprite: &mut Sprite, rect_value: &UnityValue) -> Result<()> {
151 if let UnityValue::Object(rect_obj) = rect_value {
152 if let Some(UnityValue::Float(x)) = rect_obj.get("x") {
153 sprite.rect_x = *x as f32;
154 }
155 if let Some(UnityValue::Float(y)) = rect_obj.get("y") {
156 sprite.rect_y = *y as f32;
157 }
158 if let Some(UnityValue::Float(width)) = rect_obj.get("width") {
159 sprite.rect_width = *width as f32;
160 }
161 if let Some(UnityValue::Float(height)) = rect_obj.get("height") {
162 sprite.rect_height = *height as f32;
163 }
164 }
165 Ok(())
166 }
167
168 fn extract_offset(&self, sprite: &mut Sprite, offset_value: &UnityValue) -> Result<()> {
170 if let UnityValue::Object(offset_obj) = offset_value {
171 if let Some(UnityValue::Float(x)) = offset_obj.get("x") {
172 sprite.offset_x = *x as f32;
173 }
174 if let Some(UnityValue::Float(y)) = offset_obj.get("y") {
175 sprite.offset_y = *y as f32;
176 }
177 }
178 Ok(())
179 }
180
181 fn extract_border(&self, sprite: &mut Sprite, border_value: &UnityValue) -> Result<()> {
183 if let UnityValue::Object(border_obj) = border_value {
184 if let Some(UnityValue::Float(x)) = border_obj.get("x") {
185 sprite.border_x = *x as f32;
186 }
187 if let Some(UnityValue::Float(y)) = border_obj.get("y") {
188 sprite.border_y = *y as f32;
189 }
190 if let Some(UnityValue::Float(z)) = border_obj.get("z") {
191 sprite.border_z = *z as f32;
192 }
193 if let Some(UnityValue::Float(w)) = border_obj.get("w") {
194 sprite.border_w = *w as f32;
195 }
196 }
197 Ok(())
198 }
199
200 fn extract_pivot(&self, sprite: &mut Sprite, pivot_value: &UnityValue) -> Result<()> {
202 if let UnityValue::Object(pivot_obj) = pivot_value {
203 if let Some(UnityValue::Float(x)) = pivot_obj.get("x") {
204 sprite.pivot_x = *x as f32;
205 }
206 if let Some(UnityValue::Float(y)) = pivot_obj.get("y") {
207 sprite.pivot_y = *y as f32;
208 }
209 }
210 Ok(())
211 }
212
213 fn extract_render_data(
215 &self,
216 sprite: &mut Sprite,
217 render_data_value: &UnityValue,
218 ) -> Result<()> {
219 if let UnityValue::Object(rd_obj) = render_data_value {
220 if let Some(texture_value) = rd_obj.get("texture")
222 && let UnityValue::Object(texture_obj) = texture_value
223 && let Some(UnityValue::Integer(file_id)) = texture_obj.get("m_FileID")
224 {
225 sprite.render_data.texture_path_id = *file_id;
226 }
227
228 if let Some(texture_rect_value) = rd_obj.get("textureRect")
230 && let UnityValue::Object(rect_obj) = texture_rect_value
231 {
232 if let Some(UnityValue::Float(x)) = rect_obj.get("x") {
233 sprite.render_data.texture_rect_x = *x as f32;
234 }
235 if let Some(UnityValue::Float(y)) = rect_obj.get("y") {
236 sprite.render_data.texture_rect_y = *y as f32;
237 }
238 if let Some(UnityValue::Float(width)) = rect_obj.get("width") {
239 sprite.render_data.texture_rect_width = *width as f32;
240 }
241 if let Some(UnityValue::Float(height)) = rect_obj.get("height") {
242 sprite.render_data.texture_rect_height = *height as f32;
243 }
244 }
245
246 if let Some(UnityValue::Float(downscale)) = rd_obj.get("downscaleMultiplier") {
248 sprite.render_data.downscale_multiplier = *downscale as f32;
249 }
250 }
251 Ok(())
252 }
253
254 fn extract_atlas_tags(&self, sprite: &mut Sprite, atlas_tags_value: &UnityValue) -> Result<()> {
256 if let UnityValue::Array(tags_array) = atlas_tags_value {
257 sprite.atlas_tags.clear();
258 for tag_value in tags_array {
259 if let UnityValue::String(tag) = tag_value {
260 sprite.atlas_tags.push(tag.clone());
261 }
262 }
263 }
264 Ok(())
265 }
266
267 fn extract_sprite_atlas(
269 &self,
270 sprite: &mut Sprite,
271 sprite_atlas_value: &UnityValue,
272 ) -> Result<()> {
273 if let UnityValue::Object(atlas_obj) = sprite_atlas_value
274 && let Some(UnityValue::Integer(path_id)) = atlas_obj.get("m_PathID")
275 {
276 sprite.sprite_atlas_path_id = Some(*path_id);
277 }
278 Ok(())
279 }
280
281 fn read_render_data_binary(
283 &self,
284 sprite: &mut Sprite,
285 reader: &mut BinaryReader,
286 ) -> Result<()> {
287 if reader.remaining() >= 4 {
290 sprite.render_data.texture_path_id = reader.read_i64().unwrap_or(0);
291 }
292
293 if reader.remaining() >= 16 {
294 sprite.render_data.texture_rect_x = reader.read_f32().unwrap_or(0.0);
295 sprite.render_data.texture_rect_y = reader.read_f32().unwrap_or(0.0);
296 sprite.render_data.texture_rect_width = reader.read_f32().unwrap_or(0.0);
297 sprite.render_data.texture_rect_height = reader.read_f32().unwrap_or(0.0);
298 }
299
300 Ok(())
301 }
302
303 pub fn version(&self) -> &UnityVersion {
305 &self.version
306 }
307
308 pub fn set_version(&mut self, version: UnityVersion) {
310 self.version = version;
311 }
312}
313
314impl Default for SpriteParser {
315 fn default() -> Self {
316 Self::new(UnityVersion::default())
317 }
318}
319
320#[cfg(test)]
321mod tests {
322 use super::*;
323
324 #[test]
325 fn test_parser_creation() {
326 let parser = SpriteParser::new(UnityVersion::default());
327 assert_eq!(parser.version(), &UnityVersion::default());
328 }
329
330 #[test]
331 fn test_extract_rect() {
332 let parser = SpriteParser::default();
333 let mut sprite = Sprite::default();
334
335 let mut rect_obj = IndexMap::new();
336 rect_obj.insert("x".to_string(), UnityValue::Float(10.0));
337 rect_obj.insert("y".to_string(), UnityValue::Float(20.0));
338 rect_obj.insert("width".to_string(), UnityValue::Float(100.0));
339 rect_obj.insert("height".to_string(), UnityValue::Float(200.0));
340
341 let rect_value = UnityValue::Object(rect_obj);
342 parser.extract_rect(&mut sprite, &rect_value).unwrap();
343
344 assert_eq!(sprite.rect_x, 10.0);
345 assert_eq!(sprite.rect_y, 20.0);
346 assert_eq!(sprite.rect_width, 100.0);
347 assert_eq!(sprite.rect_height, 200.0);
348 }
349}