use crate::chunk::*;
use crate::error::Result;
use crate::io_helpers::WriteLittleEndian;
use crate::version::AdtVersion;
use std::io::{Seek, SeekFrom, Write};
pub fn write_mcnk<W: Write + Seek>(
writer: &mut W,
chunk: &McnkChunk,
version: AdtVersion,
) -> Result<(u32, u32)> {
let start_pos = writer.stream_position()? as u32;
write_chunk_header(writer, b"MCNK", 0)?;
writer.write_u32_le(chunk.flags)?;
writer.write_u32_le(chunk.ix)?;
writer.write_u32_le(chunk.iy)?;
writer.write_u32_le(chunk.n_layers)?;
writer.write_u32_le(chunk.n_doodad_refs)?;
let mcvt_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
let mcnr_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
let mcly_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
let mcrf_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
let mcal_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
writer.write_u32_le(0)?;
let _mcsh_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
writer.write_u32_le(0)?; writer.write_u32_le(chunk.area_id)?;
writer.write_u32_le(chunk.n_map_obj_refs)?;
writer.write_u32_le(chunk.holes)?;
writer.write_u16_le(chunk.s1)?;
writer.write_u16_le(chunk.s2)?;
writer.write_u32_le(chunk.d1)?;
writer.write_u32_le(chunk.d2)?;
writer.write_u32_le(chunk.d3)?;
writer.write_u32_le(chunk.pred_tex)?;
writer.write_u32_le(chunk.n_effect_doodad)?;
let _mcse_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
writer.write_u32_le(chunk.n_sound_emitters)?;
let _liquid_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
writer.write_u32_le(0)?;
for i in 0..3 {
writer.write_f32_le(chunk.position[i])?;
}
let _mccv_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
let _mclv_offset_pos = writer.stream_position()? as u32;
writer.write_u32_le(0)?;
writer.write_u32_le(chunk.texture_id)?;
writer.write_u32_le(chunk.props)?;
writer.write_u32_le(chunk.effect_id)?;
let _after_header_pos = writer.stream_position()? as u32;
if !chunk.height_map.is_empty() {
let mcvt_pos = writer.stream_position()? as u32;
let rel_offset = mcvt_pos - start_pos;
writer.seek(SeekFrom::Start(mcvt_offset_pos as u64))?;
writer.write_u32_le(rel_offset)?;
writer.seek(SeekFrom::Start(mcvt_pos as u64))?;
write_chunk_header(writer, b"MCVT", 145 * 4)?;
for height in &chunk.height_map {
writer.write_f32_le(*height)?;
}
}
if !chunk.normals.is_empty() {
let mcnr_pos = writer.stream_position()? as u32;
let rel_offset = mcnr_pos - start_pos;
writer.seek(SeekFrom::Start(mcnr_offset_pos as u64))?;
writer.write_u32_le(rel_offset)?;
writer.seek(SeekFrom::Start(mcnr_pos as u64))?;
let mut normal_data_size = chunk.normals.len() * 3;
let padding = (4 - (normal_data_size % 4)) % 4;
normal_data_size += padding;
write_chunk_header(writer, b"MCNR", normal_data_size as u32)?;
for normal in &chunk.normals {
writer.write_all(normal)?;
}
for _ in 0..padding {
writer.write_u8(0)?;
}
}
if !chunk.texture_layers.is_empty() {
let mcly_pos = writer.stream_position()? as u32;
let rel_offset = mcly_pos - start_pos;
writer.seek(SeekFrom::Start(mcly_offset_pos as u64))?;
writer.write_u32_le(rel_offset)?;
writer.seek(SeekFrom::Start(mcly_pos as u64))?;
let layer_size = chunk.texture_layers.len() * 16;
write_chunk_header(writer, b"MCLY", layer_size as u32)?;
for layer in &chunk.texture_layers {
writer.write_u32_le(layer.texture_id)?;
writer.write_u32_le(layer.flags)?;
writer.write_u32_le(layer.alpha_map_offset)?;
writer.write_u32_le(layer.effect_id)?;
}
}
if !chunk.doodad_refs.is_empty() {
let mcrf_pos = writer.stream_position()? as u32;
let rel_offset = mcrf_pos - start_pos;
writer.seek(SeekFrom::Start(mcrf_offset_pos as u64))?;
writer.write_u32_le(rel_offset)?;
writer.seek(SeekFrom::Start(mcrf_pos as u64))?;
let refs_size = chunk.doodad_refs.len() * 4;
write_chunk_header(writer, b"MCRF", refs_size as u32)?;
for doodad_ref in &chunk.doodad_refs {
writer.write_u32_le(*doodad_ref)?;
}
}
if !chunk.map_obj_refs.is_empty() {
let refs_size = chunk.map_obj_refs.len() * 4;
write_chunk_header(writer, b"MCRD", refs_size as u32)?;
for map_obj_ref in &chunk.map_obj_refs {
writer.write_u32_le(*map_obj_ref)?;
}
}
if !chunk.alpha_maps.is_empty() {
let mcal_pos = writer.stream_position()? as u32;
let rel_offset = mcal_pos - start_pos;
let total_size = chunk.alpha_maps.len();
writer.seek(SeekFrom::Start(mcal_offset_pos as u64))?;
writer.write_u32_le(rel_offset)?;
writer.write_u32_le(total_size as u32)?;
writer.seek(SeekFrom::Start(mcal_pos as u64))?;
write_chunk_header(writer, b"MCAL", total_size as u32)?;
writer.write_all(&chunk.alpha_maps)?;
}
if version < AdtVersion::WotLK {
} else {
}
let end_pos = writer.stream_position()? as u32;
let chunk_size = end_pos - start_pos - 8;
writer.seek(SeekFrom::Start((start_pos + 4) as u64))?;
writer.write_u32_le(chunk_size)?;
writer.seek(SeekFrom::Start(end_pos as u64))?;
Ok((start_pos, chunk_size + 8))
}
fn write_chunk_header<W: Write>(writer: &mut W, magic: &[u8; 4], size: u32) -> Result<()> {
let mut reversed_magic = *magic;
reversed_magic.reverse();
writer.write_all(&reversed_magic)?;
writer.write_u32_le(size)?;
Ok(())
}