1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
//! The [Skel] format stores the model's skeleton used for skeletal animations. //! These files typically use the ".nusktb" suffix like "model.nusktb". //! Animations are often stored in [Anim](crate::formats::anim::Anim) files that override the [Skel] file's bone transforms. //! [Skel] files are linked with [Mesh](crate::formats::mesh::Mesh) and [Matl](crate::formats::matl::Matl) files using a [Modl](crate::formats::modl::Modl) file. use crate::{Matrix4x4, SsbhArray, SsbhString}; use binread::BinRead; #[cfg(feature = "derive_serde")] use serde::{Deserialize, Serialize}; use ssbh_write_derive::SsbhWrite; #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] #[derive(BinRead, Debug, SsbhWrite)] #[ssbhwrite(pad_after = 2)] pub struct SkelEntryFlags { pub unk1: u8, #[br(pad_after = 2)] pub billboard_type: BillboardType, } /// A named bone. /// [index](#structfield.index) and [parent_index](#structfield.parent_index) determine the skeleton's bone heirarchy. #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] #[derive(BinRead, Debug, SsbhWrite)] pub struct SkelBoneEntry { /// The name of the bone. pub name: SsbhString, // TODO: Should this be a u16 instead? /// The index of this [SkelBoneEntry] in [bone_entries](struct.Skel.html.#structfield.bone_entries). pub index: u16, /// The index of the parent [SkelBoneEntry] in [bone_entries](struct.Skel.html.#structfield.bone_entries) or `-1` if there is no parent. pub parent_index: i16, pub flags: SkelEntryFlags, } /// An ordered, hierarchical collection of bones and their associated transforms. /// Each bone entry has transformation matrices stored at the corresponding locations in the transform arrays. /// The [transforms](#structfield.transforms) array can be used to calculate the remaining arrays. /// Compatible with file version 1.0. #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] #[derive(BinRead, Debug, SsbhWrite)] pub struct Skel { pub major_version: u16, pub minor_version: u16, /// A skeleton consisting of an ordered heirarchy of bones. pub bone_entries: SsbhArray<SkelBoneEntry>, /// The transformation in world space for each bone in /// [bone_entries](#structfield.bone_entries). /// The world space transform for a bone is calculated by accumulating the transformations in [transforms](#structfield.transforms) /// with the transformation of the bone's parent recursively. pub world_transforms: SsbhArray<Matrix4x4>, /// The inverses of the matrices in [world_transforms](#structfield.world_transforms). pub inv_world_transforms: SsbhArray<Matrix4x4>, /// The associated transformation for each of the bones in [bone_entries](#structfield.bone_entries) relative to its parent's world transform. /// If the bone has no parent, this is equivalent to the corresponding value in [world_transforms](#structfield.world_transforms). pub transforms: SsbhArray<Matrix4x4>, /// The inverses of the matrices in [transforms](#structfield.transforms). pub inv_transforms: SsbhArray<Matrix4x4>, } #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] #[derive(BinRead, Debug, Clone, Copy)] #[br(repr(u8))] pub enum BillboardType { None = 0, XAxialViewpoint = 1, YAxialViewpoint = 2, Unused = 3, XYAxialViewpoint = 4, YAxial = 6, XYAxial = 8, }