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