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(())
}
}