gb-emu/gb-vst/src/ui.rs

252 lines
8.1 KiB
Rust
Raw Normal View History

use std::{
path::PathBuf,
sync::{Arc, Mutex},
2023-03-07 21:45:11 +11:00
};
2023-03-05 20:18:06 +11:00
2023-10-05 12:42:03 +11:00
use baseview::{Event, EventStatus, Size, Window, WindowEvent, WindowHandler, WindowOpenOptions};
2023-03-07 21:45:11 +11:00
use gb_emu_lib::{
connect::{JoypadButtons, JoypadState, RendererMessage, ResolutionData, HEIGHT, WIDTH},
renderer::{RendererBackend, RendererBackendManager, WindowOptions},
2023-03-05 20:18:06 +11:00
};
2023-03-08 15:19:10 +11:00
use keyboard_types::{Code, KeyState};
2023-03-05 20:18:06 +11:00
use nih_plug::prelude::*;
use crate::{access_config, EmuComms, IS_CGB};
2023-03-08 11:50:19 +11:00
2023-03-07 21:45:11 +11:00
pub struct Emulator {
emu_comms: Arc<Mutex<Option<EmuComms>>>,
2023-10-06 16:53:57 +11:00
manager: Arc<Mutex<Option<Arc<RendererBackendManager>>>>,
2023-10-05 12:42:03 +11:00
size: Size,
2023-03-07 21:45:11 +11:00
}
2023-03-05 20:18:06 +11:00
impl Emulator {
pub fn new(
emu_comms: Arc<Mutex<Option<EmuComms>>>,
2023-10-06 16:53:57 +11:00
manager: Arc<Mutex<Option<Arc<RendererBackendManager>>>>,
2023-10-05 12:42:03 +11:00
size: Size,
) -> Self {
2023-03-08 15:19:10 +11:00
Self {
emu_comms,
2023-10-06 16:53:57 +11:00
manager,
2023-10-05 12:42:03 +11:00
size,
2023-03-08 15:19:10 +11:00
}
2023-03-05 20:18:06 +11:00
}
}
impl Editor for Emulator {
fn spawn(
&self,
parent: ParentWindowHandle,
_context: Arc<dyn GuiContext>,
) -> Box<dyn std::any::Any + Send> {
let rr_cloned = self.emu_comms.clone();
2023-03-24 13:01:39 +11:00
// let (size, scale) = if cfg!(target_os = "macos") {
// (
// Size::new((WIDTH * EXTRA_SCALE) as f64, (HEIGHT * EXTRA_SCALE) as f64),
// baseview::WindowScalePolicy::SystemScaleFactor,
// )
// } else {
// (
// Size::new(WIDTH as f64, HEIGHT as f64),
// baseview::WindowScalePolicy::ScaleFactor(EXTRA_SCALE as f64),
// )
// };
2023-03-24 13:01:39 +11:00
let config = access_config();
2023-10-05 11:05:41 +11:00
#[cfg(feature = "vulkan")]
let shader_path = if IS_CGB.get().is_some_and(|v| *v) {
config.emu_config.vulkan_config.cgb_shader_path.as_ref()
} else {
config.emu_config.vulkan_config.dmg_shader_path.as_ref()
}
.map(|p| config.config_dir.join(p));
2023-10-05 21:38:43 +11:00
let scale_factor = access_config().vst_config.scale_factor;
2023-10-05 12:42:03 +11:00
let size = Size::new(
(WIDTH * scale_factor) as f64,
(HEIGHT * scale_factor) as f64,
);
2023-10-06 16:53:57 +11:00
let m = self.manager.clone();
2023-03-05 20:18:06 +11:00
Window::open_parented(
&parent,
WindowOpenOptions {
title: String::from("gb-emu"),
2023-10-05 12:42:03 +11:00
size,
scale: baseview::WindowScalePolicy::SystemScaleFactor,
2023-03-05 20:18:06 +11:00
},
2023-10-05 12:42:03 +11:00
move |w| {
2023-10-05 11:05:41 +11:00
EmulatorWindow::new(
w,
rr_cloned,
2023-10-06 16:53:57 +11:00
m,
2023-10-05 12:42:03 +11:00
size,
2023-10-05 11:05:41 +11:00
#[cfg(feature = "vulkan")]
shader_path,
)
2023-10-06 16:53:57 +11:00
.0
2023-10-05 11:05:41 +11:00
},
2023-03-05 20:18:06 +11:00
);
2023-03-08 15:19:10 +11:00
Box::new(Self::new(
self.emu_comms.clone(),
2023-10-06 16:53:57 +11:00
self.manager.clone(),
2023-10-05 12:42:03 +11:00
size,
2023-03-08 15:19:10 +11:00
))
2023-03-05 20:18:06 +11:00
}
fn size(&self) -> (u32, u32) {
2023-10-05 12:42:03 +11:00
(self.size.width as u32, self.size.height as u32)
2023-03-05 20:18:06 +11:00
}
fn set_scale_factor(&self, _factor: f32) -> bool {
true
}
fn param_value_changed(&self, _id: &str, _normalized_value: f32) {}
fn param_modulation_changed(&self, _id: &str, _modulation_offset: f32) {}
fn param_values_changed(&self) {}
}
pub struct EmulatorWindow {
renderer: RendererBackend,
manager: Arc<RendererBackendManager>,
emu_comms: Arc<Mutex<Option<EmuComms>>>,
joypad_state: JoypadState,
latest_buf: Vec<[u8; 4]>,
current_resolution: ResolutionData,
2023-03-05 20:18:06 +11:00
}
impl EmulatorWindow {
2023-03-08 15:19:10 +11:00
fn new(
window: &mut Window,
emu_comms: Arc<Mutex<Option<EmuComms>>>,
2023-10-06 16:53:57 +11:00
manager: Arc<Mutex<Option<Arc<RendererBackendManager>>>>,
2023-10-05 12:42:03 +11:00
size: Size,
2023-10-05 11:05:41 +11:00
#[cfg(feature = "vulkan")] shader_path: Option<PathBuf>,
2023-10-06 16:53:57 +11:00
) -> (Self, Arc<RendererBackendManager>) {
let current_resolution = ResolutionData {
2023-10-05 12:42:03 +11:00
real_width: size.width as u32,
real_height: size.height as u32,
scaled_width: WIDTH as u32,
scaled_height: HEIGHT as u32,
};
2023-10-05 11:05:41 +11:00
#[cfg(feature = "vulkan")]
2023-10-06 16:53:57 +11:00
let window_options = WindowOptions { shader_path };
2023-10-05 11:05:41 +11:00
#[cfg(feature = "pixels")]
2023-10-06 16:53:57 +11:00
let window_options = WindowOptions {};
2023-03-05 20:18:06 +11:00
2023-10-06 16:53:57 +11:00
let mut guard = manager.lock().unwrap();
2023-03-05 20:18:06 +11:00
2023-10-06 16:53:57 +11:00
let m = guard.get_or_insert_with(|| {
use raw_window_handle::HasRawDisplayHandle;
Arc::new(RendererBackendManager::new(window.raw_display_handle()))
});
let renderer = RendererBackend::new(current_resolution, window, window_options, m.clone());
(
Self {
renderer,
manager: m.clone(),
emu_comms,
joypad_state: Default::default(),
latest_buf: Vec::new(),
2023-10-06 16:53:57 +11:00
current_resolution,
},
m.clone(),
)
2023-03-05 20:18:06 +11:00
}
fn process_events(&mut self) {
if let Ok(comms) = self.emu_comms.lock() {
if let Some(ref comms) = *comms {
while let Ok(e) = comms.receiver.try_recv() {
match e {
RendererMessage::Prepare {
width: _,
height: _,
} => {}
RendererMessage::Resize {
width: _,
height: _,
} => {}
RendererMessage::Display { buffer } => self.latest_buf = buffer,
RendererMessage::SetTitle { title: _ } => {}
RendererMessage::Rumble { rumble: _ } => {}
}
}
}
}
}
2023-03-05 20:18:06 +11:00
}
2023-10-06 16:53:57 +11:00
2023-03-05 20:18:06 +11:00
impl WindowHandler for EmulatorWindow {
fn on_frame(&mut self, _window: &mut Window) {
self.process_events();
if self.latest_buf.len()
== (self.current_resolution.scaled_height * self.current_resolution.scaled_width)
as usize
{
self.renderer.new_frame(&self.latest_buf);
2023-03-07 21:45:11 +11:00
}
self.renderer.render(self.current_resolution, &self.manager);
2023-03-05 20:18:06 +11:00
}
fn on_event(&mut self, window: &mut Window, event: baseview::Event) -> EventStatus {
2023-03-08 15:19:10 +11:00
match event {
Event::Window(WindowEvent::Resized(info)) => {
let physical_size = info.physical_size();
self.current_resolution = ResolutionData {
real_width: physical_size.width,
real_height: physical_size.height,
scaled_width: WIDTH as u32,
scaled_height: HEIGHT as u32,
};
self.renderer.resize(self.current_resolution, window);
2023-03-08 15:19:10 +11:00
EventStatus::Captured
}
Event::Keyboard(event) => {
let status = event.state == KeyState::Down;
if let Some(button) = match event.code {
Code::Equal => Some(JoypadButtons::Start),
Code::Minus => Some(JoypadButtons::Select),
Code::Quote => Some(JoypadButtons::A),
Code::Semicolon => Some(JoypadButtons::B),
Code::KeyW | Code::ArrowUp => Some(JoypadButtons::Up),
Code::KeyA | Code::ArrowLeft => Some(JoypadButtons::Left),
Code::KeyS | Code::ArrowDown => Some(JoypadButtons::Down),
Code::KeyD | Code::ArrowRight => Some(JoypadButtons::Right),
_ => None,
} {
self.joypad_state.set(button, status);
if let Ok(comms) = self.emu_comms.lock() {
if let Some(ref comms) = *comms {
match comms.sender.send(
gb_emu_lib::connect::EmulatorMessage::JoypadUpdate(
self.joypad_state,
),
) {
Ok(_) => {}
Err(e) => println!("error sending joypad update: {e:#?}"),
}
}
2023-03-08 15:19:10 +11:00
}
EventStatus::Captured
} else {
EventStatus::Ignored
}
}
_ => EventStatus::Ignored,
2023-03-05 20:18:06 +11:00
}
}
}