# HG changeset patch # User Link Mauve # Date 1765794898 -3600 # Node ID 7f9b3f5001c2d5474dfb4887a62e1a478a5ae88f # Parent 7e940ebeb5fd79cf0307896928d739a91b9ea3e5 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! diff --git a/interpreters/src/th06/anm0.rs b/interpreters/src/th06/anm0.rs --- a/interpreters/src/th06/anm0.rs +++ b/interpreters/src/th06/anm0.rs @@ -6,7 +6,7 @@ Call, Instruction, }; -use crate::th06::interpolator::{Interpolator1, Interpolator2, Interpolator3, Formula}; +use crate::th06::interpolator::{Interpolator, Formula}; use touhou_utils::math::Mat4; use touhou_utils::prng::Prng; use std::cell::RefCell; @@ -45,11 +45,11 @@ mirrored: bool, corner_relative_placement: bool, - scale_interpolator: Option>, - fade_interpolator: Option>, // XXX: should be u8! - offset_interpolator: Option>, - rotation_interpolator: Option>, - color_interpolator: Option>, // XXX: should be u8! + scale_interpolator: Option>, + fade_interpolator: Option>, // XXX: should be u8! + offset_interpolator: Option>, + rotation_interpolator: Option>, + color_interpolator: Option>, // XXX: should be u8! anm: Option, @@ -409,7 +409,7 @@ sprite.scale_speed = [ssx, ssy]; } Instruction::Fade(new_alpha, duration) => { - sprite.fade_interpolator = Some(Interpolator1::new([sprite.color[3] as f32], sprite.frame, [new_alpha as f32], sprite.frame + duration, Formula::Linear)); + sprite.fade_interpolator = Some(Interpolator::new([sprite.color[3] as f32], sprite.frame, [new_alpha as f32], sprite.frame + duration, Formula::Linear)); } Instruction::SetBlendmodeAlphablend() => { sprite.blendfunc = 1; @@ -433,13 +433,13 @@ sprite.dest_offset = [x, y, z]; } Instruction::MoveToLinear(x, y, z, duration) => { - sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::Linear)); + sprite.offset_interpolator = Some(Interpolator::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::Linear)); } Instruction::MoveToDecel(x, y, z, duration) => { - sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::InvertPower2)); + sprite.offset_interpolator = Some(Interpolator::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::InvertPower2)); } Instruction::MoveToAccel(x, y, z, duration) => { - sprite.offset_interpolator = Some(Interpolator3::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::Power2)); + sprite.offset_interpolator = Some(Interpolator::new(sprite.dest_offset, sprite.frame, [x, y, z], sprite.frame + duration, Formula::Power2)); } Instruction::Wait() => { self.waiting = true; @@ -471,7 +471,7 @@ sprite.visible = (visible & 1) != 0; } Instruction::ScaleIn(sx, sy, duration) => { - sprite.scale_interpolator = Some(Interpolator2::new(sprite.rescale, sprite.frame, [sx, sy], sprite.frame + duration, Formula::Linear)); + sprite.scale_interpolator = Some(Interpolator::new(sprite.rescale, sprite.frame, [sx, sy], sprite.frame + duration, Formula::Linear)); } Instruction::Todo(_todo) => { // TODO. diff --git a/interpreters/src/th06/enemy.rs b/interpreters/src/th06/enemy.rs --- a/interpreters/src/th06/enemy.rs +++ b/interpreters/src/th06/enemy.rs @@ -3,7 +3,7 @@ use touhou_formats::th06::anm0::Anm0; use touhou_formats::th06::ecl::Rank; use crate::th06::anm0::{Sprite, AnmRunner}; -use crate::th06::interpolator::{Interpolator1, Interpolator2}; +use crate::th06::interpolator::Interpolator; use touhou_utils::prng::Prng; use std::cell::RefCell; use std::collections::HashMap; @@ -304,8 +304,8 @@ options: Vec, // Interpolators. - pub(crate) interpolator: Option>, - pub(crate) speed_interpolator: Option>, + pub(crate) interpolator: Option>, + pub(crate) speed_interpolator: Option>, // Misc stuff, do we need them? pub(crate) anm0: Weak>, diff --git a/interpreters/src/th06/interpolator.rs b/interpreters/src/th06/interpolator.rs --- 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 { - start_values: [T; $n], - end_values: [T; $n], - start_frame: u32, - end_frame: u32, - formula: Formula, - } - - impl $name - where f32: From, - T: From, - T: std::ops::Sub, - T: std::ops::Add, - T: Copy, - T: Default, - { - pub fn new(start_values: [T; $n], start_frame: u32, end_values: [T; $n], end_frame: u32, formula: Formula) -> $name { - $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 { + 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 Interpolator +where f32: From, + T: From, + T: std::ops::Sub, + T: std::ops::Add, + T: Copy, + T: Default, +{ + pub fn new(start_values: [T; N], start_frame: u32, end_values: [T; N], end_frame: u32, formula: Formula) -> Interpolator { + 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 + } + } +} diff --git a/interpreters/src/th06/std.rs b/interpreters/src/th06/std.rs --- a/interpreters/src/th06/std.rs +++ b/interpreters/src/th06/std.rs @@ -1,7 +1,7 @@ //! Interpreter of STD files. use touhou_formats::th06::std::{Stage, Call, Instruction}; -use crate::th06::interpolator::{Interpolator3, Formula}; +use crate::th06::interpolator::{Interpolator, Formula}; use touhou_utils::math::{Mat4, setup_camera}; use std::cell::RefCell; use std::rc::Rc; @@ -12,8 +12,8 @@ pub stage: Rc>, frame: u32, - position: Interpolator3, - direction: Interpolator3, + position: Interpolator, + direction: Interpolator, /// XXX: no pub. pub fog_color: [f32; 4], @@ -29,8 +29,8 @@ StageRunner { stage, frame: 0, - position: Interpolator3::new([0., 0., 0.], 0, [0., 0., 0.], 0, Formula::Linear), - direction: Interpolator3::new([0., 0., 0.], 0, [0., 0., 0.], 0, Formula::Linear), + position: Interpolator::new([0., 0., 0.], 0, [0., 0., 0.], 0, Formula::Linear), + direction: Interpolator::new([0., 0., 0.], 0, [0., 0., 0.], 0, Formula::Linear), fog_color: [1.; 4], fog_near: 0., fog_far: 1000.,