unity_asset_binary/mesh/
mod.rs

1//! Unity Mesh processing module
2//!
3//! This module provides comprehensive Mesh processing capabilities,
4//! organized following UnityPy and unity-rs best practices.
5//!
6//! # Architecture
7//!
8//! The module is organized into several sub-modules:
9//! - `types` - Core data structures (Mesh, VertexData, SubMesh, etc.)
10//! - `parser` - Mesh parsing from Unity objects
11//! - `processor` - High-level mesh processing and export
12//!
13//! # Examples
14//!
15//! ```rust,no_run
16//! use unity_asset_binary::mesh::{MeshProcessor, MeshConfig};
17//! use unity_asset_binary::unity_version::UnityVersion;
18//! use unity_asset_binary::object::ObjectInfo;
19//!
20//! // Create processor with custom configuration
21//! let version = UnityVersion::parse_version("2020.3.12f1")?;
22//! let config = MeshConfig {
23//!     extract_vertices: true,
24//!     extract_indices: true,
25//!     process_blend_shapes: true,
26//!     decompress_meshes: true,
27//!     max_vertex_count: Some(100000),
28//! };
29//! let processor = MeshProcessor::with_config(version, config);
30//!
31//! // Note: In real usage, you would create a UnityObject from parsed data
32//! // For demonstration, we'll just show the processor creation
33//! println!("Mesh processed successfully");
34//! # Ok::<(), unity_asset_binary::error::BinaryError>(())
35//! ```
36
37pub mod parser;
38pub mod processor;
39pub mod types;
40
41// Re-export main types for easy access
42pub use parser::MeshParser;
43pub use processor::{MeshProcessor, MeshStats};
44pub use types::{
45    AABB,
46    BlendShape,
47    BlendShapeChannel,
48    // Blend shape types
49    BlendShapeData,
50    BlendShapeVertex,
51    ChannelInfo,
52    // Compression types
53    CompressedMesh,
54    // Core mesh types
55    Mesh,
56    // Configuration and results
57    MeshConfig,
58    MeshInfo,
59    MeshResult,
60    PackedFloatVector,
61    PackedIntVector,
62    // Streaming and info
63    StreamingInfo,
64    SubMesh,
65    VertexData,
66};
67
68/// Main mesh processing facade
69///
70/// This struct provides a high-level interface for mesh processing,
71/// combining parsing and processing functionality.
72pub struct MeshManager {
73    processor: MeshProcessor,
74}
75
76impl MeshManager {
77    /// Create a new mesh manager
78    pub fn new(version: crate::unity_version::UnityVersion) -> Self {
79        Self {
80            processor: MeshProcessor::new(version),
81        }
82    }
83
84    /// Create a mesh manager with custom configuration
85    pub fn with_config(version: crate::unity_version::UnityVersion, config: MeshConfig) -> Self {
86        Self {
87            processor: MeshProcessor::with_config(version, config),
88        }
89    }
90
91    /// Process mesh from Unity object
92    pub fn process_mesh(
93        &self,
94        object: &crate::object::UnityObject,
95    ) -> crate::error::Result<MeshResult> {
96        self.processor.parse_mesh(object)
97    }
98
99    /// Export mesh to OBJ format
100    pub fn export_to_obj(&self, mesh: &Mesh) -> crate::error::Result<String> {
101        self.processor.export_to_obj(mesh)
102    }
103
104    /// Get mesh statistics
105    pub fn get_statistics(&self, meshes: &[&Mesh]) -> MeshStats {
106        self.processor.get_mesh_stats(meshes)
107    }
108
109    /// Validate mesh data
110    pub fn validate_mesh(&self, mesh: &Mesh) -> crate::error::Result<()> {
111        self.processor.validate_mesh(mesh)
112    }
113
114    /// Get supported features
115    pub fn get_supported_features(&self) -> Vec<&'static str> {
116        self.processor.get_supported_features()
117    }
118
119    /// Check if a feature is supported
120    pub fn is_feature_supported(&self, feature: &str) -> bool {
121        self.processor.is_feature_supported(feature)
122    }
123
124    /// Get the current configuration
125    pub fn config(&self) -> &MeshConfig {
126        self.processor.config()
127    }
128
129    /// Set the configuration
130    pub fn set_config(&mut self, config: MeshConfig) {
131        self.processor.set_config(config);
132    }
133
134    /// Get the Unity version
135    pub fn version(&self) -> &crate::unity_version::UnityVersion {
136        self.processor.version()
137    }
138
139    /// Set the Unity version
140    pub fn set_version(&mut self, version: crate::unity_version::UnityVersion) {
141        self.processor.set_version(version);
142    }
143
144    /// Extract vertex data
145    pub fn extract_vertices(&self, mesh: &Mesh) -> crate::error::Result<Vec<[f32; 3]>> {
146        self.processor.extract_vertex_positions(mesh)
147    }
148
149    /// Extract normals
150    pub fn extract_normals(&self, mesh: &Mesh) -> crate::error::Result<Vec<[f32; 3]>> {
151        self.processor.extract_vertex_normals(mesh)
152    }
153
154    /// Extract UV coordinates
155    pub fn extract_uvs(&self, mesh: &Mesh) -> crate::error::Result<Vec<[f32; 2]>> {
156        self.processor.extract_uv_coordinates(mesh)
157    }
158
159    /// Extract triangle indices
160    pub fn extract_indices(&self, mesh: &Mesh) -> crate::error::Result<Vec<u32>> {
161        self.processor.extract_triangle_indices(mesh)
162    }
163}
164
165impl Default for MeshManager {
166    fn default() -> Self {
167        Self::new(crate::unity_version::UnityVersion::default())
168    }
169}
170
171/// Convenience functions for common operations
172/// Create a mesh manager with default settings
173pub fn create_manager(version: crate::unity_version::UnityVersion) -> MeshManager {
174    MeshManager::new(version)
175}
176
177/// Create a mesh manager optimized for performance
178pub fn create_performance_manager(version: crate::unity_version::UnityVersion) -> MeshManager {
179    let config = MeshConfig {
180        extract_vertices: false,
181        extract_indices: false,
182        process_blend_shapes: false,
183        decompress_meshes: false,
184        max_vertex_count: Some(10000),
185    };
186    MeshManager::with_config(version, config)
187}
188
189/// Create a mesh manager with full features
190pub fn create_full_manager(version: crate::unity_version::UnityVersion) -> MeshManager {
191    let config = MeshConfig {
192        extract_vertices: true,
193        extract_indices: true,
194        process_blend_shapes: true,
195        decompress_meshes: true,
196        max_vertex_count: None,
197    };
198    MeshManager::with_config(version, config)
199}
200
201/// Parse mesh from Unity object (convenience function)
202pub fn parse_mesh(
203    object: &crate::object::UnityObject,
204    version: &crate::unity_version::UnityVersion,
205) -> crate::error::Result<Mesh> {
206    let parser = MeshParser::new(version.clone());
207    let result = parser.parse_from_unity_object(object)?;
208    Ok(result.mesh)
209}
210
211/// Export mesh to OBJ format (convenience function)
212pub fn export_mesh_to_obj(
213    mesh: &Mesh,
214    version: &crate::unity_version::UnityVersion,
215) -> crate::error::Result<String> {
216    let processor = MeshProcessor::new(version.clone());
217    processor.export_to_obj(mesh)
218}
219
220/// Validate mesh data (convenience function)
221pub fn validate_mesh(mesh: &Mesh) -> crate::error::Result<()> {
222    let processor = MeshProcessor::default();
223    processor.validate_mesh(mesh)
224}
225
226/// Get mesh vertex count
227pub fn get_vertex_count(mesh: &Mesh) -> u32 {
228    mesh.vertex_count()
229}
230
231/// Get mesh triangle count
232pub fn get_triangle_count(mesh: &Mesh) -> u32 {
233    mesh.triangle_count()
234}
235
236/// Check if mesh has blend shapes
237pub fn has_blend_shapes(mesh: &Mesh) -> bool {
238    mesh.has_blend_shapes()
239}
240
241/// Check if mesh is compressed
242pub fn is_compressed_mesh(mesh: &Mesh) -> bool {
243    mesh.is_compressed()
244}
245
246/// Check if mesh has streaming data
247pub fn has_streaming_data(mesh: &Mesh) -> bool {
248    mesh.has_streaming_data()
249}
250
251/// Get mesh bounds
252pub fn get_mesh_bounds(mesh: &Mesh) -> &AABB {
253    mesh.bounds()
254}
255
256/// Check if Unity version supports mesh feature
257pub fn is_mesh_feature_supported(
258    version: &crate::unity_version::UnityVersion,
259    feature: &str,
260) -> bool {
261    match feature {
262        "basic_mesh" | "sub_meshes" | "vertex_data" => true,
263        "blend_shapes" | "compressed_mesh" => version.major >= 5,
264        "mesh_optimization" | "streaming_info" => version.major >= 2017,
265        "mesh_usage_flags" => version.major >= 2018,
266        "mesh_topology" | "vertex_attributes" => version.major >= 2019,
267        _ => false,
268    }
269}
270
271/// Get recommended mesh configuration for Unity version
272pub fn get_recommended_config(version: &crate::unity_version::UnityVersion) -> MeshConfig {
273    if version.major >= 2019 {
274        // Modern Unity - full features
275        MeshConfig {
276            extract_vertices: true,
277            extract_indices: true,
278            process_blend_shapes: true,
279            decompress_meshes: true,
280            max_vertex_count: None,
281        }
282    } else if version.major >= 2017 {
283        // Unity 2017+ - streaming support
284        MeshConfig {
285            extract_vertices: true,
286            extract_indices: true,
287            process_blend_shapes: true,
288            decompress_meshes: true,
289            max_vertex_count: Some(100000),
290        }
291    } else if version.major >= 5 {
292        // Unity 5+ - basic features
293        MeshConfig {
294            extract_vertices: true,
295            extract_indices: true,
296            process_blend_shapes: false,
297            decompress_meshes: false,
298            max_vertex_count: Some(50000),
299        }
300    } else {
301        // Legacy Unity - minimal features
302        MeshConfig {
303            extract_vertices: false,
304            extract_indices: false,
305            process_blend_shapes: false,
306            decompress_meshes: false,
307            max_vertex_count: Some(10000),
308        }
309    }
310}
311
312/// Mesh processing options
313#[derive(Debug, Clone)]
314pub struct ProcessingOptions {
315    pub parallel_processing: bool,
316    pub cache_results: bool,
317    pub validate_meshes: bool,
318    pub generate_lods: bool,
319}
320
321impl Default for ProcessingOptions {
322    fn default() -> Self {
323        Self {
324            parallel_processing: false,
325            cache_results: true,
326            validate_meshes: true,
327            generate_lods: false,
328        }
329    }
330}
331
332#[cfg(test)]
333mod tests {
334    use super::*;
335
336    #[test]
337    fn test_manager_creation() {
338        let version = crate::unity_version::UnityVersion::default();
339        let manager = create_manager(version);
340        assert!(manager.get_supported_features().contains(&"basic_mesh"));
341    }
342
343    #[test]
344    fn test_performance_manager() {
345        let version = crate::unity_version::UnityVersion::default();
346        let manager = create_performance_manager(version);
347        assert!(!manager.config().extract_vertices);
348        assert!(!manager.config().process_blend_shapes);
349    }
350
351    #[test]
352    fn test_full_manager() {
353        let version = crate::unity_version::UnityVersion::default();
354        let manager = create_full_manager(version);
355        assert!(manager.config().extract_vertices);
356        assert!(manager.config().process_blend_shapes);
357    }
358
359    #[test]
360    fn test_feature_support() {
361        let version_2020 =
362            crate::unity_version::UnityVersion::parse_version("2020.3.12f1").unwrap();
363        assert!(is_mesh_feature_supported(&version_2020, "basic_mesh"));
364        assert!(is_mesh_feature_supported(&version_2020, "blend_shapes"));
365        assert!(is_mesh_feature_supported(
366            &version_2020,
367            "vertex_attributes"
368        ));
369
370        let version_2017 =
371            crate::unity_version::UnityVersion::parse_version("2017.4.40f1").unwrap();
372        assert!(is_mesh_feature_supported(&version_2017, "streaming_info"));
373        assert!(!is_mesh_feature_supported(
374            &version_2017,
375            "vertex_attributes"
376        ));
377    }
378
379    #[test]
380    fn test_recommended_config() {
381        let version_2020 =
382            crate::unity_version::UnityVersion::parse_version("2020.3.12f1").unwrap();
383        let config = get_recommended_config(&version_2020);
384        assert!(config.extract_vertices);
385        assert!(config.process_blend_shapes);
386        assert!(config.decompress_meshes);
387
388        let version_5 = crate::unity_version::UnityVersion::parse_version("5.6.7f1").unwrap();
389        let config = get_recommended_config(&version_5);
390        assert!(config.extract_vertices);
391        assert!(!config.process_blend_shapes);
392    }
393}