unity_asset_decode/mesh/
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 MeshParser {
18 version: UnityVersion,
19}
20
21impl MeshParser {
22 pub fn new(version: UnityVersion) -> Self {
24 Self { version }
25 }
26
27 pub fn parse_from_unity_object(&self, obj: &UnityObject) -> Result<MeshResult> {
29 let mesh = self
30 .parse_from_typetree(obj.class.properties())
31 .or_else(|_| self.parse_from_binary_data(obj.raw_data()))?;
32
33 Ok(MeshResult::new(mesh))
34 }
35
36 pub fn parse_from_typetree(&self, properties: &IndexMap<String, UnityValue>) -> Result<Mesh> {
38 let mut mesh = Mesh::default();
39
40 if let Some(UnityValue::String(name)) = properties.get("m_Name") {
42 mesh.name = name.clone();
43 }
44
45 if let Some(sub_meshes_value) = properties.get("m_SubMeshes") {
47 self.extract_sub_meshes(&mut mesh, sub_meshes_value)?;
48 }
49
50 if let Some(vertex_data_value) = properties.get("m_VertexData") {
52 self.extract_vertex_data(&mut mesh, vertex_data_value)?;
53 }
54
55 if let Some(index_buffer_value) = properties.get("m_IndexBuffer") {
57 self.extract_index_buffer(&mut mesh, index_buffer_value)?;
58 }
59
60 if let Some(UnityValue::Bool(is_readable)) = properties.get("m_IsReadable") {
62 mesh.is_readable = *is_readable;
63 }
64
65 if let Some(local_aabb_value) = properties.get("m_LocalAABB") {
67 self.extract_local_aabb(&mut mesh, local_aabb_value)?;
68 }
69
70 if let Some(UnityValue::Integer(compression)) = properties.get("m_MeshCompression") {
72 mesh.mesh_compression = *compression as u8;
73 }
74
75 if let Some(stream_data) = properties.get("m_StreamData") {
77 mesh.stream_data = self.extract_stream_data(stream_data)?;
78 }
79
80 if let Some(blend_shapes_value) = properties.get("m_Shapes") {
82 mesh.blend_shape_data = self.extract_blend_shapes(blend_shapes_value)?;
83 }
84
85 if let Some(bind_poses_value) = properties.get("m_BindPose") {
87 self.extract_bind_poses(&mut mesh, bind_poses_value)?;
88 }
89
90 Ok(mesh)
91 }
92
93 #[allow(clippy::field_reassign_with_default)]
95 pub fn parse_from_binary_data(&self, data: &[u8]) -> Result<Mesh> {
96 let mut reader = BinaryReader::new(data, crate::reader::ByteOrder::Little);
97 let mut mesh = Mesh::default();
98
99 mesh.name = reader.read_aligned_string()?;
101
102 mesh.is_readable = reader.read_bool()?;
104 mesh.keep_vertices = reader.read_bool()?;
105 mesh.keep_indices = reader.read_bool()?;
106
107 mesh.index_format = reader.read_i32()?;
109
110 let index_buffer_size = reader.read_i32()? as usize;
112 if index_buffer_size > 0 {
113 mesh.index_buffer = reader.read_bytes(index_buffer_size)?;
114 }
115
116 mesh.mesh_compression = reader.read_u8()?;
118
119 Ok(mesh)
120 }
121
122 fn extract_sub_meshes(&self, mesh: &mut Mesh, value: &UnityValue) -> Result<()> {
124 if let UnityValue::Array(sub_meshes_array) = value {
125 mesh.sub_meshes.clear();
126 for sub_mesh_value in sub_meshes_array {
127 if let UnityValue::Object(sub_mesh_obj) = sub_mesh_value {
128 let mut sub_mesh = SubMesh::default();
129
130 if let Some(UnityValue::Integer(first_byte)) = sub_mesh_obj.get("firstByte") {
131 sub_mesh.first_byte = *first_byte as u32;
132 }
133 if let Some(UnityValue::Integer(index_count)) = sub_mesh_obj.get("indexCount") {
134 sub_mesh.index_count = *index_count as u32;
135 }
136 if let Some(UnityValue::Integer(topology)) = sub_mesh_obj.get("topology") {
137 sub_mesh.topology = *topology as i32;
138 }
139 if let Some(UnityValue::Integer(triangle_count)) =
140 sub_mesh_obj.get("triangleCount")
141 {
142 sub_mesh.triangle_count = *triangle_count as u32;
143 }
144
145 mesh.sub_meshes.push(sub_mesh);
146 }
147 }
148 }
149 Ok(())
150 }
151
152 fn extract_vertex_data(&self, mesh: &mut Mesh, value: &UnityValue) -> Result<()> {
154 if let UnityValue::Object(vertex_data_obj) = value {
155 if let Some(UnityValue::Integer(vertex_count)) = vertex_data_obj.get("m_VertexCount") {
156 mesh.vertex_data.vertex_count = *vertex_count as u32;
157 }
158
159 if let Some(channels_value) = vertex_data_obj.get("m_Channels") {
161 self.extract_vertex_channels(&mut mesh.vertex_data, channels_value)?;
162 }
163
164 if let Some(data_size_value) = vertex_data_obj.get("m_DataSize") {
166 match data_size_value {
167 UnityValue::Bytes(b) => {
168 mesh.vertex_data.data_size = b.clone();
169 }
170 UnityValue::Array(arr) => {
171 mesh.vertex_data.data_size.clear();
172 for item in arr {
173 if let UnityValue::Integer(byte_val) = item {
174 mesh.vertex_data.data_size.push(*byte_val as u8);
175 }
176 }
177 }
178 _ => {}
179 }
180 }
181 }
182 Ok(())
183 }
184
185 fn extract_vertex_channels(
187 &self,
188 vertex_data: &mut VertexData,
189 value: &UnityValue,
190 ) -> Result<()> {
191 if let UnityValue::Array(channels_array) = value {
192 vertex_data.channels.clear();
193 for channel_value in channels_array {
194 if let UnityValue::Object(channel_obj) = channel_value {
195 let mut channel = ChannelInfo::default();
196
197 if let Some(UnityValue::Integer(stream)) = channel_obj.get("stream") {
198 channel.stream = *stream as u8;
199 }
200 if let Some(UnityValue::Integer(offset)) = channel_obj.get("offset") {
201 channel.offset = *offset as u8;
202 }
203 if let Some(UnityValue::Integer(format)) = channel_obj.get("format") {
204 channel.format = *format as u8;
205 }
206 if let Some(UnityValue::Integer(dimension)) = channel_obj.get("dimension") {
207 channel.dimension = *dimension as u8;
208 }
209
210 vertex_data.channels.push(channel);
211 }
212 }
213 }
214 Ok(())
215 }
216
217 fn extract_index_buffer(&self, mesh: &mut Mesh, value: &UnityValue) -> Result<()> {
219 match value {
220 UnityValue::Bytes(b) => {
221 mesh.index_buffer = b.clone();
222 }
223 UnityValue::Array(arr) => {
224 mesh.index_buffer.clear();
225 for item in arr {
226 if let UnityValue::Integer(byte_val) = item {
227 mesh.index_buffer.push(*byte_val as u8);
228 }
229 }
230 }
231 _ => {
232 }
234 }
235 Ok(())
236 }
237
238 fn extract_local_aabb(&self, mesh: &mut Mesh, value: &UnityValue) -> Result<()> {
240 if let UnityValue::Object(aabb_obj) = value {
241 if let Some(UnityValue::Object(center_obj)) = aabb_obj.get("m_Center") {
243 if let Some(UnityValue::Float(x)) = center_obj.get("x") {
244 mesh.local_aabb.center_x = *x as f32;
245 }
246 if let Some(UnityValue::Float(y)) = center_obj.get("y") {
247 mesh.local_aabb.center_y = *y as f32;
248 }
249 if let Some(UnityValue::Float(z)) = center_obj.get("z") {
250 mesh.local_aabb.center_z = *z as f32;
251 }
252 }
253
254 if let Some(UnityValue::Object(extent_obj)) = aabb_obj.get("m_Extent") {
256 if let Some(UnityValue::Float(x)) = extent_obj.get("x") {
257 mesh.local_aabb.extent_x = *x as f32;
258 }
259 if let Some(UnityValue::Float(y)) = extent_obj.get("y") {
260 mesh.local_aabb.extent_y = *y as f32;
261 }
262 if let Some(UnityValue::Float(z)) = extent_obj.get("z") {
263 mesh.local_aabb.extent_z = *z as f32;
264 }
265 }
266 }
267 Ok(())
268 }
269
270 fn extract_stream_data(&self, value: &UnityValue) -> Result<Option<StreamingInfo>> {
272 if let UnityValue::Object(stream_obj) = value {
273 let mut stream_info = StreamingInfo::default();
274
275 if let Some(UnityValue::Integer(offset)) = stream_obj.get("offset") {
276 stream_info.offset = *offset as u64;
277 }
278 if let Some(UnityValue::Integer(size)) = stream_obj.get("size") {
279 stream_info.size = *size as u32;
280 }
281 if let Some(UnityValue::String(path)) = stream_obj.get("path") {
282 stream_info.path = path.clone();
283 }
284
285 if stream_info.size > 0 || !stream_info.path.is_empty() {
287 return Ok(Some(stream_info));
288 }
289 }
290 Ok(None)
291 }
292
293 fn extract_blend_shapes(&self, _value: &UnityValue) -> Result<Option<BlendShapeData>> {
295 Ok(None)
298 }
299
300 fn extract_bind_poses(&self, mesh: &mut Mesh, value: &UnityValue) -> Result<()> {
302 if let UnityValue::Array(bind_poses_array) = value {
303 mesh.bind_pose.clear();
304 for bind_pose_value in bind_poses_array {
305 if let UnityValue::Object(matrix_obj) = bind_pose_value {
306 let mut matrix = [0.0f32; 16];
307
308 for (i, matrix_element) in matrix.iter_mut().enumerate() {
310 let key = format!("e{:02}", i);
311 if let Some(UnityValue::Float(val)) = matrix_obj.get(&key) {
312 *matrix_element = *val as f32;
313 }
314 }
315
316 mesh.bind_pose.push(matrix);
317 }
318 }
319 }
320 Ok(())
321 }
322
323 pub fn version(&self) -> &UnityVersion {
325 &self.version
326 }
327
328 pub fn set_version(&mut self, version: UnityVersion) {
330 self.version = version;
331 }
332}
333
334impl Default for MeshParser {
335 fn default() -> Self {
336 Self::new(UnityVersion::default())
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_parser_creation() {
346 let parser = MeshParser::new(UnityVersion::default());
347 assert_eq!(parser.version(), &UnityVersion::default());
348 }
349
350 #[test]
351 fn test_extract_local_aabb() {
352 let parser = MeshParser::default();
353 let mut mesh = Mesh::default();
354
355 let mut center_obj = IndexMap::new();
356 center_obj.insert("x".to_string(), UnityValue::Float(1.0));
357 center_obj.insert("y".to_string(), UnityValue::Float(2.0));
358 center_obj.insert("z".to_string(), UnityValue::Float(3.0));
359
360 let mut extent_obj = IndexMap::new();
361 extent_obj.insert("x".to_string(), UnityValue::Float(0.5));
362 extent_obj.insert("y".to_string(), UnityValue::Float(1.0));
363 extent_obj.insert("z".to_string(), UnityValue::Float(1.5));
364
365 let mut aabb_obj = IndexMap::new();
366 aabb_obj.insert("m_Center".to_string(), UnityValue::Object(center_obj));
367 aabb_obj.insert("m_Extent".to_string(), UnityValue::Object(extent_obj));
368
369 let aabb_value = UnityValue::Object(aabb_obj);
370 parser.extract_local_aabb(&mut mesh, &aabb_value).unwrap();
371
372 assert_eq!(mesh.local_aabb.center_x, 1.0);
373 assert_eq!(mesh.local_aabb.center_y, 2.0);
374 assert_eq!(mesh.local_aabb.center_z, 3.0);
375 assert_eq!(mesh.local_aabb.extent_x, 0.5);
376 assert_eq!(mesh.local_aabb.extent_y, 1.0);
377 assert_eq!(mesh.local_aabb.extent_z, 1.5);
378 }
379}