rbx_mesh 0.8.0

Rust parser for Roblox mesh files.
Documentation
use super::v2::{Face2, Vertex2};
use super::v3::Lod3;

#[binrw::binrw]
#[brw(little)]
#[derive(Debug, Clone)]
pub enum Revision4 {
	#[brw(magic = b"version 4.00")]
	Version400,
	#[brw(magic = b"version 4.01")]
	Version401,
}

#[binrw::binrw]
#[brw(little,repr=u16)]
#[derive(Debug, Clone)]
pub enum LodType4 {
	None = 0,
	Unknown = 1,
	RbxSimplifier = 2,
	ZeuxMeshOptimizer = 3,
	Type4 = 4, //shows up in sphere.mesh, don't know what it is
}

#[binrw::binrw]
#[brw(little)]
#[derive(Debug, Clone)]
pub struct Envelope4 {
	pub bones: [u8; 4],
	pub weights: [u8; 4],
}

#[binrw::binrw]
#[brw(little)]
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub struct BoneId4(u16);
impl BoneId4 {
	pub fn new(value: Option<u16>) -> Self {
		Self(value.unwrap_or(0xFFFF))
	}
	pub fn get(&self) -> Option<u16> {
		match self.0 {
			0xFFFF => None,
			other => Some(other),
		}
	}
}

#[binrw::binrw]
#[brw(little)]
#[derive(Debug, Clone)]
pub struct CFrame4 {
	pub r00: f32,
	pub r01: f32,
	pub r02: f32,
	pub r10: f32,
	pub r11: f32,
	pub r12: f32,
	pub r20: f32,
	pub r21: f32,
	pub r22: f32,
	pub x: f32,
	pub y: f32,
	pub z: f32,
}

#[binrw::binrw]
#[brw(little)]
#[derive(Debug, Clone)]
pub struct Bone4 {
	pub bone_name_pos: u32,
	pub parent: BoneId4,
	pub lod_parent: BoneId4,
	pub cull_distance: f32,
	pub cframe: CFrame4,
}

#[binrw::binrw]
#[brw(little)]
#[derive(Debug, Clone)]
pub struct Subset4 {
	pub faces_offset: u32,
	pub faces_len: u32,
	pub vertices_offset: u32,
	pub vertices_len: u32,
	pub bone_count: u32,
	pub bones: [BoneId4; 26],
}

#[binrw::binrw]
#[brw(little)]
#[derive(Debug, Clone)]
/// envelopes has the same length as vertices when header.bone_count!=0
pub struct Mesh4 {
	pub revision: Revision4,
	#[br(temp)]
	#[bw(ignore)]
	#[brw(magic = b"\n")]
	_newline: (),
	#[br(temp)]
	#[bw(ignore)]
	#[brw(magic = 24u16)]
	_sizeof_header: (),
	pub lod_type: LodType4,
	#[br(temp)]
	#[bw(try_calc=vertices.len().try_into())]
	pub vertex_count: u32,
	#[br(temp)]
	#[bw(try_calc=faces.len().try_into())]
	pub face_count: u32,
	#[br(temp)]
	#[bw(try_calc=lods.len().try_into())]
	pub lod_count: u16,
	#[br(temp)]
	#[bw(try_calc=bones.len().try_into())]
	pub bone_count: u16,
	#[br(temp)]
	#[bw(try_calc=bone_names.len().try_into())]
	pub bone_names_len: u32,
	#[br(temp)]
	#[bw(try_calc=subsets.len().try_into())]
	pub subset_count: u16,
	pub lod_hq_count: u8,
	pub _padding: u8,
	#[br(count=vertex_count)]
	pub vertices: Vec<Vertex2>,
	#[br(count=if bone_count==0{0}else{vertex_count})]
	pub envelopes: Vec<Envelope4>,
	#[br(count=face_count)]
	pub faces: Vec<Face2>,
	#[br(count=lod_count)]
	pub lods: Vec<Lod3>,
	#[br(count=bone_count)]
	pub bones: Vec<Bone4>,
	#[br(count=bone_names_len)]
	pub bone_names: Vec<u8>,
	#[br(count=subset_count)]
	pub subsets: Vec<Subset4>,
}