use crate::{
parse_count16_offset32, parse_count32_offset32, parse_offset32_count32, parse_opt_ptr32,
parse_ptr32, xc3_write_binwrite_impl,
};
use bilge::prelude::*;
use binrw::{BinRead, BinWrite, args, binread};
use xc3_write::{Xc3Write, Xc3WriteOffsets};
#[binread]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Xc3Write, PartialEq, Clone)]
#[br(stream = r)]
#[xc3(base_offset)]
pub struct VertexData {
#[br(temp, try_calc = r.stream_position())]
base_offset: u64,
#[br(parse_with = parse_offset32_count32)]
#[br(args { offset: base_offset, inner: base_offset })]
#[xc3(offset_count(u32, u32))]
pub vertex_buffers: Vec<VertexBufferDescriptor>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub index_buffers: Vec<IndexBufferDescriptor>,
pub unk0: u32,
pub unk1: u32,
pub unk2: u32,
#[br(parse_with = parse_ptr32)]
#[br(args { offset: base_offset, inner: args! { count: buffer_info_count(&vertex_buffers) }})]
#[xc3(offset(u32))]
pub vertex_buffer_info: Vec<VertexBufferExtInfo>,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub outline_buffers: Vec<OutlineBufferDescriptor>,
#[br(parse_with = parse_opt_ptr32)]
#[br(args { offset: base_offset, inner: base_offset })]
#[xc3(offset(u32))]
pub vertex_morphs: Option<VertexMorphs>,
#[br(parse_with = parse_count32_offset32, offset = base_offset)]
#[xc3(count_offset(u32, u32), align(4096))]
pub buffer: Vec<u8>,
#[br(parse_with = parse_opt_ptr32, offset = base_offset)]
#[xc3(offset(u32))]
pub unk_data: Option<UnkData>,
#[br(parse_with = parse_opt_ptr32)]
#[br(args { offset: base_offset, inner: base_offset })]
#[xc3(offset(u32))]
pub weights: Option<Weights>,
#[br(parse_with = parse_opt_ptr32, offset = base_offset)]
#[xc3(offset(u32))]
pub unk7: Option<Unk>,
pub unks: [u32; 5],
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, PartialEq, Eq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct VertexBufferDescriptor {
pub data_offset: u32,
pub vertex_count: u32,
pub vertex_size: u32,
#[br(parse_with = parse_offset32_count32, offset = base_offset)]
#[xc3(offset_count(u32, u32))]
pub attributes: Vec<VertexAttribute>,
pub unk1: u32,
pub unk2: u32,
pub unk3: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Eq, Clone, Copy)]
pub struct VertexAttribute {
pub data_type: DataType,
pub data_size: u16,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, BinWrite, PartialEq, Eq, Clone, Copy)]
#[brw(repr(u16))]
pub enum DataType {
Position = 0,
SkinWeights2 = 1,
BoneIndices2 = 2,
WeightIndex = 3,
WeightIndex2 = 4,
TexCoord0 = 5,
TexCoord1 = 6,
TexCoord2 = 7,
TexCoord3 = 8,
TexCoord4 = 9,
TexCoord5 = 10,
TexCoord6 = 11,
TexCoord7 = 12,
TexCoord8 = 13,
Blend = 14,
Unk15 = 15,
Unk16 = 16, VertexColor = 17,
Unk18 = 18,
Unk24 = 24,
Unk25 = 25,
Unk26 = 26,
Normal = 28,
Tangent = 29,
Unk30 = 30,
Unk31 = 31, Normal2 = 32,
ValInf = 33,
Normal3 = 34,
VertexColor3 = 35,
Position2 = 36,
Normal4 = 37,
OldPosition = 39,
Tangent2 = 40,
SkinWeights = 41,
BoneIndices = 42,
Flow = 52,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Eq, Clone)]
pub struct IndexBufferDescriptor {
pub data_offset: u32,
pub index_count: u32,
pub primitive_type: PrimitiveType,
pub index_format: IndexFormat,
pub unk3: u32,
pub unk4: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, BinWrite, PartialEq, Eq, Clone, Copy)]
#[brw(repr(u16))]
pub enum PrimitiveType {
TriangleList = 0,
QuadList = 1,
TriangleStrip = 2,
TriangleListAdjacency = 3,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, BinWrite, PartialEq, Eq, Clone, Copy)]
#[brw(repr(u16))]
pub enum IndexFormat {
Uint16 = 0,
Uint32 = 1,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct VertexMorphs {
#[br(parse_with = parse_count32_offset32)]
#[br(args { offset: base_offset, inner: base_offset })]
#[xc3(count_offset(u32, u32))]
pub descriptors: Vec<MorphDescriptor>,
#[br(parse_with = parse_count32_offset32, offset = base_offset)]
#[xc3(count_offset(u32, u32))]
pub targets: Vec<MorphTarget>,
pub unks: [u32; 4],
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, PartialEq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct MorphDescriptor {
pub vertex_buffer_index: u32,
pub target_start_index: u32,
#[br(parse_with = parse_count32_offset32, offset = base_offset)]
#[xc3(count_offset(u32, u32))]
pub param_indices: Vec<u16>,
pub unk2: u32, }
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, BinWrite, PartialEq, Clone)]
pub struct MorphTarget {
pub data_offset: u32,
pub vertex_count: u32,
pub vertex_size: u32,
pub flags: MorphTargetFlags,
}
#[bitsize(32)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(DebugBits, FromBits, BinRead, BinWrite, Clone, Copy, PartialEq)]
#[br(map = u32::into)]
#[bw(map = |&x| u32::from(x))]
pub struct MorphTargetFlags {
pub unk1: u16, pub blend_target_buffer: bool,
pub default_buffer: bool,
pub param_buffer: bool,
pub unk5: u13, }
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(import_raw(base_offset: u64))]
pub struct Weights {
#[br(parse_with = parse_count32_offset32, offset = base_offset)]
#[xc3(count_offset(u32, u32))]
pub groups: Vec<WeightGroup>,
pub vertex_buffer_index: u16,
#[br(parse_with = parse_count16_offset32, offset = base_offset)]
#[xc3(count_offset(u16, u32))]
pub weight_lods: Vec<WeightLod>,
pub unk4: u32,
pub unks: [u32; 4],
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, PartialEq, Clone, BinRead, Xc3Write, Xc3WriteOffsets)]
pub struct WeightGroup {
pub output_start_index: u32,
pub input_start_index: u32,
pub count: u32,
pub unks: [u32; 4], pub lod_group_index: u8,
pub lod_index: u8,
pub max_influences: u8,
pub unk4: u8,
pub unks2: [u32; 2],
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, PartialEq, Clone, BinRead, Xc3Write, Xc3WriteOffsets)]
pub struct WeightLod {
pub group_indices_plus_one: [u16; 9],
}
#[binread]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
#[br(stream = r)]
#[xc3(base_offset)]
pub struct Unk {
#[br(temp, try_calc = r.stream_position())]
base_offset: u64,
#[br(parse_with = parse_count32_offset32, offset = base_offset)]
#[xc3(count_offset(u32, u32))]
pub buffers: Vec<UnkBufferDescriptor>,
pub data_length: u32,
pub data_offset: u32,
pub unks: [u32; 8],
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct UnkBufferDescriptor {
pub unk1: u16,
pub unk2: u16, pub count: u32,
pub offset: u32,
pub unk5: u32,
pub start_index: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct VertexBufferExtInfo {
pub flags: VertexBufferExtInfoFlags,
pub outline_buffer_index: u16,
pub morph_target_start_index: u16,
pub morph_target_count: u16,
pub unk: u32,
}
#[bitsize(16)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(DebugBits, FromBits, BinRead, BinWrite, Clone, Copy, PartialEq)]
#[br(map = u16::into)]
#[bw(map = |&x| u16::from(x))]
pub struct VertexBufferExtInfoFlags {
pub has_outline_buffer: bool,
pub has_morph_targets: bool,
pub unk: u14,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct OutlineBufferDescriptor {
pub data_offset: u32,
pub vertex_count: u32,
pub vertex_size: u32,
pub unk: u32,
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Debug, BinRead, Xc3Write, Xc3WriteOffsets, PartialEq, Clone)]
pub struct UnkData {
pub unk1: u32, pub vertex_data_offset: u32,
pub vertex_data_length: u32,
pub uniform_data_offset: u32,
pub uniform_data_length: u32,
pub vertex_count: u32,
pub vertex_size: u32,
pub unk: [f32; 6],
}
impl DataType {
pub fn size_in_bytes(&self) -> usize {
match self {
DataType::Position => 12,
DataType::SkinWeights2 => 12,
DataType::BoneIndices2 => 4,
DataType::WeightIndex => 4,
DataType::WeightIndex2 => 4,
DataType::TexCoord0 => 8,
DataType::TexCoord1 => 8,
DataType::TexCoord2 => 8,
DataType::TexCoord3 => 8,
DataType::TexCoord4 => 8,
DataType::TexCoord5 => 8,
DataType::TexCoord6 => 8,
DataType::TexCoord7 => 8,
DataType::TexCoord8 => 8,
DataType::Blend => 4,
DataType::Unk15 => 12,
DataType::Unk16 => 8,
DataType::VertexColor => 4,
DataType::Unk18 => 12,
DataType::Unk24 => 16,
DataType::Unk25 => 16,
DataType::Unk26 => 16,
DataType::Normal => 4,
DataType::Tangent => 4,
DataType::Unk30 => 4, DataType::Unk31 => 4,
DataType::Normal2 => 4,
DataType::ValInf => 4,
DataType::Normal3 => 4,
DataType::VertexColor3 => 4,
DataType::Position2 => 12,
DataType::Normal4 => 4,
DataType::OldPosition => 12,
DataType::Tangent2 => 4,
DataType::SkinWeights => 8,
DataType::BoneIndices => 4,
DataType::Flow => 2,
}
}
}
impl From<DataType> for VertexAttribute {
fn from(data_type: DataType) -> Self {
Self {
data_type,
data_size: data_type.size_in_bytes() as u16,
}
}
}
xc3_write_binwrite_impl!(
DataType,
PrimitiveType,
IndexFormat,
MorphTarget,
VertexBufferExtInfoFlags
);
fn buffer_info_count(vertex_buffers: &[VertexBufferDescriptor]) -> usize {
vertex_buffers
.iter()
.filter(|b| {
!b.attributes
.iter()
.any(|a| a.data_type == DataType::SkinWeights)
})
.count()
}
impl Xc3WriteOffsets for VertexDataOffsets<'_> {
type Args = ();
fn write_offsets<W: std::io::Write + std::io::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;
let vertex_buffers = self
.vertex_buffers
.write(writer, base_offset, data_ptr, endian)?;
self.index_buffers
.write(writer, base_offset, data_ptr, endian)?;
self.vertex_buffer_info
.write(writer, base_offset, data_ptr, endian)?;
if !self.outline_buffers.data.is_empty() {
self.outline_buffers
.write(writer, base_offset, data_ptr, endian)?;
}
for vertex_buffer in vertex_buffers.0 {
vertex_buffer
.attributes
.write(writer, base_offset, data_ptr, endian)?;
}
self.weights
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.unk_data.write(writer, base_offset, data_ptr, endian)?;
if let Some(vertex_animation) =
self.vertex_morphs
.write(writer, base_offset, data_ptr, endian)?
{
let descriptors =
vertex_animation
.descriptors
.write(writer, base_offset, data_ptr, endian)?;
vertex_animation
.targets
.write(writer, base_offset, data_ptr, endian)?;
for descriptor in descriptors.0 {
descriptor
.param_indices
.write(writer, base_offset, data_ptr, endian)?;
}
}
self.unk7
.write_full(writer, base_offset, data_ptr, endian, ())?;
self.buffer.write(writer, base_offset, data_ptr, endian)?;
Ok(())
}
}