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}