diff --git a/src/bin/chirp-imgui/args.rs b/src/bin/chirp-imgui/args.rs new file mode 100644 index 0000000..75faa2b --- /dev/null +++ b/src/bin/chirp-imgui/args.rs @@ -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::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, + // #[options(help = "Enable performance benchmarking on stderr (requires -S)")] + // pub perf: bool, + #[options(help = "Run in (Chip8, SChip, XOChip) mode.")] + pub mode: Option, + #[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 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 + } +} diff --git a/src/bin/chirp-imgui/gui/menubar.rs b/src/bin/chirp-imgui/gui/menubar.rs index 08f4a61..31d37c8 100644 --- a/src/bin/chirp-imgui/gui/menubar.rs +++ b/src/bin/chirp-imgui/gui/menubar.rs @@ -2,7 +2,7 @@ use super::Drawable; -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Debug, PartialEq, PartialOrd)] pub struct Menubar { pub(super) active: bool, 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(super) target_ipf: usize, pub(super) quirks: chirp::Quirks, pub(super) mode_index: usize, - pub(super) colors: [[u8; 4]; 2], + pub(super) colors: [[f32; 4]; 2], pub(super) applied: bool, } @@ -100,6 +100,12 @@ impl Drawable for Settings { self.applied = false; ui.menu("Settings", || { 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]; if ui.combo_simple_string("Mode", &mut self.mode_index, &MODES) { 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("Shift ops ignore vY", &mut self.quirks.shift) | ui.checkbox("Jumps behave eratically", &mut self.quirks.stupid_jumps) - } + }; }) } } @@ -127,7 +133,32 @@ impl Settings { pub fn quirks(&mut self) -> &mut chirp::Quirks { &mut self.quirks } - pub fn applied(&mut self) -> Option<(usize, chirp::Quirks)> { - self.applied.then_some((self.target_ipf, self.quirks)) + pub fn set_mode(&mut self, mode: chirp::Mode) { + 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)) } } diff --git a/src/bin/chirp-imgui/main.rs b/src/bin/chirp-imgui/main.rs index 65c0d21..629e06b 100644 --- a/src/bin/chirp-imgui/main.rs +++ b/src/bin/chirp-imgui/main.rs @@ -2,10 +2,12 @@ #![deny(clippy::all)] #![allow(dead_code)] // TODO: finish writing the code +mod args; mod emu; mod error; mod gui; +use crate::args::Arguments; use crate::emu::*; use crate::gui::*; use pixels::{Pixels, SurfaceTexture}; @@ -28,17 +30,11 @@ struct Application { } fn main() -> Result<(), error::Error> { - let rom_path; - if let Some(path) = std::env::args().nth(1) { - rom_path = path; - } else { - panic!("Supply a rom!"); - } - + let args = Arguments::parse(); let event_loop = EventLoop::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() .with_title("Chirp") .with_inner_size(size) @@ -52,13 +48,18 @@ fn main() -> Result<(), error::Error> { Pixels::new(128, 64, surface_texture)? }; - let mut app = Application::new( - Emulator::new(INIT_SPEED, rom_path), - Gui::new(&window, &pixels), - ); - + let mut gui = Gui::new(&window, &pixels); // 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(); // Run event loop @@ -114,10 +115,10 @@ fn main() -> Result<(), error::Error> { state.emu.input(&input)?; // 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.set_quirks(quirks); - println!("'A"); + state.emu.colors = [fg, bg]; } // Update the scale factor