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 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 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 lib.get(Self::UPDATE_FN)
243 }
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}