mod attachment;
mod bone;
mod ik;
mod info;
mod skin;
mod slot;
use self::bone::JsonBone;
use self::ik::JsonIk;
use self::info::JsonInfo;
use self::skin::JsonSkin;
use self::slot::JsonSlot;
use crate::color::Color;
use crate::skeleton::{Bone, Ik, Skeleton, Slot};
use crate::SpinalError;
use bevy_utils::HashMap;
use serde::{Deserialize, Deserializer};
pub fn parse(b: &[u8]) -> Result<Skeleton, SpinalError> {
todo!("JSON parsing is on hold--focusing on binary.");
Ok(serde_json::from_slice::<JsonSkeleton>(b)
.unwrap()
.try_into()?) }
#[derive(Debug, Deserialize)]
pub struct JsonSkeleton {
pub skeleton: JsonInfo,
pub bones: Vec<JsonBone>,
pub slots: Vec<JsonSlot>,
pub ik: Vec<JsonIk>,
pub skins: Vec<JsonSkin>,
}
impl JsonSkeleton {
}
impl TryFrom<JsonSkeleton> for Skeleton {
type Error = SpinalError;
fn try_from(json: JsonSkeleton) -> Result<Self, Self::Error> {
let lookup = Lookup::new(&json);
let JsonSkeleton {
bones,
slots,
ik,
skins,
..
} = json;
let bones = bones
.into_iter()
.map(|b| b.into_bone(&lookup))
.collect::<Result<_, _>>()?;
let slots = slots
.into_iter()
.map(|s| s.into_slot(&lookup))
.collect::<Result<_, _>>()?;
let ik = ik
.into_iter()
.map(|i| i.into_ik(&lookup))
.collect::<Result<_, _>>()?;
Ok(Self {
info: json.skeleton.into(),
strings: vec![],
bones,
bones_tree: Default::default(),
slots,
ik,
transforms: vec![],
paths: vec![],
skins: vec![],
events: vec![],
animations: vec![],
})
}
}
pub struct Lookup {
bone_name_to_id: HashMap<String, usize>,
}
impl Lookup {
fn new(json: &JsonSkeleton) -> Self {
let bone_name_to_id = json
.bones
.iter()
.enumerate()
.map(|(i, bone)| (bone.name.to_owned(), i))
.collect();
Self { bone_name_to_id }
}
fn bone_name_to_id(&self, name: &str) -> Result<usize, SpinalError> {
self.bone_name_to_id
.get(name)
.map(|i| *i)
.ok_or_else(|| SpinalError::InvalidBoneReference(name.to_owned()))
}
fn opt_bone_name_to_id(&self, name: Option<&str>) -> Result<Option<usize>, SpinalError> {
name.map(|name| self.bone_name_to_id(name)).transpose()
}
}
pub(crate) fn f32_one() -> f32 {
1.0
}
pub(crate) fn default_true() -> bool {
true
}
pub(crate) fn white() -> String {
Color::white().into()
}
pub(crate) fn bounding_box_color() -> String {
Color::bounding_box_default().into()
}
pub(crate) fn bone_color() -> String {
Color::bone_default().into()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_all() {
let b = include_bytes!("../../assets/spineboy-pro-4.1/spineboy-pro.json");
let skel = parse(b).unwrap();
dbg!(skel);
}
}