Files
creator/app/src-tauri/src/animation/primitives/interpolations.rs
enricobuehler 8523e44029 add staggered text
rename box to rect
refactor rust
2023-05-23 10:27:45 +02:00

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