implement one tick per frame option

This commit is contained in:
Franco Colmenarez
2024-01-20 19:22:47 -05:00
parent a48dd5ac8c
commit db887b9d81
7 changed files with 65 additions and 5 deletions
+2 -2
View File
@@ -393,9 +393,9 @@ mod ppu_registers_test {
#[test] #[test]
fn test_get_bg_tile_size() { fn test_get_bg_tile_size() {
let mut registers = PPURegisters::new(); let mut registers = PPURegisters::new();
registers.write(BGMODE, 0b00000100); registers.write(BGMODE, 0b00000000);
assert_eq!(registers.get_bg_tile_size(Background::Bg1), TileSize::P8x8); 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); assert_eq!(registers.get_bg_tile_size(Background::Bg1), TileSize::P16x16);
} }
+5 -1
View File
@@ -9,7 +9,11 @@ edition = "2021"
snes-core = { path = "../snes-core" } snes-core = { path = "../snes-core" }
# Frontend stuff # Frontend stuff
eframe = "0.24.1" eframe = "0.25.0"
env_logger = "0.10.1" env_logger = "0.10.1"
rfd = "0.12.1" rfd = "0.12.1"
regex = "1.10.2" regex = "1.10.2"
wgpu = "0.18.0"
[features]
wgpu = ["eframe/wgpu"]
+2
View File
@@ -1,11 +1,13 @@
pub struct EmulationState { pub struct EmulationState {
pub is_paused: bool, pub is_paused: bool,
pub one_tick_per_frame: bool,
} }
impl EmulationState { impl EmulationState {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
is_paused: true, is_paused: true,
one_tick_per_frame: false,
} }
} }
} }
+6
View File
@@ -16,6 +16,12 @@ pub fn build_cpu_debug_controls(ctx: &egui::Context, cpu_debug_options: &mut CPU
.show(ctx, |ui| { .show(ctx, |ui| {
ui.monospace("Controls:"); ui.monospace("Controls:");
ui.horizontal(|ui| { 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"}; let pause_text = if emulation_state.is_paused {"Resume"} else {"Pause"};
if ui.button(pause_text).clicked() { if ui.button(pause_text).clicked() {
emulation_state.is_paused = !emulation_state.is_paused; emulation_state.is_paused = !emulation_state.is_paused;
+14 -2
View File
@@ -1,6 +1,7 @@
use eframe::egui; use eframe::egui;
use snes_core::emulator::Emulator; use snes_core::emulator::Emulator;
mod utils;
mod emu_ui; mod emu_ui;
mod emu_state; mod emu_state;
@@ -9,6 +10,7 @@ mod emu_state;
struct SnesEmulatorApp { struct SnesEmulatorApp {
emulator: Emulator, emulator: Emulator,
state: emu_state::AppState, state: emu_state::AppState,
frame_limit: utils::frame_limiter::FrameLimiter,
} }
impl SnesEmulatorApp { impl SnesEmulatorApp {
@@ -25,14 +27,24 @@ impl eframe::App for SnesEmulatorApp {
// ui::game::build_game_window(ctx); // ui::game::build_game_window(ctx);
}); });
if !self.state.emulation_state.is_paused { 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); 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<()> { fn main() -> eframe::Result<()> {
let native_options = eframe::NativeOptions::default(); let native_options = eframe::NativeOptions {
vsync: false,
..eframe::NativeOptions::default()
};
eframe::run_native( eframe::run_native(
"SNES Emulator", "SNES Emulator",
native_options, native_options,
+35
View File
@@ -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()
}
}
+1
View File
@@ -0,0 +1 @@
pub mod frame_limiter;