veloren_voxygen_anim/
lib.rs

1#![expect(clippy::single_match)]
2#[cfg(all(feature = "be-dyn-lib", feature = "use-dyn-lib"))]
3compile_error!("Can't use both \"be-dyn-lib\" and \"use-dyn-lib\" features at once");
4
5macro_rules! replace_with_unit {
6    ($_:tt) => {
7        ()
8    };
9}
10
11macro_rules! skeleton_impls {
12    {
13        struct $Skeleton:ident $ComputedSkeleton:ident {
14            $(+ $mesh_bone:ident)*
15            $($bone:ident)*
16            $(::
17            $($field:ident : $field_ty:ty),* $(,)?
18            )?
19        }
20    } => {
21        #[derive(Clone, Default)]
22        pub struct $ComputedSkeleton {
23            $(pub $mesh_bone: $crate::vek::Mat4<f32>,)*
24        }
25
26        impl $ComputedSkeleton {
27            pub const BONE_COUNT: usize = [$(replace_with_unit!($mesh_bone),)*].len();
28
29            pub fn set_figure_bone_data(&self, buf: &mut [$crate::FigureBoneData; $crate::MAX_BONE_COUNT]) {
30                *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
31                    $($crate::make_bone(self.$mesh_bone),)*
32                ];
33            }
34        }
35
36        #[derive(Clone, Default)]
37        pub struct $Skeleton {
38            $(pub $mesh_bone: $crate::Bone,)*
39            $(pub $bone: $crate::Bone,)*
40            $($(
41                pub $field : $field_ty,
42            )*)?
43        }
44
45        impl<'a, Factor> $crate::vek::Lerp<Factor> for &'a $Skeleton
46            where
47                Factor: Copy,
48                $crate::Bone: Lerp<Factor, Output=$crate::Bone>
49        {
50            type Output = $Skeleton;
51
52            fn lerp_unclamped_precise(from: Self, to: Self, factor: Factor) -> Self::Output {
53                Self::Output {
54                    $($mesh_bone: Lerp::lerp_unclamped_precise(from.$mesh_bone, to.$mesh_bone, factor),)*
55                    $($bone: Lerp::lerp_unclamped_precise(from.$bone, to.$bone, factor),)*
56                    $($(
57                        $field : to.$field.clone(),
58                    )*)?
59                }
60            }
61
62            fn lerp_unclamped(from: Self, to: Self, factor: Factor) -> Self::Output {
63                Self::Output {
64                    $($mesh_bone: Lerp::lerp_unclamped(from.$mesh_bone, to.$mesh_bone, factor),)*
65                    $($bone: Lerp::lerp_unclamped(from.$bone, to.$bone, factor),)*
66                    $($(
67                        $field : to.$field.clone(),
68                    )*)?
69                }
70            }
71        }
72    }
73}
74
75pub mod arthropod;
76pub mod biped_large;
77pub mod biped_small;
78pub mod bird_large;
79pub mod bird_medium;
80pub mod character;
81pub mod crustacean;
82pub mod dragon;
83pub mod fish_medium;
84pub mod fish_small;
85pub mod fixture;
86pub mod golem;
87pub mod item;
88pub mod object;
89#[cfg(feature = "plugins")] pub mod plugin;
90pub mod quadruped_low;
91pub mod quadruped_medium;
92pub mod quadruped_small;
93pub mod ship;
94pub mod theropod;
95pub mod util;
96pub mod vek;
97
98use self::vek::*;
99use bytemuck::{Pod, Zeroable};
100#[cfg(feature = "use-dyn-lib")]
101use {
102    common_dynlib::LoadedLib, lazy_static::lazy_static, std::ffi::CStr, std::sync::Arc,
103    std::sync::Mutex,
104};
105
106type MatRaw = [[f32; 4]; 4];
107
108#[repr(C)]
109#[derive(Debug, Clone, Copy, Pod, Zeroable, Default)]
110pub struct FigureBoneData(pub MatRaw, pub MatRaw);
111
112pub const MAX_BONE_COUNT: usize = 16;
113
114pub fn make_bone(mat: Mat4<f32>) -> FigureBoneData {
115    let normal = mat.map_cols(Vec4::normalized);
116    FigureBoneData(mat.into_col_arrays(), normal.into_col_arrays())
117}
118
119pub type Bone = Transform<f32, f32, f32>;
120
121#[cfg(feature = "use-dyn-lib")]
122lazy_static! {
123    static ref LIB: Arc<Mutex<Option<LoadedLib>>> =
124        common_dynlib::init("veloren-voxygen-anim", "anim", &[
125            #[cfg(feature = "plugins")]
126            "plugins",
127        ]);
128}
129
130#[cfg(feature = "use-dyn-lib")]
131pub fn init() { lazy_static::initialize(&LIB); }
132
133pub trait Skeleton: Send + Sync + 'static {
134    type Attr;
135    type Body;
136    type ComputedSkeleton;
137
138    const BONE_COUNT: usize;
139
140    #[cfg(feature = "use-dyn-lib")]
141    const COMPUTE_FN: &'static [u8];
142
143    fn compute_matrices(
144        &self,
145        base_mat: Mat4<f32>,
146        buf: &mut [FigureBoneData; MAX_BONE_COUNT],
147        body: Self::Body,
148    ) -> Self::ComputedSkeleton {
149        #[cfg(not(feature = "use-dyn-lib"))]
150        {
151            self.compute_matrices_inner(base_mat, buf, body)
152        }
153        #[cfg(feature = "use-dyn-lib")]
154        {
155            let lock = LIB.lock().unwrap();
156            let lib = &lock.as_ref().unwrap().lib;
157
158            let compute_fn: common_dynlib::Symbol<
159                fn(
160                    &Self,
161                    Mat4<f32>,
162                    &mut [FigureBoneData; MAX_BONE_COUNT],
163                    Self::Body,
164                ) -> Self::ComputedSkeleton,
165            > = unsafe { lib.get(Self::COMPUTE_FN) }.unwrap_or_else(|e| {
166                panic!(
167                    "Trying to use: {} but had error: {:?}",
168                    CStr::from_bytes_with_nul(Self::COMPUTE_FN)
169                        .map(CStr::to_str)
170                        .unwrap()
171                        .unwrap(),
172                    e
173                )
174            });
175
176            compute_fn(self, base_mat, buf, body)
177        }
178    }
179
180    fn compute_matrices_inner(
181        &self,
182        base_mat: Mat4<f32>,
183        buf: &mut [FigureBoneData; MAX_BONE_COUNT],
184        body: Self::Body,
185    ) -> Self::ComputedSkeleton;
186}
187
188pub fn compute_matrices<S: Skeleton>(
189    skeleton: &S,
190    base_mat: Mat4<f32>,
191    buf: &mut [FigureBoneData; MAX_BONE_COUNT],
192    body: S::Body,
193) -> S::ComputedSkeleton {
194    S::compute_matrices(skeleton, base_mat, buf, body)
195}
196
197pub trait Animation {
198    type Skeleton: Skeleton;
199    type Dependency<'a>;
200
201    #[cfg(feature = "use-dyn-lib")]
202    const UPDATE_FN: &'static [u8];
203
204    /// Returns a new skeleton that is generated by the animation.
205    fn update_skeleton_inner(
206        _skeleton: &Self::Skeleton,
207        _dependency: Self::Dependency<'_>,
208        _anim_time: f32,
209        _rate: &mut f32,
210        _skeleton_attr: &<<Self as Animation>::Skeleton as Skeleton>::Attr,
211    ) -> Self::Skeleton;
212
213    /// Calls `update_skeleton_inner` either directly or via `libloading` to
214    /// generate the new skeleton.
215    fn update_skeleton(
216        skeleton: &Self::Skeleton,
217        dependency: Self::Dependency<'_>,
218        anim_time: f32,
219        rate: &mut f32,
220        skeleton_attr: &<<Self as Animation>::Skeleton as Skeleton>::Attr,
221    ) -> Self::Skeleton {
222        #[cfg(not(feature = "use-dyn-lib"))]
223        {
224            Self::update_skeleton_inner(skeleton, dependency, anim_time, rate, skeleton_attr)
225        }
226        #[cfg(feature = "use-dyn-lib")]
227        {
228            let lock = LIB.lock().unwrap();
229            let lib = &lock.as_ref().unwrap().lib;
230
231            let update_fn: common_dynlib::Symbol<
232                fn(
233                    &Self::Skeleton,
234                    Self::Dependency<'_>,
235                    f32,
236                    &mut f32,
237                    &<Self::Skeleton as Skeleton>::Attr,
238                ) -> Self::Skeleton,
239            > = unsafe {
240                //let start = std::time::Instant::now();
241                // Overhead of 0.5-5 us (could use hashmap to mitigate if this is an issue)
242                lib.get(Self::UPDATE_FN)
243                //println!("{}", start.elapsed().as_nanos());
244            }
245            .unwrap_or_else(|e| {
246                panic!(
247                    "Trying to use: {} but had error: {:?}",
248                    CStr::from_bytes_with_nul(Self::UPDATE_FN)
249                        .map(CStr::to_str)
250                        .unwrap()
251                        .unwrap(),
252                    e
253                )
254            });
255
256            update_fn(skeleton, dependency, anim_time, rate, skeleton_attr)
257        }
258    }
259}