249 lines
8.2 KiB
Rust
249 lines
8.2 KiB
Rust
use std::sync::{Arc, Mutex};
|
|
|
|
use baseview::{
|
|
Event, EventStatus, Size, Window, WindowEvent, WindowHandle, WindowHandler, WindowOpenOptions,
|
|
};
|
|
use gb_emu_lib::{
|
|
connect::{JoypadButtons, JoypadState, RendererMessage, ResolutionData, HEIGHT, WIDTH},
|
|
renderer::{RendererBackend, RendererBackendManager, WindowOptions},
|
|
};
|
|
use keyboard_types::{Code, KeyState};
|
|
use nih_plug::prelude::*;
|
|
|
|
use crate::{access_config, EmuComms};
|
|
|
|
pub struct TwincEditor {
|
|
emu_comms: Arc<Mutex<Option<EmuComms>>>,
|
|
size: Size,
|
|
}
|
|
|
|
impl TwincEditor {
|
|
pub fn new(emu_comms: Arc<Mutex<Option<EmuComms>>>, size: Size) -> Self {
|
|
Self { emu_comms, size }
|
|
}
|
|
}
|
|
|
|
impl Editor for TwincEditor {
|
|
fn spawn(
|
|
&self,
|
|
parent: ParentWindowHandle,
|
|
_context: Arc<dyn GuiContext>,
|
|
) -> Box<dyn std::any::Any + Send> {
|
|
let rr_cloned = self.emu_comms.clone();
|
|
|
|
// 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),
|
|
// )
|
|
// };
|
|
|
|
let config = access_config();
|
|
|
|
#[cfg(feature = "vulkan")]
|
|
let shader_path = {
|
|
if crate::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))
|
|
};
|
|
|
|
let scale_factor = config.vst_config.scale_factor;
|
|
|
|
let size = Size::new(
|
|
(WIDTH * scale_factor) as f64,
|
|
(HEIGHT * scale_factor) as f64,
|
|
);
|
|
|
|
let window = Window::open_parented(
|
|
&parent,
|
|
WindowOpenOptions {
|
|
title: String::from("gb-emu"),
|
|
size,
|
|
scale: baseview::WindowScalePolicy::SystemScaleFactor,
|
|
},
|
|
move |window| {
|
|
let manager = {
|
|
#[cfg(feature = "vulkan")]
|
|
{
|
|
use raw_window_handle::HasRawDisplayHandle;
|
|
Arc::new(RendererBackendManager::new(window.raw_display_handle()))
|
|
}
|
|
#[cfg(feature = "pixels")]
|
|
Arc::new(RendererBackendManager::new())
|
|
};
|
|
TwincEditorWindow::new(
|
|
window,
|
|
rr_cloned,
|
|
manager,
|
|
size,
|
|
#[cfg(feature = "vulkan")]
|
|
shader_path,
|
|
)
|
|
},
|
|
);
|
|
|
|
Box::new(TwincEditorWindowHandle { window })
|
|
}
|
|
|
|
fn size(&self) -> (u32, u32) {
|
|
(self.size.width as u32, self.size.height as u32)
|
|
}
|
|
|
|
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) {}
|
|
}
|
|
|
|
struct TwincEditorWindowHandle {
|
|
window: WindowHandle,
|
|
}
|
|
|
|
unsafe impl Send for TwincEditorWindowHandle {}
|
|
|
|
impl Drop for TwincEditorWindowHandle {
|
|
fn drop(&mut self) {
|
|
self.window.close();
|
|
}
|
|
}
|
|
|
|
pub struct TwincEditorWindow {
|
|
renderer: RendererBackend,
|
|
manager: Arc<RendererBackendManager>,
|
|
emu_comms: Arc<Mutex<Option<EmuComms>>>,
|
|
joypad_state: JoypadState,
|
|
latest_buf: Vec<[u8; 4]>,
|
|
current_resolution: ResolutionData,
|
|
}
|
|
|
|
impl TwincEditorWindow {
|
|
fn new(
|
|
window: &mut Window,
|
|
emu_comms: Arc<Mutex<Option<EmuComms>>>,
|
|
manager: Arc<RendererBackendManager>,
|
|
size: Size,
|
|
#[cfg(feature = "vulkan")] shader_path: Option<std::path::PathBuf>,
|
|
) -> Self {
|
|
let current_resolution = ResolutionData {
|
|
real_width: size.width as u32,
|
|
real_height: size.height as u32,
|
|
scaled_width: WIDTH as u32,
|
|
scaled_height: HEIGHT as u32,
|
|
};
|
|
|
|
#[cfg(feature = "vulkan")]
|
|
let window_options = WindowOptions { shader_path };
|
|
#[cfg(feature = "pixels")]
|
|
let window_options = WindowOptions {};
|
|
|
|
let renderer =
|
|
RendererBackend::new(current_resolution, window, window_options, manager.clone());
|
|
|
|
Self {
|
|
renderer,
|
|
manager,
|
|
emu_comms,
|
|
joypad_state: Default::default(),
|
|
latest_buf: Vec::new(),
|
|
current_resolution,
|
|
}
|
|
}
|
|
|
|
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: _ } => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl WindowHandler for TwincEditorWindow {
|
|
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);
|
|
}
|
|
|
|
self.renderer.render(self.current_resolution, &self.manager);
|
|
}
|
|
|
|
fn on_event(&mut self, window: &mut Window, event: baseview::Event) -> EventStatus {
|
|
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);
|
|
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) => nih_error!("error sending joypad update: {e:#?}"),
|
|
}
|
|
}
|
|
}
|
|
EventStatus::Captured
|
|
} else {
|
|
EventStatus::Ignored
|
|
}
|
|
}
|
|
_ => EventStatus::Ignored,
|
|
}
|
|
}
|
|
}
|