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}