use agb::display::GraphicsFrame;
use agb::display::tiled::BackgroundId;
use agb::fixnum::{Num, num};
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Fade {
#[default]
Start,
Step1,
Step2,
Step3,
Step4,
Step5,
End,
}
impl Fade {
pub const fn next(self) -> Option<Self> {
match self {
Fade::Start => Some(Fade::Step1),
Fade::Step1 => Some(Fade::Step2),
Fade::Step2 => Some(Fade::Step3),
Fade::Step3 => Some(Fade::Step4),
Fade::Step4 => Some(Fade::Step5),
Fade::Step5 => Some(Fade::End),
Fade::End => None,
}
}
pub const fn prev(self) -> Option<Self> {
match self {
Fade::Start => None,
Fade::Step1 => Some(Fade::Start),
Fade::Step2 => Some(Fade::Step1),
Fade::Step3 => Some(Fade::Step2),
Fade::Step4 => Some(Fade::Step3),
Fade::Step5 => Some(Fade::Step4),
Fade::End => Some(Fade::Step5),
}
}
#[inline]
pub const fn is_done(self) -> bool {
matches!(self, Fade::End)
}
pub fn amount(self) -> FadeAmount {
match self {
Fade::Start => num!(0),
Fade::Step1 => num!(0.1875),
Fade::Step2 => num!(0.3125),
Fade::Step3 => num!(0.5),
Fade::Step4 => num!(0.6875),
Fade::Step5 => num!(0.8125),
Fade::End => num!(1),
}
}
}
impl From<Fade> for FadeAmount {
fn from(value: Fade) -> Self {
value.amount()
}
}
pub type FadeAmount = Num<u8, 4>;
enum FadeKind {
Darken,
Brighten,
}
fn apply_fade(
kind: FadeKind,
amount: FadeAmount,
bg_ids: &[BackgroundId],
frame: &mut GraphicsFrame,
) {
let mut effect = match kind {
FadeKind::Darken => frame.blend().darken(amount),
FadeKind::Brighten => frame.blend().brighten(amount),
};
effect.enable_object();
for id in bg_ids {
effect.enable_background(*id);
}
}
pub fn fade_to_black<A: Into<FadeAmount>>(
amount: A,
bg_ids: &[BackgroundId],
frame: &mut GraphicsFrame,
) {
apply_fade(FadeKind::Darken, amount.into(), bg_ids, frame);
}
pub fn fade_from_black<A: Into<FadeAmount>>(
amount: A,
bg_ids: &[BackgroundId],
frame: &mut GraphicsFrame,
) {
apply_fade(FadeKind::Darken, num!(1) - amount.into(), bg_ids, frame);
}
pub fn fade_to_white<A: Into<FadeAmount>>(
amount: A,
bg_ids: &[BackgroundId],
frame: &mut GraphicsFrame,
) {
apply_fade(FadeKind::Brighten, amount.into(), bg_ids, frame);
}
pub fn fade_from_white<A: Into<FadeAmount>>(
amount: A,
bg_ids: &[BackgroundId],
frame: &mut GraphicsFrame,
) {
apply_fade(FadeKind::Brighten, num!(1) - amount.into(), bg_ids, frame);
}
pub fn reset_fade(bg_ids: &[BackgroundId], frame: &mut GraphicsFrame) {
apply_fade(FadeKind::Brighten, num!(0), bg_ids, frame);
}
#[cfg(test)]
mod tests {
use super::*;
#[test_case]
fn steps_chain(_gba: &mut agb::Gba) {
let mut fade = Fade::default();
let mut count = 0;
while let Some(next) = fade.next() {
assert!(next > fade);
assert_eq!(next.prev(), Some(fade));
fade = next;
count += 1;
}
assert!(fade.is_done());
assert_eq!(count, 6);
assert_eq!(Fade::End.amount(), num!(1));
assert_eq!(Fade::Start.amount(), num!(0));
}
}