Skip to main content

modelio/
animation.rs

1use std::ffi::CString;
2use std::ptr;
3
4use crate::animated_value_types::{AnimatedQuaternionArray, AnimatedVector3Array};
5use crate::error::Result;
6use crate::ffi;
7use crate::handle::ObjectHandle;
8use crate::object::Object;
9use crate::protocols::{Component, JointAnimation};
10use crate::skeleton::Skeleton;
11use crate::types::{AnimationBindComponentInfo, PackedJointAnimationInfo};
12use crate::util::{c_string, parse_json, required_handle};
13
14fn c_string_vec(values: &[&str]) -> Result<(Vec<CString>, Vec<*const i8>)> {
15    let c_strings = values
16        .iter()
17        .map(|value| c_string(value))
18        .collect::<Result<Vec<_>>>()?;
19    let raw = c_strings.iter().map(|value| value.as_ptr()).collect();
20    Ok((c_strings, raw))
21}
22
23#[derive(Debug, Clone)]
24/// Wraps the corresponding Model I/O packed joint animation counterpart.
25pub struct PackedJointAnimation {
26    handle: ObjectHandle,
27}
28
29impl JointAnimation for PackedJointAnimation {}
30
31impl PackedJointAnimation {
32    /// Builds this wrapper from the retained handle of the wrapped Model I/O packed joint animation counterpart.
33    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
34        Self { handle }
35    }
36
37    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O packed joint animation counterpart.
38    pub fn new(name: &str, joint_paths: &[&str]) -> Result<Self> {
39        let name = c_string(name)?;
40        let (_joint_paths, raw_joint_paths) = c_string_vec(joint_paths)?;
41        let mut out_animation = ptr::null_mut();
42        let mut out_error = ptr::null_mut();
43        // SAFETY: The unsafe operation is valid in this context.
44        let status = unsafe {
45            ffi::mdl_packed_joint_animation_new(
46                name.as_ptr(),
47                raw_joint_paths.as_ptr(),
48                raw_joint_paths.len() as u64,
49                &mut out_animation,
50                &mut out_error,
51            )
52        };
53        crate::util::status_result(status, out_error)?;
54        Ok(Self::from_handle(required_handle(
55            out_animation,
56            "MDLPackedJointAnimation",
57        )?))
58    }
59
60    /// Calls the corresponding Model I/O method on the wrapped Model I/O packed joint animation counterpart.
61    pub fn info(&self) -> Result<PackedJointAnimationInfo> {
62        parse_json(
63            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
64            unsafe { ffi::mdl_packed_joint_animation_info_json(self.handle.as_ptr()) },
65            "MDLPackedJointAnimation",
66        )
67    }
68
69    /// Calls the corresponding Model I/O method on the wrapped Model I/O packed joint animation counterpart.
70    pub fn translations(&self) -> Result<AnimatedVector3Array> {
71        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
72        let ptr = unsafe { ffi::mdl_packed_joint_animation_translations(self.handle.as_ptr()) };
73        Ok(AnimatedVector3Array::from_handle(required_handle(
74            ptr,
75            "MDLPackedJointAnimation translations",
76        )?))
77    }
78
79    /// Calls the corresponding Model I/O method on the wrapped Model I/O packed joint animation counterpart.
80    pub fn rotations(&self) -> Result<AnimatedQuaternionArray> {
81        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
82        let ptr = unsafe { ffi::mdl_packed_joint_animation_rotations(self.handle.as_ptr()) };
83        Ok(AnimatedQuaternionArray::from_handle(required_handle(
84            ptr,
85            "MDLPackedJointAnimation rotations",
86        )?))
87    }
88
89    /// Calls the corresponding Model I/O method on the wrapped Model I/O packed joint animation counterpart.
90    pub fn scales(&self) -> Result<AnimatedVector3Array> {
91        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
92        let ptr = unsafe { ffi::mdl_packed_joint_animation_scales(self.handle.as_ptr()) };
93        Ok(AnimatedVector3Array::from_handle(required_handle(
94            ptr,
95            "MDLPackedJointAnimation scales",
96        )?))
97    }
98
99    #[must_use]
100    /// Calls the corresponding Model I/O method on the wrapped Model I/O packed joint animation counterpart.
101    pub fn as_object(&self) -> Object {
102        Object::from_handle(self.handle.clone())
103    }
104}
105
106#[derive(Debug, Clone)]
107/// Wraps the corresponding Model I/O animation bind component counterpart.
108pub struct AnimationBindComponent {
109    handle: ObjectHandle,
110}
111
112impl Component for AnimationBindComponent {}
113
114impl AnimationBindComponent {
115    /// Builds this wrapper from the retained handle of the wrapped Model I/O animation bind component counterpart.
116    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
117        Self { handle }
118    }
119
120    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O animation bind component counterpart.
121    pub fn new() -> Result<Self> {
122        let mut out_component = ptr::null_mut();
123        let mut out_error = ptr::null_mut();
124        let status =
125            // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
126            unsafe { ffi::mdl_animation_bind_component_new(&mut out_component, &mut out_error) };
127        crate::util::status_result(status, out_error)?;
128        Ok(Self::from_handle(required_handle(
129            out_component,
130            "MDLAnimationBindComponent",
131        )?))
132    }
133
134    /// Calls the corresponding Model I/O method on the wrapped Model I/O animation bind component counterpart.
135    pub fn info(&self) -> Result<AnimationBindComponentInfo> {
136        parse_json(
137            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
138            unsafe { ffi::mdl_animation_bind_component_info_json(self.handle.as_ptr()) },
139            "MDLAnimationBindComponent",
140        )
141    }
142
143    /// Calls the corresponding Model I/O method on the wrapped Model I/O animation bind component counterpart.
144    pub fn set_skeleton(&self, skeleton: &Skeleton) {
145        // SAFETY: The unsafe operation is valid in this context.
146        unsafe {
147            ffi::mdl_animation_bind_component_set_skeleton(
148                self.handle.as_ptr(),
149                skeleton.handle.as_ptr(),
150            );
151        };
152    }
153
154    #[must_use]
155    /// Calls the corresponding Model I/O method on the wrapped Model I/O animation bind component counterpart.
156    pub fn skeleton(&self) -> Option<Skeleton> {
157        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
158        let ptr = unsafe { ffi::mdl_animation_bind_component_skeleton(self.handle.as_ptr()) };
159        // SAFETY: The unsafe operation is valid in this context.
160        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Skeleton::from_handle)
161    }
162
163    /// Calls the corresponding Model I/O method on the wrapped Model I/O animation bind component counterpart.
164    pub fn set_packed_joint_animation(&self, animation: &PackedJointAnimation) {
165        // SAFETY: The unsafe operation is valid in this context.
166        unsafe {
167            ffi::mdl_animation_bind_component_set_packed_joint_animation(
168                self.handle.as_ptr(),
169                animation.handle.as_ptr(),
170            );
171        };
172    }
173
174    #[must_use]
175    /// Calls the corresponding Model I/O method on the wrapped Model I/O animation bind component counterpart.
176    pub fn packed_joint_animation(&self) -> Option<PackedJointAnimation> {
177        // SAFETY: The unsafe operation is valid in this context.
178        let ptr = unsafe {
179            ffi::mdl_animation_bind_component_packed_joint_animation(self.handle.as_ptr())
180        };
181        // SAFETY: The unsafe operation is valid in this context.
182        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PackedJointAnimation::from_handle)
183    }
184
185    /// Calls the corresponding Model I/O method on the wrapped Model I/O animation bind component counterpart.
186    pub fn set_joint_paths(&self, joint_paths: &[&str]) -> Result<()> {
187        let (_joint_paths, raw_joint_paths) = c_string_vec(joint_paths)?;
188        // SAFETY: The unsafe operation is valid in this context.
189        unsafe {
190            ffi::mdl_animation_bind_component_set_joint_paths(
191                self.handle.as_ptr(),
192                raw_joint_paths.as_ptr(),
193                raw_joint_paths.len() as u64,
194            );
195        };
196        Ok(())
197    }
198
199    /// Calls the corresponding Model I/O method on the wrapped Model I/O animation bind component counterpart.
200    pub fn set_geometry_bind_transform(&self, matrix: [f32; 16]) {
201        // SAFETY: The unsafe operation is valid in this context.
202        unsafe {
203            ffi::mdl_animation_bind_component_set_geometry_bind_transform(
204                self.handle.as_ptr(),
205                matrix.as_ptr(),
206            );
207        };
208    }
209}