#![doc = include_str!("../README.md")]
#![allow(mixed_script_confusables)]
#![allow(unused_comparisons)]
#![warn(missing_docs)]
use std::cell::RefCell;
use std::rc::Rc;
use rom::background_layer::BackgroundLayer;
use crate::engine::Engine;
use crate::rom::Rom;
use crate::utils::LayerParamOptions;
mod engine;
mod rom;
mod utils;
pub use engine::{SNES_HEIGHT, SNES_WIDTH};
pub const MAX_LAYER: u16 = 326;
#[derive(Debug, Default)]
pub struct Options {
pub layers: Layers,
pub aspect_ratio: AspectRatio,
}
#[derive(Debug)]
pub struct Layers {
layer1: u16,
layer2: u16,
}
impl Layers {
pub fn new(layer1: u16, layer2: u16) -> Self {
assert!(layer1 <= MAX_LAYER, "layer1 must be <= {}", MAX_LAYER);
assert!(layer2 <= MAX_LAYER, "layer2 must be <= {}", MAX_LAYER);
Layers { layer1, layer2 }
}
}
impl Default for Layers {
fn default() -> Self {
Layers {
layer1: 270,
layer2: 269,
}
}
}
#[derive(Debug, Default, Copy, Clone)]
pub enum AspectRatio {
#[default]
Full,
WideLetterbox,
MediumLetterbox,
NarrowLetterbox,
}
#[derive(Debug)]
pub struct Emulator {
engine: Engine,
}
impl Emulator {
pub fn new(options: Options) -> Self {
Emulator {
engine: setup_engine(options),
}
}
pub fn draw_frame(&mut self, pixels: &mut [u8]) {
assert_eq!(pixels.len(), usize::from(SNES_WIDTH * SNES_HEIGHT) * 4);
self.engine.draw_frame(pixels, false);
}
}
fn setup_engine(options: Options) -> Engine {
let layer_1_val = utils::parse_layer_param(
Some(options.layers.layer1),
LayerParamOptions { first_layer: true },
);
let layer_2_val = utils::parse_layer_param(
Some(options.layers.layer2),
LayerParamOptions { first_layer: false },
);
let frameskip = utils::parse_frameskip_param(None);
let aspect_ratio = utils::parse_aspect_ratio_param(Some(match options.aspect_ratio {
AspectRatio::Full => 0,
AspectRatio::WideLetterbox => 16,
AspectRatio::MediumLetterbox => 48,
AspectRatio::NarrowLetterbox => 64,
}));
let debug = false;
let fps = 30;
let mut alpha = 0.5;
if layer_2_val == 0 {
alpha = 1.0;
}
let rom = Rc::new(RefCell::new(Rom::new()));
let layer1 = BackgroundLayer::new(layer_1_val as usize, rom.clone());
let layer2 = BackgroundLayer::new(layer_2_val as usize, rom.clone());
let mut engine = Engine::new(
vec![layer1, layer2],
engine::Options {
fps,
aspect_ratio,
frame_skip: frameskip,
alpha: vec![alpha, alpha],
canvas: (),
},
);
engine.animate(debug);
engine
}