chirp-imgui: Argument parsing + colors in Settings

This commit is contained in:
John 2023-04-29 23:34:06 -05:00
parent dcbdd1383d
commit 861020a8ab
3 changed files with 106 additions and 22 deletions

View File

@ -0,0 +1,52 @@
//! Parses arguments into a struct
use std::path::PathBuf;
use super::Emulator;
use chirp::Mode;
use gumdrop::*;
/// Parses a hexadecimal string into a u16
fn parse_hex(value: &str) -> std::result::Result<u16, std::num::ParseIntError> {
u16::from_str_radix(value, 16)
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Options, Hash)]
pub struct Arguments {
#[options(help = "Load a ROM to run on Chirp.", required, free)]
pub file: PathBuf,
#[options(help = "Print this help message.")]
help: bool,
#[options(help = "Enable debug mode at startup.")]
pub debug: bool,
#[options(help = "Enable pause mode at startup.")]
pub pause: bool,
#[options(help = "Set the instructions-per-frame rate.")]
pub speed: Option<usize>,
// #[options(help = "Enable performance benchmarking on stderr (requires -S)")]
// pub perf: bool,
#[options(help = "Run in (Chip8, SChip, XOChip) mode.")]
pub mode: Option<Mode>,
#[options(help = "Set the target framerate.", default = "60", meta = "FR")]
pub frame_rate: u64,
}
impl Arguments {
pub fn parse() -> Arguments {
Arguments::parse_args_default_or_exit()
}
}
impl From<Arguments> for Emulator {
fn from(value: Arguments) -> Self {
let mut emu = Emulator::new(value.speed.unwrap_or(10), value.file);
if let Some(mode) = value.mode {
emu.set_quirks(mode.into());
}
if value.pause {
emu.pause()
}
emu.set_disasm(value.debug);
emu
}
}

View File

@ -2,7 +2,7 @@
use super::Drawable; use super::Drawable;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Menubar { pub struct Menubar {
pub(super) active: bool, pub(super) active: bool,
pub file: File, pub file: File,
@ -86,12 +86,12 @@ impl Drawable for Help {
} }
} }
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct Settings { pub struct Settings {
pub(super) target_ipf: usize, pub(super) target_ipf: usize,
pub(super) quirks: chirp::Quirks, pub(super) quirks: chirp::Quirks,
pub(super) mode_index: usize, pub(super) mode_index: usize,
pub(super) colors: [[u8; 4]; 2], pub(super) colors: [[f32; 4]; 2],
pub(super) applied: bool, pub(super) applied: bool,
} }
@ -100,6 +100,12 @@ impl Drawable for Settings {
self.applied = false; self.applied = false;
ui.menu("Settings", || { ui.menu("Settings", || {
use chirp::Mode::*; use chirp::Mode::*;
ui.menu("Foreground Color", || {
self.applied |= ui.color_picker4("", &mut self.colors[0])
});
ui.menu("Background Color", || {
self.applied |= ui.color_picker4("", &mut self.colors[1])
});
const MODES: [chirp::Mode; 3] = [Chip8, SChip, XOChip]; const MODES: [chirp::Mode; 3] = [Chip8, SChip, XOChip];
if ui.combo_simple_string("Mode", &mut self.mode_index, &MODES) { if ui.combo_simple_string("Mode", &mut self.mode_index, &MODES) {
self.quirks = MODES[self.mode_index].into(); self.quirks = MODES[self.mode_index].into();
@ -115,7 +121,7 @@ impl Drawable for Settings {
| ui.checkbox("Screen wraps at edge", &mut self.quirks.screen_wrap) | ui.checkbox("Screen wraps at edge", &mut self.quirks.screen_wrap)
| ui.checkbox("Shift ops ignore vY", &mut self.quirks.shift) | ui.checkbox("Shift ops ignore vY", &mut self.quirks.shift)
| ui.checkbox("Jumps behave eratically", &mut self.quirks.stupid_jumps) | ui.checkbox("Jumps behave eratically", &mut self.quirks.stupid_jumps)
} };
}) })
} }
} }
@ -127,7 +133,32 @@ impl Settings {
pub fn quirks(&mut self) -> &mut chirp::Quirks { pub fn quirks(&mut self) -> &mut chirp::Quirks {
&mut self.quirks &mut self.quirks
} }
pub fn applied(&mut self) -> Option<(usize, chirp::Quirks)> { pub fn set_mode(&mut self, mode: chirp::Mode) {
self.applied.then_some((self.target_ipf, self.quirks)) self.mode_index = mode as usize;
}
pub fn set_color(&mut self, fg: &[u8; 4], bg: &[u8; 4]) {
for (idx, component) in fg.iter().enumerate() {
self.colors[0][idx] = *component as f32 / 255.0;
}
for (idx, component) in bg.iter().enumerate() {
self.colors[1][idx] = *component as f32 / 255.0;
}
}
pub fn applied(&mut self) -> Option<(usize, chirp::Quirks, [u8; 4], [u8; 4])> {
let (fg, bg) = (self.colors[0], self.colors[1]);
let fg = [
(fg[0] * 255.0) as u8,
(fg[1] * 255.0) as u8,
(fg[2] * 255.0) as u8,
(fg[3] * 255.0) as u8,
];
let bg = [
(bg[0] * 255.0) as u8,
(bg[1] * 255.0) as u8,
(bg[2] * 255.0) as u8,
(bg[3] * 255.0) as u8,
];
self.applied
.then_some((self.target_ipf, self.quirks, fg, bg))
} }
} }

