use crate::{
StringOffset32, parse_offset32_count32, parse_offset32_inner_count8,
parse_offset32_inner_count32, parse_ptr32, parse_string_ptr32,
};
use binrw::{BinRead, args, binread};
use xc3_write::{Xc3Write, Xc3WriteOffsets};
#[binread]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Xc3Write, PartialEq, Clone)]
#[br(stream = r)]
#[br(magic(b"IDCM"))]
#[xc3(base_offset)]
#[xc3(magic(b"IDCM"))]
pub struct Idcm {
#[br(temp, try_calc = r.stream_position().map(|p| p - 4))]
base_offset: u64,
pub version: u32,
#[br(temp, restore_position)]
offset_count_offset: [u32; 3],
#[br(temp, restore_position, seek_before = std::io::SeekFrom::Start(base_offset + 160))]
next_offset: u32,
#[br(parse_with = parse_offset32_count32)]
#[br(args { offset: base_offset, inner: estimate_mesh_size(offset_count_offset, next_offset) })]
#[xc3(offset_count(u32, u32))]
pub meshes: Vec<MeshVersioned>,
#[br(parse_with = parse_offset32_count32)]
#[br(args { offset: base_offset, inner: base_offset })]
#[xc3(offset_count(u32, u32))]
pub face_groups: Vec<FaceGroup>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub groups: Vec<Group>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk4: Vec<[u32; 2]>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk5: Vec<u32>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk6: Vec<u32>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk7: Vec<[u32; 3]>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub vertices: Vec<[f32; 4]>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk9: Vec<Unk9>,
pub unk10: u64,
#[br(parse_with = parse_offset32_inner_count32, offset = base_offset)]
#[xc3(offset_inner_count(u32, self.instances.mesh_indices.len() as u32))]
pub instances: MeshInstances,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk13: Vec<[f32; 8]>,
#[br(parse_with = parse_offset32_count32)]
#[br(args { offset: base_offset, inner: base_offset })]
#[xc3(offset_count(u32, u32))]
pub unk19: Vec<Unk19>,
pub unks1_1: u32,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk18: Vec<[u32; 10]>,
pub unks1_3: [u32; 2],
#[br(parse_with = parse_ptr32)]
#[br(args { offset: base_offset, inner: args! { count: meshes.len(), inner: base_offset } })]
#[xc3(offset(u32))]
pub mesh_names: Vec<StringOffset32>,
pub unk21: u32,
#[br(parse_with = parse_ptr32, offset = base_offset)]
#[xc3(offset(u32))]
pub unk15: [f32; 10],
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unks1_2: Vec<u32>,
#[br(parse_with = parse_offset32_count32)]
#[br(args{ offset: base_offset, inner: base_offset})]
#[xc3(offset_count(u32, u32))]
pub unk16: Vec<Unk16>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unk17: Vec<[u32; 4]>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub unks1_4: Vec<u32>,
pub unks: [u32; 12], }
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(import_raw(size: u32))]
pub enum MeshVersioned {
#[br(pre_assert(size == 20))]
MeshLegacy(MeshLegacy),
#[br(pre_assert(size == 60))]
Mesh(Mesh),
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct Mesh {
pub unk1: u32,
pub face_group_start_index: u32,
pub face_group_start_index2: u32,
pub face_group_count: u32,
pub face_group_count2: u32,
pub unk6: u32,
pub unk7: u32,
pub unk8: u32,
pub unk9: u32,
pub unk: [u32; 6],
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct MeshLegacy {
pub unk1: u32,
pub face_group_start_index: u32,
pub face_group_count: u32,
pub unk2: u32,
pub unk3: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct FaceGroup {
#[br(parse_with = parse_offset32_inner_count8, offset = base_offset)]
#[xc3(offset_inner_count(u32, self.faces.unk1.len() as u8))]
pub faces: Faces,
pub group_index: u8,
pub unk2: u16,
pub unk3: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(import_raw(count: u8))]
pub struct Faces {
#[br(count = count)]
pub unk1: Vec<u16>,
#[br(count = count + 2)]
pub vertex_indices: Vec<u16>,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct Group {
pub count: u32,
pub start_index: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct Unk9 {
pub unk1: u16,
pub unk2: u16,
pub unk3: u16,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(import_raw(count: u32))]
pub struct MeshInstances {
#[br(count = count)]
pub transforms: Vec<InstanceTransform>,
#[br(count = count)]
pub mesh_indices: Vec<(u16, u16)>,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct InstanceTransform {
pub transform: [[f32; 4]; 4],
pub unk2: [[f32; 4]; 4],
pub unk3: [u32; 8],
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct Unk16 {
#[br(parse_with = parse_string_ptr32, offset = base_offset)]
#[xc3(offset(u32))]
pub unk1: String,
pub unk2: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct Unk19 {
#[br(parse_with = parse_ptr32, offset = base_offset)]
#[xc3(offset(u32))]
pub unk1: u32,
pub unk2: u32, pub unk3: u32,
}
impl Xc3WriteOffsets for IdcmOffsets<'_> {
type Args = ();
fn write_offsets<W: std::io::prelude::Write + std::io::prelude::Seek>(
&self,
writer: &mut W,
_base_offset: u64,
data_ptr: &mut u64,
endian: xc3_write::Endian,
_args: Self::Args,
) -> xc3_write::Xc3Result<()> {
let base_offset = self.base_offset;
self.unk15
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.meshes
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk17
.write_full(writer, base_offset, data_ptr, endian, ())?;
let unk2 = self
.face_groups
.write(writer, base_offset, data_ptr, endian)?;
self.groups
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk4
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk18
.write_full(writer, base_offset, data_ptr, endian, ())?;
let unk16 = self.unk16.write(writer, base_offset, data_ptr, endian)?;
self.unk5
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk6
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk7
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.vertices
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk9
.write_full(writer, base_offset, data_ptr, endian, ())?;
*data_ptr += 12;
self.instances
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unks1_2
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unks1_4
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk13
.write_full(writer, base_offset, data_ptr, endian, ())?;
let unk19 = self.unk19.write(writer, base_offset, data_ptr, endian)?;
for u in unk2.0 {
u.write_offsets(writer, base_offset, data_ptr, endian, ())?;
}
for u in unk19.0 {
u.write_offsets(writer, base_offset, data_ptr, endian, ())?;
}
self.mesh_names
.write_full(writer, base_offset, data_ptr, endian, ())?;
for u in unk16.0 {
u.write_offsets(writer, base_offset, data_ptr, endian, ())?;
}
Ok(())
}
}
fn estimate_mesh_size(offset_count_offset: [u32; 3], next_offset: u32) -> u32 {
let next_offset = if next_offset == 0 {
offset_count_offset[2]
} else {
next_offset
};
(next_offset - offset_count_offset[0]) / offset_count_offset[1]
}