working on gemmaegui to build a usable UI

This commit is contained in:
Trevor Merritt 2024-10-11 15:02:15 -04:00
parent ef0250b519
commit c9ef6d4e04
9 changed files with 214 additions and 115 deletions

View File

@ -1,74 +1,10 @@
use crate::support::GemmaEGuiSupport::GemmaEGui;
use crate::support::EmmaEGuiState::EmmaEGuiState;
use eframe::egui; use eframe::egui;
use egui::Ui; use egui::Ui;
use gemma::chip8::computer::Chip8Computer; use gemma::chip8::computer::Chip8Computer;
struct EmmaEGuiState { mod support;
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");
}
fn main() -> eframe::Result { fn main() -> eframe::Result {
println!("Taxation is Theft"); println!("Taxation is Theft");
@ -85,18 +21,18 @@ fn main() -> eframe::Result {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Gemma"); ui.heading("Gemma");
controls_view(&mut computer, &mut state, ui); GemmaEGui::controls_view(&mut computer, &mut state, ui);
if state.display_memory { if state.display_memory {
memory_view(&computer, ui); GemmaEGui::memory_view(&computer, ui);
} }
if state.display_video { if state.display_video {
video_view(&computer, ui); GemmaEGui::video_view(&computer, ui);
} }
if state.display_registers { if state.display_registers {
registers_view(&computer, ui); GemmaEGui::registers_view(&computer, ui);
} }
}); });
}) })

View File

@ -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,
}
}
}

View File

@ -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");
}
}

View File

@ -0,0 +1,2 @@
pub mod EmmaEGuiState;
pub mod GemmaEGuiSupport;

View File

@ -9,50 +9,20 @@ use imgui::*;
use sys::{ImColor, ImVec2, ImVector_ImU32}; use sys::{ImColor, ImVec2, ImVector_ImU32};
use rand::random; use rand::random;
use gemma::chip8::system_memory::Chip8SystemMemory; use gemma::chip8::system_memory::Chip8SystemMemory;
use support::emmagui_support::EmmaGui; use support::{emmagui_support::EmmaGui, ui_state::UiState};
mod support; mod support;
struct UiState { /// Keypad Mappings for my Linux box
pub show_registers: bool, /// 1 2 3 C
pub show_memory: bool, /// 4 5 6 D
pub show_video: bool, /// 7 8 9 E
pub filename_to_load: String, /// A 0 B F
pub on_colour: ImColor32,
pub off_colour: ImColor32,
pub is_running: bool,
pub frame_time: f32,
}
impl Clone for UiState { const LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0x0c),
fn clone(&self) -> Self { (562, 0x04),(568, 0x05),(550, 0x06),(563, 0x0d),
UiState { (546, 7),(564, 8),(549, 9),(551, 0xe),
show_registers: self.show_registers, (571, 0xa),(569, 0),(548, 0xb),(569, 0xf)];
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,
}
}
}
fn main() { fn main() {
pretty_env_logger::init(); pretty_env_logger::init();
@ -62,9 +32,35 @@ fn main() {
support::simple_init(file!(), move |_, ui| { support::simple_init(file!(), move |_, ui| {
let current_time = Instant::now(); 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(); 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 { 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; last_tick_time = current_time;
} }
@ -82,5 +78,9 @@ fn main() {
let active_instruction = system.registers.peek_pc(); let active_instruction = system.registers.peek_pc();
EmmaGui::hex_memory_display(system.memory.clone(), (0x100, 0x10), active_instruction as i16, ui); EmmaGui::hex_memory_display(system.memory.clone(), (0x100, 0x10), active_instruction as i16, ui);
} }
if ui_state.show_keypad {
EmmaGui::keypad_display(&system, ui);
}
}); });
} }

View File

@ -1,3 +1,4 @@
use gemma::constants::CHIP8_KEYBOARD;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::{Path, PathBuf}; 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 gemma::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};
use crate::UiState; use crate::UiState;
use super::ui_state;
pub struct EmmaGui {} pub struct EmmaGui {}
const CELL_WIDTH: i32 = 5i32; const CELL_WIDTH: i32 = 5i32;
@ -39,6 +42,23 @@ impl GuiFileList {
impl EmmaGui { 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) { pub fn video_display(system_to_control: &Chip8Computer, gui_state: &UiState, ui: &Ui) {
// draw area size // draw area size
let draw_area_size = ui.io().display_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; let cell_height = ((draw_area_size[1] as i32 / 32) * 6) / 10;
ui.window(format!("Display {cell_width}x{cell_height}")) ui.window(format!("Display {cell_width}x{cell_height}"))
.size([300.0, 300.0], Condition::FirstUseEver) .size([300.0, 300.0], Condition::Once)
.build(|| { .build(|| {
let origin = ui.cursor_screen_pos(); let origin = ui.cursor_screen_pos();
let fg = ui.get_window_draw_list(); let fg = ui.get_window_draw_list();
@ -94,16 +114,19 @@ impl EmmaGui {
if ui.button("Step") { if ui.button("Step") {
system_to_control.step_system(); system_to_control.step_system();
}; };
ui.same_line();
if ui.button("Run") { if ui.button("Run") {
gui_state.is_running = true; gui_state.is_running = true;
debug!("STARTING THE SYSTEM"); debug!("STARTING THE SYSTEM");
} }
ui.same_line();
if ui.button("Stop") { if ui.button("Stop") {
gui_state.is_running = false; gui_state.is_running = false;
debug!("STOPPING THE SYSTEM"); debug!("STOPPING THE SYSTEM");
} }
ui.same_line(); ui.same_line();
if ui.button("Reset") { if ui.button("Reset") {
gui_state.is_running = false;
*system_to_control = Chip8Computer::new(); *system_to_control = Chip8Computer::new();
} }
if ui.button("Dump Video Memory") { if ui.button("Dump Video Memory") {

View File

@ -10,6 +10,7 @@ use imgui_winit_support::{HiDpiMode, WinitPlatform};
use std::path::Path; use std::path::Path;
use std::time::Instant; use std::time::Instant;
pub mod ui_state;
pub mod emmagui_support; pub mod emmagui_support;
use copypasta::{ClipboardContext, ClipboardProvider}; use copypasta::{ClipboardContext, ClipboardProvider};
use imgui::ClipboardBackend; use imgui::ClipboardBackend;

View File

@ -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,
}
}
}

Binary file not shown.