diff 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
line wrap: on
line diff
--- a/interpreters/src/th06/interpolator.rs
+++ b/interpreters/src/th06/interpolator.rs
@@ -17,80 +17,71 @@
     }
 }
 
-macro_rules! generate_interpolator {
-    ($name:ident, $n:tt) => {
-        #[derive(Debug, Clone)]
-        pub(crate) struct $name<T> {
-            start_values: [T; $n],
-            end_values: [T; $n],
-            start_frame: u32,
-            end_frame: u32,
-            formula: Formula,
-        }
-
-        impl<T> $name<T>
-        where f32: From<T>,
-              T: From<f32>,
-              T: std::ops::Sub<Output = T>,
-              T: std::ops::Add<Output = T>,
-              T: Copy,
-              T: Default,
-        {
-            pub fn new(start_values: [T; $n], start_frame: u32, end_values: [T; $n], end_frame: u32, formula: Formula) -> $name<T> {
-                $name {
-                    start_values,
-                    end_values,
-                    start_frame,
-                    end_frame,
-                    formula,
-                }
-            }
-
-            pub fn set_start(&mut self, frame: u32, values: [T; $n]) {
-                self.start_values = values;
-                self.start_frame = frame;
-            }
-
-            pub fn set_end(&mut self, frame: u32, values: [T; $n]) {
-                self.end_values = values;
-                self.end_frame = frame;
-            }
-
-            pub fn set_end_values(&mut self, values: [T; $n]) {
-                self.end_values = values;
-            }
-
-            pub fn set_end_frame(&mut self, frame: u32) {
-                self.end_frame = frame;
-            }
-
-            // XXX: Make it return [T; $n] instead, we don’t want to only do f32 here.
-            pub fn values(&self, frame: u32) -> [f32; $n] {
-                if frame + 1 >= self.end_frame {
-                    // XXX: skip the last interpolation step.
-                    // This bug is replicated from the original game.
-                    //self.start_frame = self.end_frame;
-                    //self.end_values
-                    let mut values: [f32; $n] = [Default::default(); $n];
-                    for (i, value) in self.end_values.iter().enumerate() {
-                        values[i] = f32::from(*value);
-                    }
-                    values
-                } else {
-                    let mut coeff = (frame - self.start_frame) as f32 / (self.end_frame - self.start_frame) as f32;
-                    coeff = self.formula.apply(coeff);
-                    let mut values: [f32; $n] = [Default::default(); $n];
-                    for (i, (start, end)) in self.start_values.iter().zip(&self.end_values).enumerate() {
-                        values[i] = f32::from(*start + T::from(coeff * f32::from(*end - *start)));
-                    }
-                    values
-                }
-            }
-        }
-    };
+#[derive(Debug, Clone)]
+pub(crate) struct Interpolator<T, const N: usize> {
+    start_values: [T; N],
+    end_values: [T; N],
+    start_frame: u32,
+    end_frame: u32,
+    formula: Formula,
 }
 
-generate_interpolator!(Interpolator1, 1);
-generate_interpolator!(Interpolator2, 2);
-generate_interpolator!(Interpolator3, 3);
-//generate_interpolator!(Interpolator4, 4);
+impl<T, const N: usize> Interpolator<T, N>
+where f32: From<T>,
+      T: From<f32>,
+      T: std::ops::Sub<Output = T>,
+      T: std::ops::Add<Output = T>,
+      T: Copy,
+      T: Default,
+{
+    pub fn new(start_values: [T; N], start_frame: u32, end_values: [T; N], end_frame: u32, formula: Formula) -> Interpolator<T, N> {
+        Interpolator {
+            start_values,
+            end_values,
+            start_frame,
+            end_frame,
+            formula,
+        }
+    }
+
+    pub fn set_start(&mut self, frame: u32, values: [T; N]) {
+        self.start_values = values;
+        self.start_frame = frame;
+    }
+
+    pub fn set_end(&mut self, frame: u32, values: [T; N]) {
+        self.end_values = values;
+        self.end_frame = frame;
+    }
+
+    pub fn set_end_values(&mut self, values: [T; N]) {
+        self.end_values = values;
+    }
+
+    pub fn set_end_frame(&mut self, frame: u32) {
+        self.end_frame = frame;
+    }
+
+    // XXX: Make it return [T; N] instead, we don’t want to only do f32 here.
+    pub fn values(&self, frame: u32) -> [f32; N] {
+        if frame + 1 >= self.end_frame {
+            // XXX: skip the last interpolation step.
+            // This bug is replicated from the original game.
+            //self.start_frame = self.end_frame;
+            //self.end_values
+            let mut values: [f32; N] = [Default::default(); N];
+            for (i, value) in self.end_values.iter().enumerate() {
+                values[i] = f32::from(*value);
+            }
+            values
+        } else {
+            let mut coeff = (frame - self.start_frame) as f32 / (self.end_frame - self.start_frame) as f32;
+            coeff = self.formula.apply(coeff);
+            let mut values: [f32; N] = [Default::default(); N];
+            for (i, (start, end)) in self.start_values.iter().zip(&self.end_values).enumerate() {
+                values[i] = f32::from(*start + T::from(coeff * f32::from(*end - *start)));
+            }
+            values
+        }
+    }
+}