Skip to content

Commit

Permalink
[frontend] finish up work on the frontend.
Browse files Browse the repository at this point in the history
  • Loading branch information
NightShade256 committed Jan 14, 2021
1 parent 1d84edd commit 8b2424f
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 80 deletions.
12 changes: 3 additions & 9 deletions ferrous-core/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,7 @@ impl CPU {
pub fn load_rom(&mut self, buffer: &[u8]) -> Result<(), String> {
// Return an error, if bounds are exceeded.
if buffer.len() > 3584 {
return Err(
"ROM\'s length is larger than the permitted 3584 bytes."
.to_string(),
);
return Err("ROM\'s length is larger than the permitted 3584 bytes.".to_string());
}

// Copy the ROM buffer.
Expand Down Expand Up @@ -527,8 +524,7 @@ impl CPU {
/// Jump to location nnn + V0.
fn op_bnnn(&mut self, nnn: u16) {
if self.jump_quirk {
self.pc = nnn as usize
+ self.register[(nnn >> 8) as usize & 0xF] as usize;
self.pc = nnn as usize + self.register[(nnn >> 8) as usize & 0xF] as usize;
} else {
self.pc = nnn as usize + self.register[0] as usize;
}
Expand All @@ -555,9 +551,7 @@ impl CPU {
// Super Chip 16x16 sprite
for r in 0..16 {
for c in 0..16 {
let byte = self.memory
[self.i + (r * 2) + (if c > 7 { 1 } else { 0 })]
as usize;
let byte = self.memory[self.i + (r * 2) + (if c > 7 { 1 } else { 0 })] as usize;

if (byte & (0x80 >> (c % 8))) != 0 {
let index = ((x + c) % cols) + ((y + r) % rows) * cols;
Expand Down
1 change: 0 additions & 1 deletion rustfmt.toml

This file was deleted.

49 changes: 43 additions & 6 deletions src/frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ limitations under the License.
use glium::glutin::ContextBuilder;
use glium::glutin::{
dpi::LogicalSize,
event::{Event, WindowEvent},
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{Icon, WindowBuilder},
};
Expand Down Expand Up @@ -54,8 +54,7 @@ fn initialize_display(event_loop: &EventLoop<()>) -> Display {
.with_inner_size(LogicalSize::new(1152, 576));

// Create the glium display, and clear it.
let display = Display::new(wb, cb, &event_loop)
.expect("Failed to initialize the display.");
let display = Display::new(wb, cb, &event_loop).expect("Failed to initialize the display.");

let mut frame = display.draw();
frame.clear_color_srgb(0.0, 0.0, 0.0, 1.0);
Expand All @@ -64,6 +63,40 @@ fn initialize_display(event_loop: &EventLoop<()>) -> Display {
display
}

/// Handle events provided by the OS.
fn handle_keyboard_event(cpu: &mut ferrous_core::CPU, input: &KeyboardInput) {
if let KeyboardInput {
virtual_keycode: Some(keycode),
state,
..
} = input
{
let index = match keycode {
VirtualKeyCode::Key1 => Some(0x1),
VirtualKeyCode::Key2 => Some(0x2),
VirtualKeyCode::Key3 => Some(0x3),
VirtualKeyCode::Key4 => Some(0xC),
VirtualKeyCode::Q => Some(0x4),
VirtualKeyCode::W => Some(0x5),
VirtualKeyCode::E => Some(0x6),
VirtualKeyCode::R => Some(0xD),
VirtualKeyCode::A => Some(0x7),
VirtualKeyCode::S => Some(0x8),
VirtualKeyCode::D => Some(0x9),
VirtualKeyCode::F => Some(0xE),
VirtualKeyCode::Z => Some(0xA),
VirtualKeyCode::X => Some(0x0),
VirtualKeyCode::C => Some(0xB),
VirtualKeyCode::V => Some(0xF),
_ => None,
};

if let Some(i) = index {
cpu.set_key_at_index(i, *state == ElementState::Pressed);
}
}
}

/// Start the emulator, and run until
/// the user requests quitting.
pub fn start() {
Expand Down Expand Up @@ -95,9 +128,7 @@ pub fn start() {
Running => {
for _ in 0..user_interface.state.cycles_per_frame {
if cpu.execute_cycle().is_none() {
eprintln!(
"[WARN] invalid or unknown opcode encountered."
);
eprintln!("[WARN] invalid or unknown opcode encountered.");
}
}

Expand Down Expand Up @@ -128,6 +159,12 @@ pub fn start() {
*control_flow = ControlFlow::Exit;
}

WindowEvent::KeyboardInput { ref input, .. }
if user_interface.state.emulator_state == gui::EmulatorState::Running =>
{
handle_keyboard_event(&mut cpu, input);
}

_ => {}
},

Expand Down
105 changes: 41 additions & 64 deletions src/frontend/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,9 @@ limitations under the License.
//! of Dear ImGui.
use glium::glutin::event::Event;
use glium::{
texture::RawImage2d, uniforms::MagnifySamplerFilter, BlitTarget, Surface,
Texture2d,
};
use glium::{texture::RawImage2d, uniforms::MagnifySamplerFilter, BlitTarget, Surface, Texture2d};
use imgui::{
im_str, ColorEdit, FontConfig, FontId, FontSource, MenuItem, Slider,
SliderFlags, Ui, Window,
im_str, ColorEdit, FontConfig, FontId, FontSource, MenuItem, Slider, SliderFlags, Ui, Window,
};

const EMULATOR_VERSION: &str = env!("CARGO_PKG_VERSION");
Expand Down Expand Up @@ -126,9 +122,8 @@ impl UserInterface {

imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32;

let renderer =
imgui_glium_renderer::Renderer::init(&mut imgui, display)
.expect("Failed to initialize Dear ImGui glium renderer.");
let renderer = imgui_glium_renderer::Renderer::init(&mut imgui, display)
.expect("Failed to initialize Dear ImGui glium renderer.");

Self {
imgui,
Expand Down Expand Up @@ -168,30 +163,24 @@ impl UserInterface {
.map(|x| ((*x) * 255.0).round() as u8)
.collect::<Vec<u8>>();

self.framebuffer.chunks_exact_mut(3).enumerate().for_each(
|(i, rgb)| {
self.framebuffer
.chunks_exact_mut(3)
.enumerate()
.for_each(|(i, rgb)| {
if data[i] == 0 {
rgb.copy_from_slice(&bg);
} else {
rgb.copy_from_slice(&fg);
}
},
);
});
}

/// Let Dear ImGui platform handle window events.
pub fn handle_event(
&mut self,
display: &glium::Display,
event: &Event<()>,
) {
pub fn handle_event(&mut self, display: &glium::Display, event: &Event<()>) {
let gl_window = display.gl_window();

self.platform.handle_event(
self.imgui.io_mut(),
gl_window.window(),
event,
);
self.platform
.handle_event(self.imgui.io_mut(), gl_window.window(), event);
}

pub fn update_delta(&mut self, delta: std::time::Duration) {
Expand All @@ -207,11 +196,7 @@ impl UserInterface {
gl_window.window().request_redraw();
}

pub fn render_ui(
&mut self,
display: &glium::Display,
cpu: &mut ferrous_core::CPU,
) {
pub fn render_ui(&mut self, display: &glium::Display, cpu: &mut ferrous_core::CPU) {
let mut ui = self.imgui.frame();
let gl_window = display.gl_window();

Expand Down Expand Up @@ -268,13 +253,11 @@ fn render_menu(state: &mut State, ui: &mut Ui, cpu: &mut ferrous_core::CPU) {
if let nfd2::Response::Okay(path) = response {
state.emulator_state = EmulatorState::Idle;

let rom = std::fs::read(path)
.expect("Failed to read ROM file.");
let rom = std::fs::read(path).expect("Failed to read ROM file.");

cpu.reset();
cpu.load_rom(&rom).expect(
"Failed to load ROM in interpreter memory.",
);
cpu.load_rom(&rom)
.expect("Failed to load ROM in interpreter memory.");

state.rom_loaded = true;
}
Expand All @@ -288,13 +271,9 @@ fn render_menu(state: &mut State, ui: &mut Ui, cpu: &mut ferrous_core::CPU) {
file_menu.end(ui);
}

if let Some(emulation_menu) = ui.begin_menu(im_str!("Emulation"), true)
{
if let Some(emulation_menu) = ui.begin_menu(im_str!("Emulation"), true) {
if MenuItem::new(im_str!("Start"))
.enabled(
state.emulator_state != EmulatorState::Running
&& state.rom_loaded,
)
.enabled(state.emulator_state != EmulatorState::Running && state.rom_loaded)
.build(ui)
{
state.emulator_state = EmulatorState::Running;
Expand All @@ -317,12 +296,9 @@ fn render_menu(state: &mut State, ui: &mut Ui, cpu: &mut ferrous_core::CPU) {
state.emulator_state = EmulatorState::Idle;
}

MenuItem::new(im_str!("Pallete"))
.build_with_ref(ui, &mut state.pallete_window);
MenuItem::new(im_str!("Pallete")).build_with_ref(ui, &mut state.pallete_window);

if let Some(cycles_menu) =
ui.begin_menu(im_str!("Cycles per Frame"), true)
{
if let Some(cycles_menu) = ui.begin_menu(im_str!("Cycles per Frame"), true) {
Slider::<u16>::new(im_str!("cycles"))
.range(1..=2000)
.flags(SliderFlags::ALWAYS_CLAMP)
Expand All @@ -335,11 +311,9 @@ fn render_menu(state: &mut State, ui: &mut Ui, cpu: &mut ferrous_core::CPU) {
MenuItem::new(im_str!("Load and Store Quirk"))
.build_with_ref(ui, &mut cpu.load_store_quirk);

MenuItem::new(im_str!("Shift Quirk"))
.build_with_ref(ui, &mut cpu.shift_quirk);
MenuItem::new(im_str!("Shift Quirk")).build_with_ref(ui, &mut cpu.shift_quirk);

MenuItem::new(im_str!("Jump Quirk"))
.build_with_ref(ui, &mut cpu.jump_quirk);
MenuItem::new(im_str!("Jump Quirk")).build_with_ref(ui, &mut cpu.jump_quirk);

quirks_menu.end(ui);
}
Expand All @@ -351,8 +325,7 @@ fn render_menu(state: &mut State, ui: &mut Ui, cpu: &mut ferrous_core::CPU) {
MenuItem::new(im_str!("Dear ImGui Metrics"))
.build_with_ref(ui, &mut state.metrics_window);

MenuItem::new(im_str!("About"))
.build_with_ref(ui, &mut state.about_window);
MenuItem::new(im_str!("About")).build_with_ref(ui, &mut state.about_window);

help_menu.end(ui);
}
Expand All @@ -368,20 +341,24 @@ fn render_windows(state: &mut State, ui: &mut Ui) {
let font_id = state.big_font;

Window::new(im_str!("About"))
.bg_alpha(1.0)
.resizable(false)
.opened(&mut state.about_window)
.build(ui, || {
let token = ui.push_font(font_id);
ui.text_colored([0.7, 0.25, 0.1, 1.0], im_str!("Ferrous Chip-8"));
token.pop(&ui);

ui.text(im_str!("A simple, full featured (super) Chip-8 interpreter written in pure Rust."));
ui.separator();
ui.text(im_str!("v{}", EMULATOR_VERSION));
ui.text(im_str!("Author: Anish Jewalikar"));
ui.text(im_str!("Licensed under the terms of the Apache-2.0 license."));
});
.bg_alpha(1.0)
.resizable(false)
.opened(&mut state.about_window)
.build(ui, || {
let token = ui.push_font(font_id);
ui.text_colored([0.7, 0.25, 0.1, 1.0], im_str!("Ferrous Chip-8"));
token.pop(&ui);

ui.text(im_str!(
"A simple, full featured (super) Chip-8 interpreter written in pure Rust."
));
ui.separator();
ui.text(im_str!("v{}", EMULATOR_VERSION));
ui.text(im_str!("Author: Anish Jewalikar"));
ui.text(im_str!(
"Licensed under the terms of the Apache-2.0 license."
));
});
}

if state.metrics_window {
Expand Down

0 comments on commit 8b2424f

Please sign in to comment.