mmd 0.0.6

Miku Miku Dance format parser for rust programming language
use enumflags2::BitFlags;
use itertools::Itertools;
use std::fmt::{Debug, Display, Formatter};

use crate::{display::DisplayOption, Config};

#[derive(BitFlags, Copy, Clone, PartialEq, Debug)]
#[repr(u16)]
pub enum BoneFlags {
  Connection = 0b0000_0000_0000_0001,
  Rotatable = 0b0000_0000_0000_0010,
  Movable = 0b0000_0000_0000_0100,
  Display = 0b0000_0000_0000_1000,
  CanOperate = 0b0000_0000_0001_0000,
  InverseKinematics = 0b0000_0000_0010_0000,
  Unknown6 = 0b0000_0000_0100_0000,
  AddLocalDeform = 0b0000_0000_1000_0000,
  AddRotation = 0b0000_0001_0000_0000,
  AddMovement = 0b0000_0010_0000_0000,
  FixedAxis = 0b0000_0100_0000_0000,
  LocalAxis = 0b0000_1000_0000_0000,
  PhysicalTransform = 0b0001_0000_0000_0000,
  ExternalParentTransform = 0b0010_0000_0000_0000,
}

struct BoneFlagsFmt(BitFlags<BoneFlags>);

impl Display for BoneFlagsFmt {
  fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
    write!(f, "{}", self.0.iter().map(|v| format!("{:?}", v)).join("|"))
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Connection<C: Config> {
  Index(C::BoneIndex),
  Position(C::Vec3),
}

impl<C: Config> Display for Connection<C>
where
  C::BoneIndex: Display,
  C::Vec3: Display,
{
  fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
    match self {
      Connection::Index(t) => write!(f, "index({})", t),
      Connection::Position(i) => write!(f, "offset({})", i),
    }
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Additional<C: Config> {
  pub parent: C::BoneIndex,
  pub rate: f32,
}

impl<C: Config> Display for Additional<C>
where
  C::BoneIndex: Display,
{
  fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
    write!(f, "{} at rate {}", self.parent, self.rate)
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct LocalAxis<C: Config> {
  pub x: C::Vec3,
  pub z: C::Vec3,
}

impl<C: Config> Display for LocalAxis<C>
where
  C::Vec3: Display,
{
  fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
    write!(f, "x: {} z: {}", self.x, self.z)
  }
}

#[derive(Clone, Debug, PartialEq)]
pub struct InverseKinematics<C: Config> {
  pub ik_bone: C::BoneIndex,
  pub iterations: u32,
  pub limit_angle: f32,
  pub links: Vec<IKLink<C>>,
}

impl<C: Config> Display for InverseKinematics<C>
where
  C::BoneIndex: Display,
  C::Vec3: Display,
{
  fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
    write!(
      f,
      "index: {} iterations: {} limit angle: {}\n{}",
      self.ik_bone,
      self.iterations,
      self.limit_angle,
      self.links.iter().map(ToString::to_string).join("\n")
    )
  }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct IKLink<C: Config> {
  pub ik_bone: C::BoneIndex,
  pub limits: Option<(C::Vec3, C::Vec3)>,
}

impl<C: Config> Display for IKLink<C>
where
  C::BoneIndex: Display,
  C::Vec3: Display,
{
  fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
    write!(f, "link: {} ", self.ik_bone,)?;
    if let Some((ref low, ref high)) = self.limits {
      write!(f, "limits: [{} - {}]", low, high)
    } else {
      write!(f, "unlimited")
    }
  }
}

pub struct Bone<C: Config> {
  pub local_name: String,
  pub universal_name: String,
  pub position: C::Vec3,
  pub parent: C::BoneIndex,
  pub transform_level: i32,
  pub bone_flags: BitFlags<BoneFlags>,
  pub connection: Connection<C>,
  pub additional: Option<Additional<C>>,
  pub fixed_axis: Option<C::Vec3>,
  pub local_axis: Option<LocalAxis<C>>,
  pub external_parent_transform: Option<i32>,
  pub inverse_kinematics: Option<InverseKinematics<C>>,
}

impl<C: Config> Display for Bone<C>
where
  C::BoneIndex: Display,
  C::Vec3: Display,
{
  fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
    write!(
      f,
      r"local name: {}, universal name: {},
position: {}, parent: {}, transform level: {},
flags: {},
connection: {}, additional: {}, fixed axis: {}, local axis {}, parent transform: {},
inverse kinematics: {}",
      self.local_name,
      self.universal_name,
      self.position,
      self.parent,
      self.transform_level,
      BoneFlagsFmt(self.bone_flags),
      self.connection,
      DisplayOption::new(&self.additional),
      DisplayOption::new(&self.fixed_axis),
      DisplayOption::new(&self.local_axis),
      DisplayOption::new(&self.external_parent_transform),
      DisplayOption::new(&self.inverse_kinematics)
    )
  }
}