View File

@ -2,10 +2,12 @@
#![deny(clippy::all)] #![deny(clippy::all)]
#![allow(dead_code)] // TODO: finish writing the code #![allow(dead_code)] // TODO: finish writing the code
mod args;
mod emu; mod emu;
mod error; mod error;
mod gui; mod gui;
use crate::args::Arguments;
use crate::emu::*; use crate::emu::*;
use crate::gui::*; use crate::gui::*;
use pixels::{Pixels, SurfaceTexture}; use pixels::{Pixels, SurfaceTexture};
@ -28,17 +30,11 @@ struct Application {
} }
fn main() -> Result<(), error::Error> { fn main() -> Result<(), error::Error> {
let rom_path; let args = Arguments::parse();
if let Some(path) = std::env::args().nth(1) {
rom_path = path;
} else {
panic!("Supply a rom!");
}
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let mut input = WinitInputHelper::new(); let mut input = WinitInputHelper::new();
let size = LogicalSize::new(128 * 6, 64 * 6); let size = LogicalSize::new(128 * 8, 64 * 8);
let window = WindowBuilder::new() let window = WindowBuilder::new()
.with_title("Chirp") .with_title("Chirp")
.with_inner_size(size) .with_inner_size(size)
@ -52,13 +48,18 @@ fn main() -> Result<(), error::Error> {
Pixels::new(128, 64, surface_texture)? Pixels::new(128, 64, surface_texture)?
}; };
let mut app = Application::new( let mut gui = Gui::new(&window, &pixels);
Emulator::new(INIT_SPEED, rom_path),
Gui::new(&window, &pixels),
);
// set initial parameters // set initial parameters
*app.gui.menubar.settings.target_ipf() = INIT_SPEED; if let Some(mode) = args.mode {
gui.menubar.settings.set_mode(mode);
}
gui.menubar.settings.set_color(FOREGROUND, BACKGROUND);
*gui.menubar.settings.target_ipf() = args.speed.unwrap_or(INIT_SPEED);
let mut app = Application::new(args.into(), gui);
// Copy quirks from the running Emulator, for consistency
*app.gui.menubar.settings.quirks() = app.emu.quirks(); *app.gui.menubar.settings.quirks() = app.emu.quirks();
// Run event loop // Run event loop
@ -114,10 +115,10 @@ fn main() -> Result<(), error::Error> {
state.emu.input(&input)?; state.emu.input(&input)?;
// Apply settings // Apply settings
if let Some((ipf, quirks)) = state.gui.menubar.settings.applied() { if let Some((ipf, quirks, fg, bg)) = state.gui.menubar.settings.applied() {
state.emu.ipf = ipf; state.emu.ipf = ipf;
state.emu.set_quirks(quirks); state.emu.set_quirks(quirks);
println!("'A"); state.emu.colors = [fg, bg];
} }
// Update the scale factor // Update the scale factor