From c9ef6d4e043c7627ab20e705e57ccbd36df8ea0f Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Fri, 11 Oct 2024 15:02:15 -0400 Subject: [PATCH] working on gemmaegui to build a usable UI --- gemmaegui/src/bin/gemmaegui.rs | 82 ++---------------- gemmaegui/src/bin/support/EmmaEGuiState.rs | 16 ++++ gemmaegui/src/bin/support/GemmaEGuiSupport.rs | 75 ++++++++++++++++ gemmaegui/src/bin/support/mod.rs | 2 + gemmaimgui/src/bin/gemmaimgui.rs | 82 +++++++++--------- gemmaimgui/src/bin/support/emmagui_support.rs | 25 +++++- gemmaimgui/src/bin/support/mod.rs | 1 + gemmaimgui/src/bin/support/ui_state.rs | 46 ++++++++++ resources/roms/octojam2title.ch8 | Bin 0 -> 1240 bytes 9 files changed, 214 insertions(+), 115 deletions(-) create mode 100644 gemmaegui/src/bin/support/EmmaEGuiState.rs create mode 100644 gemmaegui/src/bin/support/GemmaEGuiSupport.rs create mode 100644 gemmaegui/src/bin/support/mod.rs create mode 100644 gemmaimgui/src/bin/support/ui_state.rs create mode 100644 resources/roms/octojam2title.ch8 diff --git a/gemmaegui/src/bin/gemmaegui.rs b/gemmaegui/src/bin/gemmaegui.rs index 107515c..deae0f1 100644 --- a/gemmaegui/src/bin/gemmaegui.rs +++ b/gemmaegui/src/bin/gemmaegui.rs @@ -1,74 +1,10 @@ - +use crate::support::GemmaEGuiSupport::GemmaEGui; +use crate::support::EmmaEGuiState::EmmaEGuiState; use eframe::egui; use egui::Ui; use gemma::chip8::computer::Chip8Computer; -struct EmmaEGuiState { - pub display_video: bool, - pub display_memory: bool, - pub display_registers: bool -} - -impl Default for EmmaEGuiState { - fn default() -> Self { - Self { display_video: true, - display_memory: true, - display_registers: true } - } -} - -fn controls_view(mut system: &mut Chip8Computer, state: &mut EmmaEGuiState, ui: &mut Ui) { - if ui.button("Step").clicked() { - system.step_system(); - } - if ui.button("Start").clicked() { - println!("Start"); - } - if ui.button("Stop").clicked() { - println!("STOP"); - - } - if ui.button("Reset").clicked() { - - } - - ui.checkbox(&mut state.display_memory, "Display Memory"); - ui.checkbox(&mut state.display_video, "Display Video"); - ui.checkbox(&mut state.display_registers, "Display Registers"); -} - -fn registers_view(system: &Chip8Computer, ui:& mut Ui) { - ui.label(format!("V0-7: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} ", - system.registers.peek(0x00), - system.registers.peek(0x01), - system.registers.peek(0x02), - system.registers.peek(0x03), - system.registers.peek(0x04), - system.registers.peek(0x05), - system.registers.peek(0x06), - system.registers.peek(0x07) -)); -ui.label(format!("V8-F: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} ", - system.registers.peek(0x08), - system.registers.peek(0x09), - system.registers.peek(0x0A), - system.registers.peek(0x0B), - system.registers.peek(0x0C), - system.registers.peek(0x0D), - system.registers.peek(0x0E), - system.registers.peek(0x0F) -)); -ui.label(format!("PC: {:04x}\tI: {:04x}" , system.registers.peek_pc(), system.registers.peek_i())); -} - -fn video_view(system: &Chip8Computer, ui: &mut Ui) { - ui.label("Video goes here"); -} - -fn memory_view(system: &Chip8Computer, ui: &mut Ui) { - ui.label("Memory View"); -} - +mod support; fn main() -> eframe::Result { println!("Taxation is Theft"); @@ -85,18 +21,18 @@ fn main() -> eframe::Result { egui::CentralPanel::default().show(ctx, |ui| { ui.heading("Gemma"); - controls_view(&mut computer, &mut state, ui); + GemmaEGui::controls_view(&mut computer, &mut state, ui); if state.display_memory { - memory_view(&computer, ui); + GemmaEGui::memory_view(&computer, ui); } if state.display_video { - video_view(&computer, ui); + GemmaEGui::video_view(&computer, ui); } - - if state.display_registers { - registers_view(&computer, ui); + + if state.display_registers { + GemmaEGui::registers_view(&computer, ui); } }); }) diff --git a/gemmaegui/src/bin/support/EmmaEGuiState.rs b/gemmaegui/src/bin/support/EmmaEGuiState.rs new file mode 100644 index 0000000..111203f --- /dev/null +++ b/gemmaegui/src/bin/support/EmmaEGuiState.rs @@ -0,0 +1,16 @@ + +pub struct EmmaEGuiState { + pub display_video: bool, + pub display_memory: bool, + pub display_registers: bool, +} + +impl Default for EmmaEGuiState { + fn default() -> Self { + Self { + display_video: true, + display_memory: true, + display_registers: true, + } + } +} diff --git a/gemmaegui/src/bin/support/GemmaEGuiSupport.rs b/gemmaegui/src/bin/support/GemmaEGuiSupport.rs new file mode 100644 index 0000000..e3522e3 --- /dev/null +++ b/gemmaegui/src/bin/support/GemmaEGuiSupport.rs @@ -0,0 +1,75 @@ +use egui::Color32; +use egui::Rect; +use egui::Pos2; +use egui::Vec2; +use egui::Ui; +use crate::support::EmmaEGuiState::EmmaEGuiState; +use crate::Chip8Computer; + +pub struct GemmaEGui {} +impl GemmaEGui { + pub fn controls_view(mut system: &mut Chip8Computer, state: &mut EmmaEGuiState, ui: &mut Ui) { + if ui.button("Step").clicked() { + system.step_system(); + } + if ui.button("Start").clicked() { + println!("Start"); + } + if ui.button("Stop").clicked() { + println!("STOP"); + } + if ui.button("Reset").clicked() {} + + ui.checkbox(&mut state.display_memory, "Display Memory"); + ui.checkbox(&mut state.display_video, "Display Video"); + ui.checkbox(&mut state.display_registers, "Display Registers"); + } + + pub fn registers_view(system: &Chip8Computer, ui: &mut Ui) { + ui.label(format!("V0-7: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} ", + system.registers.peek(0x00), + system.registers.peek(0x01), + system.registers.peek(0x02), + system.registers.peek(0x03), + system.registers.peek(0x04), + system.registers.peek(0x05), + system.registers.peek(0x06), + system.registers.peek(0x07) + )); + ui.label(format!("V8-F: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} ", + system.registers.peek(0x08), + system.registers.peek(0x09), + system.registers.peek(0x0A), + system.registers.peek(0x0B), + system.registers.peek(0x0C), + system.registers.peek(0x0D), + system.registers.peek(0x0E), + system.registers.peek(0x0F) + )); + ui.label(format!("PC: {:04x}\tI: {:04x}", system.registers.peek_pc(), system.registers.peek_i())); + } + + pub fn video_view(system: &Chip8Computer, ui: &mut Ui) { + ui.label("Video goes here"); + let (resp, painter) = ui.allocate_painter(Vec2::new(400.0, 500.0), egui::Sense::hover()); + for current_row in 0..32 { + for current_col in 0..64 { + let data_offset = current_row * 32 + current_col; + let origin = ui.next_widget_position(); + let colour = if system.video_memory.peek(data_offset) { + Color32::RED + } else { + Color32::BLUE + }; + let rect = Rect::from_min_size(origin, Vec2::new(10.0, 10.0)); + painter.rect_filled(rect, 0.0, colour); + } + } + } + + + + pub fn memory_view(system: &Chip8Computer, ui: &mut Ui) { + ui.label("Memory View"); + } +} diff --git a/gemmaegui/src/bin/support/mod.rs b/gemmaegui/src/bin/support/mod.rs new file mode 100644 index 0000000..a20c907 --- /dev/null +++ b/gemmaegui/src/bin/support/mod.rs @@ -0,0 +1,2 @@ +pub mod EmmaEGuiState; +pub mod GemmaEGuiSupport; \ No newline at end of file diff --git a/gemmaimgui/src/bin/gemmaimgui.rs b/gemmaimgui/src/bin/gemmaimgui.rs index 24b2324..30a7171 100644 --- a/gemmaimgui/src/bin/gemmaimgui.rs +++ b/gemmaimgui/src/bin/gemmaimgui.rs @@ -9,50 +9,20 @@ use imgui::*; use sys::{ImColor, ImVec2, ImVector_ImU32}; use rand::random; use gemma::chip8::system_memory::Chip8SystemMemory; -use support::emmagui_support::EmmaGui; +use support::{emmagui_support::EmmaGui, ui_state::UiState}; mod support; -struct UiState { - pub show_registers: bool, - pub show_memory: bool, - pub show_video: bool, - pub filename_to_load: String, - pub on_colour: ImColor32, - pub off_colour: ImColor32, - pub is_running: bool, - pub frame_time: f32, -} +/// Keypad Mappings for my Linux box +/// 1 2 3 C +/// 4 5 6 D +/// 7 8 9 E +/// A 0 B F -impl Clone for UiState { - fn clone(&self) -> Self { - UiState { - show_registers: self.show_registers, - show_memory: self.show_memory, - show_video: self.show_video, - filename_to_load: self.filename_to_load.to_string(), - on_colour: self.on_colour, - off_colour: self.off_colour, - is_running: self.is_running, - frame_time: self.frame_time, - } - } -} - -impl Default for UiState { - fn default() -> Self { - UiState { - show_registers: false, - show_memory: false, - show_video: true, - filename_to_load: String::new(), - on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00), - off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff), - is_running: false, - frame_time: 10.0, - } - } -} +const LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0x0c), + (562, 0x04),(568, 0x05),(550, 0x06),(563, 0x0d), + (546, 7),(564, 8),(549, 9),(551, 0xe), + (571, 0xa),(569, 0),(548, 0xb),(569, 0xf)]; fn main() { pretty_env_logger::init(); @@ -62,9 +32,35 @@ fn main() { support::simple_init(file!(), move |_, ui| { let current_time = Instant::now(); + + let down_keys = ui.io().keys_down; + for (key_code, key_reg) in LIN_KEYS { + if down_keys[key_code as usize] { + system.keypad.push_key(key_reg); + } else { + // do we need to release it? + if system.keypad.pressed(key_reg) { + system.keypad.release_key(key_reg); + } + } + } + // println!("KEYS DOWN = {:?}", ui.io().keys_down); let time_since_last_tick = current_time.duration_since(last_tick_time).as_millis(); if ui_state.is_running && time_since_last_tick > ui_state.frame_time as u128 { - system.step_system(); + match system.state { + gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction => { + // this is the 'regular' mode for the CPU when we get here + system.step_system(); + }, + gemma::chip8::cpu_states::Chip8CpuStates::WaitingForKey => { + // waiting for a keychange... + }, + gemma::chip8::cpu_states::Chip8CpuStates::ExecutingInstruction => { // should never see this. + }, + gemma::chip8::cpu_states::Chip8CpuStates::Error => { + panic!("System in undefined state."); + }, + } last_tick_time = current_time; } @@ -82,5 +78,9 @@ fn main() { let active_instruction = system.registers.peek_pc(); EmmaGui::hex_memory_display(system.memory.clone(), (0x100, 0x10), active_instruction as i16, ui); } + + if ui_state.show_keypad { + EmmaGui::keypad_display(&system, ui); + } }); } diff --git a/gemmaimgui/src/bin/support/emmagui_support.rs b/gemmaimgui/src/bin/support/emmagui_support.rs index 7b11fb7..7d942dc 100644 --- a/gemmaimgui/src/bin/support/emmagui_support.rs +++ b/gemmaimgui/src/bin/support/emmagui_support.rs @@ -1,3 +1,4 @@ +use gemma::constants::CHIP8_KEYBOARD; use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; @@ -10,6 +11,8 @@ use gemma::chip8::system_memory::Chip8SystemMemory; use gemma::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH}; use crate::UiState; +use super::ui_state; + pub struct EmmaGui {} const CELL_WIDTH: i32 = 5i32; @@ -39,6 +42,23 @@ impl GuiFileList { impl EmmaGui { + pub fn keypad_display(system_to_display: &Chip8Computer, ui: &Ui) { + ui.text("Keypad"); + + for row in CHIP8_KEYBOARD { + for key in row { + let label = if system_to_display.keypad.pressed(key) { + format!("*{:1x}*", key) + } else { + format!("{:1x}", key) + }; + ui.text(format!("{}", label)); + ui.same_line(); + } + ui.text(""); + } + } + pub fn video_display(system_to_control: &Chip8Computer, gui_state: &UiState, ui: &Ui) { // draw area size let draw_area_size = ui.io().display_size; @@ -46,7 +66,7 @@ impl EmmaGui { let cell_height = ((draw_area_size[1] as i32 / 32) * 6) / 10; ui.window(format!("Display {cell_width}x{cell_height}")) - .size([300.0, 300.0], Condition::FirstUseEver) + .size([300.0, 300.0], Condition::Once) .build(|| { let origin = ui.cursor_screen_pos(); let fg = ui.get_window_draw_list(); @@ -94,16 +114,19 @@ impl EmmaGui { if ui.button("Step") { system_to_control.step_system(); }; + ui.same_line(); if ui.button("Run") { gui_state.is_running = true; debug!("STARTING THE SYSTEM"); } + ui.same_line(); if ui.button("Stop") { gui_state.is_running = false; debug!("STOPPING THE SYSTEM"); } ui.same_line(); if ui.button("Reset") { + gui_state.is_running = false; *system_to_control = Chip8Computer::new(); } if ui.button("Dump Video Memory") { diff --git a/gemmaimgui/src/bin/support/mod.rs b/gemmaimgui/src/bin/support/mod.rs index a0be20e..fe177a4 100644 --- a/gemmaimgui/src/bin/support/mod.rs +++ b/gemmaimgui/src/bin/support/mod.rs @@ -10,6 +10,7 @@ use imgui_winit_support::{HiDpiMode, WinitPlatform}; use std::path::Path; use std::time::Instant; +pub mod ui_state; pub mod emmagui_support; use copypasta::{ClipboardContext, ClipboardProvider}; use imgui::ClipboardBackend; diff --git a/gemmaimgui/src/bin/support/ui_state.rs b/gemmaimgui/src/bin/support/ui_state.rs new file mode 100644 index 0000000..dd1bb71 --- /dev/null +++ b/gemmaimgui/src/bin/support/ui_state.rs @@ -0,0 +1,46 @@ +use imgui::ImColor32; + + +pub struct UiState { + pub show_registers: bool, + pub show_memory: bool, + pub show_video: bool, + pub show_keypad: bool, + pub filename_to_load: String, + pub on_colour: ImColor32, + pub off_colour: ImColor32, + pub is_running: bool, + pub frame_time: f32, +} + +impl Clone for UiState { + fn clone(&self) -> Self { + UiState { + show_registers: self.show_registers, + show_memory: self.show_memory, + show_video: self.show_video, + show_keypad: self.show_keypad, + filename_to_load: self.filename_to_load.to_string(), + on_colour: self.on_colour, + off_colour: self.off_colour, + is_running: self.is_running, + frame_time: self.frame_time, + } + } +} + +impl Default for UiState { + fn default() -> Self { + UiState { + show_registers: false, + show_memory: false, + show_video: true, + show_keypad: true, + filename_to_load: String::new(), + on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00), + off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff), + is_running: false, + frame_time: 10.0, + } + } +} diff --git a/resources/roms/octojam2title.ch8 b/resources/roms/octojam2title.ch8 new file mode 100644 index 0000000000000000000000000000000000000000..6e19074790fe94742e8594b6b109d4946c38d9dc GIT binary patch literal 1240 zcmYL|&u`N(6vtocDE3g4xI3U6rlt!O;zqdjP^nQ>O*`>7l(9b`#~o1XXgw5(1Kbfv zAn|v2(!`nn0P{mbT#yAETv5$DI~lw-e)0R-e*XA5kAf5aIDK=kxcxROZnwYvTMPJ* z{~CO_|7%dQvf9t!hjlh#d!3n`4_Ip?plNe$ZA!o09Xb0NCQjWcCqY072|y@qIo~~7 zuYVsL*lR5?p5`liz0+Eov$KgUhgVlu@7^i>aaC2@?^`J?O;ckG4*2xt^U-oPTRxoq z{AdYz_3~AZU_P4X)0N$sKS_8R#;2!Y@<$rGnx>S1kjiK&a08aHZI*4fdwUjp%I_S< z;5%+EwbT4H{$D?Tu6;ykM6ozhXjA$K;7bHut)NPDIvrY>37s!$^`(}1{(3lhcIc)gy_ieleQLe$E8fQ1kM4~mn+JH^p_ zetgWi6G9l?!(73h>m2rZ6f-`o8rN$rMBwBc^JNJ=hk&F=e50Yy@ez9BiJ$0JAsr}Q zgsC4Yl$oY^S3#v~A4K(9_&1U+4M=qs;jP8_PKpQp{!^z`T_gPQ0nFxW&ijW&G3qYH5W)&DP0yt|D(+mI(*=93$YFpr;KwO_^y(b2B>|Q-Q#dD={DY+uRa#vM_mjnG1tJEzIe*xN{A1D9- literal 0 HcmV?d00001