wow_m2/lib.rs
1//! A parser for World of Warcraft M2 model files with version conversion support
2//!
3//! This library allows parsing, validating, and converting M2 model files between different versions
4//! of the World of Warcraft client, with automatic format detection for SKIN and ANIM dependencies.
5//!
6//! # Format Evolution
7//!
8//! M2 files evolved significantly across WoW versions:
9//! - **Classic/TBC**: Embedded SKIN and ANIM data within M2
10//! - **WotLK**: External SKIN files introduced
11//! - **Cataclysm/MoP**: External ANIM files (raw format)
12//! - **Legion+**: ANIM files use chunked format with MAOF magic
13//!
14//! # Example
15//! ```rust,no_run
16//! use wow_m2::{
17//! M2Model, M2Format, SkinFile, AnimFile, AnimFormat, M2Version, M2Converter,
18//! CoordinateSystem, CoordinateTransformer, transform_position,
19//! skinning::{M2Skinner, SkinningOptions}
20//! };
21//!
22//! // Load a model with format detection
23//! let model_format = M2Model::load("path/to/model.m2").unwrap();
24//! let model = model_format.model();
25//!
26//! // Print model info
27//! println!("Model name: {:?}", model.name);
28//! println!("Model version: {:?}", model.header.version());
29//! println!("Vertices: {}", model.vertices.len());
30//! println!("Is chunked format: {}", model_format.is_chunked());
31//!
32//! // Transform vertices using skinning system
33//! let mut skinner = M2Skinner::new(&model.bones, SkinningOptions::default());
34//! skinner.calculate_bind_pose();
35//! let skinned_vertices = skinner.skin_vertices(&model.vertices);
36//! for (i, vertex) in skinned_vertices.iter().enumerate() {
37//! println!("Skinned vertex {}: {:?}", i, vertex);
38//! }
39//!
40//! // Transform coordinates for Blender
41//! let transformer = CoordinateTransformer::new(CoordinateSystem::Blender);
42//! for vertex in &model.vertices {
43//! let blender_pos = transformer.transform_position(vertex.position);
44//! println!("WoW: {:?} → Blender: {:?}", vertex.position, blender_pos);
45//! }
46//!
47//! // Convert to a different version
48//! let converter = M2Converter::new();
49//! let converted = converter.convert(model, M2Version::MoP).unwrap();
50//!
51//! // Save the converted model
52//! converted.save("path/to/converted.m2").unwrap();
53//!
54//! // Load SKIN files with automatic format detection
55//! let skin_file = SkinFile::load("path/to/model00.skin").unwrap();
56//! match &skin_file {
57//! SkinFile::New(skin) => println!("New format SKIN with version {}", skin.header.version),
58//! SkinFile::Old(skin) => println!("Old format SKIN with {} indices", skin.indices.len()),
59//! }
60//!
61//! // Access data regardless of format
62//! let indices = skin_file.indices();
63//! let submeshes = skin_file.submeshes();
64//! println!("SKIN has {} indices and {} submeshes", indices.len(), submeshes.len());
65//!
66//! // Load ANIM files with automatic format detection
67//! let anim_file = AnimFile::load("path/to/model0-0.anim").unwrap();
68//! match &anim_file.format {
69//! AnimFormat::Legacy => println!("Legacy format with {} sections", anim_file.sections.len()),
70//! AnimFormat::Modern => println!("Modern format with {} sections", anim_file.sections.len()),
71//! }
72//! ```
73//!
74//! # Vertex Skinning
75//!
76//! The library provides a comprehensive vertex skinning system that transforms vertices
77//! from their bind pose using bone weights and transformations:
78//!
79//! ```rust,no_run
80//! use wow_m2::{M2Model, skinning::{M2Skinner, SkinningOptions}};
81//!
82//! // Load a model
83//! let model_format = M2Model::load("path/to/model.m2").unwrap();
84//! let model = model_format.model();
85//!
86//! // Create skinner with options
87//! let options = SkinningOptions {
88//! normalize_weights: true,
89//! weight_threshold: 0.001,
90//! validate_bone_indices: true,
91//! handle_invalid_indices: true,
92//! };
93//! let mut skinner = M2Skinner::new(&model.bones, options);
94//!
95//! // Calculate bind pose (rest position)
96//! skinner.calculate_bind_pose();
97//!
98//! // Transform all vertices
99//! let skinned_vertices = skinner.skin_vertices(&model.vertices);
100//! println!("Transformed {} vertices", skinned_vertices.len());
101//!
102//! // Or transform individual vertices
103//! for vertex in &model.vertices {
104//! let skinned_pos = skinner.skin_single_vertex(vertex);
105//! println!("Original: {:?} → Skinned: {:?}", vertex.position, skinned_pos);
106//! }
107//! ```
108//!
109//! # Vertex Validation
110//!
111//! The library supports different validation modes when parsing vertex data to handle corruption
112//! in older WoW models while preserving valid static geometry:
113//!
114//! ```rust,no_run
115//! use wow_m2::{ValidationMode, chunks::vertex::M2Vertex};
116//! use std::io::Cursor;
117//!
118//! # let data = vec![0u8; 48]; // Mock vertex data
119//! let mut cursor = Cursor::new(data);
120//!
121//! // Strict mode: fixes all zero-weight vertices (legacy behavior)
122//! // Use when you need all vertices to be animated
123//! let vertex = M2Vertex::parse_with_validation(
124//! &mut cursor, 256, Some(34), ValidationMode::Strict
125//! );
126//!
127//! // Permissive mode: preserves valid static geometry, fixes corruption (default)
128//! // Best balance between fixing corruption and preserving intentional data
129//! let vertex = M2Vertex::parse_with_validation(
130//! &mut cursor, 256, Some(34), ValidationMode::Permissive
131//! );
132//!
133//! // No validation: preserves all original data
134//! // Use when you need exact original data, even if corrupted
135//! let vertex = M2Vertex::parse_with_validation(
136//! &mut cursor, 256, Some(34), ValidationMode::None
137//! );
138//! ```
139
140// Re-export main components
141pub mod anim;
142pub mod animation;
143pub mod chunks;
144pub mod common;
145pub mod converter;
146pub mod coordinate;
147pub mod embedded_skin;
148pub mod error;
149pub mod file_resolver;
150pub mod header;
151pub mod io_ext;
152pub mod model;
153pub mod model_animation_resolver;
154pub mod model_enhanced;
155pub mod particles;
156pub mod skin;
157pub mod skinning;
158pub mod version;
159
160// Re-export common types
161pub use anim::{AnimFile, AnimFormat, AnimMetadata, AnimSection, MemoryUsage};
162pub use animation::{
163 AnimSequence, AnimationManager, AnimationManagerBuilder, AnimationState, BoneFlags,
164 BoneTransformComputer, ComputedBone, Fixedi16, Lerp, Mat4 as AnimMat4, Quat, ResolvedBone,
165 ResolvedTrack, Vec3 as AnimVec3,
166};
167pub use chunks::particle_emitter::{M2ParticleEmitter, M2ParticleEmitterType, M2ParticleFlags};
168pub use chunks::vertex::ValidationMode;
169pub use converter::M2Converter;
170pub use coordinate::{
171 CoordinateSystem, CoordinateTransformer, transform_position, transform_quaternion,
172};
173pub use error::{M2Error, Result};
174pub use file_resolver::{FileResolver, ListfileResolver, PathResolver};
175pub use model::{M2Format, M2Model, parse_m2};
176pub use model_animation_resolver::{M2ModelAnimationExt, ResolvedBoneAnimation};
177pub use model_enhanced::{
178 AnimationInfo, BoneInfo, BoundingBox, EnhancedModelData, MaterialInfo, ModelStats, TextureInfo,
179};
180pub use particles::{EmissionType, EmitterParams, Particle, ParticleEmitter, TEXELS_PER_PARTICLE};
181pub use skin::{OldSkin, Skin, SkinFile, load_skin, parse_skin};
182pub use skinning::{BoneTransform, M2Skinner, SkinningOptions};
183pub use version::M2Version;
184
185// Re-export BLP types from wow-blp crate for backwards compatibility
186pub use wow_blp::BlpImage as BlpTexture;
187
188/// Library version
189pub const VERSION: &str = env!("CARGO_PKG_VERSION");