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::types::TransformOpRotationOrder;
11use crate::util::{c_string, required_handle, take_string};
12
13fn copy_matrix(
14 handle: *mut core::ffi::c_void,
15 getter: unsafe extern "C" fn(*mut core::ffi::c_void, *mut f32),
16) -> [f32; 16] {
17 let mut matrix = [0.0_f32; 16];
18 unsafe { getter(handle, matrix.as_mut_ptr()) };
19 matrix
20}
21
22fn array_objects<T, F>(array_ptr: *mut core::ffi::c_void, context: &'static str, mut map: F) -> Result<Vec<T>>
23where
24 F: FnMut(ObjectHandle) -> T,
25{
26 let array = required_handle(array_ptr, context)?;
27 let count = unsafe { ffi::mdl_array_count(array.as_ptr()) as usize };
28 let mut values = Vec::with_capacity(count);
29 for index in 0..count {
30 let ptr = unsafe { ffi::mdl_array_object_at(array.as_ptr(), index as u64) };
31 if let Some(handle) = unsafe { ObjectHandle::from_retained_ptr(ptr) } {
32 values.push(map(handle));
33 }
34 }
35 Ok(values)
36}
37
38#[derive(Debug, Clone)]
39pub struct TransformComponent {
40 handle: ObjectHandle,
41}
42
43impl TransformComponent {
44 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
45 Self { handle }
46 }
47
48 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
49 self.handle.as_ptr()
50 }
51
52 #[must_use]
53 pub fn matrix(&self) -> [f32; 16] {
54 copy_matrix(self.handle.as_ptr(), ffi::mdl_transform_component_matrix)
55 }
56
57 pub fn set_matrix(&self, matrix: [f32; 16]) {
58 unsafe { ffi::mdl_transform_component_set_matrix(self.handle.as_ptr(), matrix.as_ptr()) };
59 }
60
61 #[must_use]
62 pub fn resets_transform(&self) -> bool {
63 unsafe { ffi::mdl_transform_component_resets_transform(self.handle.as_ptr()) != 0 }
64 }
65
66 pub fn set_resets_transform(&self, resets_transform: bool) {
67 unsafe {
68 ffi::mdl_transform_component_set_resets_transform(
69 self.handle.as_ptr(),
70 i32::from(resets_transform),
71 );
72 }
73 }
74
75 #[must_use]
76 pub fn minimum_time(&self) -> f64 {
77 unsafe { ffi::mdl_transform_component_minimum_time(self.handle.as_ptr()) }
78 }
79
80 #[must_use]
81 pub fn maximum_time(&self) -> f64 {
82 unsafe { ffi::mdl_transform_component_maximum_time(self.handle.as_ptr()) }
83 }
84
85 #[must_use]
86 pub fn key_times(&self) -> Vec<f64> {
87 let count = unsafe { ffi::mdl_transform_component_key_time_count(self.handle.as_ptr()) as usize };
88 let mut values = vec![0.0_f64; count];
89 if values.is_empty() {
90 return values;
91 }
92 let written = unsafe {
93 ffi::mdl_transform_component_copy_key_times(
94 self.handle.as_ptr(),
95 values.as_mut_ptr(),
96 values.len() as u64,
97 )
98 } as usize;
99 values.truncate(written);
100 values
101 }
102
103 #[must_use]
104 pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
105 let mut matrix = [0.0_f32; 16];
106 unsafe {
107 ffi::mdl_transform_component_local_transform_at_time(
108 self.handle.as_ptr(),
109 time,
110 matrix.as_mut_ptr(),
111 );
112 }
113 matrix
114 }
115
116 #[must_use]
117 pub fn as_transform(&self) -> Option<Transform> {
118 (unsafe { ffi::mdl_transform_component_is_transform(self.handle.as_ptr()) != 0 })
119 .then(|| Transform::from_handle(self.handle.clone()))
120 }
121
122 #[must_use]
123 pub fn as_transform_stack(&self) -> Option<TransformStack> {
124 (unsafe { ffi::mdl_transform_component_is_transform_stack(self.handle.as_ptr()) != 0 })
125 .then(|| TransformStack::from_handle(self.handle.clone()))
126 }
127
128 #[must_use]
129 pub fn global_transform_with_object(object: &Object, time: f64) -> [f32; 16] {
130 let mut matrix = [0.0_f32; 16];
131 unsafe {
132 ffi::mdl_transform_component_global_transform_with_object(
133 object.as_ptr(),
134 time,
135 matrix.as_mut_ptr(),
136 );
137 }
138 matrix
139 }
140}
141
142#[derive(Debug, Clone)]
143pub struct Transform {
144 handle: ObjectHandle,
145}
146
147impl Transform {
148 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
149 Self { handle }
150 }
151
152 pub fn new() -> Result<Self> {
153 let mut out_transform = ptr::null_mut();
154 let mut out_error = ptr::null_mut();
155 let status = unsafe { ffi::mdl_transform_new(&mut out_transform, &mut out_error) };
156 crate::util::status_result(status, out_error)?;
157 Ok(Self::from_handle(required_handle(out_transform, "MDLTransform")?))
158 }
159
160 pub fn from_component(component: &TransformComponent) -> Result<Self> {
161 let mut out_transform = ptr::null_mut();
162 let mut out_error = ptr::null_mut();
163 let status = unsafe {
164 ffi::mdl_transform_new_with_component(
165 component.as_ptr(),
166 &mut out_transform,
167 &mut out_error,
168 )
169 };
170 crate::util::status_result(status, out_error)?;
171 Ok(Self::from_handle(required_handle(out_transform, "MDLTransform")?))
172 }
173
174 pub fn from_component_with_resets_transform(
175 component: &TransformComponent,
176 resets_transform: bool,
177 ) -> Result<Self> {
178 let mut out_transform = ptr::null_mut();
179 let mut out_error = ptr::null_mut();
180 let status = unsafe {
181 ffi::mdl_transform_new_with_component_resets_transform(
182 component.as_ptr(),
183 i32::from(resets_transform),
184 &mut out_transform,
185 &mut out_error,
186 )
187 };
188 crate::util::status_result(status, out_error)?;
189 Ok(Self::from_handle(required_handle(out_transform, "MDLTransform")?))
190 }
191
192 pub fn from_matrix(matrix: [f32; 16]) -> Result<Self> {
193 let mut out_transform = ptr::null_mut();
194 let mut out_error = ptr::null_mut();
195 let status = unsafe {
196 ffi::mdl_transform_new_with_matrix(
197 matrix.as_ptr(),
198 &mut out_transform,
199 &mut out_error,
200 )
201 };
202 crate::util::status_result(status, out_error)?;
203 Ok(Self::from_handle(required_handle(out_transform, "MDLTransform")?))
204 }
205
206 pub fn from_matrix_with_resets_transform(
207 matrix: [f32; 16],
208 resets_transform: bool,
209 ) -> Result<Self> {
210 let mut out_transform = ptr::null_mut();
211 let mut out_error = ptr::null_mut();
212 let status = unsafe {
213 ffi::mdl_transform_new_with_matrix_resets_transform(
214 matrix.as_ptr(),
215 i32::from(resets_transform),
216 &mut out_transform,
217 &mut out_error,
218 )
219 };
220 crate::util::status_result(status, out_error)?;
221 Ok(Self::from_handle(required_handle(out_transform, "MDLTransform")?))
222 }
223
224 #[must_use]
225 pub fn matrix(&self) -> [f32; 16] {
226 self.as_transform_component().matrix()
227 }
228
229 pub fn set_matrix(&self, matrix: [f32; 16]) {
230 self.as_transform_component().set_matrix(matrix);
231 }
232
233 #[must_use]
234 pub fn resets_transform(&self) -> bool {
235 self.as_transform_component().resets_transform()
236 }
237
238 pub fn set_resets_transform(&self, resets_transform: bool) {
239 self.as_transform_component().set_resets_transform(resets_transform);
240 }
241
242 #[must_use]
243 pub fn minimum_time(&self) -> f64 {
244 self.as_transform_component().minimum_time()
245 }
246
247 #[must_use]
248 pub fn maximum_time(&self) -> f64 {
249 self.as_transform_component().maximum_time()
250 }
251
252 #[must_use]
253 pub fn key_times(&self) -> Vec<f64> {
254 self.as_transform_component().key_times()
255 }
256
257 #[must_use]
258 pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
259 self.as_transform_component().local_transform_at_time(time)
260 }
261
262 pub fn set_identity(&self) {
263 unsafe { ffi::mdl_transform_set_identity(self.handle.as_ptr()) };
264 }
265
266 #[must_use]
267 pub fn translation_at_time(&self, time: f64) -> [f32; 3] {
268 let mut value = [0.0_f32; 3];
269 unsafe {
270 ffi::mdl_transform_translation_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
271 }
272 value
273 }
274
275 #[must_use]
276 pub fn rotation_at_time(&self, time: f64) -> [f32; 3] {
277 let mut value = [0.0_f32; 3];
278 unsafe {
279 ffi::mdl_transform_rotation_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
280 }
281 value
282 }
283
284 #[must_use]
285 pub fn shear_at_time(&self, time: f64) -> [f32; 3] {
286 let mut value = [0.0_f32; 3];
287 unsafe {
288 ffi::mdl_transform_shear_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
289 }
290 value
291 }
292
293 #[must_use]
294 pub fn scale_at_time(&self, time: f64) -> [f32; 3] {
295 let mut value = [0.0_f32; 3];
296 unsafe {
297 ffi::mdl_transform_scale_at_time(self.handle.as_ptr(), time, value.as_mut_ptr());
298 }
299 value
300 }
301
302 pub fn set_matrix_for_time(&self, matrix: [f32; 16], time: f64) {
303 unsafe { ffi::mdl_transform_set_matrix_for_time(self.handle.as_ptr(), matrix.as_ptr(), time) };
304 }
305
306 pub fn set_translation_for_time(&self, translation: [f32; 3], time: f64) {
307 unsafe {
308 ffi::mdl_transform_set_translation_for_time(
309 self.handle.as_ptr(),
310 translation[0],
311 translation[1],
312 translation[2],
313 time,
314 );
315 }
316 }
317
318 pub fn set_rotation_for_time(&self, rotation: [f32; 3], time: f64) {
319 unsafe {
320 ffi::mdl_transform_set_rotation_for_time(
321 self.handle.as_ptr(),
322 rotation[0],
323 rotation[1],
324 rotation[2],
325 time,
326 );
327 }
328 }
329
330 pub fn set_shear_for_time(&self, shear: [f32; 3], time: f64) {
331 unsafe {
332 ffi::mdl_transform_set_shear_for_time(
333 self.handle.as_ptr(),
334 shear[0],
335 shear[1],
336 shear[2],
337 time,
338 );
339 }
340 }
341
342 pub fn set_scale_for_time(&self, scale: [f32; 3], time: f64) {
343 unsafe {
344 ffi::mdl_transform_set_scale_for_time(
345 self.handle.as_ptr(),
346 scale[0],
347 scale[1],
348 scale[2],
349 time,
350 );
351 }
352 }
353
354 #[must_use]
355 pub fn rotation_matrix_at_time(&self, time: f64) -> [f32; 16] {
356 let mut matrix = [0.0_f32; 16];
357 unsafe {
358 ffi::mdl_transform_rotation_matrix_at_time(
359 self.handle.as_ptr(),
360 time,
361 matrix.as_mut_ptr(),
362 );
363 }
364 matrix
365 }
366
367 #[must_use]
368 pub fn translation(&self) -> [f32; 3] {
369 let mut value = [0.0_f32; 3];
370 unsafe { ffi::mdl_transform_translation(self.handle.as_ptr(), value.as_mut_ptr()) };
371 value
372 }
373
374 pub fn set_translation(&self, translation: [f32; 3]) {
375 unsafe {
376 ffi::mdl_transform_set_translation(
377 self.handle.as_ptr(),
378 translation[0],
379 translation[1],
380 translation[2],
381 );
382 }
383 }
384
385 #[must_use]
386 pub fn rotation(&self) -> [f32; 3] {
387 let mut value = [0.0_f32; 3];
388 unsafe { ffi::mdl_transform_rotation(self.handle.as_ptr(), value.as_mut_ptr()) };
389 value
390 }
391
392 pub fn set_rotation(&self, rotation: [f32; 3]) {
393 unsafe {
394 ffi::mdl_transform_set_rotation(
395 self.handle.as_ptr(),
396 rotation[0],
397 rotation[1],
398 rotation[2],
399 );
400 }
401 }
402
403 #[must_use]
404 pub fn shear(&self) -> [f32; 3] {
405 let mut value = [0.0_f32; 3];
406 unsafe { ffi::mdl_transform_shear(self.handle.as_ptr(), value.as_mut_ptr()) };
407 value
408 }
409
410 pub fn set_shear(&self, shear: [f32; 3]) {
411 unsafe {
412 ffi::mdl_transform_set_shear(
413 self.handle.as_ptr(),
414 shear[0],
415 shear[1],
416 shear[2],
417 );
418 }
419 }
420
421 #[must_use]
422 pub fn scale(&self) -> [f32; 3] {
423 let mut value = [0.0_f32; 3];
424 unsafe { ffi::mdl_transform_scale(self.handle.as_ptr(), value.as_mut_ptr()) };
425 value
426 }
427
428 pub fn set_scale(&self, scale: [f32; 3]) {
429 unsafe {
430 ffi::mdl_transform_set_scale(
431 self.handle.as_ptr(),
432 scale[0],
433 scale[1],
434 scale[2],
435 );
436 }
437 }
438
439 #[must_use]
440 pub fn as_transform_component(&self) -> TransformComponent {
441 TransformComponent::from_handle(self.handle.clone())
442 }
443}
444
445#[derive(Debug, Clone)]
446pub struct TransformOp {
447 handle: ObjectHandle,
448}
449
450impl TransformOp {
451 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
452 Self { handle }
453 }
454
455 #[must_use]
456 pub fn name(&self) -> Option<String> {
457 take_string(unsafe { ffi::mdl_transform_op_name_string(self.handle.as_ptr()) })
458 }
459
460 #[must_use]
461 pub fn is_inverse(&self) -> bool {
462 unsafe { ffi::mdl_transform_op_is_inverse(self.handle.as_ptr()) != 0 }
463 }
464
465 #[must_use]
466 pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
467 let mut matrix = [0.0_f32; 16];
468 unsafe { ffi::mdl_transform_op_copy_float4x4_at_time(self.handle.as_ptr(), time, matrix.as_mut_ptr()) };
469 matrix
470 }
471}
472
473macro_rules! define_transform_op {
474 ($name:ident, $ffi_name:ident, $animated:ty) => {
475 #[derive(Debug, Clone)]
476 pub struct $name {
477 handle: ObjectHandle,
478 }
479
480 impl $name {
481 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
482 Self { handle }
483 }
484
485 #[must_use]
486 pub fn name(&self) -> Option<String> {
487 TransformOp::from_handle(self.handle.clone()).name()
488 }
489
490 #[must_use]
491 pub fn is_inverse(&self) -> bool {
492 TransformOp::from_handle(self.handle.clone()).is_inverse()
493 }
494
495 #[must_use]
496 pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
497 TransformOp::from_handle(self.handle.clone()).float4x4_at_time(time)
498 }
499
500 #[must_use]
501 pub fn animated_value(&self) -> Option<$animated> {
502 let ptr = unsafe { ffi::$ffi_name(self.handle.as_ptr()) };
503 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(<$animated>::from_handle)
504 }
505
506 #[must_use]
507 pub fn as_transform_op(&self) -> TransformOp {
508 TransformOp::from_handle(self.handle.clone())
509 }
510 }
511 };
512}
513
514define_transform_op!(TransformRotateXOp, mdl_transform_rotate_x_op_animated_value, AnimatedScalar);
515define_transform_op!(TransformRotateYOp, mdl_transform_rotate_y_op_animated_value, AnimatedScalar);
516define_transform_op!(TransformRotateZOp, mdl_transform_rotate_z_op_animated_value, AnimatedScalar);
517define_transform_op!(TransformRotateOp, mdl_transform_rotate_op_animated_value, AnimatedVector3);
518define_transform_op!(TransformTranslateOp, mdl_transform_translate_op_animated_value, AnimatedVector3);
519define_transform_op!(TransformScaleOp, mdl_transform_scale_op_animated_value, AnimatedVector3);
520define_transform_op!(TransformMatrixOp, mdl_transform_matrix_op_animated_value, AnimatedMatrix4x4);
521define_transform_op!(TransformOrientOp, mdl_transform_orient_op_animated_value, AnimatedQuaternion);
522
523#[derive(Debug, Clone)]
524pub struct TransformStack {
525 handle: ObjectHandle,
526}
527
528impl TransformStack {
529 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
530 Self { handle }
531 }
532
533 pub fn new() -> Result<Self> {
534 let mut out_stack = ptr::null_mut();
535 let mut out_error = ptr::null_mut();
536 let status = unsafe { ffi::mdl_transform_stack_new(&mut out_stack, &mut out_error) };
537 crate::util::status_result(status, out_error)?;
538 Ok(Self::from_handle(required_handle(
539 out_stack,
540 "MDLTransformStack",
541 )?))
542 }
543
544 #[must_use]
545 pub fn matrix(&self) -> [f32; 16] {
546 self.as_transform_component().matrix()
547 }
548
549 pub fn set_matrix(&self, matrix: [f32; 16]) {
550 self.as_transform_component().set_matrix(matrix);
551 }
552
553 #[must_use]
554 pub fn resets_transform(&self) -> bool {
555 self.as_transform_component().resets_transform()
556 }
557
558 pub fn set_resets_transform(&self, resets_transform: bool) {
559 self.as_transform_component().set_resets_transform(resets_transform);
560 }
561
562 #[must_use]
563 pub fn minimum_time(&self) -> f64 {
564 self.as_transform_component().minimum_time()
565 }
566
567 #[must_use]
568 pub fn maximum_time(&self) -> f64 {
569 self.as_transform_component().maximum_time()
570 }
571
572 #[must_use]
573 pub fn key_times(&self) -> Vec<f64> {
574 self.as_transform_component().key_times()
575 }
576
577 #[must_use]
578 pub fn local_transform_at_time(&self, time: f64) -> [f32; 16] {
579 self.as_transform_component().local_transform_at_time(time)
580 }
581
582 pub fn add_translate_op(&self, name: &str, inverse: bool) -> Result<TransformTranslateOp> {
583 let name = c_string(name)?;
584 let ptr = unsafe {
585 ffi::mdl_transform_stack_add_translate_op(
586 self.handle.as_ptr(),
587 name.as_ptr(),
588 i32::from(inverse),
589 )
590 };
591 Ok(TransformTranslateOp::from_handle(required_handle(
592 ptr,
593 "MDLTransformTranslateOp",
594 )?))
595 }
596
597 pub fn add_rotate_x_op(&self, name: &str, inverse: bool) -> Result<TransformRotateXOp> {
598 let name = c_string(name)?;
599 let ptr = unsafe {
600 ffi::mdl_transform_stack_add_rotate_x_op(
601 self.handle.as_ptr(),
602 name.as_ptr(),
603 i32::from(inverse),
604 )
605 };
606 Ok(TransformRotateXOp::from_handle(required_handle(
607 ptr,
608 "MDLTransformRotateXOp",
609 )?))
610 }
611
612 pub fn add_rotate_y_op(&self, name: &str, inverse: bool) -> Result<TransformRotateYOp> {
613 let name = c_string(name)?;
614 let ptr = unsafe {
615 ffi::mdl_transform_stack_add_rotate_y_op(
616 self.handle.as_ptr(),
617 name.as_ptr(),
618 i32::from(inverse),
619 )
620 };
621 Ok(TransformRotateYOp::from_handle(required_handle(
622 ptr,
623 "MDLTransformRotateYOp",
624 )?))
625 }
626
627 pub fn add_rotate_z_op(&self, name: &str, inverse: bool) -> Result<TransformRotateZOp> {
628 let name = c_string(name)?;
629 let ptr = unsafe {
630 ffi::mdl_transform_stack_add_rotate_z_op(
631 self.handle.as_ptr(),
632 name.as_ptr(),
633 i32::from(inverse),
634 )
635 };
636 Ok(TransformRotateZOp::from_handle(required_handle(
637 ptr,
638 "MDLTransformRotateZOp",
639 )?))
640 }
641
642 pub fn add_rotate_op(
643 &self,
644 name: &str,
645 rotation_order: TransformOpRotationOrder,
646 inverse: bool,
647 ) -> Result<TransformRotateOp> {
648 let name = c_string(name)?;
649 let ptr = unsafe {
650 ffi::mdl_transform_stack_add_rotate_op(
651 self.handle.as_ptr(),
652 name.as_ptr(),
653 rotation_order.as_raw(),
654 i32::from(inverse),
655 )
656 };
657 Ok(TransformRotateOp::from_handle(required_handle(
658 ptr,
659 "MDLTransformRotateOp",
660 )?))
661 }
662
663 pub fn add_scale_op(&self, name: &str, inverse: bool) -> Result<TransformScaleOp> {
664 let name = c_string(name)?;
665 let ptr = unsafe {
666 ffi::mdl_transform_stack_add_scale_op(
667 self.handle.as_ptr(),
668 name.as_ptr(),
669 i32::from(inverse),
670 )
671 };
672 Ok(TransformScaleOp::from_handle(required_handle(
673 ptr,
674 "MDLTransformScaleOp",
675 )?))
676 }
677
678 pub fn add_matrix_op(&self, name: &str, inverse: bool) -> Result<TransformMatrixOp> {
679 let name = c_string(name)?;
680 let ptr = unsafe {
681 ffi::mdl_transform_stack_add_matrix_op(
682 self.handle.as_ptr(),
683 name.as_ptr(),
684 i32::from(inverse),
685 )
686 };
687 Ok(TransformMatrixOp::from_handle(required_handle(
688 ptr,
689 "MDLTransformMatrixOp",
690 )?))
691 }
692
693 pub fn add_orient_op(&self, name: &str, inverse: bool) -> Result<TransformOrientOp> {
694 let name = c_string(name)?;
695 let ptr = unsafe {
696 ffi::mdl_transform_stack_add_orient_op(
697 self.handle.as_ptr(),
698 name.as_ptr(),
699 i32::from(inverse),
700 )
701 };
702 Ok(TransformOrientOp::from_handle(required_handle(
703 ptr,
704 "MDLTransformOrientOp",
705 )?))
706 }
707
708 pub fn animated_value_named(&self, name: &str) -> Result<Option<AnimatedValue>> {
709 let name = c_string(name)?;
710 let ptr = unsafe { ffi::mdl_transform_stack_animated_value_named(self.handle.as_ptr(), name.as_ptr()) };
711 Ok(unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(AnimatedValue::from_handle))
712 }
713
714 #[must_use]
715 pub fn float4x4_at_time(&self, time: f64) -> [f32; 16] {
716 let mut matrix = [0.0_f32; 16];
717 unsafe { ffi::mdl_transform_stack_copy_float4x4_at_time(self.handle.as_ptr(), time, matrix.as_mut_ptr()) };
718 matrix
719 }
720
721 #[must_use]
722 pub fn count(&self) -> usize {
723 unsafe { ffi::mdl_transform_stack_count(self.handle.as_ptr()) as usize }
724 }
725
726 pub fn transform_ops(&self) -> Result<Vec<TransformOp>> {
727 let ptr = unsafe { ffi::mdl_transform_stack_transform_ops(self.handle.as_ptr()) };
728 if ptr.is_null() {
729 return Ok(Vec::new());
730 }
731 array_objects(ptr, "MDLTransformStack transformOps", TransformOp::from_handle)
732 }
733
734 #[must_use]
735 pub fn as_transform_component(&self) -> TransformComponent {
736 TransformComponent::from_handle(self.handle.clone())
737 }
738}
739
740impl Object {
741 #[must_use]
742 pub fn transform_component(&self) -> Option<TransformComponent> {
743 let ptr = unsafe { ffi::mdl_object_transform_component(self.as_ptr()) };
744 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(TransformComponent::from_handle)
745 }
746
747 pub fn set_transform_component(&self, component: Option<&TransformComponent>) {
748 unsafe {
749 ffi::mdl_object_set_transform_component(
750 self.as_ptr(),
751 component.map_or(ptr::null_mut(), TransformComponent::as_ptr),
752 );
753 }
754 }
755}