use std::io::Cursor;
use wow_m2::chunks::infrastructure::{ChunkHeader, ChunkReader};
use wow_m2::chunks::rendering_enhancements::*;
use wow_m2::error::Result;
fn main() -> Result<()> {
println!("=== Phase 7 M2 Specialized Chunks Demo ===\n");
demo_txac_chunk()?;
demo_pgd1_chunk()?;
demo_unknown_chunks()?;
demo_dpiv_chunk()?;
println!("\n=== All Phase 7 chunks demonstrated successfully! ===");
Ok(())
}
fn demo_txac_chunk() -> Result<()> {
println!("--- TXAC Texture Animation Chunk ---");
let mut data = Vec::new();
data.extend_from_slice(&1u32.to_le_bytes());
data.extend_from_slice(&1u16.to_le_bytes()); data.extend_from_slice(&0u16.to_le_bytes());
for _ in 0..5 {
data.extend_from_slice(&0u16.to_le_bytes()); data.extend_from_slice(&(-1i16).to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); }
data.extend_from_slice(&1.0f32.to_le_bytes()); data.extend_from_slice(&0.0f32.to_le_bytes()); data.extend_from_slice(&(-0.5f32).to_le_bytes()); data.extend_from_slice(&2.0f32.to_le_bytes()); data.extend_from_slice(&0.3f32.to_le_bytes()); data.extend_from_slice(&2u8.to_le_bytes()); data.extend_from_slice(&2u8.to_le_bytes()); data.extend_from_slice(&1u8.to_le_bytes()); data.extend_from_slice(&0u8.to_le_bytes());
let header = ChunkHeader {
magic: *b"TXAC",
size: data.len() as u32,
};
let cursor = Cursor::new(data);
let mut chunk_reader = ChunkReader::new(cursor, header)?;
let txac = TextureAnimationChunk::parse(&mut chunk_reader)?;
println!("TXAC chunk parsed successfully!");
println!(
" Texture animations count: {}",
txac.texture_animations.len()
);
if let Some(anim) = txac.texture_animations.first() {
println!(" First animation:");
println!(" Base type: {:?}", anim.base_animation.animation_type);
println!(
" Flow direction: {:?}",
anim.extended_properties.flow_direction
);
println!(
" Speed multiplier: {}",
anim.extended_properties.speed_multiplier
);
println!(
" Animation mode: {:?}",
anim.extended_properties.animation_mode
);
println!(
" Loop behavior: {:?}",
anim.extended_properties.loop_behavior
);
println!(" Blend mode: {:?}", anim.extended_properties.blend_mode);
}
Ok(())
}
fn demo_pgd1_chunk() -> Result<()> {
println!("\n--- PGD1 Particle Geoset Data Chunk ---");
let data = vec![
0x01, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x00, ];
let header = ChunkHeader {
magic: *b"PGD1",
size: data.len() as u32,
};
let cursor = Cursor::new(data);
let mut chunk_reader = ChunkReader::new(cursor, header)?;
let pgd1 = ParticleGeosetData::parse(&mut chunk_reader)?;
println!("PGD1 chunk parsed successfully!");
println!(
" Particle emitter count: {}",
pgd1.geoset_assignments.len()
);
for (i, assignment) in pgd1.geoset_assignments.iter().enumerate() {
println!(" Particle emitter {}: geoset {}", i, assignment.geoset);
}
println!(" This allows particle emitters to follow geoset visibility rules");
println!(" (useful for character models with different armor pieces)");
Ok(())
}
fn demo_unknown_chunks() -> Result<()> {
println!("\n--- Unknown Chunks (DBOC, AFRA) ---");
let dboc_data = vec![
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10,
];
let dboc_header = ChunkHeader {
magic: *b"DBOC",
size: dboc_data.len() as u32,
};
let dboc_cursor = Cursor::new(dboc_data.clone());
let mut dboc_reader = ChunkReader::new(dboc_cursor, dboc_header)?;
let dboc = DbocChunk::parse(&mut dboc_reader)?;
println!("DBOC chunk parsed successfully!");
println!(" Raw data length: {} bytes", dboc.data.len());
println!(" First 8 bytes: {:02X?}", &dboc.data[..8]);
println!(" Purpose: Currently unknown, preserves raw data for future research");
let afra_data = vec![0xFF, 0xAA, 0x55, 0x00];
let afra_header = ChunkHeader {
magic: *b"AFRA",
size: afra_data.len() as u32,
};
let afra_cursor = Cursor::new(afra_data);
let mut afra_reader = ChunkReader::new(afra_cursor, afra_header)?;
let afra = AfraChunk::parse(&mut afra_reader)?;
println!("\nAFRA chunk parsed successfully!");
println!(" Raw data length: {} bytes", afra.data.len());
println!(" Purpose: Unknown, added in Dragonflight but not yet observed");
Ok(())
}
fn demo_dpiv_chunk() -> Result<()> {
println!("\n--- DPIV Collision Mesh Chunk ---");
let mut data = Vec::new();
let vertex_count = 4u32;
let normal_count = 2u32;
let index_count = 6u32;
let flags_count = 2u32;
let header_size = 32u32; let vertex_offset = header_size;
let normal_offset = vertex_offset + (vertex_count * 12); let index_offset = normal_offset + (normal_count * 12); let flags_offset = index_offset + (index_count * 2);
data.extend_from_slice(&vertex_count.to_le_bytes());
data.extend_from_slice(&vertex_offset.to_le_bytes());
data.extend_from_slice(&normal_count.to_le_bytes());
data.extend_from_slice(&normal_offset.to_le_bytes());
data.extend_from_slice(&index_count.to_le_bytes());
data.extend_from_slice(&index_offset.to_le_bytes());
data.extend_from_slice(&flags_count.to_le_bytes());
data.extend_from_slice(&flags_offset.to_le_bytes());
let vertices = [
[-1.0f32, 0.0, -1.0], [1.0f32, 0.0, -1.0], [1.0f32, 0.0, 1.0], [-1.0f32, 0.0, 1.0], ];
for vertex in &vertices {
for &component in vertex {
data.extend_from_slice(&component.to_le_bytes());
}
}
let normals = [
[0.0f32, 1.0, 0.0], [0.0f32, 1.0, 0.0], ];
for normal in &normals {
for &component in normal {
data.extend_from_slice(&component.to_le_bytes());
}
}
let indices = [0u16, 1, 2, 0, 2, 3];
for &index in &indices {
data.extend_from_slice(&index.to_le_bytes());
}
let flags = [0x01u16, 0x02u16]; for &flag in &flags {
data.extend_from_slice(&flag.to_le_bytes());
}
let header = ChunkHeader {
magic: *b"DPIV",
size: data.len() as u32,
};
let cursor = Cursor::new(data);
let mut chunk_reader = ChunkReader::new(cursor, header)?;
let dpiv = DpivChunk::parse(&mut chunk_reader)?;
println!("DPIV chunk parsed successfully!");
println!(" Vertex positions: {}", dpiv.vertex_positions.len());
println!(" Face normals: {}", dpiv.face_normals.len());
println!(" Indices: {}", dpiv.indices.len());
println!(" Flags: {}", dpiv.flags.len());
println!(" Sample vertex: {:?}", dpiv.vertex_positions[0]);
println!(" Sample normal: {:?}", dpiv.face_normals[0]);
println!(" Indices: {:?}", dpiv.indices);
println!(" Purpose: Collision mesh data for player housing furniture");
println!(" Added in Midnight expansion for housing collision detection");
Ok(())
}