holy shit it works
This commit is contained in:
parent
a1f0d68c19
commit
3fcaca4654
|
@ -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 {
|
||||||
|
|
115
gb-vst/src/ui.rs
115
gb-vst/src/ui.rs
|
@ -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(¤t_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()
|
||||||
|
|
Loading…
Reference in a new issue