171 lines
5.3 KiB
Rust
171 lines
5.3 KiB
Rust
use std::cmp::Ordering;
|
|
|
|
use super::keyframe::RenderedKeyframe;
|
|
use serde::{Deserialize, Serialize};
|
|
use simple_easing::{
|
|
circ_in, circ_in_out, circ_out, cubic_in, cubic_in_out, cubic_out, expo_in, expo_in_out,
|
|
expo_out, quad_in, quad_in_out, quad_out, quart_in, quart_in_out, quart_out, quint_in,
|
|
quint_in_out, quint_out,
|
|
};
|
|
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
|
pub struct SpringProperties {
|
|
pub mass: f32,
|
|
pub damping: f32,
|
|
pub stiffness: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
|
pub struct SpringState {
|
|
pub velocity: f32,
|
|
pub last_val: f32,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
|
#[serde(tag = "easing_function")]
|
|
pub enum EasingFunction {
|
|
QuintOut,
|
|
QuintIn,
|
|
QuintInOut,
|
|
CircOut,
|
|
CircIn,
|
|
CircInOut,
|
|
CubicOut,
|
|
CubicIn,
|
|
CubicInOut,
|
|
ExpoOut,
|
|
ExpoIn,
|
|
ExpoInOut,
|
|
QuadOut,
|
|
QuadIn,
|
|
QuadInOut,
|
|
QuartOut,
|
|
QuartIn,
|
|
QuartInOut,
|
|
}
|
|
|
|
impl EasingFunction {
|
|
fn ease(self: &Self, t: f32) -> f32 {
|
|
match self {
|
|
EasingFunction::QuintOut => quint_out(t),
|
|
EasingFunction::QuintIn => quint_in(t),
|
|
EasingFunction::QuintInOut => quint_in_out(t),
|
|
EasingFunction::CircOut => circ_out(t),
|
|
EasingFunction::CircIn => circ_in(t),
|
|
EasingFunction::CircInOut => circ_in_out(t),
|
|
EasingFunction::CubicOut => cubic_out(t),
|
|
EasingFunction::CubicIn => cubic_in(t),
|
|
EasingFunction::CubicInOut => cubic_in_out(t),
|
|
EasingFunction::ExpoOut => expo_out(t),
|
|
EasingFunction::ExpoIn => expo_in(t),
|
|
EasingFunction::ExpoInOut => expo_in_out(t),
|
|
EasingFunction::QuadOut => quad_out(t),
|
|
EasingFunction::QuadIn => quad_in(t),
|
|
EasingFunction::QuadInOut => quad_in_out(t),
|
|
EasingFunction::QuartOut => quart_out(t),
|
|
EasingFunction::QuartIn => quart_in(t),
|
|
EasingFunction::QuartInOut => quart_in_out(t),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
|
#[serde(tag = "type")]
|
|
pub enum InterpolationType {
|
|
Linear,
|
|
Spring(SpringProperties),
|
|
EasingFunction(EasingFunction),
|
|
}
|
|
|
|
pub fn calculate_spring_value(
|
|
curr_frame: i32,
|
|
start_value: f32,
|
|
target_value: f32,
|
|
start_frame: i32,
|
|
_end_frame: i32,
|
|
spring_props: &SpringProperties,
|
|
) -> f32 {
|
|
const PRECISION: f32 = 0.01;
|
|
const STEP: f32 = 10.0;
|
|
const REST_VELOCITY: f32 = PRECISION / 10.0;
|
|
|
|
let _is_growing = match start_value.total_cmp(&target_value) {
|
|
Ordering::Equal => false,
|
|
Ordering::Less => false,
|
|
Ordering::Greater => true,
|
|
};
|
|
|
|
let mut _is_moving = false;
|
|
let mut spring_state = SpringState {
|
|
last_val: start_value,
|
|
velocity: 0.0,
|
|
};
|
|
|
|
let mut position = start_value;
|
|
let relative_curr_frame = curr_frame - start_frame;
|
|
|
|
// println!("target_value {target_value} start_value {start_value}");
|
|
// println!("start_frame {start_frame} end_frame {end_frame}");
|
|
|
|
for _ in 0..relative_curr_frame {
|
|
let _is_moving = spring_state.velocity.abs() > REST_VELOCITY;
|
|
|
|
let spring_force = -spring_props.stiffness * 0.000001 * (position - target_value);
|
|
let damping_force = -spring_props.damping * 0.001 * spring_state.velocity;
|
|
let acceleration = (spring_force + damping_force) / spring_props.mass; // pt/ms^2
|
|
|
|
spring_state.velocity = spring_state.velocity + acceleration * STEP; // pt/ms
|
|
position = position + spring_state.velocity * STEP;
|
|
// println!("{position}")
|
|
}
|
|
|
|
position
|
|
}
|
|
|
|
pub fn interpolate_rendered_keyframes(
|
|
first_ren_keyframe: &RenderedKeyframe,
|
|
second_ren_keyframe: &RenderedKeyframe,
|
|
curr_frame: i32,
|
|
interpolation_type: InterpolationType,
|
|
_fps: i16,
|
|
) -> f32 {
|
|
let frame_range = second_ren_keyframe.absolute_frame - first_ren_keyframe.absolute_frame;
|
|
let position_in_range = curr_frame - first_ren_keyframe.absolute_frame;
|
|
let progress: f32 = (1.0 / frame_range as f32) * position_in_range as f32;
|
|
|
|
/* println!(
|
|
"Progress:{0} Frame_Range: {1} Position_In_Range: {2}",
|
|
progress, frame_range, position_in_range
|
|
); */
|
|
|
|
let value_diff = second_ren_keyframe.keyframe.value - first_ren_keyframe.keyframe.value;
|
|
|
|
match interpolation_type {
|
|
InterpolationType::Linear => {
|
|
let interpolated_val =
|
|
first_ren_keyframe.keyframe.value + (value_diff * progress as f32);
|
|
|
|
return interpolated_val;
|
|
}
|
|
InterpolationType::EasingFunction(easing_function) => {
|
|
let eased_progress = easing_function.ease(progress);
|
|
|
|
let interpolated_val =
|
|
first_ren_keyframe.keyframe.value + (value_diff * eased_progress as f32);
|
|
|
|
return interpolated_val;
|
|
}
|
|
InterpolationType::Spring(spring_properties) => {
|
|
let interpolated_value = calculate_spring_value(
|
|
curr_frame,
|
|
first_ren_keyframe.keyframe.value,
|
|
second_ren_keyframe.keyframe.value,
|
|
first_ren_keyframe.absolute_frame,
|
|
second_ren_keyframe.absolute_frame,
|
|
&spring_properties,
|
|
);
|
|
return interpolated_value;
|
|
}
|
|
};
|
|
}
|