Mercurial > touhou
comparison interpreters/src/th06/interpolator.rs @ 787:7f9b3f5001c2
interpreters: Make Interpolator generic over N
This was a workaround for Rust < 1.51 which didn’t support const generics yet,
but we’ve had tat for close to five years now!
| author | Link Mauve <linkmauve@linkmauve.fr> |
|---|---|
| date | Mon, 15 Dec 2025 11:34:58 +0100 |
| parents | 21b186be2590 |
| children |
comparison
equal
deleted
inserted
replaced
| 786:7e940ebeb5fd | 787:7f9b3f5001c2 |
|---|---|
| 15 Formula::InvertPower2 => 2. * x - x * x, | 15 Formula::InvertPower2 => 2. * x - x * x, |
| 16 } | 16 } |
| 17 } | 17 } |
| 18 } | 18 } |
| 19 | 19 |
| 20 macro_rules! generate_interpolator { | 20 #[derive(Debug, Clone)] |
| 21 ($name:ident, $n:tt) => { | 21 pub(crate) struct Interpolator<T, const N: usize> { |
| 22 #[derive(Debug, Clone)] | 22 start_values: [T; N], |
| 23 pub(crate) struct $name<T> { | 23 end_values: [T; N], |
| 24 start_values: [T; $n], | 24 start_frame: u32, |
| 25 end_values: [T; $n], | 25 end_frame: u32, |
| 26 start_frame: u32, | 26 formula: Formula, |
| 27 end_frame: u32, | |
| 28 formula: Formula, | |
| 29 } | |
| 30 | |
| 31 impl<T> $name<T> | |
| 32 where f32: From<T>, | |
| 33 T: From<f32>, | |
| 34 T: std::ops::Sub<Output = T>, | |
| 35 T: std::ops::Add<Output = T>, | |
| 36 T: Copy, | |
| 37 T: Default, | |
| 38 { | |
| 39 pub fn new(start_values: [T; $n], start_frame: u32, end_values: [T; $n], end_frame: u32, formula: Formula) -> $name<T> { | |
| 40 $name { | |
| 41 start_values, | |
| 42 end_values, | |
| 43 start_frame, | |
| 44 end_frame, | |
| 45 formula, | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 pub fn set_start(&mut self, frame: u32, values: [T; $n]) { | |
| 50 self.start_values = values; | |
| 51 self.start_frame = frame; | |
| 52 } | |
| 53 | |
| 54 pub fn set_end(&mut self, frame: u32, values: [T; $n]) { | |
| 55 self.end_values = values; | |
| 56 self.end_frame = frame; | |
| 57 } | |
| 58 | |
| 59 pub fn set_end_values(&mut self, values: [T; $n]) { | |
| 60 self.end_values = values; | |
| 61 } | |
| 62 | |
| 63 pub fn set_end_frame(&mut self, frame: u32) { | |
| 64 self.end_frame = frame; | |
| 65 } | |
| 66 | |
| 67 // XXX: Make it return [T; $n] instead, we don’t want to only do f32 here. | |
| 68 pub fn values(&self, frame: u32) -> [f32; $n] { | |
| 69 if frame + 1 >= self.end_frame { | |
| 70 // XXX: skip the last interpolation step. | |
| 71 // This bug is replicated from the original game. | |
| 72 //self.start_frame = self.end_frame; | |
| 73 //self.end_values | |
| 74 let mut values: [f32; $n] = [Default::default(); $n]; | |
| 75 for (i, value) in self.end_values.iter().enumerate() { | |
| 76 values[i] = f32::from(*value); | |
| 77 } | |
| 78 values | |
| 79 } else { | |
| 80 let mut coeff = (frame - self.start_frame) as f32 / (self.end_frame - self.start_frame) as f32; | |
| 81 coeff = self.formula.apply(coeff); | |
| 82 let mut values: [f32; $n] = [Default::default(); $n]; | |
| 83 for (i, (start, end)) in self.start_values.iter().zip(&self.end_values).enumerate() { | |
| 84 values[i] = f32::from(*start + T::from(coeff * f32::from(*end - *start))); | |
| 85 } | |
| 86 values | |
| 87 } | |
| 88 } | |
| 89 } | |
| 90 }; | |
| 91 } | 27 } |
| 92 | 28 |
| 93 generate_interpolator!(Interpolator1, 1); | 29 impl<T, const N: usize> Interpolator<T, N> |
| 94 generate_interpolator!(Interpolator2, 2); | 30 where f32: From<T>, |
| 95 generate_interpolator!(Interpolator3, 3); | 31 T: From<f32>, |
| 96 //generate_interpolator!(Interpolator4, 4); | 32 T: std::ops::Sub<Output = T>, |
| 33 T: std::ops::Add<Output = T>, | |
| 34 T: Copy, | |
| 35 T: Default, | |
| 36 { | |
| 37 pub fn new(start_values: [T; N], start_frame: u32, end_values: [T; N], end_frame: u32, formula: Formula) -> Interpolator<T, N> { | |
| 38 Interpolator { | |
| 39 start_values, | |
| 40 end_values, | |
| 41 start_frame, | |
| 42 end_frame, | |
| 43 formula, | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 pub fn set_start(&mut self, frame: u32, values: [T; N]) { | |
| 48 self.start_values = values; | |
| 49 self.start_frame = frame; | |
| 50 } | |
| 51 | |
| 52 pub fn set_end(&mut self, frame: u32, values: [T; N]) { | |
| 53 self.end_values = values; | |
| 54 self.end_frame = frame; | |
| 55 } | |
| 56 | |
| 57 pub fn set_end_values(&mut self, values: [T; N]) { | |
| 58 self.end_values = values; | |
| 59 } | |
| 60 | |
| 61 pub fn set_end_frame(&mut self, frame: u32) { | |
| 62 self.end_frame = frame; | |
| 63 } | |
| 64 | |
| 65 // XXX: Make it return [T; N] instead, we don’t want to only do f32 here. | |
| 66 pub fn values(&self, frame: u32) -> [f32; N] { | |
| 67 if frame + 1 >= self.end_frame { | |
| 68 // XXX: skip the last interpolation step. | |
| 69 // This bug is replicated from the original game. | |
| 70 //self.start_frame = self.end_frame; | |
| 71 //self.end_values | |
| 72 let mut values: [f32; N] = [Default::default(); N]; | |
| 73 for (i, value) in self.end_values.iter().enumerate() { | |
| 74 values[i] = f32::from(*value); | |
| 75 } | |
| 76 values | |
| 77 } else { | |
| 78 let mut coeff = (frame - self.start_frame) as f32 / (self.end_frame - self.start_frame) as f32; | |
| 79 coeff = self.formula.apply(coeff); | |
| 80 let mut values: [f32; N] = [Default::default(); N]; | |
| 81 for (i, (start, end)) in self.start_values.iter().zip(&self.end_values).enumerate() { | |
| 82 values[i] = f32::from(*start + T::from(coeff * f32::from(*end - *start))); | |
| 83 } | |
| 84 values | |
| 85 } | |
| 86 } | |
| 87 } |
