From ed26f3f42aaccb88acf3ceef3b09c7848d27c885 Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Sun, 21 Jul 2024 17:26:04 -0500 Subject: [PATCH] Show game framebuffer --- snes-core/src/ppu/interface.rs | 10 +++--- snes-core/src/ppu/registers.rs | 3 ++ snes-frontend/src/emu_state/state.rs | 4 ++- snes-frontend/src/emu_ui/game.rs | 53 ++++++++++++++++++++++++++++ snes-frontend/src/emu_ui/mod.rs | 1 + snes-frontend/src/main.rs | 9 +++-- 6 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 snes-frontend/src/emu_ui/game.rs diff --git a/snes-core/src/ppu/interface.rs b/snes-core/src/ppu/interface.rs index fd11581..5a7afde 100644 --- a/snes-core/src/ppu/interface.rs +++ b/snes-core/src/ppu/interface.rs @@ -1,7 +1,9 @@ -use super::registers::PPURegisters; +use super::registers::{PPURegisters, MAX_TV_HEIGHT, MAX_TV_WIDTH}; + +const FRAMEBUFFER_SIZE: usize = MAX_TV_HEIGHT * MAX_TV_WIDTH * 4; pub struct PPU { - framebuffer: Vec, + framebuffer: [u8; FRAMEBUFFER_SIZE], pub registers: PPURegisters, was_vblank_nmi_set: bool, pub is_irq_set: bool, @@ -10,7 +12,7 @@ pub struct PPU { impl PPU { pub fn new() -> Self { Self { - framebuffer: vec![], + framebuffer: [0xFF; FRAMEBUFFER_SIZE], registers: PPURegisters::new(), was_vblank_nmi_set: false, is_irq_set: false, @@ -46,7 +48,7 @@ impl PPU { } } - pub fn framebuffer(&self) -> &Vec { + pub fn framebuffer(&self) -> &[u8] { &self.framebuffer } } diff --git a/snes-core/src/ppu/registers.rs b/snes-core/src/ppu/registers.rs index 8b2e610..17d3c0b 100644 --- a/snes-core/src/ppu/registers.rs +++ b/snes-core/src/ppu/registers.rs @@ -88,6 +88,9 @@ pub const STAT78: u16 = 0x213F; // PPU1 Status and PPU1 Version Number pub const MAX_BG_WIDTH: usize = 16 * 64; pub const MAX_BG_HEIGHT: usize = 16 * 64; +pub const MAX_TV_WIDTH: usize = 512; +pub const MAX_TV_HEIGHT: usize = 448; + #[derive(Debug, PartialEq, Copy, Clone)] pub enum TileSize { diff --git a/snes-frontend/src/emu_state/state.rs b/snes-frontend/src/emu_state/state.rs index f70d232..d9dc91c 100644 --- a/snes-frontend/src/emu_state/state.rs +++ b/snes-frontend/src/emu_state/state.rs @@ -1,10 +1,11 @@ use crate::emu_state::debug_options::DebugOptions; use crate::emu_state::emulation::EmulationState; - +use eframe::epaint::TextureHandle; pub struct AppState { pub debug_options: DebugOptions, pub emulation_state: EmulationState, + pub game_tv_texture: Option, } impl AppState { @@ -12,6 +13,7 @@ impl AppState { Self { debug_options: DebugOptions::new(), emulation_state: EmulationState::new(), + game_tv_texture: None, } } } diff --git a/snes-frontend/src/emu_ui/game.rs b/snes-frontend/src/emu_ui/game.rs new file mode 100644 index 0000000..2ed9760 --- /dev/null +++ b/snes-frontend/src/emu_ui/game.rs @@ -0,0 +1,53 @@ +use eframe::egui; +use eframe::{egui::Context, epaint::ColorImage}; +use eframe::egui::{TextureOptions, Ui}; +use eframe::epaint::{Vec2, TextureHandle}; +use snes_core::ppu::registers::{ + MAX_TV_WIDTH, + MAX_TV_HEIGHT, +}; + + +pub fn build_game_window( + ctx: &egui::Context, + game_tv_texture: &mut Option, + framebuffer: &[u8], +) { + egui::Window::new("TV") + .collapsible(false) + .show(ctx, |ui| { + paint_game_texture(ui, game_tv_texture, framebuffer); + }); +} + +pub fn initialize_game_texture(ctx: &Context, game_tv_texture: &mut Option) { + if game_tv_texture.is_none() { + println!("Initializing Game TV texture"); + let _ = game_tv_texture.insert( + ctx.load_texture( + "Game TV texture", + ColorImage::default(), + Default::default(), + ) + ); + } +} + +fn paint_game_texture(ui: &mut Ui, texture: &mut Option, framebuffer: &[u8]) { + if let Some(txt) = texture { + txt.set( + ColorImage::from_rgba_premultiplied([MAX_TV_WIDTH, MAX_TV_HEIGHT], framebuffer), + TextureOptions::default(), + ); + let (whole_rect, _) = + ui.allocate_exact_size( + Vec2::from([(MAX_TV_WIDTH) as f32, (MAX_TV_HEIGHT) as f32]), + egui::Sense::focusable_noninteractive(), + ); + egui::Image::new(( + txt.id(), + txt.size_vec2(), + )) + .paint_at(ui, whole_rect); + } +} diff --git a/snes-frontend/src/emu_ui/mod.rs b/snes-frontend/src/emu_ui/mod.rs index 8c91f71..33e82e4 100644 --- a/snes-frontend/src/emu_ui/mod.rs +++ b/snes-frontend/src/emu_ui/mod.rs @@ -1,2 +1,3 @@ pub mod menu; +pub mod game; pub mod debug; diff --git a/snes-frontend/src/main.rs b/snes-frontend/src/main.rs index 63aa2cf..2155e39 100644 --- a/snes-frontend/src/main.rs +++ b/snes-frontend/src/main.rs @@ -24,8 +24,14 @@ impl eframe::App for SnesEmulatorApp { egui::CentralPanel::default().show(ctx, |ui| { emu_ui::menu::build_menu_bar(&mut self.emulator, ui, &mut self.state); ui.separator(); - // ui::game::build_game_window(ctx); }); + emu_ui::game::initialize_game_texture(ctx, &mut self.state.game_tv_texture); + emu_ui::game::build_game_window( + ctx, + &mut self.state.game_tv_texture, + self.emulator.bus.ppu.framebuffer(), + ); + emu_ui::debug::build_all_debug_options(ctx, &mut self.state.debug_options, &mut self.state.emulation_state, &mut self.emulator); if !self.state.emulation_state.is_paused { if self.state.emulation_state.one_tick_per_frame { self.emulator.tick(); @@ -33,7 +39,6 @@ impl eframe::App for SnesEmulatorApp { 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();