pmx_parser 0.2.0

load and save .pmx model file.
Documentation
use std::fmt::{Debug, Formatter};
use std::io::{Read, Write};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crate::BoneIndex;

use crate::error::PmxError;
use crate::header::Header;
use crate::kits::{read_f32x3, read_vec, write_f32x3};

#[derive(Debug, Default, PartialEq, Clone)]
pub struct RigidBodies {
    pub rigid_bodies: Vec<RigidBody>,
}

impl RigidBodies {
    pub fn count(&self) -> u32 {
        self.rigid_bodies.len() as u32
    }
    pub fn read<R: Read>(header: &Header, read: &mut R) -> Result<Self, PmxError> {
        Ok(Self {
            rigid_bodies: read_vec(read, |read| RigidBody::read(header, read))?,
        })
    }
    pub fn write<W: Write>(&self, header: &Header, write: &mut W) -> Result<(), PmxError> {
        write.write_u32::<LittleEndian>(self.count())?;
        for i in &self.rigid_bodies {
            i.write(header, write)?;
        }
        Ok(())
    }
}

#[derive(Clone, PartialEq)]
pub struct RigidBody {
    pub name: String,
    pub name_en: String,
    pub bone_index: BoneIndex,
    pub group: u8,
    pub un_collision_group_flag: u16,
    pub form: RigidForm,
    pub size: [f32; 3],
    pub position: [f32; 3],
    pub rotation: [f32; 3],
    pub mass: f32,
    pub move_resist: f32,
    pub rotation_resist: f32,
    pub repulsion: f32,
    pub friction: f32,
    pub calc_method: RigidCalcMethod,
}

impl Debug for RigidBody {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let mut s = f.debug_struct("RigidBody");
        s.field("name", &self.name);
        s.finish()
    }
}

impl RigidBody {
    pub fn read<R: Read>(header: &Header, read: &mut R) -> Result<Self, PmxError> {
        Ok(Self {
            name: header.encoding.read(read)?,
            name_en: header.encoding.read(read)?,
            bone_index: header.bone_index.read(read)?,
            group: read.read_u8()?,
            un_collision_group_flag: read.read_u16::<LittleEndian>()?,
            form: RigidForm::try_from(read.read_u8()?)?,
            size: read_f32x3(read)?,
            position: read_f32x3(read)?,
            rotation: read_f32x3(read)?,
            mass: read.read_f32::<LittleEndian>()?,
            move_resist: read.read_f32::<LittleEndian>()?,
            rotation_resist: read.read_f32::<LittleEndian>()?,
            repulsion: read.read_f32::<LittleEndian>()?,
            friction: read.read_f32::<LittleEndian>()?,
            calc_method: RigidCalcMethod::try_from(read.read_u8()?)?,
        })
    }
    pub fn write<W: Write>(&self, header: &Header, write: &mut W) -> Result<(), PmxError> {
        header.encoding.write(write, self.name.as_str())?;
        header.encoding.write(write, self.name_en.as_str())?;
        header.bone_index.write(write, self.bone_index)?;
        write.write_u8(self.group)?;
        write.write_u16::<LittleEndian>(self.un_collision_group_flag)?;
        write.write_u8(self.form as u8)?;
        write_f32x3(write, self.size)?;
        write_f32x3(write, self.position)?;
        write_f32x3(write, self.rotation)?;
        write.write_f32::<LittleEndian>(self.mass)?;
        write.write_f32::<LittleEndian>(self.move_resist)?;
        write.write_f32::<LittleEndian>(self.rotation_resist)?;
        write.write_f32::<LittleEndian>(self.repulsion)?;
        write.write_f32::<LittleEndian>(self.friction)?;
        write.write_u8(self.calc_method as u8)?;
        Ok(())
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum RigidForm {
    Sphere = 0x00,
    Box = 0x01,
    Capsule = 0x02,
}

impl TryFrom<u8> for RigidForm {
    type Error = PmxError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0x00 => Ok(Self::Sphere),
            0x01 => Ok(Self::Box),
            0x02 => Ok(Self::Capsule),
            _ => Err(PmxError::RigidFormError),
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u8)]
pub enum RigidCalcMethod {
    Static = 0x00,
    Dynamic = 0x01,
    DynamicWithBonePosition = 0x02,
}

impl TryFrom<u8> for RigidCalcMethod {
    type Error = PmxError;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0x00 => Ok(Self::Static),
            0x01 => Ok(Self::Dynamic),
            0x02 => Ok(Self::DynamicWithBonePosition),
            _ => Err(PmxError::RigidCalcMethodError),
        }
    }
}