vmd_parser 0.1.0

load and save .vmd animation file.
Documentation
use std::fmt::Debug;
use std::io::{Read, Write};
use std::ops::Deref;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use thiserror::Error;

pub fn vmd_read<R: Read>(read: &mut R) -> Result<Vmd, VmdError> {
    Vmd::read(read)
}

pub fn vmd_write<W: Write>(write: &mut W, vmd: &Vmd) -> Result<(), VmdError> {
    vmd.write(write)
}

#[derive(Error, Debug)]
pub enum VmdError {
    #[error("magic error")]
    MagicError,

    #[error("encoding error")]
    EncodingError,

    #[error("io error {0}")]
    Io(#[from] std::io::Error),
}

const MAGIC1: [u8; 30] = *b"Vocaloid Motion Data file\0\0\0\0\0";
const MAGIC2: [u8; 30] = *b"Vocaloid Motion Data 0002\0\0\0\0\0";

fn read_u8<R: Read>(read: &mut R) -> Result<u8, std::io::Error> {
    read.read_u8()
}

fn write_u8<W: Write>(write: &mut W, v: u8) -> Result<(), std::io::Error> {
    write.write_u8(v)
}

fn read_u32<R: Read>(read: &mut R) -> Result<u32, std::io::Error> {
    read.read_u32::<LittleEndian>()
}

fn write_u32<W: Write>(write: &mut W, v: u32) -> Result<(), std::io::Error> {
    write.write_u32::<LittleEndian>(v)
}

fn read_f32<R: Read>(read: &mut R) -> Result<f32, std::io::Error> {
    read.read_f32::<LittleEndian>()
}

fn write_f32<W: Write>(write: &mut W, v: f32) -> Result<(), std::io::Error> {
    write.write_f32::<LittleEndian>(v)
}

fn read_f32x3<R: Read>(read: &mut R) -> Result<[f32; 3], std::io::Error> {
    Ok([read_f32(read)?, read_f32(read)?, read_f32(read)?])
}

fn write_f32x3<W: Write>(write: &mut W, v: [f32; 3]) -> Result<(), std::io::Error> {
    write_f32(write, v[0])?;
    write_f32(write, v[1])?;
    write_f32(write, v[2])?;
    Ok(())
}

fn read_f32x4<R: Read>(read: &mut R) -> Result<[f32; 4], std::io::Error> {
    Ok([
        read_f32(read)?,
        read_f32(read)?,
        read_f32(read)?,
        read_f32(read)?,
    ])
}

fn write_f32x4<W: Write>(write: &mut W, v: [f32; 4]) -> Result<(), std::io::Error> {
    write_f32(write, v[0])?;
    write_f32(write, v[1])?;
    write_f32(write, v[2])?;
    write_f32(write, v[3])?;
    Ok(())
}

fn read_shift_jis<R: Read>(read: &mut R, length: usize) -> Result<String, VmdError> {
    let mut buffer = vec![0_u8; length];
    read.read_exact(buffer.as_mut_slice())?;
    let (r, e) = encoding_rs::SHIFT_JIS.decode_without_bom_handling(buffer.as_slice());
    if e {
        Err(VmdError::EncodingError)
    } else {
        if let Some(i) = r.find('\0') {
            return Ok(r.get(..i).unwrap().to_string());
        }
        Ok(r.to_string())
    }
}

fn write_shift_jis<W: Write>(write: &mut W, value: &str, length: usize) -> Result<(), VmdError> {
    let (buffer, _, _) = encoding_rs::SHIFT_JIS.encode(value);
    if buffer.len() > length {
        return Err(VmdError::EncodingError);
    }
    write.write_all(buffer.deref())?;
    for _ in buffer.len()..length {
        write.write_u8(0)?;
    }
    Ok(())
}

fn read_buff<const N: usize, R: Read>(read: &mut R) -> Result<[u8; N], std::io::Error> {
    let mut buff = [0_u8; N];
    read.read_exact(&mut buff)?;
    Ok(buff)
}

fn read_vec<R: Read, F: FnMut(&mut R) -> Result<T, VmdError>, T>(
    read: &mut R,
    mut f: F,
) -> Result<Vec<T>, VmdError> {
    let len = read_u32(read)? as usize;
    let mut vec = Vec::with_capacity(len);
    for _ in 0..len {
        vec.push(f(read.by_ref())?);
    }
    Ok(vec)
}

#[derive(Debug)]
pub struct Vmd {
    pub header: Header,
    pub bone: Vec<BoneKeyFrameRecord>,
    pub morph: Vec<MorphKeyFrameRecord>,
    pub camera: Vec<CameraKeyFrameRecord>,
    pub light: Vec<LightKeyFrameRecord>,
}

impl Vmd {
    pub fn read<R: Read>(read: &mut R) -> Result<Self, VmdError> {
        Ok(Self {
            header: Header::read(read)?,
            bone: read_vec(read, |read| BoneKeyFrameRecord::read(read))?,
            morph: read_vec(read, |read| MorphKeyFrameRecord::read(read))?,
            camera: read_vec(read, |read| CameraKeyFrameRecord::read(read))?,
            light: read_vec(read, |read| LightKeyFrameRecord::read(read))?,
        })
    }
    pub fn write<W: Write>(&self, write: &mut W) -> Result<(), VmdError> {
        self.header.write(write)?;
        write_u32(write, self.bone.len() as u32)?;
        for i in &self.bone {
            i.write(write)?;
        }
        write_u32(write, self.morph.len() as u32)?;
        for i in &self.morph {
            i.write(write)?;
        }
        write_u32(write, self.camera.len() as u32)?;
        for i in &self.camera {
            i.write(write)?;
        }
        write_u32(write, self.light.len() as u32)?;
        for i in &self.light {
            i.write(write)?;
        }
        Ok(())
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Header {
    pub version: Version,
    pub name: String,
}

impl Header {
    pub fn read<R: Read>(read: &mut R) -> Result<Self, VmdError> {
        let version = Version::read(read)?;
        let name = read_shift_jis(
            read,
            match version {
                Version::V1 => 10,
                Version::V2 => 20,
            },
        )?;
        Ok(Self { version, name })
    }
    pub fn write<W: Write>(&self, write: &mut W) -> Result<(), VmdError> {
        self.version.write(write)?;
        write_shift_jis(
            write,
            self.name.as_str(),
            match self.version {
                Version::V1 => 10,
                Version::V2 => 20,
            },
        )?;
        Ok(())
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Version {
    V1,
    V2,
}

impl Version {
    pub fn read<R: Read>(read: &mut R) -> Result<Self, VmdError> {
        let mut magic = [0_u8; 30];
        read.read_exact(&mut magic)?;
        match magic {
            MAGIC1 => Ok(Self::V1),
            MAGIC2 => Ok(Self::V2),
            _ => Err(VmdError::MagicError),
        }
    }

    pub fn write<W: Write>(&self, write: &mut W) -> Result<(), VmdError> {
        match self {
            Version::V1 => {
                write.write_all(MAGIC1.as_slice())?;
            }
            Version::V2 => {
                write.write_all(MAGIC2.as_slice())?;
            }
        }
        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct BoneKeyFrameRecord {
    bone_name: String,
    frame_time: u32,
    translation: [f32; 3],
    rotation: [f32; 4],
    x_curve: [u8; 16],
    y_curve: [u8; 16],
    z_curve: [u8; 16],
    r_curve: [u8; 16],
}

impl BoneKeyFrameRecord {
    pub fn read<R: Read>(read: &mut R) -> Result<Self, VmdError> {
        Ok(Self {
            bone_name: read_shift_jis(read, 15)?,
            frame_time: read_u32(read)?,
            translation: read_f32x3(read)?,
            rotation: read_f32x4(read)?,
            x_curve: read_buff(read)?,
            y_curve: read_buff(read)?,
            z_curve: read_buff(read)?,
            r_curve: read_buff(read)?,
        })
    }
    pub fn write<W: Write>(&self, write: &mut W) -> Result<(), VmdError> {
        write_shift_jis(write, self.bone_name.as_str(), 15)?;
        write_u32(write, self.frame_time)?;
        write_f32x3(write, self.translation)?;
        write_f32x4(write, self.rotation)?;
        write.write_all(self.x_curve.as_slice())?;
        write.write_all(self.y_curve.as_slice())?;
        write.write_all(self.z_curve.as_slice())?;
        write.write_all(self.r_curve.as_slice())?;
        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct MorphKeyFrameRecord {
    morph_name: String,
    frame_time: u32,
    weight: f32,
}

impl MorphKeyFrameRecord {
    pub fn read<R: Read>(read: &mut R) -> Result<Self, VmdError> {
        Ok(Self {
            morph_name: read_shift_jis(read, 15)?,
            frame_time: read_u32(read)?,
            weight: read_f32(read)?,
        })
    }
    pub fn write<W: Write>(&self, write: &mut W) -> Result<(), VmdError> {
        write_shift_jis(write, self.morph_name.as_str(), 15)?;
        write_u32(write, self.frame_time)?;
        write_f32(write, self.weight)?;
        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct CameraKeyFrameRecord {
    frame_time: u32,
    distance: f32,
    position: [f32; 3],
    rotation: [f32; 3],
    curve: [u8; 24],
    view_angle: f32,
    orthographic: u8,
}

impl CameraKeyFrameRecord {
    pub fn read<R: Read>(read: &mut R) -> Result<Self, VmdError> {
        Ok(Self {
            frame_time: read_u32(read)?,
            distance: read_f32(read)?,
            position: read_f32x3(read)?,
            rotation: read_f32x3(read)?,
            curve: read_buff(read)?,
            view_angle: read_f32(read)?,
            orthographic: read_u8(read)?,
        })
    }
    pub fn write<W: Write>(&self, write: &mut W) -> Result<(), VmdError> {
        write_u32(write, self.frame_time)?;
        write_f32(write, self.distance)?;
        write_f32x3(write, self.position)?;
        write_f32x3(write, self.rotation)?;
        write.write_all(self.curve.as_slice())?;
        write_f32(write, self.view_angle)?;
        write_u8(write, self.orthographic)?;
        Ok(())
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct LightKeyFrameRecord {
    frame_time: u32,
    color: [f32; 3],
    direction: [f32; 3],
}

impl LightKeyFrameRecord {
    pub fn read<R: Read>(read: &mut R) -> Result<Self, VmdError> {
        Ok(Self {
            frame_time: read_u32(read)?,
            color: read_f32x3(read)?,
            direction: read_f32x3(read)?,
        })
    }
    pub fn write<W: Write>(&self, write: &mut W) -> Result<(), VmdError> {
        write_u32(write, self.frame_time)?;
        write_f32x3(write, self.color)?;
        write_f32x3(write, self.direction)?;
        Ok(())
    }
}