Skip to main content

modelio/
transform.rs

1use std::ptr;
2
3use crate::animated_value_types::{
4    AnimatedMatrix4x4, AnimatedQuaternion, AnimatedScalar, AnimatedValue, AnimatedVector3,
5};
6use crate::error::Result;
7use crate::ffi;
8use crate::handle::ObjectHandle;
9use crate::object::Object;
10use crate::protocols::Component;
11use crate::types::TransformOpRotationOrder;
12use crate::util::{c_string, required_handle, take_string};
13
14fn copy_matrix(
15    handle: *mut core::ffi::c_void,
16    getter: unsafe extern "C" fn(*mut core::ffi::c_void, *mut f32),
17) -> [f32; 16] {
18    let mut matrix = [0.0_f32; 16];
19    // SAFETY: The unsafe operation is valid in this context.
20    unsafe { getter(handle, matrix.as_mut_ptr()) };
21    matrix
22}
23
24fn array_objects<T, F>(
25    array_ptr: *mut core::ffi::c_void,
26    context: &'static str,
27    mut map: F,
28) -> Result<Vec<T>>
29where
30    F: FnMut(ObjectHandle) -> T,
31{
32    let array = required_handle(array_ptr, context)?;
33    // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
34    let count = unsafe { ffi::mdl_array_count(array.as_ptr()) as usize };
35    let mut values = Vec::with_capacity(count);
36    for index in 0..count {
37        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
38        let ptr = unsafe { ffi::mdl_array_object_at(array.as_ptr(), index as u64) };
39        // SAFETY: The unsafe operation is valid in this context.
40        if let Some(handle) = unsafe { ObjectHandle::from_retained_ptr(ptr) } {
41            values.push(map(handle));
42        }
43    }
44    Ok(values)
45}
46
47#[derive(Debug, Clone)]
48/// Wraps the corresponding Model I/O transform component counterpart.
49pub struct TransformComponent {
50    handle: ObjectHandle,
51}
52
53impl TransformComponent {
54    /// Builds this wrapper from the retained handle of the wrapped Model I/O transform component counterpart.
55    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
56        Self { handle }
57    }
58
59    /// Returns the opaque pointer used to call the wrapped Model I/O transform component counterpart.
60    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
61        self.handle.as_ptr()
62    }
63
64    #[must_use]
65    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
66    pub fn matrix(&self) -> [f32; 16] {
67        copy_matrix(self.handle.as_ptr(), ffi::mdl_transform_component_matrix)
68    }
69
70    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
71    pub fn set_matrix(&self, matrix: [f32; 16]) {
72        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
73        unsafe { ffi::mdl_transform_component_set_matrix(self.handle.as_ptr(), matrix.as_ptr()) };
74    }
75
76    #[must_use]
77    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
78    pub fn resets_transform(&self) -> bool {
79        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
80        unsafe { ffi::mdl_transform_component_resets_transform(self.handle.as_ptr()) != 0 }
81    }
82
83    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
84    pub fn set_resets_transform(&self, resets_transform: bool) {
85        // SAFETY: The unsafe operation is valid in this context.
86        unsafe {
87            ffi::mdl_transform_component_set_resets_transform(
88                self.handle.as_ptr(),
89                i32::from(resets_transform),
90            );
91        }
92    }
93
94    #[must_use]
95    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
96    pub fn minimum_time(&self) -> f64 {
97        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
98        unsafe { ffi::mdl_transform_component_minimum_time(self.handle.as_ptr()) }
99    }
100
101    #[must_use]
102    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
103    pub fn maximum_time(&self) -> f64 {
104        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
105        unsafe { ffi::mdl_transform_component_maximum_time(self.handle.as_ptr()) }
106    }
107
108    #[must_use]
109    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
110    pub fn key_times(&self) -> Vec<f64> {
111        let count =
112            // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
113            unsafe { ffi::mdl_transform_component_key_time_count(self.handle.as_ptr()) as usize };
114        let mut values = vec![0.0_f64; count];
115        if values.is_empty() {
116            return values;
117        }
118        // SAFETY: The unsafe operation is valid in this context.
119        let written = unsafe {
120            ffi::mdl_transform_component_copy_key_times(
121                self.handle.as_ptr(),
122                values.as_mut_ptr(),
123                values.len() as u64,
124            )
125        } as usize;
126        values.truncate(written);
127        values
128    }
129
130    #[must_use]
131    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
132    pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
133        let mut matrix = [0.0_f32; 16];
134        // SAFETY: The unsafe operation is valid in this context.
135        unsafe {
136            ffi::mdl_transform_component_local_transform_at_time(
137                self.handle.as_ptr(),
138                time,
139                matrix.as_mut_ptr(),
140            );
141        }
142        matrix
143    }
144
145    #[must_use]
146    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
147    pub fn as_transform(&self) -> Option<Transform> {
148        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
149        (unsafe { ffi::mdl_transform_component_is_transform(self.handle.as_ptr()) != 0 })
150            .then(|| Transform::from_handle(self.handle.clone()))
151    }
152
153    #[must_use]
154    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
155    pub fn as_transform_stack(&self) -> Option<TransformStack> {
156        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
157        (unsafe { ffi::mdl_transform_component_is_transform_stack(self.handle.as_ptr()) != 0 })
158            .then(|| TransformStack::from_handle(self.handle.clone()))
159    }
160
161    #[must_use]
162    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform component counterpart.
163    pub fn global_transform_with_object(object: &Object, time: f64) -> [f32; 16] {
164        let mut matrix = [0.0_f32; 16];
165        // SAFETY: The unsafe operation is valid in this context.
166        unsafe {
167            ffi::mdl_transform_component_global_transform_with_object(
168                object.as_ptr(),
169                time,
170                matrix.as_mut_ptr(),
171            );
172        }
173        matrix
174    }
175}
176
177#[derive(Debug, Clone)]
178/// Wraps the corresponding Model I/O transform counterpart.
179pub struct Transform {
180    handle: ObjectHandle,
181}
182
183impl Component for Transform {}
184
185impl Transform {
186    /// Builds this wrapper from the retained handle of the wrapped Model I/O transform counterpart.
187    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
188        Self { handle }
189    }
190
191    /// Returns the opaque pointer used to call the wrapped Model I/O transform counterpart.
192    pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
193        self.handle.as_ptr()
194    }
195
196    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O transform counterpart.
197    pub fn new() -> Result<Self> {
198        let mut out_transform = ptr::null_mut();
199        let mut out_error = ptr::null_mut();
200        // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
201        let status = unsafe { ffi::mdl_transform_new(&mut out_transform, &mut out_error) };
202        crate::util::status_result(status, out_error)?;
203        Ok(Self::from_handle(required_handle(
204            out_transform,
205            "MDLTransform",
206        )?))
207    }
208
209    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
210    pub fn from_component(component: &TransformComponent) -> Result<Self> {
211        let mut out_transform = ptr::null_mut();
212        let mut out_error = ptr::null_mut();
213        // SAFETY: The unsafe operation is valid in this context.
214        let status = unsafe {
215            ffi::mdl_transform_new_with_component(
216                component.as_ptr(),
217                &mut out_transform,
218                &mut out_error,
219            )
220        };
221        crate::util::status_result(status, out_error)?;
222        Ok(Self::from_handle(required_handle(
223            out_transform,
224            "MDLTransform",
225        )?))
226    }
227
228    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
229    pub fn from_component_with_resets_transform(
230        component: &TransformComponent,
231        resets_transform: bool,
232    ) -> Result<Self> {
233        let mut out_transform = ptr::null_mut();
234        let mut out_error = ptr::null_mut();
235        // SAFETY: The unsafe operation is valid in this context.
236        let status = unsafe {
237            ffi::mdl_transform_new_with_component_resets_transform(
238                component.as_ptr(),
239                i32::from(resets_transform),
240                &mut out_transform,
241                &mut out_error,
242            )
243        };
244        crate::util::status_result(status, out_error)?;
245        Ok(Self::from_handle(required_handle(
246            out_transform,
247            "MDLTransform",
248        )?))
249    }
250
251    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
252    pub fn from_matrix(matrix: [f32; 16]) -> Result<Self> {
253        let mut out_transform = ptr::null_mut();
254        let mut out_error = ptr::null_mut();
255        // SAFETY: The unsafe operation is valid in this context.
256        let status = unsafe {
257            ffi::mdl_transform_new_with_matrix(matrix.as_ptr(), &mut out_transform, &mut out_error)
258        };
259        crate::util::status_result(status, out_error)?;
260        Ok(Self::from_handle(required_handle(
261            out_transform,
262            "MDLTransform",
263        )?))
264    }
265
266    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
267    pub fn from_matrix_with_resets_transform(
268        matrix: [f32; 16],
269        resets_transform: bool,
270    ) -> Result<Self> {
271        let mut out_transform = ptr::null_mut();
272        let mut out_error = ptr::null_mut();
273        // SAFETY: The unsafe operation is valid in this context.
274        let status = unsafe {
275            ffi::mdl_transform_new_with_matrix_resets_transform(
276                matrix.as_ptr(),
277                i32::from(resets_transform),
278                &mut out_transform,
279                &mut out_error,
280            )
281        };
282        crate::util::status_result(status, out_error)?;
283        Ok(Self::from_handle(required_handle(
284            out_transform,
285            "MDLTransform",
286        )?))
287    }
288
289    #[must_use]
290    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
291    pub fn matrix(&self) -> [f32; 16] {
292        self.as_transform_component().matrix()
293    }
294
295    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
296    pub fn set_matrix(&self, matrix: [f32; 16]) {
297        self.as_transform_component().set_matrix(matrix);
298    }
299
300    #[must_use]
301    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
302    pub fn resets_transform(&self) -> bool {
303        self.as_transform_component().resets_transform()
304    }
305
306    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
307    pub fn set_resets_transform(&self, resets_transform: bool) {
308        self.as_transform_component()
309            .set_resets_transform(resets_transform);
310    }
311
312    #[must_use]
313    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
314    pub fn minimum_time(&self) -> f64 {
315        self.as_transform_component().minimum_time()
316    }
317
318    #[must_use]
319    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
320    pub fn maximum_time(&self) -> f64 {
321        self.as_transform_component().maximum_time()
322    }
323
324    #[must_use]
325    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
326    pub fn key_times(&self) -> Vec<f64> {
327        self.as_transform_component().key_times()
328    }
329
330    #[must_use]
331    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
332    pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
333        self.as_transform_component().local_transform_at_time(time)
334    }
335
336    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
337    pub fn set_identity(&self) {
338        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
339        unsafe { ffi::mdl_transform_set_identity(self.handle.as_ptr()) };
340    }
341
342    #[must_use]
343    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
344    pub fn translation_at_time(&self, time: f64) -> [f32; 3] {
345        let mut value = [0.0_f32; 3];
346        // SAFETY: The unsafe operation is valid in this context.
347        unsafe {
348            ffi::mdl_transform_translation_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
349        }
350        value
351    }
352
353    #[must_use]
354    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
355    pub fn rotation_at_time(&self, time: f64) -> [f32; 3] {
356        let mut value = [0.0_f32; 3];
357        // SAFETY: The unsafe operation is valid in this context.
358        unsafe {
359            ffi::mdl_transform_rotation_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
360        }
361        value
362    }
363
364    #[must_use]
365    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
366    pub fn shear_at_time(&self, time: f64) -> [f32; 3] {
367        let mut value = [0.0_f32; 3];
368        // SAFETY: The unsafe operation is valid in this context.
369        unsafe {
370            ffi::mdl_transform_shear_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
371        }
372        value
373    }
374
375    #[must_use]
376    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
377    pub fn scale_at_time(&self, time: f64) -> [f32; 3] {
378        let mut value = [0.0_f32; 3];
379        // SAFETY: The unsafe operation is valid in this context.
380        unsafe {
381            ffi::mdl_transform_scale_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
382        }
383        value
384    }
385
386    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
387    pub fn set_matrix_for_time(&self, matrix: [f32; 16], time: f64) {
388        // SAFETY: The unsafe operation is valid in this context.
389        unsafe {
390            ffi::mdl_transform_set_matrix_for_time(self.handle.as_ptr(), matrix.as_ptr(), time);
391        };
392    }
393
394    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
395    pub fn set_translation_for_time(&self, translation: [f32; 3], time: f64) {
396        // SAFETY: The unsafe operation is valid in this context.
397        unsafe {
398            ffi::mdl_transform_set_translation_for_time(
399                self.handle.as_ptr(),
400                translation[0],
401                translation[1],
402                translation[2],
403                time,
404            );
405        }
406    }
407
408    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
409    pub fn set_rotation_for_time(&self, rotation: [f32; 3], time: f64) {
410        // SAFETY: The unsafe operation is valid in this context.
411        unsafe {
412            ffi::mdl_transform_set_rotation_for_time(
413                self.handle.as_ptr(),
414                rotation[0],
415                rotation[1],
416                rotation[2],
417                time,
418            );
419        }
420    }
421
422    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
423    pub fn set_shear_for_time(&self, shear: [f32; 3], time: f64) {
424        // SAFETY: The unsafe operation is valid in this context.
425        unsafe {
426            ffi::mdl_transform_set_shear_for_time(
427                self.handle.as_ptr(),
428                shear[0],
429                shear[1],
430                shear[2],
431                time,
432            );
433        }
434    }
435
436    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
437    pub fn set_scale_for_time(&self, scale: [f32; 3], time: f64) {
438        // SAFETY: The unsafe operation is valid in this context.
439        unsafe {
440            ffi::mdl_transform_set_scale_for_time(
441                self.handle.as_ptr(),
442                scale[0],
443                scale[1],
444                scale[2],
445                time,
446            );
447        }
448    }
449
450    #[must_use]
451    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
452    pub fn rotation_matrix_at_time(&self, time: f64) -> [f32; 16] {
453        let mut matrix = [0.0_f32; 16];
454        // SAFETY: The unsafe operation is valid in this context.
455        unsafe {
456            ffi::mdl_transform_rotation_matrix_at_time(
457                self.handle.as_ptr(),
458                time,
459                matrix.as_mut_ptr(),
460            );
461        }
462        matrix
463    }
464
465    #[must_use]
466    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
467    pub fn translation(&self) -> [f32; 3] {
468        let mut value = [0.0_f32; 3];
469        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
470        unsafe { ffi::mdl_transform_translation(self.handle.as_ptr(), value.as_mut_ptr()) };
471        value
472    }
473
474    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
475    pub fn set_translation(&self, translation: [f32; 3]) {
476        // SAFETY: The unsafe operation is valid in this context.
477        unsafe {
478            ffi::mdl_transform_set_translation(
479                self.handle.as_ptr(),
480                translation[0],
481                translation[1],
482                translation[2],
483            );
484        }
485    }
486
487    #[must_use]
488    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
489    pub fn rotation(&self) -> [f32; 3] {
490        let mut value = [0.0_f32; 3];
491        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
492        unsafe { ffi::mdl_transform_rotation(self.handle.as_ptr(), value.as_mut_ptr()) };
493        value
494    }
495
496    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
497    pub fn set_rotation(&self, rotation: [f32; 3]) {
498        // SAFETY: The unsafe operation is valid in this context.
499        unsafe {
500            ffi::mdl_transform_set_rotation(
501                self.handle.as_ptr(),
502                rotation[0],
503                rotation[1],
504                rotation[2],
505            );
506        }
507    }
508
509    #[must_use]
510    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
511    pub fn shear(&self) -> [f32; 3] {
512        let mut value = [0.0_f32; 3];
513        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
514        unsafe { ffi::mdl_transform_shear(self.handle.as_ptr(), value.as_mut_ptr()) };
515        value
516    }
517
518    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
519    pub fn set_shear(&self, shear: [f32; 3]) {
520        // SAFETY: The unsafe operation is valid in this context.
521        unsafe {
522            ffi::mdl_transform_set_shear(self.handle.as_ptr(), shear[0], shear[1], shear[2]);
523        }
524    }
525
526    #[must_use]
527    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
528    pub fn scale(&self) -> [f32; 3] {
529        let mut value = [0.0_f32; 3];
530        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
531        unsafe { ffi::mdl_transform_scale(self.handle.as_ptr(), value.as_mut_ptr()) };
532        value
533    }
534
535    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
536    pub fn set_scale(&self, scale: [f32; 3]) {
537        // SAFETY: The unsafe operation is valid in this context.
538        unsafe {
539            ffi::mdl_transform_set_scale(self.handle.as_ptr(), scale[0], scale[1], scale[2]);
540        }
541    }
542
543    #[must_use]
544    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform counterpart.
545    pub fn as_transform_component(&self) -> TransformComponent {
546        TransformComponent::from_handle(self.handle.clone())
547    }
548}
549
550#[derive(Debug, Clone)]
551/// Wraps the corresponding Model I/O transform op counterpart.
552pub struct TransformOp {
553    handle: ObjectHandle,
554}
555
556impl TransformOp {
557    /// Builds this wrapper from the retained handle of the wrapped Model I/O transform op counterpart.
558    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
559        Self { handle }
560    }
561
562    #[must_use]
563    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform op counterpart.
564    pub fn name(&self) -> Option<String> {
565        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
566        take_string(unsafe { ffi::mdl_transform_op_name_string(self.handle.as_ptr()) })
567    }
568
569    #[must_use]
570    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform op counterpart.
571    pub fn is_inverse(&self) -> bool {
572        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
573        unsafe { ffi::mdl_transform_op_is_inverse(self.handle.as_ptr()) != 0 }
574    }
575
576    #[must_use]
577    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform op counterpart.
578    pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
579        let mut matrix = [0.0_f32; 16];
580        // SAFETY: The unsafe operation is valid in this context.
581        unsafe {
582            ffi::mdl_transform_op_copy_float4x4_at_time(
583                self.handle.as_ptr(),
584                time,
585                matrix.as_mut_ptr(),
586            );
587        };
588        matrix
589    }
590}
591
592macro_rules! define_transform_op {
593    ($name:ident, $ffi_name:ident, $animated:ty) => {
594        #[derive(Debug, Clone)]
595        /// Wraps the corresponding Model I/O counterpart.
596        pub struct $name {
597            handle: ObjectHandle,
598        }
599
600        impl $name {
601            /// Builds this wrapper from the retained handle of the wrapped Model I/O name counterpart.
602            pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
603                Self { handle }
604            }
605
606            #[must_use]
607            /// Calls the corresponding Model I/O method on the wrapped Model I/O name counterpart.
608            pub fn name(&self) -> Option<String> {
609                TransformOp::from_handle(self.handle.clone()).name()
610            }
611
612            #[must_use]
613            /// Calls the corresponding Model I/O method on the wrapped Model I/O name counterpart.
614            pub fn is_inverse(&self) -> bool {
615                TransformOp::from_handle(self.handle.clone()).is_inverse()
616            }
617
618            #[must_use]
619            /// Calls the corresponding Model I/O method on the wrapped Model I/O name counterpart.
620            pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
621                TransformOp::from_handle(self.handle.clone()).float4x4_at_time(time)
622            }
623
624            #[must_use]
625            /// Calls the corresponding Model I/O method on the wrapped Model I/O name counterpart.
626            pub fn animated_value(&self) -> Option<$animated> {
627                // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
628                let ptr = unsafe { ffi::$ffi_name(self.handle.as_ptr()) };
629                // SAFETY: The unsafe operation is valid in this context.
630                unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(<$animated>::from_handle)
631            }
632
633            #[must_use]
634            /// Calls the corresponding Model I/O method on the wrapped Model I/O name counterpart.
635            pub fn as_transform_op(&self) -> TransformOp {
636                TransformOp::from_handle(self.handle.clone())
637            }
638        }
639    };
640}
641
642define_transform_op!(
643    TransformRotateXOp,
644    mdl_transform_rotate_x_op_animated_value,
645    AnimatedScalar
646);
647define_transform_op!(
648    TransformRotateYOp,
649    mdl_transform_rotate_y_op_animated_value,
650    AnimatedScalar
651);
652define_transform_op!(
653    TransformRotateZOp,
654    mdl_transform_rotate_z_op_animated_value,
655    AnimatedScalar
656);
657define_transform_op!(
658    TransformRotateOp,
659    mdl_transform_rotate_op_animated_value,
660    AnimatedVector3
661);
662define_transform_op!(
663    TransformTranslateOp,
664    mdl_transform_translate_op_animated_value,
665    AnimatedVector3
666);
667define_transform_op!(
668    TransformScaleOp,
669    mdl_transform_scale_op_animated_value,
670    AnimatedVector3
671);
672define_transform_op!(
673    TransformMatrixOp,
674    mdl_transform_matrix_op_animated_value,
675    AnimatedMatrix4x4
676);
677define_transform_op!(
678    TransformOrientOp,
679    mdl_transform_orient_op_animated_value,
680    AnimatedQuaternion
681);
682
683#[derive(Debug, Clone)]
684/// Wraps the corresponding Model I/O transform stack counterpart.
685pub struct TransformStack {
686    handle: ObjectHandle,
687}
688
689impl TransformStack {
690    /// Builds this wrapper from the retained handle of the wrapped Model I/O transform stack counterpart.
691    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
692        Self { handle }
693    }
694
695    /// Wraps the corresponding Model I/O initializer for the wrapped Model I/O transform stack counterpart.
696    pub fn new() -> Result<Self> {
697        let mut out_stack = ptr::null_mut();
698        let mut out_error = ptr::null_mut();
699        // SAFETY: Output pointers are initialized and managed; FFI function is called safely.
700        let status = unsafe { ffi::mdl_transform_stack_new(&mut out_stack, &mut out_error) };
701        crate::util::status_result(status, out_error)?;
702        Ok(Self::from_handle(required_handle(
703            out_stack,
704            "MDLTransformStack",
705        )?))
706    }
707
708    #[must_use]
709    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
710    pub fn matrix(&self) -> [f32; 16] {
711        self.as_transform_component().matrix()
712    }
713
714    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
715    pub fn set_matrix(&self, matrix: [f32; 16]) {
716        self.as_transform_component().set_matrix(matrix);
717    }
718
719    #[must_use]
720    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
721    pub fn resets_transform(&self) -> bool {
722        self.as_transform_component().resets_transform()
723    }
724
725    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
726    pub fn set_resets_transform(&self, resets_transform: bool) {
727        self.as_transform_component()
728            .set_resets_transform(resets_transform);
729    }
730
731    #[must_use]
732    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
733    pub fn minimum_time(&self) -> f64 {
734        self.as_transform_component().minimum_time()
735    }
736
737    #[must_use]
738    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
739    pub fn maximum_time(&self) -> f64 {
740        self.as_transform_component().maximum_time()
741    }
742
743    #[must_use]
744    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
745    pub fn key_times(&self) -> Vec<f64> {
746        self.as_transform_component().key_times()
747    }
748
749    #[must_use]
750    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
751    pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
752        self.as_transform_component().local_transform_at_time(time)
753    }
754
755    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
756    pub fn add_translate_op(&self, name: &str, inverse: bool) -> Result<TransformTranslateOp> {
757        let name = c_string(name)?;
758        // SAFETY: The unsafe operation is valid in this context.
759        let ptr = unsafe {
760            ffi::mdl_transform_stack_add_translate_op(
761                self.handle.as_ptr(),
762                name.as_ptr(),
763                i32::from(inverse),
764            )
765        };
766        Ok(TransformTranslateOp::from_handle(required_handle(
767            ptr,
768            "MDLTransformTranslateOp",
769        )?))
770    }
771
772    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
773    pub fn add_rotate_x_op(&self, name: &str, inverse: bool) -> Result<TransformRotateXOp> {
774        let name = c_string(name)?;
775        // SAFETY: The unsafe operation is valid in this context.
776        let ptr = unsafe {
777            ffi::mdl_transform_stack_add_rotate_x_op(
778                self.handle.as_ptr(),
779                name.as_ptr(),
780                i32::from(inverse),
781            )
782        };
783        Ok(TransformRotateXOp::from_handle(required_handle(
784            ptr,
785            "MDLTransformRotateXOp",
786        )?))
787    }
788
789    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
790    pub fn add_rotate_y_op(&self, name: &str, inverse: bool) -> Result<TransformRotateYOp> {
791        let name = c_string(name)?;
792        // SAFETY: The unsafe operation is valid in this context.
793        let ptr = unsafe {
794            ffi::mdl_transform_stack_add_rotate_y_op(
795                self.handle.as_ptr(),
796                name.as_ptr(),
797                i32::from(inverse),
798            )
799        };
800        Ok(TransformRotateYOp::from_handle(required_handle(
801            ptr,
802            "MDLTransformRotateYOp",
803        )?))
804    }
805
806    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
807    pub fn add_rotate_z_op(&self, name: &str, inverse: bool) -> Result<TransformRotateZOp> {
808        let name = c_string(name)?;
809        // SAFETY: The unsafe operation is valid in this context.
810        let ptr = unsafe {
811            ffi::mdl_transform_stack_add_rotate_z_op(
812                self.handle.as_ptr(),
813                name.as_ptr(),
814                i32::from(inverse),
815            )
816        };
817        Ok(TransformRotateZOp::from_handle(required_handle(
818            ptr,
819            "MDLTransformRotateZOp",
820        )?))
821    }
822
823    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
824    pub fn add_rotate_op(
825        &self,
826        name: &str,
827        rotation_order: TransformOpRotationOrder,
828        inverse: bool,
829    ) -> Result<TransformRotateOp> {
830        let name = c_string(name)?;
831        // SAFETY: The unsafe operation is valid in this context.
832        let ptr = unsafe {
833            ffi::mdl_transform_stack_add_rotate_op(
834                self.handle.as_ptr(),
835                name.as_ptr(),
836                rotation_order.as_raw(),
837                i32::from(inverse),
838            )
839        };
840        Ok(TransformRotateOp::from_handle(required_handle(
841            ptr,
842            "MDLTransformRotateOp",
843        )?))
844    }
845
846    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
847    pub fn add_scale_op(&self, name: &str, inverse: bool) -> Result<TransformScaleOp> {
848        let name = c_string(name)?;
849        // SAFETY: The unsafe operation is valid in this context.
850        let ptr = unsafe {
851            ffi::mdl_transform_stack_add_scale_op(
852                self.handle.as_ptr(),
853                name.as_ptr(),
854                i32::from(inverse),
855            )
856        };
857        Ok(TransformScaleOp::from_handle(required_handle(
858            ptr,
859            "MDLTransformScaleOp",
860        )?))
861    }
862
863    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
864    pub fn add_matrix_op(&self, name: &str, inverse: bool) -> Result<TransformMatrixOp> {
865        let name = c_string(name)?;
866        // SAFETY: The unsafe operation is valid in this context.
867        let ptr = unsafe {
868            ffi::mdl_transform_stack_add_matrix_op(
869                self.handle.as_ptr(),
870                name.as_ptr(),
871                i32::from(inverse),
872            )
873        };
874        Ok(TransformMatrixOp::from_handle(required_handle(
875            ptr,
876            "MDLTransformMatrixOp",
877        )?))
878    }
879
880    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
881    pub fn add_orient_op(&self, name: &str, inverse: bool) -> Result<TransformOrientOp> {
882        let name = c_string(name)?;
883        // SAFETY: The unsafe operation is valid in this context.
884        let ptr = unsafe {
885            ffi::mdl_transform_stack_add_orient_op(
886                self.handle.as_ptr(),
887                name.as_ptr(),
888                i32::from(inverse),
889            )
890        };
891        Ok(TransformOrientOp::from_handle(required_handle(
892            ptr,
893            "MDLTransformOrientOp",
894        )?))
895    }
896
897    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
898    pub fn animated_value_named(&self, name: &str) -> Result<Option<AnimatedValue>> {
899        let name = c_string(name)?;
900        // SAFETY: The unsafe operation is valid in this context.
901        let ptr = unsafe {
902            ffi::mdl_transform_stack_animated_value_named(self.handle.as_ptr(), name.as_ptr())
903        };
904        // SAFETY: The unsafe operation is valid in this context.
905        Ok(unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(AnimatedValue::from_handle))
906    }
907
908    #[must_use]
909    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
910    pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
911        let mut matrix = [0.0_f32; 16];
912        // SAFETY: The unsafe operation is valid in this context.
913        unsafe {
914            ffi::mdl_transform_stack_copy_float4x4_at_time(
915                self.handle.as_ptr(),
916                time,
917                matrix.as_mut_ptr(),
918            );
919        };
920        matrix
921    }
922
923    #[must_use]
924    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
925    pub fn count(&self) -> usize {
926        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
927        unsafe { ffi::mdl_transform_stack_count(self.handle.as_ptr()) as usize }
928    }
929
930    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
931    pub fn transform_ops(&self) -> Result<Vec<TransformOp>> {
932        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
933        let ptr = unsafe { ffi::mdl_transform_stack_transform_ops(self.handle.as_ptr()) };
934        if ptr.is_null() {
935            return Ok(Vec::new());
936        }
937        array_objects(
938            ptr,
939            "MDLTransformStack transformOps",
940            TransformOp::from_handle,
941        )
942    }
943
944    #[must_use]
945    /// Calls the corresponding Model I/O method on the wrapped Model I/O transform stack counterpart.
946    pub fn as_transform_component(&self) -> TransformComponent {
947        TransformComponent::from_handle(self.handle.clone())
948    }
949}
950
951impl Object {
952    #[must_use]
953    /// Calls the corresponding Model I/O method on the wrapped Model I/O object counterpart.
954    pub fn transform_component(&self) -> Option<TransformComponent> {
955        // SAFETY: ObjectHandle wraps a valid opaque pointer from Swift; FFI function accepts it safely.
956        let ptr = unsafe { ffi::mdl_object_transform_component(self.as_ptr()) };
957        // SAFETY: The unsafe operation is valid in this context.
958        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(TransformComponent::from_handle)
959    }
960
961    /// Calls the corresponding Model I/O method on the wrapped Model I/O object counterpart.
962    pub fn set_transform_component(&self, component: Option<&TransformComponent>) {
963        // SAFETY: The unsafe operation is valid in this context.
964        unsafe {
965            ffi::mdl_object_set_transform_component(
966                self.as_ptr(),
967                component.map_or(ptr::null_mut(), TransformComponent::as_ptr),
968            );
969        }
970    }
971}