feat: integrate eui and pixels-rs for debug info
This commit is contained in:
105
src/main.rs
105
src/main.rs
@@ -1,8 +1,9 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
|
||||
use gb::Egui;
|
||||
use gb::LR35902_CLOCK_SPEED;
|
||||
use gb::{ButtonState, Cycle, LR35902};
|
||||
use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType, Gamepad, Gilrs};
|
||||
use gilrs::{Button, Event as GamepadEvent, EventType as GamepadEventType, Gilrs};
|
||||
use pixels::{Pixels, SurfaceTexture};
|
||||
use std::time::{Duration, Instant};
|
||||
use winit::dpi::LogicalSize;
|
||||
@@ -11,6 +12,9 @@ use winit::event_loop::{ControlFlow, EventLoop};
|
||||
use winit::window::{Window, WindowBuilder};
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
use gb::RegisterPair;
|
||||
|
||||
// 160 x 144
|
||||
const GB_WIDTH: u32 = 160;
|
||||
const GB_HEIGHT: u32 = 144;
|
||||
@@ -19,6 +23,9 @@ const SCALE: f64 = 5.0;
|
||||
const LR35902_CYCLE_TIME: f64 = 1.0f64 / LR35902_CLOCK_SPEED as f64;
|
||||
const CYCLES_IN_FRAME: Cycle = Cycle::new(70224);
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
const STEP_MODE_BY_DEFAULT: bool = true;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let app = App::new(crate_name!())
|
||||
.version(crate_version!())
|
||||
@@ -64,20 +71,46 @@ fn main() -> Result<()> {
|
||||
|
||||
// Initialize Gamepad Support
|
||||
let mut gilrs = Gilrs::new().expect("Failed to initialize Gilrs");
|
||||
let mut active_gamepad = None;
|
||||
|
||||
// Initialize GUI
|
||||
let event_loop = EventLoop::new();
|
||||
let mut input = WinitInputHelper::new();
|
||||
let window = create_window(&event_loop, cartridge_title)?;
|
||||
let mut pixels = create_pixels(&window)?;
|
||||
|
||||
let (mut pixels, mut egui) = {
|
||||
let size = window.inner_size();
|
||||
let scale_factor = window.scale_factor();
|
||||
let surface_texture = SurfaceTexture::new(size.width, size.height, &window);
|
||||
let pixels = Pixels::new(GB_WIDTH, GB_HEIGHT, surface_texture)?;
|
||||
let egui = Egui::new(size.width, size.height, scale_factor, pixels.context());
|
||||
|
||||
(pixels, egui)
|
||||
};
|
||||
|
||||
let mut now = Instant::now();
|
||||
let mut cycles_in_frame: Cycle = Default::default();
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
let mut step_mode = STEP_MODE_BY_DEFAULT;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Update egui
|
||||
egui.handle_event(&event);
|
||||
|
||||
if let Event::RedrawRequested(_) = event {
|
||||
if pixels
|
||||
.render()
|
||||
// Prepare egui
|
||||
egui.prepare(&game_boy);
|
||||
|
||||
// Render everything together
|
||||
let render_result = pixels.render_with(|encoder, target, ctx| {
|
||||
// Render the texture
|
||||
ctx.scaling_renderer.render(encoder, target);
|
||||
|
||||
// Render egui
|
||||
egui.render(encoder, target, ctx);
|
||||
});
|
||||
|
||||
if render_result
|
||||
.map_err(|e| anyhow!("pixels.render() failed: {}", e))
|
||||
.is_err()
|
||||
{
|
||||
@@ -92,39 +125,75 @@ fn main() -> Result<()> {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(size) = input.window_resized() {
|
||||
pixels.resize_surface(size.width, size.height);
|
||||
#[cfg(feature = "debug")]
|
||||
if input.key_pressed(VirtualKeyCode::S) {
|
||||
step_mode = !step_mode;
|
||||
}
|
||||
|
||||
if active_gamepad.is_none() {
|
||||
active_gamepad = gilrs.next_event().map(|e| e.id);
|
||||
if let Some(scale_factor) = input.scale_factor() {
|
||||
egui.scale_factor(scale_factor);
|
||||
}
|
||||
|
||||
if let Some(size) = input.window_resized() {
|
||||
pixels.resize_surface(size.width, size.height);
|
||||
egui.resize(size.width, size.height);
|
||||
}
|
||||
|
||||
// Emulate Game Boy
|
||||
let mut elapsed_cycles: Cycle = Default::default();
|
||||
let delta = now.elapsed().subsec_nanos();
|
||||
now = Instant::now();
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
if step_mode {
|
||||
if input.key_pressed(VirtualKeyCode::Space) {
|
||||
if let Some(event) = gilrs.next_event() {
|
||||
handle_gamepad_input(&mut game_boy, event);
|
||||
}
|
||||
|
||||
for _ in 0..egui.config.spacebar_step {
|
||||
elapsed_cycles += game_boy.step();
|
||||
}
|
||||
|
||||
cycles_in_frame %= CYCLES_IN_FRAME;
|
||||
}
|
||||
|
||||
game_boy.get_ppu().copy_to_gui(pixels.get_frame());
|
||||
window.request_redraw();
|
||||
return;
|
||||
}
|
||||
|
||||
let cycle_time = Duration::from_secs_f64(LR35902_CYCLE_TIME).subsec_nanos();
|
||||
let pending_cycles = Cycle::new(delta / cycle_time);
|
||||
|
||||
let mut elapsed_cycles: Cycle = Default::default();
|
||||
while elapsed_cycles <= pending_cycles {
|
||||
if let Some(event) = gilrs.next_event() {
|
||||
handle_gamepad_input(&mut game_boy, event);
|
||||
}
|
||||
|
||||
elapsed_cycles += game_boy.step();
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
{
|
||||
let pc = game_boy.register_pair(RegisterPair::PC);
|
||||
|
||||
if let Some(break_point) = egui.break_point {
|
||||
if pc == break_point {
|
||||
step_mode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cycles_in_frame += elapsed_cycles;
|
||||
|
||||
if cycles_in_frame >= CYCLES_IN_FRAME {
|
||||
let ppu = game_boy.get_ppu();
|
||||
let frame = pixels.get_frame();
|
||||
ppu.copy_to_gui(frame);
|
||||
window.request_redraw();
|
||||
// Redraw
|
||||
cycles_in_frame = Default::default();
|
||||
|
||||
cycles_in_frame = Default::default()
|
||||
game_boy.get_ppu().copy_to_gui(pixels.get_frame());
|
||||
window.request_redraw();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -139,12 +208,6 @@ fn create_window(event_loop: &EventLoop<()>, title: &str) -> Result<Window> {
|
||||
.build(&event_loop)?)
|
||||
}
|
||||
|
||||
fn create_pixels(window: &Window) -> Result<Pixels> {
|
||||
let window_size = window.inner_size();
|
||||
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, window);
|
||||
Ok(Pixels::new(GB_WIDTH, GB_HEIGHT, surface_texture)?)
|
||||
}
|
||||
|
||||
fn handle_gamepad_input(game_boy: &mut LR35902, event: GamepadEvent) {
|
||||
use GamepadEventType::*;
|
||||
let joypad_status = &mut game_boy.bus.joypad.status;
|
||||
|
||||
Reference in New Issue
Block a user