holy shit it works

This commit is contained in:
Alex Janka 2023-03-07 21:45:11 +11:00
parent a1f0d68c19
commit 3fcaca4654
2 changed files with 76 additions and 66 deletions

View file

@ -6,16 +6,13 @@ use gb_emu_lib::{
}; };
use nih_plug::prelude::*; use nih_plug::prelude::*;
use std::sync::{ use std::sync::{
mpsc::{channel, Sender}, mpsc::{channel, Receiver, Sender},
Arc, Arc, Mutex,
}; };
use ui::{Emulator, EmulatorRenderer}; use ui::{Emulator, EmulatorRenderer};
mod ui; mod ui;
const WIDTH: u32 = 320;
const HEIGHT: u32 = 240;
#[derive(Params, Default)] #[derive(Params, Default)]
struct EmuParams {} struct EmuParams {}
@ -28,6 +25,7 @@ struct EmuVars {
#[derive(Default)] #[derive(Default)]
pub struct GameboyEmu { pub struct GameboyEmu {
vars: Option<EmuVars>, vars: Option<EmuVars>,
frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>,
} }
const ROM: &[u8; 32768] = include_bytes!("../../test-roms/Tetris.gb"); const ROM: &[u8; 32768] = include_bytes!("../../test-roms/Tetris.gb");
@ -89,7 +87,7 @@ impl Plugin for GameboyEmu {
} }
fn editor(&self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> { fn editor(&self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
Some(Box::new(Emulator::new())) Some(Box::new(Emulator::new(self.frame_receiver.clone())))
} }
fn initialize( fn initialize(
@ -111,9 +109,12 @@ impl Plugin for GameboyEmu {
let (output, rx) = AudioOutput::new_unfilled(buffer_config.sample_rate); let (output, rx) = AudioOutput::new_unfilled(buffer_config.sample_rate);
let renderer = Box::<EmulatorRenderer>::default(); let (renderer, frame_receiver) = EmulatorRenderer::new();
let mut emulator_core = EmulatorCore::init(receiver, options, renderer, output, None); *self.frame_receiver.lock().unwrap() = Some(frame_receiver);
let mut emulator_core =
EmulatorCore::init(receiver, options, Box::new(renderer), output, None);
emulator_core.run_until_buffer_full(); emulator_core.run_until_buffer_full();
self.vars = Some(EmuVars { self.vars = Some(EmuVars {

View file

@ -1,20 +1,25 @@
use std::sync::Arc; use std::sync::{
mpsc::{self, Receiver, Sender},
Arc, Mutex,
};
use baseview::{ use baseview::{
Event, EventStatus, MouseButton, MouseEvent, Size, Window, WindowEvent, WindowHandler, Event, EventStatus, Size, Window, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
WindowInfo, WindowOpenOptions, };
use gb_emu_lib::{
connect::{Renderer, HEIGHT, WIDTH},
util::scale_buffer,
}; };
use gb_emu_lib::connect::Renderer;
use nih_plug::prelude::*; use nih_plug::prelude::*;
use pixels::{Pixels, SurfaceTexture}; use pixels::{Pixels, SurfaceTexture};
use crate::{HEIGHT, WIDTH}; pub struct Emulator {
frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>,
pub struct Emulator {} }
impl Emulator { impl Emulator {
pub fn new() -> Self { pub fn new(frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>) -> Self {
Self {} Self { frame_receiver }
} }
} }
@ -24,6 +29,7 @@ impl Editor for Emulator {
parent: ParentWindowHandle, parent: ParentWindowHandle,
_context: Arc<dyn GuiContext>, _context: Arc<dyn GuiContext>,
) -> Box<dyn std::any::Any + Send> { ) -> Box<dyn std::any::Any + Send> {
let cloned = self.frame_receiver.clone();
Window::open_parented( Window::open_parented(
&parent, &parent,
WindowOpenOptions { WindowOpenOptions {
@ -32,13 +38,13 @@ impl Editor for Emulator {
scale: baseview::WindowScalePolicy::SystemScaleFactor, scale: baseview::WindowScalePolicy::SystemScaleFactor,
gl_config: None, gl_config: None,
}, },
EmulatorWindow::new, |w| EmulatorWindow::new(w, cloned),
); );
Box::new(Self::new()) Box::new(Self::new(self.frame_receiver.clone()))
} }
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
(WIDTH, HEIGHT) (WIDTH as u32, HEIGHT as u32)
} }
fn set_scale_factor(&self, _factor: f32) -> bool { fn set_scale_factor(&self, _factor: f32) -> bool {
@ -54,84 +60,87 @@ impl Editor for Emulator {
pub struct EmulatorWindow { pub struct EmulatorWindow {
pix: Pixels, pix: Pixels,
current_colour: [u8; 4], scale: usize,
frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>,
} }
impl EmulatorWindow { impl EmulatorWindow {
fn new(window: &mut Window) -> Self { fn new(window: &mut Window, frame_receiver: Arc<Mutex<Option<Receiver<Vec<u32>>>>>) -> Self {
let info = WindowInfo::from_logical_size(Size::new(WIDTH as f64, HEIGHT as f64), 1.); let info = WindowInfo::from_logical_size(Size::new(WIDTH as f64, HEIGHT as f64), 1.);
let mut pix = init_pixbuf(info, window); let (pix, scale) = init_pixbuf(info, window);
let current_colour: [u8; 4] = [0xFF, 0x0, 0x0, 0xFF];
for pixel in pix.get_frame_mut().chunks_exact_mut(4) {
pixel.copy_from_slice(&current_colour);
}
Self { Self {
pix, pix,
current_colour, scale,
} frame_receiver,
}
fn update_pixbuf(&mut self) {
self.current_colour = rotate_colour(&self.current_colour);
self.render_pixbuf();
}
fn render_pixbuf(&mut self) {
for pixel in self.pix.get_frame_mut().chunks_exact_mut(4) {
pixel.copy_from_slice(&self.current_colour);
} }
} }
} }
fn init_pixbuf(info: WindowInfo, window: &mut Window) -> Pixels { fn init_pixbuf(info: WindowInfo, window: &mut Window) -> (Pixels, usize) {
let physical_size = info.physical_size(); let physical_size = info.physical_size();
let scale = (physical_size.width as usize / WIDTH).min(physical_size.height as usize / HEIGHT);
(
pixels::Pixels::new( pixels::Pixels::new(
physical_size.width, physical_size.width,
physical_size.height, physical_size.height,
SurfaceTexture::new(physical_size.width, physical_size.height, window), SurfaceTexture::new(physical_size.width, physical_size.height, window),
) )
.unwrap() .unwrap(),
} scale,
)
fn rotate_colour(current: &[u8; 4]) -> [u8; 4] {
[current[1], current[2], current[0], current[3]]
} }
impl WindowHandler for EmulatorWindow { impl WindowHandler for EmulatorWindow {
fn on_frame(&mut self, _window: &mut Window) { fn on_frame(&mut self, _window: &mut Window) {
if let Some(ref mut receiver) = *self.frame_receiver.lock().expect("failed to lock mutex") {
match receiver.recv() {
Ok(buf) => {
let scaled_buf = if self.scale != 1 {
scale_buffer(&buf, WIDTH, HEIGHT, self.scale)
} else {
buf
};
for (pixel, source) in
self.pix.get_frame_mut().chunks_exact_mut(4).zip(scaled_buf)
{
pixel.copy_from_slice(&source.to_be_bytes());
}
self.pix.render().unwrap(); self.pix.render().unwrap();
} }
Err(e) => nih_log!("recv error: {e}"),
}
}
}
fn on_event(&mut self, window: &mut Window, event: baseview::Event) -> EventStatus { fn on_event(&mut self, window: &mut Window, event: baseview::Event) -> EventStatus {
if let Event::Window(WindowEvent::Resized(info)) = event { if let Event::Window(WindowEvent::Resized(info)) = event {
self.pix = init_pixbuf(info, window); (self.pix, self.scale) = init_pixbuf(info, window);
self.update_pixbuf();
return EventStatus::Captured;
}
if let Event::Mouse(MouseEvent::ButtonPressed {
button: MouseButton::Left,
..
}) = event
{
nih_log!("nih click!");
self.update_pixbuf();
return EventStatus::Captured; return EventStatus::Captured;
} }
EventStatus::Ignored EventStatus::Ignored
} }
} }
#[derive(Default)] pub struct EmulatorRenderer {
pub struct EmulatorRenderer {} tx: Sender<Vec<u32>>,
}
impl EmulatorRenderer {
pub(super) fn new() -> (Self, Receiver<Vec<u32>>) {
let (tx, rx) = mpsc::channel::<Vec<u32>>();
(Self { tx }, rx)
}
}
impl Renderer for EmulatorRenderer { impl Renderer for EmulatorRenderer {
fn prepare(&mut self, _width: usize, _height: usize) {} fn prepare(&mut self, _width: usize, _height: usize) {}
fn display(&mut self, _buffer: &[u32]) {} #[allow(unused_must_use)]
fn display(&mut self, buffer: &[u32]) {
self.tx.send(buffer.to_vec());
}
fn latest_joypad_state(&mut self) -> gb_emu_lib::connect::JoypadState { fn latest_joypad_state(&mut self) -> gb_emu_lib::connect::JoypadState {
gb_emu_lib::connect::JoypadState::default() gb_emu_lib::connect::JoypadState::default()