175 lines
6.2 KiB
Rust
175 lines
6.2 KiB
Rust
|
use std::sync::{
|
||
|
atomic::{AtomicBool, Ordering},
|
||
|
Arc,
|
||
|
};
|
||
|
|
||
|
use crate::emulator::{EmulatorClient, EmulatorCommand, SimId};
|
||
|
use egui::{
|
||
|
menu, Button, CentralPanel, Color32, Context, Response, TopBottomPanel, Ui, ViewportBuilder,
|
||
|
ViewportCommand, ViewportId, WidgetText,
|
||
|
};
|
||
|
|
||
|
use super::{game_screen::GameScreen, AppWindow};
|
||
|
|
||
|
pub struct GameWindow {
|
||
|
client: EmulatorClient,
|
||
|
sim_id: SimId,
|
||
|
input_window_open: Arc<AtomicBool>,
|
||
|
screen: Option<GameScreen>,
|
||
|
}
|
||
|
|
||
|
impl GameWindow {
|
||
|
pub fn new(client: EmulatorClient, sim_id: SimId, input_window_open: Arc<AtomicBool>) -> Self {
|
||
|
Self {
|
||
|
client,
|
||
|
sim_id,
|
||
|
input_window_open,
|
||
|
screen: None,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn init_renderer(&mut self, render_state: &egui_wgpu::RenderState) {
|
||
|
let (screen, sink) = GameScreen::init(render_state);
|
||
|
self.client
|
||
|
.send_command(EmulatorCommand::SetRenderer(self.sim_id, sink));
|
||
|
self.screen = Some(screen)
|
||
|
}
|
||
|
|
||
|
fn show_menu(&mut self, ctx: &Context, ui: &mut Ui) {
|
||
|
ui.menu_button("ROM", |ui| {
|
||
|
if ui.button("Open ROM").clicked() {
|
||
|
let rom = rfd::FileDialog::new()
|
||
|
.add_filter("Virtual Boy ROMs", &["vb", "vbrom"])
|
||
|
.pick_file();
|
||
|
if let Some(path) = rom {
|
||
|
self.client
|
||
|
.send_command(EmulatorCommand::LoadGame(SimId::Player1, path));
|
||
|
}
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
if ui.button("Quit").clicked() {
|
||
|
ctx.send_viewport_cmd(ViewportCommand::Close);
|
||
|
}
|
||
|
});
|
||
|
ui.menu_button("Emulation", |ui| {
|
||
|
let has_game = self.client.has_game(self.sim_id);
|
||
|
if self.client.is_running(self.sim_id) {
|
||
|
if ui.add_enabled(has_game, Button::new("Pause")).clicked() {
|
||
|
self.client.send_command(EmulatorCommand::Pause);
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
} else if ui.add_enabled(has_game, Button::new("Resume")).clicked() {
|
||
|
self.client.send_command(EmulatorCommand::Resume);
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
if ui.add_enabled(has_game, Button::new("Reset")).clicked() {
|
||
|
self.client
|
||
|
.send_command(EmulatorCommand::Reset(self.sim_id));
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
});
|
||
|
ui.menu_button("Video", |ui| {
|
||
|
let current_dims = ctx.input(|i| i.viewport().inner_rect.unwrap());
|
||
|
let current_dims = current_dims.max - current_dims.min;
|
||
|
|
||
|
for scale in 1..=4 {
|
||
|
let label = format!("x{scale}");
|
||
|
let scale = scale as f32;
|
||
|
let dims = (384.0 * scale, 224.0 * scale + 20.0).into();
|
||
|
if ui
|
||
|
.selectable_button((current_dims - dims).length() < 1.0, label)
|
||
|
.clicked()
|
||
|
{
|
||
|
ctx.send_viewport_cmd(ViewportCommand::InnerSize(dims));
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
ui.menu_button("Audio", |ui| {
|
||
|
let p1_enabled = self.client.is_audio_enabled(SimId::Player1);
|
||
|
let p2_enabled = self.client.is_audio_enabled(SimId::Player2);
|
||
|
if ui.selectable_button(p1_enabled, "Player 1").clicked() {
|
||
|
self.client
|
||
|
.send_command(EmulatorCommand::SetAudioEnabled(!p1_enabled, p2_enabled));
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
if ui.selectable_button(p2_enabled, "Player 2").clicked() {
|
||
|
self.client
|
||
|
.send_command(EmulatorCommand::SetAudioEnabled(p1_enabled, !p2_enabled));
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
});
|
||
|
ui.menu_button("Input", |ui| {
|
||
|
if ui.button("Bind Inputs").clicked() {
|
||
|
self.input_window_open.store(true, Ordering::Relaxed);
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
});
|
||
|
ui.menu_button("Multiplayer", |ui| {
|
||
|
if self.sim_id == SimId::Player1
|
||
|
&& !self.client.has_player_2()
|
||
|
&& ui.button("Open Player 2").clicked()
|
||
|
{
|
||
|
self.client
|
||
|
.send_command(EmulatorCommand::StartSecondSim(None));
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
if self.client.has_player_2() {
|
||
|
let linked = self.client.are_sims_linked();
|
||
|
if linked && ui.button("Unlink").clicked() {
|
||
|
self.client.send_command(EmulatorCommand::Unlink);
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
if !linked && ui.button("Link").clicked() {
|
||
|
self.client.send_command(EmulatorCommand::Link);
|
||
|
ui.close_menu();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl AppWindow for GameWindow {
|
||
|
fn viewport_id(&self) -> ViewportId {
|
||
|
match self.sim_id {
|
||
|
SimId::Player1 => ViewportId::ROOT,
|
||
|
SimId::Player2 => ViewportId::from_hash_of("Player2"),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn initial_viewport(&self) -> ViewportBuilder {
|
||
|
ViewportBuilder::default()
|
||
|
.with_title("Shrooms VB")
|
||
|
.with_inner_size((384.0, 244.0))
|
||
|
}
|
||
|
|
||
|
fn show(&mut self, ctx: &Context) {
|
||
|
TopBottomPanel::top("menubar")
|
||
|
.exact_height(20.0)
|
||
|
.show(ctx, |ui| {
|
||
|
menu::bar(ui, |ui| {
|
||
|
self.show_menu(ctx, ui);
|
||
|
});
|
||
|
});
|
||
|
CentralPanel::default().show(ctx, |ui| {
|
||
|
if let Some(screen) = self.screen.as_ref() {
|
||
|
ui.add(screen);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
trait UiExt {
|
||
|
fn selectable_button(&mut self, selected: bool, text: impl Into<WidgetText>) -> Response;
|
||
|
}
|
||
|
|
||
|
impl UiExt for Ui {
|
||
|
fn selectable_button(&mut self, selected: bool, text: impl Into<WidgetText>) -> Response {
|
||
|
self.style_mut().visuals.widgets.inactive.bg_fill = Color32::TRANSPARENT;
|
||
|
self.style_mut().visuals.widgets.hovered.bg_fill = Color32::TRANSPARENT;
|
||
|
self.style_mut().visuals.widgets.active.bg_fill = Color32::TRANSPARENT;
|
||
|
let mut selected = selected;
|
||
|
self.checkbox(&mut selected, text)
|
||
|
}
|
||
|
}
|