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