1use std::panic::AssertUnwindSafe;
2use std::ptr;
3
4use crate::animated_value_types::{
5 AnimatedMatrix4x4, AnimatedQuaternion, AnimatedScalar, AnimatedValue, AnimatedVector3,
6};
7use crate::error::Result;
8use crate::ffi;
9use crate::handle::ObjectHandle;
10use crate::object::Object;
11use crate::protocols::Component;
12use crate::types::TransformOpRotationOrder;
13use crate::util::{c_string, required_handle, take_string};
14
15fn copy_matrix(
16 handle: *mut core::ffi::c_void,
17 getter: unsafe extern "C" fn(*mut core::ffi::c_void, *mut f32),
18) -> [f32; 16] {
19 let mut matrix = [0.0_f32; 16];
20 unsafe { getter(handle, matrix.as_mut_ptr()) };
22 matrix
23}
24
25fn array_objects<T, F>(
26 array_ptr: *mut core::ffi::c_void,
27 context: &'static str,
28 mut map: F,
29) -> Result<Vec<T>>
30where
31 F: FnMut(ObjectHandle) -> T,
32{
33 let array = required_handle(array_ptr, context)?;
34 let count = unsafe { ffi::mdl_array_count(array.as_ptr()) as usize };
36 let mut values = Vec::with_capacity(count);
37 for index in 0..count {
38 let ptr = unsafe { ffi::mdl_array_object_at(array.as_ptr(), index as u64) };
40 if let Some(handle) = unsafe { ObjectHandle::from_retained_ptr(ptr) } {
42 values.push(map(handle));
43 }
44 }
45 Ok(values)
46}
47
48const IDENTITY_MATRIX_F32: [f32; 16] = [
49 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
50];
51const IDENTITY_MATRIX_F64: [f64; 16] = [
52 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
53];
54
55type TransformComponentCallbackFn =
56 dyn Fn(TransformComponentEvent) -> TransformComponentResponse + Send + Sync + 'static;
57type TransformOpCallbackFn = dyn Fn(TransformOpEvent) -> TransformOpResponse + Send + Sync + 'static;
58
59struct TransformComponentCallback {
60 callback: Box<TransformComponentCallbackFn>,
61}
62
63struct TransformOpCallback {
64 callback: Box<TransformOpCallbackFn>,
65}
66
67#[derive(Debug, Clone)]
68pub enum TransformComponentEvent {
70 Matrix,
72 SetMatrix([f32; 16]),
74 ResetsTransform,
76 SetResetsTransform(bool),
78 MinimumTime,
80 MaximumTime,
82 KeyTimes,
84 SetLocalTransform([f32; 16]),
86 SetLocalTransformForTime { transform: [f32; 16], time: f64 },
88 LocalTransformAtTime(f64),
90}
91
92#[derive(Debug, Clone)]
93pub enum TransformComponentResponse {
95 Matrix([f32; 16]),
97 Bool(bool),
99 Time(f64),
101 KeyTimes(Vec<f64>),
103 None,
105}
106
107#[derive(Debug, Clone)]
108pub enum TransformOpEvent {
110 Name,
112 Float4x4AtTime(f64),
114 Double4x4AtTime(f64),
116 IsInverseOp,
118}
119
120#[derive(Debug, Clone)]
121pub enum TransformOpResponse {
123 Name(Option<String>),
125 Float4x4([f32; 16]),
127 Double4x4([f64; 16]),
129 Bool(bool),
131 None,
133}
134
135fn duplicate_c_string(value: &str) -> *mut core::ffi::c_char {
136 let Ok(value) = std::ffi::CString::new(value) else {
137 return ptr::null_mut();
138 };
139 unsafe { libc::strdup(value.as_ptr()) }
141}
142
143fn matrix_f32_from_ptr(values: *const f32) -> [f32; 16] {
144 if values.is_null() {
145 return IDENTITY_MATRIX_F32;
146 }
147 let mut matrix = [0.0_f32; 16];
148 unsafe { matrix.as_mut_ptr().copy_from_nonoverlapping(values, matrix.len()) };
150 matrix
151}
152
153fn write_matrix_f32(out_values: *mut f32, values: [f32; 16]) {
154 if out_values.is_null() {
155 return;
156 }
157 unsafe { out_values.copy_from_nonoverlapping(values.as_ptr(), values.len()) };
159}
160
161fn write_matrix_f64(out_values: *mut f64, values: [f64; 16]) {
162 if out_values.is_null() {
163 return;
164 }
165 unsafe { out_values.copy_from_nonoverlapping(values.as_ptr(), values.len()) };
167}
168
169fn transform_component_response(
170 context: *mut core::ffi::c_void,
171 event: TransformComponentEvent,
172) -> Option<TransformComponentResponse> {
173 let context = (!context.is_null()).then_some(context.cast::<TransformComponentCallback>())?;
174 std::panic::catch_unwind(AssertUnwindSafe(|| {
175 (unsafe { &*context }.callback)(event)
177 }))
178 .ok()
179}
180
181fn transform_component_matrix_response(context: *mut core::ffi::c_void) -> [f32; 16] {
182 match transform_component_response(context, TransformComponentEvent::Matrix) {
183 Some(TransformComponentResponse::Matrix(matrix)) => matrix,
184 _ => IDENTITY_MATRIX_F32,
185 }
186}
187
188fn transform_component_key_times_response(context: *mut core::ffi::c_void) -> Vec<f64> {
189 match transform_component_response(context, TransformComponentEvent::KeyTimes) {
190 Some(TransformComponentResponse::KeyTimes(key_times)) => key_times,
191 _ => vec![0.0],
192 }
193}
194
195fn transform_op_response(
196 context: *mut core::ffi::c_void,
197 event: TransformOpEvent,
198) -> Option<TransformOpResponse> {
199 let context = (!context.is_null()).then_some(context.cast::<TransformOpCallback>())?;
200 std::panic::catch_unwind(AssertUnwindSafe(|| {
201 (unsafe { &*context }.callback)(event)
203 }))
204 .ok()
205}
206
207fn transform_op_matrix_f32(context: *mut core::ffi::c_void, time: f64) -> [f32; 16] {
208 match transform_op_response(context, TransformOpEvent::Float4x4AtTime(time)) {
209 Some(TransformOpResponse::Float4x4(matrix)) => matrix,
210 Some(TransformOpResponse::Double4x4(matrix)) => matrix.map(|value| value as f32),
211 _ => IDENTITY_MATRIX_F32,
212 }
213}
214
215fn transform_op_matrix_f64(context: *mut core::ffi::c_void, time: f64) -> [f64; 16] {
216 match transform_op_response(context, TransformOpEvent::Double4x4AtTime(time)) {
217 Some(TransformOpResponse::Double4x4(matrix)) => matrix,
218 Some(TransformOpResponse::Float4x4(matrix)) => matrix.map(f64::from),
219 _ => IDENTITY_MATRIX_F64,
220 }
221}
222
223#[no_mangle]
224pub extern "C" fn mdlx_transform_component_copy_matrix(
225 context: *mut core::ffi::c_void,
226 out_values: *mut f32,
227) {
228 write_matrix_f32(out_values, transform_component_matrix_response(context));
229}
230
231#[no_mangle]
232pub extern "C" fn mdlx_transform_component_set_matrix(
233 context: *mut core::ffi::c_void,
234 values: *const f32,
235) {
236 let _ = transform_component_response(
237 context,
238 TransformComponentEvent::SetMatrix(matrix_f32_from_ptr(values)),
239 );
240}
241
242#[no_mangle]
243pub extern "C" fn mdlx_transform_component_resets_transform(
244 context: *mut core::ffi::c_void,
245) -> i32 {
246 match transform_component_response(context, TransformComponentEvent::ResetsTransform) {
247 Some(TransformComponentResponse::Bool(resets_transform)) => i32::from(resets_transform),
248 _ => 0,
249 }
250}
251
252#[no_mangle]
253pub extern "C" fn mdlx_transform_component_set_resets_transform(
254 context: *mut core::ffi::c_void,
255 resets_transform: i32,
256) {
257 let _ = transform_component_response(
258 context,
259 TransformComponentEvent::SetResetsTransform(resets_transform != 0),
260 );
261}
262
263#[no_mangle]
264pub extern "C" fn mdlx_transform_component_minimum_time(
265 context: *mut core::ffi::c_void,
266) -> f64 {
267 match transform_component_response(context, TransformComponentEvent::MinimumTime) {
268 Some(TransformComponentResponse::Time(time)) => time,
269 _ => 0.0,
270 }
271}
272
273#[no_mangle]
274pub extern "C" fn mdlx_transform_component_maximum_time(
275 context: *mut core::ffi::c_void,
276) -> f64 {
277 match transform_component_response(context, TransformComponentEvent::MaximumTime) {
278 Some(TransformComponentResponse::Time(time)) => time,
279 _ => 0.0,
280 }
281}
282
283#[no_mangle]
284pub extern "C" fn mdlx_transform_component_key_time_count(
285 context: *mut core::ffi::c_void,
286) -> u64 {
287 transform_component_key_times_response(context).len() as u64
288}
289
290#[no_mangle]
291pub extern "C" fn mdlx_transform_component_copy_key_times(
292 context: *mut core::ffi::c_void,
293 out_values: *mut f64,
294 capacity: u64,
295) -> u64 {
296 let values = transform_component_key_times_response(context);
297 let total = values.len();
298 if out_values.is_null() || capacity == 0 {
299 return total as u64;
300 }
301 let write_count = total.min(capacity as usize);
302 unsafe { out_values.copy_from_nonoverlapping(values.as_ptr(), write_count) };
304 total as u64
305}
306
307#[no_mangle]
308pub extern "C" fn mdlx_transform_component_set_local_transform(
309 context: *mut core::ffi::c_void,
310 values: *const f32,
311) {
312 let _ = transform_component_response(
313 context,
314 TransformComponentEvent::SetLocalTransform(matrix_f32_from_ptr(values)),
315 );
316}
317
318#[no_mangle]
319pub extern "C" fn mdlx_transform_component_set_local_transform_for_time(
320 context: *mut core::ffi::c_void,
321 values: *const f32,
322 time: f64,
323) {
324 let _ = transform_component_response(
325 context,
326 TransformComponentEvent::SetLocalTransformForTime {
327 transform: matrix_f32_from_ptr(values),
328 time,
329 },
330 );
331}
332
333#[no_mangle]
334pub extern "C" fn mdlx_transform_component_copy_local_transform_at_time(
335 context: *mut core::ffi::c_void,
336 time: f64,
337 out_values: *mut f32,
338) {
339 let matrix = match transform_component_response(context, TransformComponentEvent::LocalTransformAtTime(time)) {
340 Some(TransformComponentResponse::Matrix(matrix)) => matrix,
341 _ => transform_component_matrix_response(context),
342 };
343 write_matrix_f32(out_values, matrix);
344}
345
346#[no_mangle]
347pub extern "C" fn mdlx_transform_component_release(context: *mut core::ffi::c_void) {
348 if context.is_null() {
349 return;
350 }
351 unsafe { drop(Box::from_raw(context.cast::<TransformComponentCallback>())) };
353}
354
355#[no_mangle]
356pub extern "C" fn mdlx_transform_op_name(
357 context: *mut core::ffi::c_void,
358) -> *mut core::ffi::c_char {
359 match transform_op_response(context, TransformOpEvent::Name) {
360 Some(TransformOpResponse::Name(Some(name))) => duplicate_c_string(&name),
361 _ => ptr::null_mut(),
362 }
363}
364
365#[no_mangle]
366pub extern "C" fn mdlx_transform_op_is_inverse(context: *mut core::ffi::c_void) -> i32 {
367 match transform_op_response(context, TransformOpEvent::IsInverseOp) {
368 Some(TransformOpResponse::Bool(is_inverse)) => i32::from(is_inverse),
369 _ => 0,
370 }
371}
372
373#[no_mangle]
374pub extern "C" fn mdlx_transform_op_copy_float4x4_at_time(
375 context: *mut core::ffi::c_void,
376 time: f64,
377 out_values: *mut f32,
378) {
379 write_matrix_f32(out_values, transform_op_matrix_f32(context, time));
380}
381
382#[no_mangle]
383pub extern "C" fn mdlx_transform_op_copy_double4x4_at_time(
384 context: *mut core::ffi::c_void,
385 time: f64,
386 out_values: *mut f64,
387) {
388 write_matrix_f64(out_values, transform_op_matrix_f64(context, time));
389}
390
391#[no_mangle]
392pub extern "C" fn mdlx_transform_op_release(context: *mut core::ffi::c_void) {
393 if context.is_null() {
394 return;
395 }
396 unsafe { drop(Box::from_raw(context.cast::<TransformOpCallback>())) };
398}
399
400fn release_transform_component_callback_context(context: *mut core::ffi::c_void) {
401 mdlx_transform_component_release(context);
402}
403
404fn release_transform_op_callback_context(context: *mut core::ffi::c_void) {
405 mdlx_transform_op_release(context);
406}
407
408#[derive(Debug, Clone)]
409pub struct TransformComponent {
411 handle: ObjectHandle,
412}
413
414impl Component for TransformComponent {}
415
416impl TransformComponent {
417 pub fn new<F>(callback: F) -> Result<Self>
419 where
420 F: Fn(TransformComponentEvent) -> TransformComponentResponse + Send + Sync + 'static,
421 {
422 let callback = Box::new(TransformComponentCallback {
423 callback: Box::new(callback),
424 });
425 let callback_ptr = Box::into_raw(callback).cast::<core::ffi::c_void>();
426 let mut out_component = ptr::null_mut();
427 let mut out_error = ptr::null_mut();
428 let status = unsafe {
430 ffi::mdl_transform_component_new_with_callback(
431 callback_ptr,
432 &mut out_component,
433 &mut out_error,
434 )
435 };
436 if let Err(error) = crate::util::status_result(status, out_error) {
437 release_transform_component_callback_context(callback_ptr);
438 return Err(error);
439 }
440 match required_handle(out_component, "MDLTransformComponent") {
441 Ok(handle) => Ok(Self::from_handle(handle)),
442 Err(error) => {
443 release_transform_component_callback_context(callback_ptr);
444 Err(error)
445 }
446 }
447 }
448
449 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
451 Self { handle }
452 }
453
454 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
456 self.handle.as_ptr()
457 }
458
459 #[must_use]
460 pub fn matrix(&self) -> [f32; 16] {
462 copy_matrix(self.handle.as_ptr(), ffi::mdl_transform_component_matrix)
463 }
464
465 pub fn set_matrix(&self, matrix: [f32; 16]) {
467 unsafe { ffi::mdl_transform_component_set_matrix(self.handle.as_ptr(), matrix.as_ptr()) };
469 }
470
471 #[must_use]
472 pub fn resets_transform(&self) -> bool {
474 unsafe { ffi::mdl_transform_component_resets_transform(self.handle.as_ptr()) != 0 }
476 }
477
478 pub fn set_resets_transform(&self, resets_transform: bool) {
480 unsafe {
482 ffi::mdl_transform_component_set_resets_transform(
483 self.handle.as_ptr(),
484 i32::from(resets_transform),
485 );
486 }
487 }
488
489 #[must_use]
490 pub fn minimum_time(&self) -> f64 {
492 unsafe { ffi::mdl_transform_component_minimum_time(self.handle.as_ptr()) }
494 }
495
496 #[must_use]
497 pub fn maximum_time(&self) -> f64 {
499 unsafe { ffi::mdl_transform_component_maximum_time(self.handle.as_ptr()) }
501 }
502
503 #[must_use]
504 pub fn key_times(&self) -> Vec<f64> {
506 let count =
507 unsafe { ffi::mdl_transform_component_key_time_count(self.handle.as_ptr()) as usize };
509 let mut values = vec![0.0_f64; count];
510 if values.is_empty() {
511 return values;
512 }
513 let written = unsafe {
515 ffi::mdl_transform_component_copy_key_times(
516 self.handle.as_ptr(),
517 values.as_mut_ptr(),
518 values.len() as u64,
519 )
520 } as usize;
521 values.truncate(written);
522 values
523 }
524
525 #[must_use]
526 pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
528 let mut matrix = [0.0_f32; 16];
529 unsafe {
531 ffi::mdl_transform_component_local_transform_at_time(
532 self.handle.as_ptr(),
533 time,
534 matrix.as_mut_ptr(),
535 );
536 }
537 matrix
538 }
539
540 #[must_use]
541 pub fn as_transform(&self) -> Option<Transform> {
543 (unsafe { ffi::mdl_transform_component_is_transform(self.handle.as_ptr()) != 0 })
545 .then(|| Transform::from_handle(self.handle.clone()))
546 }
547
548 #[must_use]
549 pub fn as_transform_stack(&self) -> Option<TransformStack> {
551 (unsafe { ffi::mdl_transform_component_is_transform_stack(self.handle.as_ptr()) != 0 })
553 .then(|| TransformStack::from_handle(self.handle.clone()))
554 }
555
556 #[must_use]
557 pub fn global_transform_with_object(object: &Object, time: f64) -> [f32; 16] {
559 let mut matrix = [0.0_f32; 16];
560 unsafe {
562 ffi::mdl_transform_component_global_transform_with_object(
563 object.as_ptr(),
564 time,
565 matrix.as_mut_ptr(),
566 );
567 }
568 matrix
569 }
570}
571
572#[derive(Debug, Clone)]
573pub struct Transform {
575 handle: ObjectHandle,
576}
577
578impl Component for Transform {}
579
580impl Transform {
581 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
583 Self { handle }
584 }
585
586 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
588 self.handle.as_ptr()
589 }
590
591 pub fn new() -> Result<Self> {
593 let mut out_transform = ptr::null_mut();
594 let mut out_error = ptr::null_mut();
595 let status = unsafe { ffi::mdl_transform_new(&mut out_transform, &mut out_error) };
597 crate::util::status_result(status, out_error)?;
598 Ok(Self::from_handle(required_handle(
599 out_transform,
600 "MDLTransform",
601 )?))
602 }
603
604 pub fn from_component(component: &TransformComponent) -> Result<Self> {
606 let mut out_transform = ptr::null_mut();
607 let mut out_error = ptr::null_mut();
608 let status = unsafe {
610 ffi::mdl_transform_new_with_component(
611 component.as_ptr(),
612 &mut out_transform,
613 &mut out_error,
614 )
615 };
616 crate::util::status_result(status, out_error)?;
617 Ok(Self::from_handle(required_handle(
618 out_transform,
619 "MDLTransform",
620 )?))
621 }
622
623 pub fn from_component_with_resets_transform(
625 component: &TransformComponent,
626 resets_transform: bool,
627 ) -> Result<Self> {
628 let mut out_transform = ptr::null_mut();
629 let mut out_error = ptr::null_mut();
630 let status = unsafe {
632 ffi::mdl_transform_new_with_component_resets_transform(
633 component.as_ptr(),
634 i32::from(resets_transform),
635 &mut out_transform,
636 &mut out_error,
637 )
638 };
639 crate::util::status_result(status, out_error)?;
640 Ok(Self::from_handle(required_handle(
641 out_transform,
642 "MDLTransform",
643 )?))
644 }
645
646 pub fn from_matrix(matrix: [f32; 16]) -> Result<Self> {
648 let mut out_transform = ptr::null_mut();
649 let mut out_error = ptr::null_mut();
650 let status = unsafe {
652 ffi::mdl_transform_new_with_matrix(matrix.as_ptr(), &mut out_transform, &mut out_error)
653 };
654 crate::util::status_result(status, out_error)?;
655 Ok(Self::from_handle(required_handle(
656 out_transform,
657 "MDLTransform",
658 )?))
659 }
660
661 pub fn from_matrix_with_resets_transform(
663 matrix: [f32; 16],
664 resets_transform: bool,
665 ) -> Result<Self> {
666 let mut out_transform = ptr::null_mut();
667 let mut out_error = ptr::null_mut();
668 let status = unsafe {
670 ffi::mdl_transform_new_with_matrix_resets_transform(
671 matrix.as_ptr(),
672 i32::from(resets_transform),
673 &mut out_transform,
674 &mut out_error,
675 )
676 };
677 crate::util::status_result(status, out_error)?;
678 Ok(Self::from_handle(required_handle(
679 out_transform,
680 "MDLTransform",
681 )?))
682 }
683
684 #[must_use]
685 pub fn matrix(&self) -> [f32; 16] {
687 self.as_transform_component().matrix()
688 }
689
690 pub fn set_matrix(&self, matrix: [f32; 16]) {
692 self.as_transform_component().set_matrix(matrix);
693 }
694
695 #[must_use]
696 pub fn resets_transform(&self) -> bool {
698 self.as_transform_component().resets_transform()
699 }
700
701 pub fn set_resets_transform(&self, resets_transform: bool) {
703 self.as_transform_component()
704 .set_resets_transform(resets_transform);
705 }
706
707 #[must_use]
708 pub fn minimum_time(&self) -> f64 {
710 self.as_transform_component().minimum_time()
711 }
712
713 #[must_use]
714 pub fn maximum_time(&self) -> f64 {
716 self.as_transform_component().maximum_time()
717 }
718
719 #[must_use]
720 pub fn key_times(&self) -> Vec<f64> {
722 self.as_transform_component().key_times()
723 }
724
725 #[must_use]
726 pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
728 self.as_transform_component().local_transform_at_time(time)
729 }
730
731 pub fn set_identity(&self) {
733 unsafe { ffi::mdl_transform_set_identity(self.handle.as_ptr()) };
735 }
736
737 #[must_use]
738 pub fn translation_at_time(&self, time: f64) -> [f32; 3] {
740 let mut value = [0.0_f32; 3];
741 unsafe {
743 ffi::mdl_transform_translation_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
744 }
745 value
746 }
747
748 #[must_use]
749 pub fn rotation_at_time(&self, time: f64) -> [f32; 3] {
751 let mut value = [0.0_f32; 3];
752 unsafe {
754 ffi::mdl_transform_rotation_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
755 }
756 value
757 }
758
759 #[must_use]
760 pub fn shear_at_time(&self, time: f64) -> [f32; 3] {
762 let mut value = [0.0_f32; 3];
763 unsafe {
765 ffi::mdl_transform_shear_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
766 }
767 value
768 }
769
770 #[must_use]
771 pub fn scale_at_time(&self, time: f64) -> [f32; 3] {
773 let mut value = [0.0_f32; 3];
774 unsafe {
776 ffi::mdl_transform_scale_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
777 }
778 value
779 }
780
781 pub fn set_matrix_for_time(&self, matrix: [f32; 16], time: f64) {
783 unsafe {
785 ffi::mdl_transform_set_matrix_for_time(self.handle.as_ptr(), matrix.as_ptr(), time);
786 };
787 }
788
789 pub fn set_translation_for_time(&self, translation: [f32; 3], time: f64) {
791 unsafe {
793 ffi::mdl_transform_set_translation_for_time(
794 self.handle.as_ptr(),
795 translation[0],
796 translation[1],
797 translation[2],
798 time,
799 );
800 }
801 }
802
803 pub fn set_rotation_for_time(&self, rotation: [f32; 3], time: f64) {
805 unsafe {
807 ffi::mdl_transform_set_rotation_for_time(
808 self.handle.as_ptr(),
809 rotation[0],
810 rotation[1],
811 rotation[2],
812 time,
813 );
814 }
815 }
816
817 pub fn set_shear_for_time(&self, shear: [f32; 3], time: f64) {
819 unsafe {
821 ffi::mdl_transform_set_shear_for_time(
822 self.handle.as_ptr(),
823 shear[0],
824 shear[1],
825 shear[2],
826 time,
827 );
828 }
829 }
830
831 pub fn set_scale_for_time(&self, scale: [f32; 3], time: f64) {
833 unsafe {
835 ffi::mdl_transform_set_scale_for_time(
836 self.handle.as_ptr(),
837 scale[0],
838 scale[1],
839 scale[2],
840 time,
841 );
842 }
843 }
844
845 #[must_use]
846 pub fn rotation_matrix_at_time(&self, time: f64) -> [f32; 16] {
848 let mut matrix = [0.0_f32; 16];
849 unsafe {
851 ffi::mdl_transform_rotation_matrix_at_time(
852 self.handle.as_ptr(),
853 time,
854 matrix.as_mut_ptr(),
855 );
856 }
857 matrix
858 }
859
860 #[must_use]
861 pub fn translation(&self) -> [f32; 3] {
863 let mut value = [0.0_f32; 3];
864 unsafe { ffi::mdl_transform_translation(self.handle.as_ptr(), value.as_mut_ptr()) };
866 value
867 }
868
869 pub fn set_translation(&self, translation: [f32; 3]) {
871 unsafe {
873 ffi::mdl_transform_set_translation(
874 self.handle.as_ptr(),
875 translation[0],
876 translation[1],
877 translation[2],
878 );
879 }
880 }
881
882 #[must_use]
883 pub fn rotation(&self) -> [f32; 3] {
885 let mut value = [0.0_f32; 3];
886 unsafe { ffi::mdl_transform_rotation(self.handle.as_ptr(), value.as_mut_ptr()) };
888 value
889 }
890
891 pub fn set_rotation(&self, rotation: [f32; 3]) {
893 unsafe {
895 ffi::mdl_transform_set_rotation(
896 self.handle.as_ptr(),
897 rotation[0],
898 rotation[1],
899 rotation[2],
900 );
901 }
902 }
903
904 #[must_use]
905 pub fn shear(&self) -> [f32; 3] {
907 let mut value = [0.0_f32; 3];
908 unsafe { ffi::mdl_transform_shear(self.handle.as_ptr(), value.as_mut_ptr()) };
910 value
911 }
912
913 pub fn set_shear(&self, shear: [f32; 3]) {
915 unsafe {
917 ffi::mdl_transform_set_shear(self.handle.as_ptr(), shear[0], shear[1], shear[2]);
918 }
919 }
920
921 #[must_use]
922 pub fn scale(&self) -> [f32; 3] {
924 let mut value = [0.0_f32; 3];
925 unsafe { ffi::mdl_transform_scale(self.handle.as_ptr(), value.as_mut_ptr()) };
927 value
928 }
929
930 pub fn set_scale(&self, scale: [f32; 3]) {
932 unsafe {
934 ffi::mdl_transform_set_scale(self.handle.as_ptr(), scale[0], scale[1], scale[2]);
935 }
936 }
937
938 #[must_use]
939 pub fn as_transform_component(&self) -> TransformComponent {
941 TransformComponent::from_handle(self.handle.clone())
942 }
943}
944
945#[derive(Debug, Clone)]
946pub struct TransformOp {
948 handle: ObjectHandle,
949}
950
951impl TransformOp {
952 pub fn new<F>(callback: F) -> Result<Self>
954 where
955 F: Fn(TransformOpEvent) -> TransformOpResponse + Send + Sync + 'static,
956 {
957 let callback = Box::new(TransformOpCallback {
958 callback: Box::new(callback),
959 });
960 let callback_ptr = Box::into_raw(callback).cast::<core::ffi::c_void>();
961 let mut out_transform_op = ptr::null_mut();
962 let mut out_error = ptr::null_mut();
963 let status = unsafe {
965 ffi::mdl_transform_op_new_with_callback(
966 callback_ptr,
967 &mut out_transform_op,
968 &mut out_error,
969 )
970 };
971 if let Err(error) = crate::util::status_result(status, out_error) {
972 release_transform_op_callback_context(callback_ptr);
973 return Err(error);
974 }
975 match required_handle(out_transform_op, "MDLTransformOp") {
976 Ok(handle) => Ok(Self::from_handle(handle)),
977 Err(error) => {
978 release_transform_op_callback_context(callback_ptr);
979 Err(error)
980 }
981 }
982 }
983
984 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
986 Self { handle }
987 }
988
989 #[must_use]
990 pub fn name(&self) -> Option<String> {
992 take_string(unsafe { ffi::mdl_transform_op_name_string(self.handle.as_ptr()) })
994 }
995
996 #[must_use]
997 pub fn is_inverse(&self) -> bool {
999 unsafe { ffi::mdl_transform_op_is_inverse(self.handle.as_ptr()) != 0 }
1001 }
1002
1003 #[must_use]
1004 pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
1006 let mut matrix = [0.0_f32; 16];
1007 unsafe {
1009 ffi::mdl_transform_op_copy_float4x4_at_time(
1010 self.handle.as_ptr(),
1011 time,
1012 matrix.as_mut_ptr(),
1013 );
1014 };
1015 matrix
1016 }
1017
1018 #[must_use]
1019 pub fn double4x4_at_time(&self, time: f64) -> [f64; 16] {
1021 let mut matrix = [0.0_f64; 16];
1022 unsafe {
1024 ffi::mdl_transform_op_copy_double4x4_at_time(
1025 self.handle.as_ptr(),
1026 time,
1027 matrix.as_mut_ptr(),
1028 );
1029 };
1030 matrix
1031 }
1032}
1033
1034macro_rules! define_transform_op {
1035 ($name:ident, $ffi_name:ident, $animated:ty) => {
1036 #[derive(Debug, Clone)]
1037 pub struct $name {
1039 handle: ObjectHandle,
1040 }
1041
1042 impl $name {
1043 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
1045 Self { handle }
1046 }
1047
1048 #[must_use]
1049 pub fn name(&self) -> Option<String> {
1051 TransformOp::from_handle(self.handle.clone()).name()
1052 }
1053
1054 #[must_use]
1055 pub fn is_inverse(&self) -> bool {
1057 TransformOp::from_handle(self.handle.clone()).is_inverse()
1058 }
1059
1060 #[must_use]
1061 pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
1063 TransformOp::from_handle(self.handle.clone()).float4x4_at_time(time)
1064 }
1065
1066 #[must_use]
1067 pub fn animated_value(&self) -> Option<$animated> {
1069 let ptr = unsafe { ffi::$ffi_name(self.handle.as_ptr()) };
1071 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(<$animated>::from_handle)
1073 }
1074
1075 #[must_use]
1076 pub fn as_transform_op(&self) -> TransformOp {
1078 TransformOp::from_handle(self.handle.clone())
1079 }
1080 }
1081 };
1082}
1083
1084define_transform_op!(
1085 TransformRotateXOp,
1086 mdl_transform_rotate_x_op_animated_value,
1087 AnimatedScalar
1088);
1089define_transform_op!(
1090 TransformRotateYOp,
1091 mdl_transform_rotate_y_op_animated_value,
1092 AnimatedScalar
1093);
1094define_transform_op!(
1095 TransformRotateZOp,
1096 mdl_transform_rotate_z_op_animated_value,
1097 AnimatedScalar
1098);
1099define_transform_op!(
1100 TransformRotateOp,
1101 mdl_transform_rotate_op_animated_value,
1102 AnimatedVector3
1103);
1104define_transform_op!(
1105 TransformTranslateOp,
1106 mdl_transform_translate_op_animated_value,
1107 AnimatedVector3
1108);
1109define_transform_op!(
1110 TransformScaleOp,
1111 mdl_transform_scale_op_animated_value,
1112 AnimatedVector3
1113);
1114define_transform_op!(
1115 TransformMatrixOp,
1116 mdl_transform_matrix_op_animated_value,
1117 AnimatedMatrix4x4
1118);
1119define_transform_op!(
1120 TransformOrientOp,
1121 mdl_transform_orient_op_animated_value,
1122 AnimatedQuaternion
1123);
1124
1125#[derive(Debug, Clone)]
1126pub struct TransformStack {
1128 handle: ObjectHandle,
1129}
1130
1131impl TransformStack {
1132 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
1134 Self { handle }
1135 }
1136
1137 pub fn new() -> Result<Self> {
1139 let mut out_stack = ptr::null_mut();
1140 let mut out_error = ptr::null_mut();
1141 let status = unsafe { ffi::mdl_transform_stack_new(&mut out_stack, &mut out_error) };
1143 crate::util::status_result(status, out_error)?;
1144 Ok(Self::from_handle(required_handle(
1145 out_stack,
1146 "MDLTransformStack",
1147 )?))
1148 }
1149
1150 #[must_use]
1151 pub fn matrix(&self) -> [f32; 16] {
1153 self.as_transform_component().matrix()
1154 }
1155
1156 pub fn set_matrix(&self, matrix: [f32; 16]) {
1158 self.as_transform_component().set_matrix(matrix);
1159 }
1160
1161 #[must_use]
1162 pub fn resets_transform(&self) -> bool {
1164 self.as_transform_component().resets_transform()
1165 }
1166
1167 pub fn set_resets_transform(&self, resets_transform: bool) {
1169 self.as_transform_component()
1170 .set_resets_transform(resets_transform);
1171 }
1172
1173 #[must_use]
1174 pub fn minimum_time(&self) -> f64 {
1176 self.as_transform_component().minimum_time()
1177 }
1178
1179 #[must_use]
1180 pub fn maximum_time(&self) -> f64 {
1182 self.as_transform_component().maximum_time()
1183 }
1184
1185 #[must_use]
1186 pub fn key_times(&self) -> Vec<f64> {
1188 self.as_transform_component().key_times()
1189 }
1190
1191 #[must_use]
1192 pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
1194 self.as_transform_component().local_transform_at_time(time)
1195 }
1196
1197 pub fn add_translate_op(&self, name: &str, inverse: bool) -> Result<TransformTranslateOp> {
1199 let name = c_string(name)?;
1200 let ptr = unsafe {
1202 ffi::mdl_transform_stack_add_translate_op(
1203 self.handle.as_ptr(),
1204 name.as_ptr(),
1205 i32::from(inverse),
1206 )
1207 };
1208 Ok(TransformTranslateOp::from_handle(required_handle(
1209 ptr,
1210 "MDLTransformTranslateOp",
1211 )?))
1212 }
1213
1214 pub fn add_rotate_x_op(&self, name: &str, inverse: bool) -> Result<TransformRotateXOp> {
1216 let name = c_string(name)?;
1217 let ptr = unsafe {
1219 ffi::mdl_transform_stack_add_rotate_x_op(
1220 self.handle.as_ptr(),
1221 name.as_ptr(),
1222 i32::from(inverse),
1223 )
1224 };
1225 Ok(TransformRotateXOp::from_handle(required_handle(
1226 ptr,
1227 "MDLTransformRotateXOp",
1228 )?))
1229 }
1230
1231 pub fn add_rotate_y_op(&self, name: &str, inverse: bool) -> Result<TransformRotateYOp> {
1233 let name = c_string(name)?;
1234 let ptr = unsafe {
1236 ffi::mdl_transform_stack_add_rotate_y_op(
1237 self.handle.as_ptr(),
1238 name.as_ptr(),
1239 i32::from(inverse),
1240 )
1241 };
1242 Ok(TransformRotateYOp::from_handle(required_handle(
1243 ptr,
1244 "MDLTransformRotateYOp",
1245 )?))
1246 }
1247
1248 pub fn add_rotate_z_op(&self, name: &str, inverse: bool) -> Result<TransformRotateZOp> {
1250 let name = c_string(name)?;
1251 let ptr = unsafe {
1253 ffi::mdl_transform_stack_add_rotate_z_op(
1254 self.handle.as_ptr(),
1255 name.as_ptr(),
1256 i32::from(inverse),
1257 )
1258 };
1259 Ok(TransformRotateZOp::from_handle(required_handle(
1260 ptr,
1261 "MDLTransformRotateZOp",
1262 )?))
1263 }
1264
1265 pub fn add_rotate_op(
1267 &self,
1268 name: &str,
1269 rotation_order: TransformOpRotationOrder,
1270 inverse: bool,
1271 ) -> Result<TransformRotateOp> {
1272 let name = c_string(name)?;
1273 let ptr = unsafe {
1275 ffi::mdl_transform_stack_add_rotate_op(
1276 self.handle.as_ptr(),
1277 name.as_ptr(),
1278 rotation_order.as_raw(),
1279 i32::from(inverse),
1280 )
1281 };
1282 Ok(TransformRotateOp::from_handle(required_handle(
1283 ptr,
1284 "MDLTransformRotateOp",
1285 )?))
1286 }
1287
1288 pub fn add_scale_op(&self, name: &str, inverse: bool) -> Result<TransformScaleOp> {
1290 let name = c_string(name)?;
1291 let ptr = unsafe {
1293 ffi::mdl_transform_stack_add_scale_op(
1294 self.handle.as_ptr(),
1295 name.as_ptr(),
1296 i32::from(inverse),
1297 )
1298 };
1299 Ok(TransformScaleOp::from_handle(required_handle(
1300 ptr,
1301 "MDLTransformScaleOp",
1302 )?))
1303 }
1304
1305 pub fn add_matrix_op(&self, name: &str, inverse: bool) -> Result<TransformMatrixOp> {
1307 let name = c_string(name)?;
1308 let ptr = unsafe {
1310 ffi::mdl_transform_stack_add_matrix_op(
1311 self.handle.as_ptr(),
1312 name.as_ptr(),
1313 i32::from(inverse),
1314 )
1315 };
1316 Ok(TransformMatrixOp::from_handle(required_handle(
1317 ptr,
1318 "MDLTransformMatrixOp",
1319 )?))
1320 }
1321
1322 pub fn add_orient_op(&self, name: &str, inverse: bool) -> Result<TransformOrientOp> {
1324 let name = c_string(name)?;
1325 let ptr = unsafe {
1327 ffi::mdl_transform_stack_add_orient_op(
1328 self.handle.as_ptr(),
1329 name.as_ptr(),
1330 i32::from(inverse),
1331 )
1332 };
1333 Ok(TransformOrientOp::from_handle(required_handle(
1334 ptr,
1335 "MDLTransformOrientOp",
1336 )?))
1337 }
1338
1339 pub fn animated_value_named(&self, name: &str) -> Result<Option<AnimatedValue>> {
1341 let name = c_string(name)?;
1342 let ptr = unsafe {
1344 ffi::mdl_transform_stack_animated_value_named(self.handle.as_ptr(), name.as_ptr())
1345 };
1346 Ok(unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(AnimatedValue::from_handle))
1348 }
1349
1350 #[must_use]
1351 pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
1353 let mut matrix = [0.0_f32; 16];
1354 unsafe {
1356 ffi::mdl_transform_stack_copy_float4x4_at_time(
1357 self.handle.as_ptr(),
1358 time,
1359 matrix.as_mut_ptr(),
1360 );
1361 };
1362 matrix
1363 }
1364
1365 #[must_use]
1366 pub fn count(&self) -> usize {
1368 unsafe { ffi::mdl_transform_stack_count(self.handle.as_ptr()) as usize }
1370 }
1371
1372 pub fn transform_ops(&self) -> Result<Vec<TransformOp>> {
1374 let ptr = unsafe { ffi::mdl_transform_stack_transform_ops(self.handle.as_ptr()) };
1376 if ptr.is_null() {
1377 return Ok(Vec::new());
1378 }
1379 array_objects(
1380 ptr,
1381 "MDLTransformStack transformOps",
1382 TransformOp::from_handle,
1383 )
1384 }
1385
1386 #[must_use]
1387 pub fn as_transform_component(&self) -> TransformComponent {
1389 TransformComponent::from_handle(self.handle.clone())
1390 }
1391}
1392
1393impl Object {
1394 #[must_use]
1395 pub fn transform_component(&self) -> Option<TransformComponent> {
1397 let ptr = unsafe { ffi::mdl_object_transform_component(self.as_ptr()) };
1399 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(TransformComponent::from_handle)
1401 }
1402
1403 pub fn set_transform_component(&self, component: Option<&TransformComponent>) {
1405 unsafe {
1407 ffi::mdl_object_set_transform_component(
1408 self.as_ptr(),
1409 component.map_or(ptr::null_mut(), TransformComponent::as_ptr),
1410 );
1411 }
1412 }
1413}