split renderer works!!! no keyboard input any more though lolllll
This commit is contained in:
parent
c54027e5f6
commit
a36d161939
2
src/connect/mod.rs
Normal file
2
src/connect/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
mod renderer;
|
||||
pub use renderer::Renderer;
|
7
src/connect/renderer.rs
Normal file
7
src/connect/renderer.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
pub trait Renderer {
|
||||
fn prepare(&mut self, width: usize, height: usize);
|
||||
|
||||
fn display(&mut self, buffer: &[u32]);
|
||||
|
||||
fn set_title(&mut self, _title: String) {}
|
||||
}
|
18
src/lib.rs
18
src/lib.rs
|
@ -10,8 +10,8 @@ use crate::{
|
|||
processor::memory::Memory,
|
||||
util::{pause, print_cycles},
|
||||
};
|
||||
use connect::Renderer;
|
||||
use gilrs::Gilrs;
|
||||
use minifb::Window;
|
||||
use once_cell::sync::OnceCell;
|
||||
use processor::{memory::Rom, Cpu};
|
||||
use std::{
|
||||
|
@ -20,6 +20,7 @@ use std::{
|
|||
};
|
||||
use util::pause_then_step;
|
||||
|
||||
pub mod connect;
|
||||
mod constants;
|
||||
mod processor;
|
||||
pub mod util;
|
||||
|
@ -31,7 +32,6 @@ pub struct Options {
|
|||
pub verbose: bool,
|
||||
pub step_by: Option<usize>,
|
||||
pub cycle_count: bool,
|
||||
pub factor: usize,
|
||||
}
|
||||
|
||||
static mut PAUSE_ENABLED: bool = false;
|
||||
|
@ -41,13 +41,13 @@ static VERBOSE: OnceCell<bool> = OnceCell::new();
|
|||
|
||||
pub const WIDTH: usize = 160;
|
||||
pub const HEIGHT: usize = 144;
|
||||
static FACTOR: OnceCell<usize> = OnceCell::new();
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn init(options: Options, mut window: Window, tile_window: bool) {
|
||||
pub fn init(
|
||||
options: Options,
|
||||
mut window: Box<dyn Renderer>,
|
||||
tile_window: Option<Box<dyn Renderer>>,
|
||||
) {
|
||||
VERBOSE.set(options.verbose).unwrap();
|
||||
FACTOR.set(options.factor).unwrap();
|
||||
crate::processor::memory::mmio::gpu::init_statics();
|
||||
|
||||
let rom: Rom = match fs::read(options.rom_path) {
|
||||
Ok(data) => Rom::load(data),
|
||||
|
@ -56,7 +56,9 @@ pub fn init(options: Options, mut window: Window, tile_window: bool) {
|
|||
return;
|
||||
}
|
||||
};
|
||||
window.set_title(format!("{} on {}", rom.get_title(), rom.mbc_type()).as_str());
|
||||
|
||||
window.prepare(WIDTH, HEIGHT);
|
||||
window.set_title(format!("{} on {}", rom.get_title(), rom.mbc_type()));
|
||||
|
||||
let bootrom_enabled = options.bootrom_path.is_some();
|
||||
let bootrom: Option<Vec<u8>> = if let Some(path) = options.bootrom_path {
|
||||
|
|
80
src/main.rs
80
src/main.rs
|
@ -1,5 +1,5 @@
|
|||
use clap::{ArgGroup, Parser};
|
||||
use gb_emu::{HEIGHT, WIDTH};
|
||||
use gb_emu::{connect::Renderer, util::scale_buffer};
|
||||
|
||||
use minifb::{Window, WindowOptions};
|
||||
|
||||
|
@ -50,20 +50,6 @@ fn main() {
|
|||
3
|
||||
};
|
||||
|
||||
let mut window = Window::new(
|
||||
"emu",
|
||||
WIDTH * factor,
|
||||
HEIGHT * factor,
|
||||
WindowOptions::default(),
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("{e}");
|
||||
});
|
||||
|
||||
window.set_position(500, 50);
|
||||
|
||||
window.topmost(true);
|
||||
|
||||
let options = gb_emu::Options {
|
||||
rom_path: args.rom,
|
||||
bootrom_path: args.bootrom,
|
||||
|
@ -71,8 +57,68 @@ fn main() {
|
|||
verbose: args.verbose,
|
||||
step_by: args.step_by,
|
||||
cycle_count: args.cycle_count,
|
||||
factor,
|
||||
};
|
||||
|
||||
gb_emu::init(options, window, args.tile_window);
|
||||
let tile_window: Option<Box<dyn Renderer>> = if args.tile_window {
|
||||
Some(Box::new(WindowRenderer::new(factor)))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
gb_emu::init(options, Box::new(WindowRenderer::new(factor)), tile_window);
|
||||
}
|
||||
|
||||
struct WindowRenderer {
|
||||
window: Option<Window>,
|
||||
scaled_buf: Vec<u32>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
factor: usize,
|
||||
}
|
||||
|
||||
impl WindowRenderer {
|
||||
fn new(factor: usize) -> Self {
|
||||
Self {
|
||||
window: None,
|
||||
scaled_buf: vec![],
|
||||
width: 0,
|
||||
height: 0,
|
||||
factor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for WindowRenderer {
|
||||
fn prepare(&mut self, width: usize, height: usize) {
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.window = Some(
|
||||
Window::new(
|
||||
"Gameboy",
|
||||
width * self.factor,
|
||||
height * self.factor,
|
||||
WindowOptions::default(),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
fn display(&mut self, buffer: &[u32]) {
|
||||
if let Some(ref mut window) = self.window {
|
||||
self.scaled_buf = scale_buffer(buffer, self.width, self.height, self.factor);
|
||||
window
|
||||
.update_with_buffer(
|
||||
&self.scaled_buf,
|
||||
self.width * self.factor,
|
||||
self.height * self.factor,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn set_title(&mut self, title: String) {
|
||||
if let Some(ref mut window) = self.window {
|
||||
window.set_title(&title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use self::mmio::{Apu, Gpu, Joypad, Serial, Timer};
|
||||
pub use self::rom::Rom;
|
||||
use crate::{processor::SplitRegister, verbose_println, Cpu};
|
||||
use crate::{connect::Renderer, processor::SplitRegister, verbose_println, Cpu};
|
||||
use gilrs::Gilrs;
|
||||
use minifb::{Key, Window};
|
||||
|
||||
mod interrupts;
|
||||
pub use interrupts::{Interrupt, Interrupts};
|
||||
|
@ -33,9 +32,9 @@ impl Memory {
|
|||
pub fn init(
|
||||
bootrom: Option<Vec<u8>>,
|
||||
rom: Rom,
|
||||
window: Window,
|
||||
window: Box<dyn Renderer>,
|
||||
connect_serial: bool,
|
||||
enable_tile_window: bool,
|
||||
tile_window: Option<Box<dyn Renderer>>,
|
||||
) -> Self {
|
||||
let serial = if connect_serial {
|
||||
Serial::default().connected()
|
||||
|
@ -53,7 +52,7 @@ impl Memory {
|
|||
ime_scheduled: 0x0,
|
||||
dma_addr: 0xFF,
|
||||
joypad: Joypad::default(),
|
||||
gpu: Gpu::new(window, enable_tile_window),
|
||||
gpu: Gpu::new(window, tile_window),
|
||||
apu: Apu::init_default(),
|
||||
serial,
|
||||
timers: Timer::init(),
|
||||
|
@ -185,8 +184,8 @@ impl Memory {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_pressed_keys(&mut self, keys: Vec<Key>, gamepads: &mut Gilrs) -> bool {
|
||||
self.joypad.update_pressed_keys(keys, gamepads)
|
||||
pub fn update_pressed_keys(&mut self, gamepads: &mut Gilrs) -> bool {
|
||||
self.joypad.update_pressed_keys(gamepads)
|
||||
}
|
||||
|
||||
pub(super) fn cpu_ram_init(&mut self) {
|
||||
|
@ -247,9 +246,7 @@ impl Cpu {
|
|||
.set_interrupt(Interrupt::LcdStat, gpu_interrupts.lcd_stat);
|
||||
|
||||
if gpu_interrupts.vblank {
|
||||
let joypad_interrupt = self
|
||||
.memory
|
||||
.update_pressed_keys(self.memory.gpu.window.get_keys(), &mut self.gamepad_handler);
|
||||
let joypad_interrupt = self.memory.update_pressed_keys(&mut self.gamepad_handler);
|
||||
self.memory
|
||||
.interrupts
|
||||
.set_interrupt(Interrupt::Joypad, joypad_interrupt);
|
||||
|
|
|
@ -6,12 +6,11 @@ use self::{
|
|||
},
|
||||
};
|
||||
use crate::{
|
||||
connect::Renderer,
|
||||
processor::SplitRegister,
|
||||
util::{clear_bit, get_bit},
|
||||
FACTOR, HEIGHT, WIDTH,
|
||||
HEIGHT, WIDTH,
|
||||
};
|
||||
use minifb::{Window, WindowOptions};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
mod addresses;
|
||||
mod tile_window;
|
||||
|
@ -19,24 +18,12 @@ mod types;
|
|||
|
||||
const TILE_WINDOW_WIDTH: usize = 16 * 8;
|
||||
const TILE_WINDOW_HEIGHT: usize = 24 * 8;
|
||||
static TILE_WINDOW_WIDTH_SCALED: OnceCell<usize> = OnceCell::new();
|
||||
static TILE_WINDOW_HEIGHT_SCALED: OnceCell<usize> = OnceCell::new();
|
||||
|
||||
pub fn init_statics() {
|
||||
TILE_WINDOW_WIDTH_SCALED
|
||||
.set(TILE_WINDOW_WIDTH * FACTOR.get().unwrap())
|
||||
.unwrap();
|
||||
TILE_WINDOW_HEIGHT_SCALED
|
||||
.set(TILE_WINDOW_HEIGHT * FACTOR.get().unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub struct Gpu {
|
||||
pub buffer: Vec<u32>,
|
||||
pub vram: Vram,
|
||||
pub oam: Oam,
|
||||
pub window: Window,
|
||||
scaled_buffer: Vec<u32>,
|
||||
pub window: Box<dyn Renderer>,
|
||||
lcdc: Lcdc,
|
||||
stat: Stat,
|
||||
mode_clock: usize,
|
||||
|
@ -55,21 +42,10 @@ pub struct Gpu {
|
|||
}
|
||||
|
||||
impl Gpu {
|
||||
pub fn new(window: Window, enable_tile_window: bool) -> Self {
|
||||
let tile_window = if enable_tile_window {
|
||||
let mut window = Window::new(
|
||||
"Tiles",
|
||||
*TILE_WINDOW_WIDTH_SCALED.get().unwrap(),
|
||||
*TILE_WINDOW_HEIGHT_SCALED.get().unwrap(),
|
||||
WindowOptions::default(),
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("{e}");
|
||||
});
|
||||
|
||||
window.set_position((550 + (WIDTH * FACTOR.get().unwrap())) as isize, 50);
|
||||
window.topmost(true);
|
||||
Some(TileWindow::new(window))
|
||||
pub fn new(window: Box<dyn Renderer>, tile_window_renderer: Option<Box<dyn Renderer>>) -> Self {
|
||||
let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer {
|
||||
tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT);
|
||||
Some(TileWindow::new(tile_window_renderer))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -79,7 +55,6 @@ impl Gpu {
|
|||
vram: Vram::default(),
|
||||
oam: Oam::default(),
|
||||
window,
|
||||
scaled_buffer: vec![0; WIDTH * HEIGHT * 4],
|
||||
lcdc: Lcdc::default(),
|
||||
stat: Stat::default(),
|
||||
mode_clock: 0,
|
||||
|
@ -370,27 +345,6 @@ impl Gpu {
|
|||
}
|
||||
|
||||
fn render_window(&mut self) {
|
||||
self.scaled_buffer = scale_buffer(&self.buffer, WIDTH, HEIGHT, *FACTOR.get().unwrap());
|
||||
self.window
|
||||
.update_with_buffer(
|
||||
&self.scaled_buffer,
|
||||
WIDTH * FACTOR.get().unwrap(),
|
||||
HEIGHT * FACTOR.get().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
self.window.display(&self.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
fn scale_buffer(buffer: &[u32], width: usize, height: usize, factor: usize) -> Vec<u32> {
|
||||
let mut v = vec![];
|
||||
for y in 0..height {
|
||||
for _ in 0..factor {
|
||||
for x in 0..width {
|
||||
for _ in 0..factor {
|
||||
v.push(buffer[(y * width) + x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
|
|
|
@ -1,32 +1,21 @@
|
|||
use minifb::Window;
|
||||
|
||||
use crate::{
|
||||
processor::memory::mmio::gpu::{
|
||||
scale_buffer, Palette, TiledataArea, TILE_WINDOW_HEIGHT, TILE_WINDOW_HEIGHT_SCALED,
|
||||
TILE_WINDOW_WIDTH, TILE_WINDOW_WIDTH_SCALED,
|
||||
},
|
||||
connect::Renderer,
|
||||
processor::memory::mmio::gpu::{Palette, TiledataArea, TILE_WINDOW_HEIGHT, TILE_WINDOW_WIDTH},
|
||||
util::get_bit,
|
||||
FACTOR,
|
||||
};
|
||||
|
||||
use super::types::Vram;
|
||||
|
||||
pub(super) struct TileWindow {
|
||||
sprite_buffer: Vec<u32>,
|
||||
sprite_buffer_scaled: Vec<u32>,
|
||||
sprite_window: Window,
|
||||
sprite_renderer: Box<dyn Renderer>,
|
||||
}
|
||||
|
||||
impl TileWindow {
|
||||
pub(super) fn new(window: Window) -> Self {
|
||||
pub(super) fn new(window: Box<dyn Renderer>) -> Self {
|
||||
Self {
|
||||
sprite_buffer: vec![0; TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT],
|
||||
sprite_buffer_scaled: vec![
|
||||
0;
|
||||
TILE_WINDOW_WIDTH_SCALED.get().unwrap()
|
||||
* TILE_WINDOW_HEIGHT_SCALED.get().unwrap()
|
||||
],
|
||||
sprite_window: window,
|
||||
sprite_renderer: window,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,19 +41,7 @@ impl TileWindow {
|
|||
);
|
||||
}
|
||||
|
||||
self.sprite_buffer_scaled = scale_buffer(
|
||||
&self.sprite_buffer,
|
||||
TILE_WINDOW_WIDTH,
|
||||
TILE_WINDOW_HEIGHT,
|
||||
*FACTOR.get().unwrap(),
|
||||
);
|
||||
self.sprite_window
|
||||
.update_with_buffer(
|
||||
&self.sprite_buffer_scaled,
|
||||
*TILE_WINDOW_WIDTH_SCALED.get().unwrap(),
|
||||
*TILE_WINDOW_HEIGHT_SCALED.get().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
self.sprite_renderer.display(&self.sprite_buffer);
|
||||
}
|
||||
|
||||
fn draw_row(
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::util::{clear_bit, get_bit};
|
||||
use gilrs::{Button, Gilrs};
|
||||
use minifb::Key;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Joypad {
|
||||
|
@ -57,7 +56,7 @@ impl Joypad {
|
|||
self.sel_direction = !get_bit(data, 4);
|
||||
}
|
||||
|
||||
pub fn update_pressed_keys(&mut self, keys: Vec<Key>, gamepad_handler: &mut Gilrs) -> bool {
|
||||
pub fn update_pressed_keys(&mut self, gamepad_handler: &mut Gilrs) -> bool {
|
||||
let old = *self;
|
||||
self.clear_buttons();
|
||||
|
||||
|
@ -87,14 +86,6 @@ impl Joypad {
|
|||
self.a |= pad.is_pressed(Button::East);
|
||||
self.b |= pad.is_pressed(Button::South);
|
||||
}
|
||||
self.down |= keys.contains(&Key::Down) || keys.contains(&Key::S);
|
||||
self.up |= keys.contains(&Key::Up) || keys.contains(&Key::W);
|
||||
self.left |= keys.contains(&Key::Left) || keys.contains(&Key::A);
|
||||
self.right |= keys.contains(&Key::Right) || keys.contains(&Key::D);
|
||||
self.start |= keys.contains(&Key::Equal);
|
||||
self.select |= keys.contains(&Key::Minus);
|
||||
self.a |= keys.contains(&Key::Apostrophe);
|
||||
self.b |= keys.contains(&Key::Semicolon);
|
||||
*self != old
|
||||
}
|
||||
|
||||
|
|
14
src/util.rs
14
src/util.rs
|
@ -137,3 +137,17 @@ impl Nibbles for u8 {
|
|||
*self = (*self & 0x0F) | (val << 4);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale_buffer(buffer: &[u32], width: usize, height: usize, factor: usize) -> Vec<u32> {
|
||||
let mut v = vec![];
|
||||
for y in 0..height {
|
||||
for _ in 0..factor {
|
||||
for x in 0..width {
|
||||
for _ in 0..factor {
|
||||
v.push(buffer[(y * width) + x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue