Expand description
A parser for World of Warcraft M2 model files with version conversion support
This library allows parsing, validating, and converting M2 model files between different versions of the World of Warcraft client, with automatic format detection for SKIN and ANIM dependencies.
§Format Evolution
M2 files evolved significantly across WoW versions:
- Classic/TBC: Embedded SKIN and ANIM data within M2
- WotLK: External SKIN files introduced
- Cataclysm/MoP: External ANIM files (raw format)
- Legion+: ANIM files use chunked format with MAOF magic
§Example
use wow_m2::{
M2Model, M2Format, SkinFile, AnimFile, AnimFormat, M2Version, M2Converter,
CoordinateSystem, CoordinateTransformer, transform_position,
skinning::{M2Skinner, SkinningOptions}
};
// Load a model with format detection
let model_format = M2Model::load("path/to/model.m2").unwrap();
let model = model_format.model();
// Print model info
println!("Model name: {:?}", model.name);
println!("Model version: {:?}", model.header.version());
println!("Vertices: {}", model.vertices.len());
println!("Is chunked format: {}", model_format.is_chunked());
// Transform vertices using skinning system
let mut skinner = M2Skinner::new(&model.bones, SkinningOptions::default());
skinner.calculate_bind_pose();
let skinned_vertices = skinner.skin_vertices(&model.vertices);
for (i, vertex) in skinned_vertices.iter().enumerate() {
println!("Skinned vertex {}: {:?}", i, vertex);
}
// Transform coordinates for Blender
let transformer = CoordinateTransformer::new(CoordinateSystem::Blender);
for vertex in &model.vertices {
let blender_pos = transformer.transform_position(vertex.position);
println!("WoW: {:?} → Blender: {:?}", vertex.position, blender_pos);
}
// Convert to a different version
let converter = M2Converter::new();
let converted = converter.convert(model, M2Version::MoP).unwrap();
// Save the converted model
converted.save("path/to/converted.m2").unwrap();
// Load SKIN files with automatic format detection
let skin_file = SkinFile::load("path/to/model00.skin").unwrap();
match &skin_file {
SkinFile::New(skin) => println!("New format SKIN with version {}", skin.header.version),
SkinFile::Old(skin) => println!("Old format SKIN with {} indices", skin.indices.len()),
}
// Access data regardless of format
let indices = skin_file.indices();
let submeshes = skin_file.submeshes();
println!("SKIN has {} indices and {} submeshes", indices.len(), submeshes.len());
// Load ANIM files with automatic format detection
let anim_file = AnimFile::load("path/to/model0-0.anim").unwrap();
match &anim_file.format {
AnimFormat::Legacy => println!("Legacy format with {} sections", anim_file.sections.len()),
AnimFormat::Modern => println!("Modern format with {} sections", anim_file.sections.len()),
}§Vertex Skinning
The library provides a comprehensive vertex skinning system that transforms vertices from their bind pose using bone weights and transformations:
use wow_m2::{M2Model, skinning::{M2Skinner, SkinningOptions}};
// Load a model
let model_format = M2Model::load("path/to/model.m2").unwrap();
let model = model_format.model();
// Create skinner with options
let options = SkinningOptions {
normalize_weights: true,
weight_threshold: 0.001,
validate_bone_indices: true,
handle_invalid_indices: true,
};
let mut skinner = M2Skinner::new(&model.bones, options);
// Calculate bind pose (rest position)
skinner.calculate_bind_pose();
// Transform all vertices
let skinned_vertices = skinner.skin_vertices(&model.vertices);
println!("Transformed {} vertices", skinned_vertices.len());
// Or transform individual vertices
for vertex in &model.vertices {
let skinned_pos = skinner.skin_single_vertex(vertex);
println!("Original: {:?} → Skinned: {:?}", vertex.position, skinned_pos);
}§Vertex Validation
The library supports different validation modes when parsing vertex data to handle corruption in older WoW models while preserving valid static geometry:
use wow_m2::{ValidationMode, chunks::vertex::M2Vertex};
use std::io::Cursor;
let mut cursor = Cursor::new(data);
// Strict mode: fixes all zero-weight vertices (legacy behavior)
// Use when you need all vertices to be animated
let vertex = M2Vertex::parse_with_validation(
&mut cursor, 256, Some(34), ValidationMode::Strict
);
// Permissive mode: preserves valid static geometry, fixes corruption (default)
// Best balance between fixing corruption and preserving intentional data
let vertex = M2Vertex::parse_with_validation(
&mut cursor, 256, Some(34), ValidationMode::Permissive
);
// No validation: preserves all original data
// Use when you need exact original data, even if corrupted
let vertex = M2Vertex::parse_with_validation(
&mut cursor, 256, Some(34), ValidationMode::None
);Re-exports§
pub use anim::AnimFile;pub use anim::AnimFormat;pub use anim::AnimMetadata;pub use anim::AnimSection;pub use anim::MemoryUsage;pub use animation::AnimSequence;pub use animation::AnimationManager;pub use animation::AnimationManagerBuilder;pub use animation::AnimationState;pub use animation::BoneFlags;pub use animation::BoneTransformComputer;pub use animation::ComputedBone;pub use animation::Fixedi16;pub use animation::Lerp;pub use animation::Mat4 as AnimMat4;pub use animation::Quat;pub use animation::ResolvedBone;pub use animation::ResolvedTrack;pub use animation::Vec3 as AnimVec3;pub use chunks::particle_emitter::M2ParticleEmitter;pub use chunks::particle_emitter::M2ParticleEmitterType;pub use chunks::particle_emitter::M2ParticleFlags;pub use chunks::vertex::ValidationMode;pub use converter::M2Converter;pub use coordinate::CoordinateSystem;pub use coordinate::CoordinateTransformer;pub use coordinate::transform_position;pub use coordinate::transform_quaternion;pub use error::M2Error;pub use error::Result;pub use file_resolver::FileResolver;pub use file_resolver::ListfileResolver;pub use file_resolver::PathResolver;pub use model::M2Format;pub use model::M2Model;pub use model::parse_m2;pub use model_animation_resolver::M2ModelAnimationExt;pub use model_animation_resolver::ResolvedBoneAnimation;pub use model_enhanced::AnimationInfo;pub use model_enhanced::BoneInfo;pub use model_enhanced::BoundingBox;pub use model_enhanced::EnhancedModelData;pub use model_enhanced::MaterialInfo;pub use model_enhanced::ModelStats;pub use model_enhanced::TextureInfo;pub use particles::EmissionType;pub use particles::EmitterParams;pub use particles::Particle;pub use particles::ParticleEmitter;pub use particles::TEXELS_PER_PARTICLE;pub use skin::OldSkin;pub use skin::Skin;pub use skin::SkinFile;pub use skin::load_skin;pub use skin::parse_skin;pub use skinning::BoneTransform;pub use skinning::M2Skinner;pub use skinning::SkinningOptions;pub use version::M2Version;
Modules§
- anim
- animation
- M2 Animation System
- chunks
- common
- converter
- coordinate
- Coordinate system transformations for World of Warcraft models
- embedded_
skin - Support for parsing embedded skin data from pre-WotLK M2 models
- error
- file_
resolver - FileDataID resolution system for M2 chunked format
- header
- io_ext
- model
- model_
animation_ resolver - model_
enhanced - Enhanced M2 model parser with comprehensive data extraction methods
- particles
- Particle system for M2 models
- skin
- skinning
- Vertex skinning system for M2 models
- version
Structs§
- BlpTexture
- Parsed information from BLP file. The structure of the type strictly follows how the file is stored on the disk for easy encoding/decoding and further transformations.
Constants§
- VERSION
- Library version