unity_asset_decode/mesh/
types.rs

1//! Mesh type definitions
2//!
3//! This module defines all the data structures used for Unity Mesh processing.
4
5use serde::{Deserialize, Serialize};
6
7/// Vertex data structure
8///
9/// Contains information about vertex layout and data for a mesh.
10#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11pub struct VertexData {
12    pub vertex_count: u32,
13    pub channels: Vec<ChannelInfo>,
14    pub data_size: Vec<u8>,
15}
16
17/// Channel information for vertex data
18///
19/// Describes how vertex attributes are laid out in the vertex buffer.
20#[derive(Debug, Clone, Default, Serialize, Deserialize)]
21pub struct ChannelInfo {
22    pub stream: u8,
23    pub offset: u8,
24    pub format: u8,
25    pub dimension: u8,
26}
27
28/// SubMesh data structure
29///
30/// Represents a portion of a mesh that uses the same material.
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32pub struct SubMesh {
33    pub first_byte: u32,
34    pub index_count: u32,
35    pub topology: i32,
36    pub triangle_count: u32,
37    pub base_vertex: u32,
38    pub first_vertex: u32,
39    pub vertex_count: u32,
40    pub local_aabb: Option<AABB>,
41}
42
43/// Axis-Aligned Bounding Box
44///
45/// Defines the spatial bounds of a mesh or submesh.
46#[derive(Debug, Clone, Default, Serialize, Deserialize)]
47pub struct AABB {
48    pub center_x: f32,
49    pub center_y: f32,
50    pub center_z: f32,
51    pub extent_x: f32,
52    pub extent_y: f32,
53    pub extent_z: f32,
54}
55
56/// Blend shape data
57///
58/// Contains morph target information for mesh animation.
59#[derive(Debug, Clone, Default, Serialize, Deserialize)]
60pub struct BlendShapeData {
61    pub vertices: Vec<BlendShapeVertex>,
62    pub shapes: Vec<BlendShape>,
63    pub channels: Vec<BlendShapeChannel>,
64    pub full_weights: Vec<f32>,
65}
66
67/// Blend shape vertex
68///
69/// Represents a vertex delta for blend shape animation.
70#[derive(Debug, Clone, Default, Serialize, Deserialize)]
71pub struct BlendShapeVertex {
72    pub vertex: [f32; 3],
73    pub normal: [f32; 3],
74    pub tangent: [f32; 3],
75    pub index: u32,
76}
77
78/// Blend shape
79///
80/// Defines a morph target shape.
81#[derive(Debug, Clone, Default, Serialize, Deserialize)]
82pub struct BlendShape {
83    pub first_vertex: u32,
84    pub vertex_count: u32,
85    pub has_normals: bool,
86    pub has_tangents: bool,
87}
88
89/// Blend shape channel
90///
91/// Named channel for blend shape animation.
92#[derive(Debug, Clone, Default, Serialize, Deserialize)]
93pub struct BlendShapeChannel {
94    pub name: String,
95    pub name_hash: u32,
96    pub frame_index: i32,
97    pub frame_count: i32,
98}
99
100/// Streaming info for external mesh data
101///
102/// Information about mesh data stored in external files.
103#[derive(Debug, Clone, Default, Serialize, Deserialize)]
104pub struct StreamingInfo {
105    pub offset: u64,
106    pub size: u32,
107    pub path: String,
108}
109
110/// Compressed mesh data
111///
112/// Contains compressed vertex and index data for memory efficiency.
113#[derive(Debug, Clone, Default, Serialize, Deserialize)]
114pub struct CompressedMesh {
115    pub vertices: PackedFloatVector,
116    pub uv: PackedFloatVector,
117    pub normals: PackedFloatVector,
118    pub tangents: PackedFloatVector,
119    pub weights: PackedIntVector,
120    pub normal_signs: PackedIntVector,
121    pub tangent_signs: PackedIntVector,
122    pub float_colors: Option<PackedFloatVector>,
123    pub bone_indices: PackedIntVector,
124    pub triangles: PackedIntVector,
125    pub colors: Option<PackedIntVector>,
126    pub uv_info: u32,
127}
128
129/// Packed float vector for compressed data
130///
131/// Compressed floating-point data with quantization information.
132#[derive(Debug, Clone, Default, Serialize, Deserialize)]
133pub struct PackedFloatVector {
134    pub num_items: u32,
135    pub range: f32,
136    pub start: f32,
137    pub data: Vec<u8>,
138    pub bit_size: u8,
139}
140
141/// Packed int vector for compressed data
142///
143/// Compressed integer data with bit packing.
144#[derive(Debug, Clone, Default, Serialize, Deserialize)]
145pub struct PackedIntVector {
146    pub num_items: u32,
147    pub data: Vec<u8>,
148    pub bit_size: u8,
149}
150
151/// Mesh object representation
152///
153/// Main mesh structure containing all mesh data and metadata.
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct Mesh {
156    pub name: String,
157    pub sub_meshes: Vec<SubMesh>,
158    pub blend_shape_data: Option<BlendShapeData>,
159    pub bind_pose: Vec<[f32; 16]>, // Matrix4x4 as array
160    pub bone_name_hashes: Vec<u32>,
161    pub root_bone_name_hash: u32,
162    pub mesh_compression: u8,
163    pub is_readable: bool,
164    pub keep_vertices: bool,
165    pub keep_indices: bool,
166    pub index_format: i32,
167    pub index_buffer: Vec<u8>,
168    pub vertex_data: VertexData,
169    pub compressed_mesh: Option<CompressedMesh>,
170    pub local_aabb: AABB,
171    pub mesh_usage_flags: i32,
172    pub baked_convex_collision_mesh: Vec<u8>,
173    pub baked_triangle_collision_mesh: Vec<u8>,
174    pub mesh_metrics: [f32; 2],
175    pub stream_data: Option<StreamingInfo>,
176}
177
178impl Default for Mesh {
179    fn default() -> Self {
180        Self {
181            name: String::new(),
182            sub_meshes: Vec::new(),
183            blend_shape_data: None,
184            bind_pose: Vec::new(),
185            bone_name_hashes: Vec::new(),
186            root_bone_name_hash: 0,
187            mesh_compression: 0,
188            is_readable: true,
189            keep_vertices: true,
190            keep_indices: true,
191            index_format: 0,
192            index_buffer: Vec::new(),
193            vertex_data: VertexData::default(),
194            compressed_mesh: None,
195            local_aabb: AABB::default(),
196            mesh_usage_flags: 0,
197            baked_convex_collision_mesh: Vec::new(),
198            baked_triangle_collision_mesh: Vec::new(),
199            mesh_metrics: [0.0, 0.0],
200            stream_data: None,
201        }
202    }
203}
204
205/// Mesh processing configuration
206#[derive(Debug, Clone)]
207pub struct MeshConfig {
208    /// Whether to extract vertex data
209    pub extract_vertices: bool,
210    /// Whether to extract index data
211    pub extract_indices: bool,
212    /// Whether to process blend shapes
213    pub process_blend_shapes: bool,
214    /// Whether to decompress compressed meshes
215    pub decompress_meshes: bool,
216    /// Maximum vertex count to process
217    pub max_vertex_count: Option<u32>,
218}
219
220impl Default for MeshConfig {
221    fn default() -> Self {
222        Self {
223            extract_vertices: true,
224            extract_indices: true,
225            process_blend_shapes: true,
226            decompress_meshes: true,
227            max_vertex_count: None,
228        }
229    }
230}
231
232/// Mesh processing result
233#[derive(Debug, Clone)]
234pub struct MeshResult {
235    pub mesh: Mesh,
236    pub warnings: Vec<String>,
237    pub errors: Vec<String>,
238}
239
240impl MeshResult {
241    pub fn new(mesh: Mesh) -> Self {
242        Self {
243            mesh,
244            warnings: Vec::new(),
245            errors: Vec::new(),
246        }
247    }
248
249    pub fn add_warning(&mut self, warning: String) {
250        self.warnings.push(warning);
251    }
252
253    pub fn add_error(&mut self, error: String) {
254        self.errors.push(error);
255    }
256
257    pub fn has_warnings(&self) -> bool {
258        !self.warnings.is_empty()
259    }
260
261    pub fn has_errors(&self) -> bool {
262        !self.errors.is_empty()
263    }
264}
265
266/// Mesh information summary
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct MeshInfo {
269    pub name: String,
270    pub vertex_count: u32,
271    pub sub_mesh_count: u32,
272    pub triangle_count: u32,
273    pub has_blend_shapes: bool,
274    pub is_readable: bool,
275    pub is_compressed: bool,
276    pub has_streaming_data: bool,
277}
278
279/// Helper functions for mesh types
280impl Mesh {
281    /// Get total vertex count
282    pub fn vertex_count(&self) -> u32 {
283        self.vertex_data.vertex_count
284    }
285
286    /// Get total triangle count
287    pub fn triangle_count(&self) -> u32 {
288        self.sub_meshes.iter().map(|sm| sm.triangle_count).sum()
289    }
290
291    /// Check if mesh has blend shapes
292    pub fn has_blend_shapes(&self) -> bool {
293        self.blend_shape_data.is_some()
294    }
295
296    /// Check if mesh is compressed
297    pub fn is_compressed(&self) -> bool {
298        self.compressed_mesh.is_some()
299    }
300
301    /// Check if mesh has streaming data
302    pub fn has_streaming_data(&self) -> bool {
303        self.stream_data.is_some()
304    }
305
306    /// Get mesh bounds
307    pub fn bounds(&self) -> &AABB {
308        &self.local_aabb
309    }
310
311    /// Get mesh information summary
312    pub fn get_info(&self) -> MeshInfo {
313        MeshInfo {
314            name: self.name.clone(),
315            vertex_count: self.vertex_count(),
316            sub_mesh_count: self.sub_meshes.len() as u32,
317            triangle_count: self.triangle_count(),
318            has_blend_shapes: self.has_blend_shapes(),
319            is_readable: self.is_readable,
320            is_compressed: self.is_compressed(),
321            has_streaming_data: self.has_streaming_data(),
322        }
323    }
324}
325
326impl AABB {
327    /// Create a new AABB
328    pub fn new(center: [f32; 3], extent: [f32; 3]) -> Self {
329        Self {
330            center_x: center[0],
331            center_y: center[1],
332            center_z: center[2],
333            extent_x: extent[0],
334            extent_y: extent[1],
335            extent_z: extent[2],
336        }
337    }
338
339    /// Get center as array
340    pub fn center(&self) -> [f32; 3] {
341        [self.center_x, self.center_y, self.center_z]
342    }
343
344    /// Get extent as array
345    pub fn extent(&self) -> [f32; 3] {
346        [self.extent_x, self.extent_y, self.extent_z]
347    }
348
349    /// Get minimum point
350    pub fn min(&self) -> [f32; 3] {
351        [
352            self.center_x - self.extent_x,
353            self.center_y - self.extent_y,
354            self.center_z - self.extent_z,
355        ]
356    }
357
358    /// Get maximum point
359    pub fn max(&self) -> [f32; 3] {
360        [
361            self.center_x + self.extent_x,
362            self.center_y + self.extent_y,
363            self.center_z + self.extent_z,
364        ]
365    }
366
367    /// Get volume
368    pub fn volume(&self) -> f32 {
369        8.0 * self.extent_x * self.extent_y * self.extent_z
370    }
371}
372
373impl SubMesh {
374    /// Check if submesh has valid data
375    pub fn is_valid(&self) -> bool {
376        self.vertex_count > 0 && self.index_count > 0
377    }
378
379    /// Get topology name
380    pub fn topology_name(&self) -> &'static str {
381        match self.topology {
382            0 => "Triangles",
383            1 => "Quads",
384            2 => "Lines",
385            3 => "LineStrip",
386            4 => "Points",
387            _ => "Unknown",
388        }
389    }
390}