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};
10use crate::value_types::Matrix4x4Array;
11
12fn c_string_vec(values: &[&str]) -> Result<(Vec<CString>, Vec<*const i8>)> {
13 let c_strings = values
14 .iter()
15 .map(|value| c_string(value))
16 .collect::<Result<Vec<_>>>()?;
17 let raw = c_strings.iter().map(|value| value.as_ptr()).collect();
18 Ok((c_strings, raw))
19}
20
21fn copy_matrices(
22 handle: &ObjectHandle,
23 count: usize,
24 copier: unsafe extern "C" fn(*mut std::ffi::c_void, *mut f32, u64) -> u64,
25) -> Vec<[f32; 16]> {
26 if count == 0 {
27 return Vec::new();
28 }
29 let mut flattened = vec![0.0_f32; count * 16];
30 let written = unsafe { copier(handle.as_ptr(), flattened.as_mut_ptr(), count as u64) } as usize;
32 flattened.truncate(written * 16);
33 flattened
34 .chunks_exact(16)
35 .map(|chunk| {
36 let mut matrix = [0.0_f32; 16];
37 matrix.copy_from_slice(chunk);
38 matrix
39 })
40 .collect()
41}
42
43#[derive(Debug, Clone)]
44pub struct Skeleton {
46 pub(crate) handle: ObjectHandle,
48}
49
50impl Skeleton {
51 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
53 Self { handle }
54 }
55
56 pub fn new(name: &str, joint_paths: &[&str]) -> Result<Self> {
58 let name = c_string(name)?;
59 let (_joint_paths, raw_joint_paths) = c_string_vec(joint_paths)?;
60 let mut out_skeleton = ptr::null_mut();
61 let mut out_error = ptr::null_mut();
62 let status = unsafe {
64 ffi::mdl_skeleton_new(
65 name.as_ptr(),
66 raw_joint_paths.as_ptr(),
67 raw_joint_paths.len() as u64,
68 &mut out_skeleton,
69 &mut out_error,
70 )
71 };
72 crate::util::status_result(status, out_error)?;
73 Ok(Self::from_handle(required_handle(
74 out_skeleton,
75 "MDLSkeleton",
76 )?))
77 }
78
79 pub fn info(&self) -> Result<SkeletonInfo> {
81 parse_json(
82 unsafe { ffi::mdl_skeleton_info_json(self.handle.as_ptr()) },
84 "MDLSkeleton",
85 )
86 }
87
88 pub fn joint_bind_transform_array(&self) -> Result<Matrix4x4Array> {
90 let ptr = unsafe { ffi::mdl_skeleton_joint_bind_transform_array(self.handle.as_ptr()) };
92 Ok(Matrix4x4Array::from_handle(required_handle(
93 ptr,
94 "MDLSkeleton jointBindTransforms",
95 )?))
96 }
97
98 pub fn joint_rest_transform_array(&self) -> Result<Matrix4x4Array> {
100 let ptr = unsafe { ffi::mdl_skeleton_joint_rest_transform_array(self.handle.as_ptr()) };
102 Ok(Matrix4x4Array::from_handle(required_handle(
103 ptr,
104 "MDLSkeleton jointRestTransforms",
105 )?))
106 }
107
108 pub fn joint_bind_transforms(&self) -> Result<Vec<[f32; 16]>> {
110 let count = self.info()?.joint_bind_transform_count;
111 Ok(copy_matrices(
112 &self.handle,
113 count,
114 ffi::mdl_skeleton_copy_joint_bind_transforms,
115 ))
116 }
117
118 pub fn joint_rest_transforms(&self) -> Result<Vec<[f32; 16]>> {
120 let count = self.info()?.joint_rest_transform_count;
121 Ok(copy_matrices(
122 &self.handle,
123 count,
124 ffi::mdl_skeleton_copy_joint_rest_transforms,
125 ))
126 }
127
128 #[must_use]
129 pub fn as_object(&self) -> Object {
131 Object::from_handle(self.handle.clone())
132 }
133}