rusty_spine/
bone.rs

1use crate::{
2    c::{
3        spBone, spBoneData, spBone_getWorldRotationX, spBone_getWorldRotationY,
4        spBone_getWorldScaleX, spBone_getWorldScaleY, spBone_isYDown, spBone_localToWorld,
5        spBone_rotateWorld, spBone_setToSetupPose, spBone_setYDown, spBone_update,
6        spBone_updateAppliedTransform, spBone_updateWorldTransform,
7        spBone_updateWorldTransformWith, spBone_worldToLocal, spBone_worldToLocalRotation,
8        spInherit, spSkeleton,
9    },
10    c_interface::{NewFromPtr, SyncPtr},
11    Skeleton,
12};
13
14#[cfg(feature = "mint")]
15use mint::Vector2;
16
17/// A bone within the [`Skeleton`] hierarchy.
18///
19/// [Spine API Reference](http://esotericsoftware.com/spine-api-reference#Bone)
20///
21/// Bones can be acquired from a [`Skeleton`] and a safe [`BoneHandle`] can be obtained using the
22/// [`Bone::handle`] method to store long-term references to a specific
23/// bone.
24///
25/// The hierarchy can be traversed using [`Bone::parent`] and [`Bone::children`], and specific
26/// bones can be located using [`Skeleton::find_bone`].
27#[derive(Debug)]
28pub struct Bone {
29    c_bone: SyncPtr<spBone>,
30}
31
32impl NewFromPtr<spBone> for Bone {
33    unsafe fn new_from_ptr(c_bone: *mut spBone) -> Self {
34        Self {
35            c_bone: SyncPtr(c_bone),
36        }
37    }
38}
39
40impl Bone {
41    /// Sets this bone's local transform to the setup pose.
42    pub fn set_to_setup_pose(&mut self) {
43        unsafe {
44            spBone_setToSetupPose(self.c_ptr());
45        }
46    }
47
48    /// Computes the world transform using the parent bone and this bone's local applied transform.
49    pub fn update(&mut self) {
50        unsafe {
51            spBone_update(self.c_ptr());
52        }
53    }
54
55    /// Computes the world transform using the parent bone and this bone's local transform.
56    ///
57    /// See [`update_world_transform_with`](`Self::update_world_transform_with`).
58    pub fn update_world_transform(&mut self) {
59        unsafe {
60            spBone_updateWorldTransform(self.c_ptr());
61        }
62    }
63
64    /// Computes the world transform using the parent bone and the specified local transform. The
65    /// applied transform is set to the specified local transform. Child bones are not updated.
66    ///
67    /// See
68    /// [`World transforms`](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms)
69    /// in the Spine Runtimes Guide.
70    #[allow(clippy::too_many_arguments)]
71    pub fn update_world_transform_with(
72        &mut self,
73        x: f32,
74        y: f32,
75        rotation: f32,
76        scale_x: f32,
77        scale_y: f32,
78        shear_x: f32,
79        shear_y: f32,
80    ) {
81        unsafe {
82            spBone_updateWorldTransformWith(
83                self.c_ptr(),
84                x,
85                y,
86                rotation,
87                scale_x,
88                scale_y,
89                shear_x,
90                shear_y,
91            );
92        }
93    }
94
95    /// Computes the applied transform values from the world transform.
96    ///
97    /// If the world transform is modified (by a constraint, [`rotate_world`](`Self::rotate_world`),
98    /// etc) then this method should be called so the applied transform matches the world transform.
99    /// The applied transform may be needed by other code (eg to apply another constraint).
100    ///
101    /// Some information is ambiguous in the world transform, such as -1,-1 scale versus 180
102    /// rotation. The applied transform after calling this method is equivalent to the local
103    /// transform used to compute the world transform, but may not be identical.
104    pub fn update_applied_transform(&mut self) {
105        unsafe {
106            spBone_updateAppliedTransform(self.c_ptr());
107        }
108    }
109
110    /// The world rotation for the X axis, calculated using [`a`](`Self::a`) and [`c`](`Self::c`).
111    #[must_use]
112    pub fn world_rotation_x(&self) -> f32 {
113        unsafe { spBone_getWorldRotationX(self.c_ptr()) }
114    }
115
116    /// The world rotation for the Y axis, calculated using [`b`](`Self::b`) and [`d`](`Self::d`).
117    #[must_use]
118    pub fn world_rotation_y(&self) -> f32 {
119        unsafe { spBone_getWorldRotationY(self.c_ptr()) }
120    }
121
122    /// The magnitude (always positive) of the world scale X, calculated using [`a`](`Self::a`) and
123    /// [`c`](`Self::c`).
124    #[must_use]
125    pub fn world_scale_x(&self) -> f32 {
126        unsafe { spBone_getWorldScaleX(self.c_ptr()) }
127    }
128
129    /// The magnitude (always positive) of the world scale Y, calculated using [`b`](`Self::b`) and
130    /// [`d`](`Self::d`).
131    #[must_use]
132    pub fn world_scale_y(&self) -> f32 {
133        unsafe { spBone_getWorldScaleY(self.c_ptr()) }
134    }
135
136    /// Transforms a point from world coordinates to the bone's local coordinates.
137    #[must_use]
138    pub fn world_to_local(&self, world_x: f32, world_y: f32) -> (f32, f32) {
139        let mut local_x: f32 = 0.;
140        let mut local_y: f32 = 0.;
141        unsafe {
142            spBone_worldToLocal(self.c_ptr(), world_x, world_y, &mut local_x, &mut local_y);
143        }
144        (local_x, local_y)
145    }
146
147    /// Transforms a point from the bone's local coordinates to world coordinates.
148    #[must_use]
149    pub fn local_to_world(&self, local_x: f32, local_y: f32) -> (f32, f32) {
150        let mut world_x: f32 = 0.;
151        let mut world_y: f32 = 0.;
152        unsafe {
153            spBone_localToWorld(self.c_ptr(), local_x, local_y, &mut world_x, &mut world_y);
154        }
155        (world_x, world_y)
156    }
157
158    /// Transforms a world rotation to a local rotation.
159    #[must_use]
160    pub fn world_to_local_rotation(&self, world_rotation: f32) -> f32 {
161        unsafe { spBone_worldToLocalRotation(self.c_ptr(), world_rotation) }
162    }
163
164    /// Transforms a local rotation to a world rotation.
165    #[must_use]
166    pub fn local_to_world_rotation(&self, local_rotation: f32) -> f32 {
167        unsafe { spBone_worldToLocalRotation(self.c_ptr(), local_rotation) }
168    }
169
170    /// Rotates the world transform the specified amount.
171    ///
172    /// After changes are made to the world transform,
173    /// [`update_applied_transform`](`Self::update_applied_transform`) should be called and update
174    /// will need to be called on any child bones, recursively.
175    pub fn rotate_world(&self, degrees: f32) {
176        unsafe {
177            spBone_rotateWorld(self.c_ptr(), degrees);
178        }
179    }
180
181    /// Create a persistent [`BoneHandle`] to this [`Bone`].
182    #[must_use]
183    pub fn handle(&self) -> BoneHandle {
184        BoneHandle::new(self.c_ptr(), unsafe { self.c_ptr_mut().skeleton })
185    }
186
187    c_accessor_mut!(
188        /// The local x translation.
189        x,
190        /// Set the local x translation.
191        set_x,
192        x,
193        f32
194    );
195    c_accessor_mut!(
196        /// The local y translation.
197        y,
198        /// Set the local y translation.
199        set_y,
200        y,
201        f32
202    );
203    c_accessor_mut!(
204        /// The local rotation in degrees, counter clockwise.
205        rotation,
206        /// Set the local rotation in degrees, counter clockwise.
207        set_rotation,
208        rotation,
209        f32
210    );
211    c_accessor_mut!(
212        /// The local scaleX.
213        scale_x,
214        /// Set the local scaleX.
215        set_scale_x,
216        scaleX,
217        f32
218    );
219    c_accessor_mut!(
220        /// The local scaleY.
221        scale_y,
222        /// Set the local scaleY.
223        set_scale_y,
224        scaleY,
225        f32
226    );
227    c_accessor_mut!(
228        /// The local shearX.
229        shear_x,
230        /// Set the local shearX.
231        set_shear_x,
232        shearX,
233        f32
234    );
235    c_accessor_mut!(
236        /// The local shearY.
237        shear_y,
238        /// Set the local shearY.
239        set_shear_y,
240        shearY,
241        f32
242    );
243    c_accessor_mut!(
244        /// The applied local x translation.
245        applied_x,
246        /// Set the applied local x translation.
247        set_applied_x,
248        ax,
249        f32
250    );
251    c_accessor_mut!(
252        /// The applied local y translation.
253        applied_y,
254        /// Set the applied local y translation.
255        set_applied_y,
256        ay,
257        f32
258    );
259    c_accessor_mut!(
260        /// The applied local rotation in degrees, counter clockwise.
261        applied_rotation,
262        /// Set the applied local rotation in degrees, counter clockwise.
263        set_applied_rotation,
264        arotation,
265        f32
266    );
267    c_accessor_mut!(
268        /// The applied local scaleX.
269        applied_scale_x,
270        /// Set the applied local scaleX.
271        set_applied_scale_x,
272        ascaleX,
273        f32
274    );
275    c_accessor_mut!(
276        /// The applied local scaleY.
277        applied_scale_y,
278        /// Set the applied local scaleY.
279        set_applied_scale_y,
280        ascaleY,
281        f32
282    );
283    c_accessor_mut!(
284        /// The applied local shearX.
285        applied_shear_x,
286        /// Set the applied local shearX.
287        set_applied_shear_x,
288        ashearX,
289        f32
290    );
291    c_accessor_mut!(
292        /// The applied local shearY.
293        applied_shear_y,
294        /// Set the applied local shearY.
295        set_applied_shear_y,
296        ashearY,
297        f32
298    );
299    c_accessor_mut!(
300        /// Part of the world transform matrix for the X axis.
301        a,
302        /// Set part of the world transform matrix for the X axis. If changed,
303        /// [`update_applied_transform`](`Self::update_applied_transform`) should be called.
304        set_a,
305        a,
306        f32
307    );
308    c_accessor_mut!(
309        /// Part of the world transform matrix for the Y axis.
310        b,
311        /// Set part of the world transform matrix for the Y axis. If changed,
312        /// [`update_applied_transform`](`Self::update_applied_transform`) should be called.
313        set_b,
314        b,
315        f32
316    );
317    c_accessor_mut!(
318        /// Part of the world transform matrix for the X axis.
319        c,
320        /// Set part of the world transform matrix for the X axis. If changed,
321        /// [`update_applied_transform`](`Self::update_applied_transform`) should be called.
322        set_c,
323        c,
324        f32
325    );
326    c_accessor_mut!(
327        /// Part of the world transform matrix for the Y axis.
328        d,
329        /// Set part of the world transform matrix for the Y axis. If changed,
330        /// [`update_applied_transform`](`Self::update_applied_transform`) should be called.
331        set_d,
332        d,
333        f32
334    );
335    c_accessor_mut!(
336        /// Set the world X translation.
337        world_x,
338        /// The world X translation. If changed,
339        /// [`update_applied_transform`](`Self::update_applied_transform`) should be called.
340        set_world_x,
341        worldX,
342        f32
343    );
344    c_accessor_mut!(
345        /// The world Y translation.
346        world_y,
347        /// Set the world Y translation. If changed,
348        /// [`update_applied_transform`](`Self::update_applied_transform`) should be called.
349        set_world_y,
350        worldY,
351        f32
352    );
353    c_accessor_bool!(sorted, sorted);
354    c_accessor_bool!(active, active);
355    c_accessor_tmp_ptr_mut!(
356        /// The bone's setup pose data.
357        data,
358        /// The bone's mutable setup pose data.
359        data_mut,
360        data,
361        BoneData,
362        spBoneData
363    );
364    c_accessor_tmp_ptr_optional_mut!(parent, parent_mut, parent, Bone, spBone);
365    c_accessor!(children_count, childrenCount, usize);
366    c_accessor_array_mut!(
367        /// An iterator over the children of this bone.
368        ///
369        /// ```
370        /// # #[path="./test.rs"]
371        /// # mod test;
372        /// use rusty_spine::{BoneHandle, Skeleton};
373        ///
374        /// fn traverse_bones(
375        ///     bone_handle: BoneHandle,
376        ///     skeleton: &Skeleton,
377        ///     ident: usize,
378        /// ) {
379        ///     if let Some(bone) = bone_handle.get(skeleton) {
380        ///         println!(
381        ///             "{:ident$}{name}",
382        ///             "",
383        ///             ident = ident,
384        ///             name = bone.data().name()
385        ///         );
386        ///         for child in bone.children() {
387        ///             traverse_bones(child.handle(), skeleton, ident + 2);
388        ///         }
389        ///     }
390        /// }
391        ///
392        /// // Traverse all bones in a skeleton
393        /// # let (skeleton, animation_state) = test::TestAsset::spineboy().instance(true);
394        /// let root_bone = skeleton.bone_root().handle();
395        /// traverse_bones(root_bone, &skeleton, 0);
396        /// ```
397        children,
398        children_mut,
399        children_at_index,
400        children_at_index_mut,
401        Bone,
402        Bone,
403        spBone,
404        children,
405        children_count
406    );
407
408    pub fn set_y_down(y_down: bool) {
409        unsafe {
410            spBone_setYDown(i32::from(y_down));
411        }
412    }
413
414    #[must_use]
415    pub fn is_y_down() -> bool {
416        unsafe { spBone_isYDown() != 0 }
417    }
418
419    c_ptr!(c_bone, spBone);
420}
421
422/// Functions available if using the `mint` feature.
423#[cfg(feature = "mint")]
424impl Bone {
425    /// The local translation.
426    #[must_use]
427    pub fn translation(&self) -> Vector2<f32> {
428        Vector2 {
429            x: self.x(),
430            y: self.y(),
431        }
432    }
433
434    /// Set the local translation.
435    pub fn set_translation(&mut self, translation: impl Into<Vector2<f32>>) {
436        let translation: Vector2<f32> = translation.into();
437        self.set_x(translation.x);
438        self.set_y(translation.y);
439    }
440
441    /// The world translation.
442    #[must_use]
443    pub fn world_translation(&self) -> Vector2<f32> {
444        Vector2 {
445            x: self.world_x(),
446            y: self.world_y(),
447        }
448    }
449
450    /// Set the world translation.
451    pub fn set_world_translation(&mut self, translation: impl Into<Vector2<f32>>) {
452        let translation: Vector2<f32> = translation.into();
453        self.set_world_x(translation.x);
454        self.set_world_y(translation.y);
455    }
456
457    /// The applied translation.
458    #[must_use]
459    pub fn applied_translation(&self) -> Vector2<f32> {
460        Vector2 {
461            x: self.world_x(),
462            y: self.world_y(),
463        }
464    }
465
466    /// Set the applied translation.
467    pub fn set_applied_translation(&mut self, translation: impl Into<Vector2<f32>>) {
468        let translation: Vector2<f32> = translation.into();
469        self.set_applied_x(translation.x);
470        self.set_applied_y(translation.y);
471    }
472
473    /// The local scale.
474    #[must_use]
475    pub fn scale(&self) -> Vector2<f32> {
476        Vector2 {
477            x: self.scale_x(),
478            y: self.scale_y(),
479        }
480    }
481
482    /// Set the local scale.
483    pub fn set_scale(&mut self, scale: impl Into<Vector2<f32>>) {
484        let scale: Vector2<f32> = scale.into();
485        self.set_scale_x(scale.x);
486        self.set_scale_y(scale.y);
487    }
488
489    /// The world scale.
490    #[must_use]
491    pub fn world_scale(&self) -> Vector2<f32> {
492        Vector2 {
493            x: self.world_x(),
494            y: self.world_y(),
495        }
496    }
497
498    /// The applied scale.
499    #[must_use]
500    pub fn applied_scale(&self) -> Vector2<f32> {
501        Vector2 {
502            x: self.applied_scale_x(),
503            y: self.applied_scale_y(),
504        }
505    }
506
507    /// Set the applied scale.
508    pub fn set_applied_scale(&mut self, scale: impl Into<Vector2<f32>>) {
509        let scale: Vector2<f32> = scale.into();
510        self.set_applied_scale_x(scale.x);
511        self.set_applied_scale_y(scale.y);
512    }
513
514    /// The local shear.
515    #[must_use]
516    pub fn shear(&self) -> Vector2<f32> {
517        Vector2 {
518            x: self.shear_x(),
519            y: self.shear_y(),
520        }
521    }
522
523    /// Set the local shear.
524    pub fn set_shear(&mut self, shear: impl Into<Vector2<f32>>) {
525        let shear: Vector2<f32> = shear.into();
526        self.set_shear_x(shear.x);
527        self.set_shear_y(shear.y);
528    }
529
530    /// The applied shear.
531    #[must_use]
532    pub fn applied_shear(&self) -> Vector2<f32> {
533        Vector2 {
534            x: self.applied_shear_x(),
535            y: self.applied_shear_y(),
536        }
537    }
538
539    /// Set the applied shear.
540    pub fn set_applied_shear(&mut self, shear: impl Into<Vector2<f32>>) {
541        let shear: Vector2<f32> = shear.into();
542        self.set_applied_shear_x(shear.x);
543        self.set_applied_shear_y(shear.y);
544    }
545
546    #[must_use]
547    pub fn world_rotation(&self) -> Vector2<f32> {
548        Vector2 {
549            x: self.world_rotation_x(),
550            y: self.world_rotation_y(),
551        }
552    }
553
554    pub fn update_world_transform_with2(
555        &mut self,
556        translation: mint::Vector2<f32>,
557        rotation: f32,
558        scale: mint::Vector2<f32>,
559        shear: mint::Vector2<f32>,
560    ) {
561        unsafe {
562            spBone_updateWorldTransformWith(
563                self.c_ptr(),
564                translation.x,
565                translation.y,
566                rotation,
567                scale.x,
568                scale.y,
569                shear.x,
570                shear.y,
571            );
572        }
573    }
574}
575
576c_handle_decl!(
577    /// A storeable reference to a [`Bone`].
578    ///
579    /// Can be acquired from any instance of [`Bone`].
580    ///
581    /// ```
582    /// # #[path="./test.rs"]
583    /// # mod test;
584    /// # use rusty_spine::{AnimationState, EventType, BoneHandle};
585    /// # let (skeleton, _) = test::TestAsset::spineboy().instance(true);
586    /// let bone_handles: Vec<BoneHandle> = skeleton.bones().map(|bone| bone.handle()).collect();
587    /// for bone_handle in bone_handles.iter() {
588    ///     let bone = bone_handle.get(&skeleton).unwrap();
589    ///     println!("{}", bone.data().name());
590    /// }
591    /// ```
592    BoneHandle,
593    Bone,
594    Skeleton,
595    spBone,
596    spSkeleton
597);
598
599/// Static bone data imported from Spine.
600#[derive(Debug)]
601pub struct BoneData {
602    c_bone_data: SyncPtr<spBoneData>,
603}
604
605impl NewFromPtr<spBoneData> for BoneData {
606    unsafe fn new_from_ptr(c_bone_data: *mut spBoneData) -> Self {
607        Self {
608            c_bone_data: SyncPtr(c_bone_data),
609        }
610    }
611}
612
613impl BoneData {
614    c_ptr!(c_bone_data, spBoneData);
615    c_accessor_string!(name, name);
616    c_accessor!(index, index, usize);
617    c_accessor!(length, length, f32);
618    c_accessor!(x, x, f32);
619    c_accessor!(y, y, f32);
620    c_accessor!(rotation, rotation, f32);
621    c_accessor!(scale_x, scaleX, f32);
622    c_accessor!(scale_y, scaleY, f32);
623    c_accessor!(shear_x, shearX, f32);
624    c_accessor!(shear_y, shearY, f32);
625    c_accessor_color!(color, color);
626    c_accessor_bool!(skin_required, skinRequired);
627    c_accessor_enum!(
628        /// The transform mode for how parent world transforms affect this bone.
629        inherit,
630        inherit,
631        Inherit
632    );
633    c_accessor_tmp_ptr_optional!(parent, parent, BoneData, spBoneData);
634}
635
636/// Functions available if using the `mint` feature.
637#[cfg(feature = "mint")]
638impl BoneData {
639    #[must_use]
640    pub fn translation(&self) -> Vector2<f32> {
641        Vector2 {
642            x: self.x(),
643            y: self.y(),
644        }
645    }
646
647    #[must_use]
648    pub fn scale(&self) -> Vector2<f32> {
649        Vector2 {
650            x: self.scale_x(),
651            y: self.scale_y(),
652        }
653    }
654
655    #[must_use]
656    pub fn shear(&self) -> Vector2<f32> {
657        Vector2 {
658            x: self.shear_x(),
659            y: self.shear_y(),
660        }
661    }
662}
663
664/// The inherited transform for how bones are affected by their parents.
665///
666/// See [`BoneData::inherit`].
667pub enum Inherit {
668    Normal = 0,
669    OnlyTranslation = 1,
670    NoRotationOrReflection = 2,
671    NoScale = 3,
672    NoScaleOrReflection = 4,
673    Unknown = 99,
674}
675
676impl From<spInherit> for Inherit {
677    fn from(mode: spInherit) -> Self {
678        match mode {
679            0 => Self::Normal,
680            1 => Self::OnlyTranslation,
681            2 => Self::NoRotationOrReflection,
682            3 => Self::NoScale,
683            4 => Self::NoScaleOrReflection,
684            _ => Self::Unknown,
685        }
686    }
687}