diff --git a/snes-core/src/ppu/registers.rs b/snes-core/src/ppu/registers.rs index 0e5af73..1c5886d 100644 --- a/snes-core/src/ppu/registers.rs +++ b/snes-core/src/ppu/registers.rs @@ -393,9 +393,9 @@ mod ppu_registers_test { #[test] fn test_get_bg_tile_size() { let mut registers = PPURegisters::new(); - registers.write(BGMODE, 0b00000100); + registers.write(BGMODE, 0b00000000); assert_eq!(registers.get_bg_tile_size(Background::Bg1), TileSize::P8x8); - registers.write(BGMODE, 0b00001100); + registers.write(BGMODE, 0b00010000); assert_eq!(registers.get_bg_tile_size(Background::Bg1), TileSize::P16x16); } diff --git a/snes-frontend/Cargo.toml b/snes-frontend/Cargo.toml index 5b56b10..f330aec 100644 --- a/snes-frontend/Cargo.toml +++ b/snes-frontend/Cargo.toml @@ -9,7 +9,11 @@ edition = "2021" snes-core = { path = "../snes-core" } # Frontend stuff -eframe = "0.24.1" +eframe = "0.25.0" env_logger = "0.10.1" rfd = "0.12.1" regex = "1.10.2" +wgpu = "0.18.0" + +[features] +wgpu = ["eframe/wgpu"] diff --git a/snes-frontend/src/emu_state/emulation.rs b/snes-frontend/src/emu_state/emulation.rs index 69faad6..ca696b0 100644 --- a/snes-frontend/src/emu_state/emulation.rs +++ b/snes-frontend/src/emu_state/emulation.rs @@ -1,11 +1,13 @@ pub struct EmulationState { pub is_paused: bool, + pub one_tick_per_frame: bool, } impl EmulationState { pub fn new() -> Self { Self { is_paused: true, + one_tick_per_frame: false, } } } \ No newline at end of file diff --git a/snes-frontend/src/emu_ui/debug/cpu.rs b/snes-frontend/src/emu_ui/debug/cpu.rs index c3f42fd..d1923d3 100644 --- a/snes-frontend/src/emu_ui/debug/cpu.rs +++ b/snes-frontend/src/emu_ui/debug/cpu.rs @@ -16,6 +16,12 @@ pub fn build_cpu_debug_controls(ctx: &egui::Context, cpu_debug_options: &mut CPU .show(ctx, |ui| { ui.monospace("Controls:"); ui.horizontal(|ui| { + if ui.selectable_label( + emulation_state.one_tick_per_frame, + "Tick per frame" + ).clicked() { + emulation_state.one_tick_per_frame = !emulation_state.one_tick_per_frame; + } let pause_text = if emulation_state.is_paused {"Resume"} else {"Pause"}; if ui.button(pause_text).clicked() { emulation_state.is_paused = !emulation_state.is_paused; diff --git a/snes-frontend/src/main.rs b/snes-frontend/src/main.rs index 65341c2..63aa2cf 100644 --- a/snes-frontend/src/main.rs +++ b/snes-frontend/src/main.rs @@ -1,6 +1,7 @@ use eframe::egui; use snes_core::emulator::Emulator; +mod utils; mod emu_ui; mod emu_state; @@ -9,6 +10,7 @@ mod emu_state; struct SnesEmulatorApp { emulator: Emulator, state: emu_state::AppState, + frame_limit: utils::frame_limiter::FrameLimiter, } impl SnesEmulatorApp { @@ -25,14 +27,24 @@ impl eframe::App for SnesEmulatorApp { // ui::game::build_game_window(ctx); }); if !self.state.emulation_state.is_paused { - self.emulator.loop_frame(); + if self.state.emulation_state.one_tick_per_frame { + self.emulator.tick(); + } else { + self.emulator.loop_frame(); + } } emu_ui::debug::build_all_debug_options(ctx, &mut self.state.debug_options, &mut self.state.emulation_state, &mut self.emulator); + ctx.request_repaint(); + self.frame_limit.limit(); + self.frame_limit.reset_timer(); } } fn main() -> eframe::Result<()> { - let native_options = eframe::NativeOptions::default(); + let native_options = eframe::NativeOptions { + vsync: false, + ..eframe::NativeOptions::default() + }; eframe::run_native( "SNES Emulator", native_options, diff --git a/snes-frontend/src/utils/frame_limiter.rs b/snes-frontend/src/utils/frame_limiter.rs new file mode 100644 index 0000000..75b370f --- /dev/null +++ b/snes-frontend/src/utils/frame_limiter.rs @@ -0,0 +1,35 @@ +use std::{thread, time}; +use std::time::Instant; + +pub struct FrameLimiter { + timer: Instant, + fps: u128, +} + +impl FrameLimiter { + pub fn new() -> Self { + Self { + timer: Instant::now(), + fps: 16600, + } + } + + pub fn reset_timer(&mut self) { + self.timer = Instant::now(); + } + + pub fn limit(&self) { + let elapsed = self.timer.elapsed().as_micros(); + if elapsed > self.fps { + return; + } + let wait = (self.fps - elapsed).try_into().unwrap(); + thread::sleep(time::Duration::from_micros(wait)); + } +} + +impl Default for FrameLimiter { + fn default() -> Self { + Self::new() + } +} diff --git a/snes-frontend/src/utils/mod.rs b/snes-frontend/src/utils/mod.rs new file mode 100644 index 0000000..daa8ae8 --- /dev/null +++ b/snes-frontend/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod frame_limiter; \ No newline at end of file