1use glam::{Quat, Vec3, Vec4};
2use myth_core::MAX_MORPH_TARGETS;
3use smallvec::{SmallVec, smallvec};
4
5pub trait Interpolatable: Clone + Sized {
10 fn interpolate_linear(start: &Self, end: &Self, t: f32) -> Self;
11
12 fn interpolate_cubic(
13 v0: &Self,
14 out_tangent0: &Self,
15 in_tangent1: &Self,
16 v1: &Self,
17 t: f32,
18 dt: f32,
19 ) -> Self;
20
21 fn interpolate_linear_into(start: &Self, end: &Self, t: f32, out: &mut Self) {
22 *out = Self::interpolate_linear(start, end, t);
23 }
24
25 fn interpolate_cubic_into(
26 v0: &Self,
27 out_tangent0: &Self,
28 in_tangent1: &Self,
29 v1: &Self,
30 t: f32,
31 dt: f32,
32 out: &mut Self,
33 ) {
34 *out = Self::interpolate_cubic(v0, out_tangent0, in_tangent1, v1, t, dt);
35 }
36}
37
38#[repr(C)]
43#[derive(Clone, Debug, Default)]
44pub struct MorphWeightData {
45 pub weights: SmallVec<[f32; MAX_MORPH_TARGETS]>,
46}
47
48impl MorphWeightData {
49 #[must_use]
51 pub fn allocate(n: usize) -> Self {
52 Self {
53 weights: smallvec![0.0; n],
54 }
55 }
56
57 pub fn interpolate_linear_into(start: &Self, end: &Self, t: f32, out_buffer: &mut [f32]) {
62 let len = start
63 .weights
64 .len()
65 .min(end.weights.len())
66 .min(out_buffer.len());
67 for (i, item) in out_buffer.iter_mut().enumerate().take(len) {
69 *item = start.weights[i] + (end.weights[i] - start.weights[i]) * t;
70 }
71 }
72
73 pub fn interpolate_cubic_into(
76 v0: &Self,
77 out_tangent0: &Self,
78 in_tangent1: &Self,
79 v1: &Self,
80 t: f32,
81 dt: f32,
82 out_buffer: &mut [f32],
83 ) {
84 let t2 = t * t;
85 let t3 = t2 * t;
86 let s2 = -2.0 * t3 + 3.0 * t2;
87 let s3 = t3 - t2;
88 let s0 = 1.0 - s2;
89 let s1 = s3 - t2 + t;
90
91 let len = v0.weights.len().min(v1.weights.len()).min(out_buffer.len());
92 for (i, item) in out_buffer.iter_mut().enumerate().take(len) {
93 let m0 = out_tangent0.weights[i] * dt;
94 let m1 = in_tangent1.weights[i] * dt;
95 *item = s0 * v0.weights[i] + s1 * m0 + s2 * v1.weights[i] + s3 * m1;
96 }
97 }
98}
99
100impl Interpolatable for MorphWeightData {
101 fn interpolate_linear(start: &Self, end: &Self, t: f32) -> Self {
102 let len = start.weights.len().max(end.weights.len());
103 let mut result = MorphWeightData::allocate(len);
104 for i in 0..len {
105 let s = if i < start.weights.len() {
106 start.weights[i]
107 } else {
108 0.0
109 };
110 let e = if i < end.weights.len() {
111 end.weights[i]
112 } else {
113 0.0
114 };
115 result.weights[i] = s + (e - s) * t;
116 }
117 result
118 }
119
120 fn interpolate_cubic(
121 v0: &Self,
122 out_tangent0: &Self,
123 in_tangent1: &Self,
124 v1: &Self,
125 t: f32,
126 dt: f32,
127 ) -> Self {
128 let t2 = t * t;
129 let t3 = t2 * t;
130 let s2 = -2.0 * t3 + 3.0 * t2;
131 let s3 = t3 - t2;
132 let s0 = 1.0 - s2;
133 let s1 = s3 - t2 + t;
134
135 let len = v0.weights.len().max(v1.weights.len());
136 let mut result = MorphWeightData::allocate(len);
137
138 for i in 0..len {
139 let m0 = out_tangent0.weights[i] * dt;
140 let m1 = in_tangent1.weights[i] * dt;
141 result.weights[i] = s0 * v0.weights[i] + s1 * m0 + s2 * v1.weights[i] + s3 * m1;
142 }
143 result
144 }
145
146 fn interpolate_linear_into(start: &Self, end: &Self, t: f32, out: &mut Self) {
147 let len = start.weights.len().min(end.weights.len());
148 if out.weights.len() < len {
149 out.weights.resize(len, 0.0);
150 }
151 for i in 0..len {
152 out.weights[i] = start.weights[i] + (end.weights[i] - start.weights[i]) * t;
153 }
154 }
155
156 fn interpolate_cubic_into(
157 v0: &Self,
158 out_tangent0: &Self,
159 in_tangent1: &Self,
160 v1: &Self,
161 t: f32,
162 dt: f32,
163 out: &mut Self,
164 ) {
165 let len = v0.weights.len().min(v1.weights.len());
166 if out.weights.len() < len {
167 out.weights.resize(len, 0.0);
168 }
169
170 let t2 = t * t;
171 let t3 = t2 * t;
172 let s2 = -2.0 * t3 + 3.0 * t2;
173 let s3 = t3 - t2;
174 let s0 = 1.0 - s2;
175 let s1 = s3 - t2 + t;
176
177 for i in 0..len {
178 let m0 = out_tangent0.weights[i] * dt;
179 let m1 = in_tangent1.weights[i] * dt;
180 out.weights[i] = s0 * v0.weights[i] + s1 * m0 + s2 * v1.weights[i] + s3 * m1;
181 }
182 }
183}
184
185impl Interpolatable for f32 {
186 fn interpolate_linear(start: &Self, end: &Self, t: f32) -> Self {
187 start + (end - start) * t
188 }
189
190 fn interpolate_cubic(
191 v0: &Self,
192 out_tangent0: &Self,
193 in_tangent1: &Self,
194 v1: &Self,
195 t: f32,
196 dt: f32,
197 ) -> Self {
198 let t2 = t * t;
199 let t3 = t2 * t;
200
201 let s2 = -2.0 * t3 + 3.0 * t2;
202 let s3 = t3 - t2;
203 let s0 = 1.0 - s2;
204 let s1 = s3 - t2 + t;
205
206 let m0 = out_tangent0 * dt;
207 let m1 = in_tangent1 * dt;
208
209 s0 * v0 + s1 * m0 + s2 * v1 + s3 * m1
210 }
211}
212
213impl Interpolatable for Vec3 {
214 fn interpolate_linear(start: &Self, end: &Self, t: f32) -> Self {
215 start.lerp(*end, t)
216 }
217
218 fn interpolate_cubic(
219 v0: &Self,
220 out_tangent0: &Self,
221 in_tangent1: &Self,
222 v1: &Self,
223 t: f32,
224 dt: f32,
225 ) -> Self {
226 let t2 = t * t;
227 let t3 = t2 * t;
228
229 let s2 = -2.0 * t3 + 3.0 * t2;
230 let s3 = t3 - t2;
231 let s0 = 1.0 - s2;
232 let s1 = s3 - t2 + t;
233
234 let m0 = out_tangent0 * dt;
235 let m1 = in_tangent1 * dt;
236
237 v0 * s0 + m0 * s1 + v1 * s2 + m1 * s3
238 }
239}
240
241impl Interpolatable for Quat {
242 fn interpolate_linear(start: &Self, end: &Self, t: f32) -> Self {
243 start.slerp(*end, t)
244 }
245
246 fn interpolate_cubic(
247 v0: &Self,
248 out_tangent0: &Self,
249 in_tangent1: &Self,
250 v1: &Self,
251 t: f32,
252 dt: f32,
253 ) -> Self {
254 let t2 = t * t;
255 let t3 = t2 * t;
256
257 let s2 = -2.0 * t3 + 3.0 * t2;
258 let s3 = t3 - t2;
259 let s0 = 1.0 - s2;
260 let s1 = s3 - t2 + t;
261
262 let v0_v = Vec4::from(*v0);
263 let v1_v = Vec4::from(*v1);
264 let m0_v = Vec4::from(*out_tangent0) * dt;
265 let m1_v = Vec4::from(*in_tangent1) * dt;
266
267 let result = v0_v * s0 + m0_v * s1 + v1_v * s2 + m1_v * s3;
268
269 Quat::from_vec4(result).normalize()
270 }
271}