orphism 0.3.0

a library for interacting with a certain format sometimes used for VTuber model assets
Documentation
use crate::{Result, Runtime};
use std::collections::BTreeMap;

mod display_info;
mod expression;
mod motion;
mod motion_sync;
mod physics;
mod pose;
mod sound;
mod texture;

pub use display_info::DisplayInfo;
pub use expression::Expression;
pub use motion::Motion;
pub use motion_sync::MotionSync;
pub use physics::Physics;
pub use pose::Pose;
pub use sound::Sound;
pub use texture::Texture;

#[derive(derivative::Derivative, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[derivative(Debug)]
#[serde(deny_unknown_fields)]
#[remain::sorted]
pub struct Model {
  #[derivative(Debug = "ignore")]
  pub data: Vec<u8>,
  pub display_info: DisplayInfo,
  pub expressions: Vec<Expression>,
  pub groups: Vec<model3::Group>,
  pub hit_areas: Vec<model3::HitArea>,
  pub motion_sync: Option<MotionSync>,
  pub motions: BTreeMap<String, Vec<Motion>>,
  pub physics: Option<Physics>,
  pub pose: Option<Pose>,
  pub textures: Vec<Texture>,
  pub version: u8,
}

impl Model {
  pub fn load(runtime: &Runtime, model: model3::Model3) -> Result<Self> {
    let model3::Model3 {
      file_references: model3::FileReferences {
        display_info,
        expressions,
        moc,
        motion_sync,
        motions,
        physics,
        pose,
        textures,
      },
      groups,
      hit_areas,
      version,
    } = model;

    let display_info = DisplayInfo::load(runtime, display_info)?;

    let motion_sync = match motion_sync {
      Some(file) => Some(MotionSync::load(runtime, file)?),
      None => None,
    };

    let physics = match physics {
      Some(file) => Some(Physics::load(runtime, file)?),
      None => None,
    };

    let pose = match pose {
      Some(file) => Some(Pose::load(runtime, file)?),
      None => None,
    };

    let expressions = expressions.into_iter().map(|expression| Expression::load(runtime, expression)).collect::<Result<Vec<Expression>>>()?;

    let textures = textures.into_iter().map(|texture| Texture::load(runtime, texture)).collect::<Result<Vec<Texture>>>()?;

    let motions = {
      let mut map = BTreeMap::new();
      for (key, values) in motions {
        let mut value = Vec::new();
        for motion in values {
          let motion = Motion::load(runtime, motion)?;
          value.push(motion);
        }
        map.insert(key, value);
      }
      map
    };

    let data = runtime.read_bytes(moc)?;

    Ok(Self {
      data,
      display_info,
      expressions,
      groups,
      hit_areas,
      motion_sync,
      motions,
      physics,
      pose,
      textures,
      version,
    })
  }
}