use crate::draw2d::Color;
#[derive(Clone, Copy, Debug, Default)]
pub enum Easing {
#[default]
Linear,
EaseIn,
EaseOut,
EaseInOut,
}
impl Easing {
pub fn apply(&self, t: f32) -> f32 {
let t = t.clamp(0.0, 1.0);
match self {
Easing::Linear => t,
Easing::EaseIn => t * t,
Easing::EaseOut => 1.0 - (1.0 - t) * (1.0 - t),
Easing::EaseInOut => {
if t < 0.5 {
2.0 * t * t
} else {
1.0 - (-2.0 * t + 2.0).powi(2) / 2.0
}
}
}
}
}
#[derive(Clone, Debug)]
pub enum TransitionKind {
Instant,
FadeToColor { color: Color },
Crossfade,
}
#[derive(Clone, Debug)]
pub struct Transition {
pub kind: TransitionKind,
pub duration: f32,
pub easing: Easing,
}
impl Default for Transition {
fn default() -> Self {
Self::instant()
}
}
impl Transition {
pub fn instant() -> Self {
Self {
kind: TransitionKind::Instant,
duration: 0.0,
easing: Easing::Linear,
}
}
pub fn fade_to_black(duration: f32) -> Self {
Self {
kind: TransitionKind::FadeToColor {
color: Color::BLACK,
},
duration,
easing: Easing::EaseInOut,
}
}
pub fn fade_to_white(duration: f32) -> Self {
Self {
kind: TransitionKind::FadeToColor {
color: Color::WHITE,
},
duration,
easing: Easing::EaseInOut,
}
}
pub fn fade_to_color(color: Color, duration: f32) -> Self {
Self {
kind: TransitionKind::FadeToColor { color },
duration,
easing: Easing::EaseInOut,
}
}
pub fn crossfade(duration: f32) -> Self {
Self {
kind: TransitionKind::Crossfade,
duration,
easing: Easing::EaseInOut,
}
}
pub fn easing(mut self, easing: Easing) -> Self {
self.easing = easing;
self
}
pub fn duration(mut self, duration: f32) -> Self {
self.duration = duration;
self
}
}
#[derive(Debug, Clone, Copy)]
pub enum TransitionPhase {
FadingOut,
Midpoint,
FadingIn,
Crossfading,
}
#[derive(Debug)]
pub struct ActiveTransition {
pub transition: Transition,
pub phase: TransitionPhase,
pub progress: f32,
pub start_time: f32,
pub target_scene: String,
pub source_scene: String,
}
impl ActiveTransition {
pub fn new(
transition: Transition,
source_scene: String,
target_scene: String,
start_time: f32,
) -> Self {
let phase = match transition.kind {
TransitionKind::Instant => TransitionPhase::Midpoint,
TransitionKind::FadeToColor { .. } => TransitionPhase::FadingOut,
TransitionKind::Crossfade => TransitionPhase::Crossfading,
};
Self {
transition,
phase,
progress: 0.0,
start_time,
target_scene,
source_scene,
}
}
pub fn update(&mut self, current_time: f32) -> bool {
let elapsed = current_time - self.start_time;
match self.transition.kind {
TransitionKind::Instant => {
self.phase = TransitionPhase::Midpoint;
true
}
TransitionKind::FadeToColor { .. } => {
let half_duration = self.transition.duration / 2.0;
match self.phase {
TransitionPhase::FadingOut => {
let raw_progress = (elapsed / half_duration).clamp(0.0, 1.0);
self.progress = self.transition.easing.apply(raw_progress);
if raw_progress >= 1.0 {
self.phase = TransitionPhase::Midpoint;
}
false
}
TransitionPhase::Midpoint => {
self.phase = TransitionPhase::FadingIn;
self.progress = 0.0;
false
}
TransitionPhase::FadingIn => {
let fade_in_elapsed = elapsed - half_duration;
let raw_progress = (fade_in_elapsed / half_duration).clamp(0.0, 1.0);
self.progress = self.transition.easing.apply(raw_progress);
raw_progress >= 1.0
}
TransitionPhase::Crossfading => unreachable!(),
}
}
TransitionKind::Crossfade => {
let raw_progress = (elapsed / self.transition.duration).clamp(0.0, 1.0);
self.progress = self.transition.easing.apply(raw_progress);
self.phase = TransitionPhase::Crossfading;
raw_progress >= 1.0
}
}
}
pub fn get_fade_alpha(&self) -> (f32, f32) {
match self.phase {
TransitionPhase::FadingOut => {
(1.0 - self.progress, self.progress)
}
TransitionPhase::Midpoint => {
(0.0, 1.0)
}
TransitionPhase::FadingIn => {
(self.progress, 1.0 - self.progress)
}
TransitionPhase::Crossfading => {
(1.0, 0.0)
}
}
}
pub fn get_crossfade_blend(&self) -> f32 {
self.progress
}
pub fn is_midpoint(&self) -> bool {
matches!(self.phase, TransitionPhase::Midpoint)
}
pub fn is_crossfade(&self) -> bool {
matches!(self.transition.kind, TransitionKind::Crossfade)
}
pub fn fade_color(&self) -> Option<Color> {
match &self.transition.kind {
TransitionKind::FadeToColor { color } => Some(*color),
_ => None,
}
}
}