Skip to main content

modelio/
skeleton.rs

1use std::ffi::CString;
2use std::ptr;
3
4use crate::error::Result;
5use crate::ffi;
6use crate::handle::ObjectHandle;
7use crate::object::Object;
8use crate::types::SkeletonInfo;
9use crate::util::{c_string, parse_json, required_handle};
10
11fn c_string_vec(values: &[&str]) -> Result<(Vec<CString>, Vec<*const i8>)> {
12    let c_strings = values
13        .iter()
14        .map(|value| c_string(value))
15        .collect::<Result<Vec<_>>>()?;
16    let raw = c_strings.iter().map(|value| value.as_ptr()).collect();
17    Ok((c_strings, raw))
18}
19
20fn copy_matrices(
21    handle: &ObjectHandle,
22    count: usize,
23    copier: unsafe extern "C" fn(*mut std::ffi::c_void, *mut f32, u64) -> u64,
24) -> Vec<[f32; 16]> {
25    if count == 0 {
26        return Vec::new();
27    }
28    let mut flattened = vec![0.0_f32; count * 16];
29    let written = unsafe { copier(handle.as_ptr(), flattened.as_mut_ptr(), count as u64) } as usize;
30    flattened.truncate(written * 16);
31    flattened
32        .chunks_exact(16)
33        .map(|chunk| {
34            let mut matrix = [0.0_f32; 16];
35            matrix.copy_from_slice(chunk);
36            matrix
37        })
38        .collect()
39}
40
41#[derive(Debug, Clone)]
42pub struct Skeleton {
43    pub(crate) handle: ObjectHandle,
44}
45
46impl Skeleton {
47    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
48        Self { handle }
49    }
50
51    pub fn new(name: &str, joint_paths: &[&str]) -> Result<Self> {
52        let name = c_string(name)?;
53        let (_joint_paths, raw_joint_paths) = c_string_vec(joint_paths)?;
54        let mut out_skeleton = ptr::null_mut();
55        let mut out_error = ptr::null_mut();
56        let status = unsafe {
57            ffi::mdl_skeleton_new(
58                name.as_ptr(),
59                raw_joint_paths.as_ptr(),
60                raw_joint_paths.len() as u64,
61                &mut out_skeleton,
62                &mut out_error,
63            )
64        };
65        crate::util::status_result(status, out_error)?;
66        Ok(Self::from_handle(required_handle(
67            out_skeleton,
68            "MDLSkeleton",
69        )?))
70    }
71
72    pub fn info(&self) -> Result<SkeletonInfo> {
73        parse_json(
74            unsafe { ffi::mdl_skeleton_info_json(self.handle.as_ptr()) },
75            "MDLSkeleton",
76        )
77    }
78
79    pub fn joint_bind_transforms(&self) -> Result<Vec<[f32; 16]>> {
80        let count = self.info()?.joint_bind_transform_count;
81        Ok(copy_matrices(
82            &self.handle,
83            count,
84            ffi::mdl_skeleton_copy_joint_bind_transforms,
85        ))
86    }
87
88    pub fn joint_rest_transforms(&self) -> Result<Vec<[f32; 16]>> {
89        let count = self.info()?.joint_rest_transform_count;
90        Ok(copy_matrices(
91            &self.handle,
92            count,
93            ffi::mdl_skeleton_copy_joint_rest_transforms,
94        ))
95    }
96
97    #[must_use]
98    pub fn as_object(&self) -> Object {
99        Object::from_handle(self.handle.clone())
100    }
101}