earthbound-battle-backgrounds 0.1.0

Emulate and render the battle backgrounds from EarthBound / Mother 2.
Documentation
use std::time::{SystemTime, UNIX_EPOCH};

use log::*;

use crate::rom::background_layer::BackgroundLayer;

/// Height of the SNES screen in pixels.
pub const SNES_WIDTH: u16 = 256;

/// Width of the SNES screen in pixels.
pub const SNES_HEIGHT: u16 = 224;

pub struct Options {
    pub fps: u32,
    pub aspect_ratio: u8,
    pub frame_skip: u8,
    pub alpha: Vec<f32>,
    pub canvas: (),
}

#[derive(Debug)]
pub struct Engine {
    layers: Vec<BackgroundLayer>,
    fps: u32,
    aspect_ratio: u8,
    frame_skip: u8,
    alpha: Vec<f32>,
    _canvas: (),
    tick: u64,
    fps_interval: f64,
    then: f64,
}

impl Engine {
    pub fn new(layers: Vec<BackgroundLayer>, opts: Options) -> Self {
        Engine {
            layers,
            fps: opts.fps,
            aspect_ratio: opts.aspect_ratio,
            frame_skip: opts.frame_skip,
            alpha: opts.alpha,
            _canvas: opts.canvas,
            tick: 0,
            fps_interval: 0.,
            then: 0.,
        }
    }

    pub fn animate(&mut self, _debug: bool) {
        self.then = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as f64;
        self.fps_interval = 1000. / f64::from(self.fps);

        if self.layers[0].entry != 0 && self.layers[1].entry == 0 {
            self.alpha[0] = 1.0;
            self.alpha[1] = 0.0;
        }
        if self.layers[0].entry == 0 && self.layers[1].entry != 0 {
            self.alpha[0] = 0.0;
            self.alpha[1] = 1.0;
        }
    }

    pub fn draw_frame(&mut self, image: &mut [u8], debug: bool) {
        let now = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as f64;
        let elapsed = now - self.then;
        if elapsed > self.fps_interval {
            // FIXME
            self.then = now - (elapsed % self.fps_interval);

            let mut _bitmap;

            for i in 0..self.layers.len() {
                if debug {
                    debug!("{:?}", image);
                }
                _bitmap = self.layers[i].overlay_frame(
                    image,
                    self.aspect_ratio,
                    self.tick,
                    self.alpha[i],
                    i == 0,
                );
            }
            self.tick += u64::from(self.frame_skip);
        }
    }
}