earthbound_battle_backgrounds/
lib.rs1#![doc = include_str!("../README.md")]
2#![allow(mixed_script_confusables)]
3#![allow(unused_comparisons)]
4#![warn(missing_docs)]
5
6use std::cell::RefCell;
7use std::rc::Rc;
8
9use rom::background_layer::BackgroundLayer;
10
11use crate::engine::Engine;
12use crate::rom::Rom;
13use crate::utils::LayerParamOptions;
14
15mod engine;
16mod rom;
17mod utils;
18
19pub use engine::{SNES_HEIGHT, SNES_WIDTH};
20
21pub const MAX_LAYER: u16 = 326;
23
24#[derive(Debug, Default)]
26pub struct Options {
27 pub layers: Layers,
29
30 pub aspect_ratio: AspectRatio,
32}
33
34#[derive(Debug)]
36pub struct Layers {
37 layer1: u16,
38 layer2: u16,
39}
40
41impl Layers {
42 pub fn new(layer1: u16, layer2: u16) -> Self {
53 assert!(layer1 <= MAX_LAYER, "layer1 must be <= {}", MAX_LAYER);
54 assert!(layer2 <= MAX_LAYER, "layer2 must be <= {}", MAX_LAYER);
55
56 Layers { layer1, layer2 }
57 }
58}
59
60impl Default for Layers {
61 fn default() -> Self {
62 Layers {
63 layer1: 270,
64 layer2: 269,
65 }
66 }
67}
68
69#[derive(Debug, Default, Copy, Clone)]
72pub enum AspectRatio {
73 #[default]
75 Full,
76
77 WideLetterbox,
79
80 MediumLetterbox,
82
83 NarrowLetterbox,
85}
86
87#[derive(Debug)]
89pub struct Emulator {
90 engine: Engine,
91}
92
93impl Emulator {
94 pub fn new(options: Options) -> Self {
96 Emulator {
97 engine: setup_engine(options),
98 }
99 }
100
101 pub fn draw_frame(&mut self, pixels: &mut [u8]) {
109 assert_eq!(pixels.len(), usize::from(SNES_WIDTH * SNES_HEIGHT) * 4);
110 self.engine.draw_frame(pixels, false);
111 }
112}
113
114fn setup_engine(options: Options) -> Engine {
115 let layer_1_val = utils::parse_layer_param(
116 Some(options.layers.layer1),
117 LayerParamOptions { first_layer: true },
118 );
119 let layer_2_val = utils::parse_layer_param(
120 Some(options.layers.layer2),
121 LayerParamOptions { first_layer: false },
122 );
123 let frameskip = utils::parse_frameskip_param(None);
124 let aspect_ratio = utils::parse_aspect_ratio_param(Some(match options.aspect_ratio {
125 AspectRatio::Full => 0,
126 AspectRatio::WideLetterbox => 16,
127 AspectRatio::MediumLetterbox => 48,
128 AspectRatio::NarrowLetterbox => 64,
129 }));
130 let debug = false;
131
132 let fps = 30;
133 let mut alpha = 0.5;
134
135 if layer_2_val == 0 {
136 alpha = 1.0;
137 }
138
139 let rom = Rc::new(RefCell::new(Rom::new()));
140
141 let layer1 = BackgroundLayer::new(layer_1_val as usize, rom.clone());
142 let layer2 = BackgroundLayer::new(layer_2_val as usize, rom.clone());
143
144 let mut engine = Engine::new(
145 vec![layer1, layer2],
146 engine::Options {
147 fps,
148 aspect_ratio,
149 frame_skip: frameskip,
150 alpha: vec![alpha, alpha],
151 canvas: (),
152 },
153 );
154
155 engine.animate(debug);
156
157 engine
158}