nif 0.4.0

A super-primitive Gamebryo NIF parser targeting version 20.0.0.4
Documentation
use binread::{
    io::{Read, Seek},
    BinRead, BinReaderExt,
};

use crate::common::Triangle;

#[derive(Debug, PartialEq, BinRead)]
pub struct NiSkinPartition {
    pub num_partitions: u32,
    #[br(count = num_partitions)]
    pub partitions: Vec<SkinPartition>,
}

#[derive(Debug, PartialEq, BinRead)]
pub struct SkinPartition {
    pub num_vertices: u16,
    pub num_triangles: u16,
    pub num_bones: u16,
    pub num_strips: u16,
    pub num_weights_per_vertex: u16,

    #[br(count = num_bones)]
    pub bones: Vec<u16>,

    pub has_vertex_map: u8,
    #[br(if(has_vertex_map > 0), count = num_vertices)]
    pub vertex_map: Option<Vec<u16>>,

    #[br(map = |x: u8| x > 0)]
    pub has_vertex_weights: bool,
    #[br(if(has_vertex_weights), count = num_vertices, args(num_weights_per_vertex))]
    pub vertex_weights: Option<Vec<VertexWeights>>,

    #[br(count = num_strips)]
    pub strip_lengths: Vec<u16>,
    #[br(map = |x: u8| x > 0)]
    pub has_faces: bool,
    #[br(if(has_faces && num_strips != 0), count = num_strips * strip_lengths.iter().sum::<u16>())]
    pub strips: Option<Vec<u16>>,
    #[br(if(has_faces && num_strips == 0), count = num_triangles)]
    pub triangles: Option<Vec<Triangle>>,

    #[br(map = |x: u8| x > 0)]
    pub has_bone_indices: bool,
    #[br(if(has_bone_indices), count = num_vertices * num_weights_per_vertex)]
    pub bone_indices: Option<Vec<u8>>,
}

#[derive(Debug, PartialEq, BinRead)]
#[br(import(num_weights_per_vertex: u16))]
pub struct VertexWeights {
    #[br(count = num_weights_per_vertex)]
    pub weights: Vec<f32>,
}

impl NiSkinPartition {
    pub fn parse<R: Read + Seek>(reader: &mut R) -> anyhow::Result<Self> {
        Ok(reader.read_le()?)
    }
}