view interpreters/src/th06/interpolator.rs @ 791:a29122662cde

utils: Simplify translate_2d and align Mat4 to 16 bytes This lowers the amount of instructions from 61 to 32 on PowerPC with AltiVec, and from 25 to 14 on amd64 with AVX2.
author Link Mauve <linkmauve@linkmauve.fr>
date Sat, 17 Jan 2026 14:19:58 +0100
parents 7f9b3f5001c2
children
line wrap: on
line source

//! Animation runner.

#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum Formula {
    Linear,
    Power2,
    InvertPower2,
}

impl Formula {
    fn apply(&self, x: f32) -> f32 {
        match self {
            Formula::Linear => x,
            Formula::Power2 => x * x,
            Formula::InvertPower2 => 2. * x - x * x,
        }
    }
}

#[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,
}

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
        }
    }
}