1#![allow(clippy::needless_pass_by_value)]
2
3use crate::{
4 ffi,
5 skeleton::{Skeleton, SkeletonData},
6 SpineMutPtr,
7};
8use std::{
9 ffi::{CStr, CString},
10 marker::PhantomData,
11};
12
13pub struct TrackIndex(i32);
14impl TrackIndex {
15 pub fn zero() -> Self {
16 Self(0)
17 }
18}
19impl Default for TrackIndex {
20 fn default() -> Self {
21 Self::zero()
22 }
23}
24
25pub struct Animation<'a> {
26 pub(crate) inner: *mut ffi::spAnimation,
27 pub(crate) _lifetime: PhantomData<&'a ()>,
28}
29impl<'a> Animation<'a> {
30 pub fn name(&self) -> &str {
31 unsafe { CStr::from_ptr(self.inner.as_ref().unwrap().name) }
32 .to_str()
33 .unwrap()
34 }
35
36 pub fn duration(&self) -> f32 {
37 unsafe { self.inner.as_ref().unwrap().duration }
38 }
39 }
41
42pub struct AnimationState {
43 pub(crate) inner: SpineMutPtr<ffi::spAnimationState>,
44 pub(crate) parent: SpineMutPtr<ffi::spAnimationStateData>,
45}
46impl AnimationState {
47 pub fn new(data: &AnimationStateData) -> Self {
48 Self {
49 inner: SpineMutPtr::new(
50 unsafe { ffi::spAnimationState_create(data.inner.as_mut_ptr()) },
51 Some(ffi::spAnimationState_dispose),
52 ),
53 parent: data.inner.clone(),
54 }
55 }
56
57 pub fn update(&mut self, delta: f32) {
58 unsafe {
59 ffi::spAnimationState_update(self.inner.as_mut_ptr(), delta);
60 }
61 }
62
63 pub fn clear_track(&self, track: TrackIndex) {
64 unsafe {
65 ffi::spAnimationState_clearTrack(self.inner.as_mut_ptr(), track.0);
66 }
67 }
68
69 pub fn clear(&self) {
70 unsafe {
71 ffi::spAnimationState_clearTracks(self.inner.as_mut_ptr());
72 }
73 }
74
75 pub fn set(&mut self, animation: &Animation, track_index: TrackIndex, do_loop: bool) {
76 unsafe {
77 let _track_entry = ffi::spAnimationState_setAnimation(
78 self.inner.as_mut_ptr(),
79 track_index.0,
80 animation.inner,
81 do_loop as std::os::raw::c_int,
82 );
83 }
84 }
85
86 pub fn set_by_name(&mut self, animation_name: &str, track_index: TrackIndex, do_loop: bool) {
87 let name = CString::new(animation_name).unwrap();
88 unsafe {
89 let track_entry = ffi::spAnimationState_setAnimationByName(
90 self.inner.as_mut_ptr(),
91 track_index.0,
92 name.as_ptr(),
93 do_loop as std::os::raw::c_int,
94 );
95 if track_entry.is_null() {
96 panic!("Failed to set animation?");
97 }
98 }
99 }
100
101 pub fn apply(&self, skeleton: &mut Skeleton) -> bool {
102 unsafe {
103 ffi::spAnimationState_apply(self.inner.as_mut_ptr(), skeleton.inner.as_mut_ptr()) != 0
104 }
105 }
106}
107
108pub struct AnimationStateData {
109 pub(crate) inner: SpineMutPtr<ffi::spAnimationStateData>,
110 pub(crate) parent: SpineMutPtr<ffi::spSkeletonData>,
111}
112impl AnimationStateData {
113 pub fn new(data: &SkeletonData) -> Self {
114 Self {
115 inner: SpineMutPtr::new(
116 unsafe { ffi::spAnimationStateData_create(data.inner.as_mut_ptr()) },
117 Some(ffi::spAnimationStateData_dispose),
118 ),
119 parent: data.inner.clone(),
120 }
121 }
122
123 fn get_mix(&mut self, from: &Animation, to: &Animation) -> f32 {
124 unsafe { ffi::spAnimationStateData_getMix(self.inner.as_mut_ptr(), from.inner, to.inner) }
125 }
126
127 fn set_mix(&mut self, from: &Animation, to: &Animation, mix: f32) {
128 unsafe {
129 ffi::spAnimationStateData_setMix(self.inner.as_mut_ptr(), from.inner, to.inner, mix)
130 }
131 }
132
133 fn set_mix_by_name(&mut self, from: &str, to: &str, mix: f32) {
134 let from = CString::new(from).unwrap();
135 let to = CString::new(to).unwrap();
136
137 unsafe {
138 ffi::spAnimationStateData_setMixByName(
139 self.inner.as_mut_ptr(),
140 from.as_ptr(),
141 to.as_ptr(),
142 mix,
143 )
144 }
145 }
146}