Skip to content

Commit

Permalink
Cleaned up to use iced 0.13. Split ghast into an library and binary
Browse files Browse the repository at this point in the history
  • Loading branch information
TylerBloom committed Oct 3, 2024
1 parent 5d1156c commit 7a6cfb9
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 76 deletions.
8 changes: 8 additions & 0 deletions ghast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ name = "ghast"
version = "0.1.0"
edition = "2021"

[lib]
name = "ghast"
path = "src/lib.rs"

[[bin]]
name = "ghast"
path = "src/main.rs"

[dependencies]
iced = { version = "0.13.1", features = ["advanced", "canvas", "image", "tokio"] }
itertools = "0.13.0"
Expand Down
14 changes: 9 additions & 5 deletions ghast/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use iced::{
widget::{image::Handle, column, row, text, Column, Image, Row},
widget::{column, image::Handle, row, text, Column, Image, Row},
Element,
};
use itertools::Itertools;

use spirit::{
cpu::check_bit_const,
mem::OamObjectIndex,
Expand All @@ -15,7 +15,7 @@ pub struct Debugger(pub u8);

impl Debugger {
pub fn view<M: 'static>(&self, gb: &Gameboy) -> impl Into<Element<'static, M>> {
println!("Screen pos: ({}, {})", gb.mem[0xFF43], gb.mem[0xFF42]);
println!("Screen pos: ({}, {})", gb.mem[0xFF43], gb.mem[0xFF42]);
row![
column![
Column::from_vec(vram_0_to_tiles(gb, self.0).map(Into::into).collect()).spacing(3),
Expand Down Expand Up @@ -62,7 +62,11 @@ fn tile_map<M: 'static>(map: &[u8]) -> impl '_ + Iterator<Item = impl Into<Eleme
val
})
.collect::<Vec<Vec<Element<'static, M>>>>();
cols[0].extend((0..32).map(|index| text(format!("{index:0>2X }"))).map(Into::into));
cols[0].extend(
(0..32)
.map(|index| text(format!("{index:0>2X }")))
.map(Into::into),
);
map.iter()
.copied()
.map(to_str)
Expand Down Expand Up @@ -158,7 +162,7 @@ fn tiles_into_rows<M>(iter: impl Iterator<Item = [[Pixel; 8]; 8]>) -> Row<'stati
}

fn pixels_to_image(chunk: [[Pixel; 8]; 8]) -> Image<Handle> {
Image::new(Handle::from_pixels(
Image::new(Handle::from_rgba(
8,
8,
chunk
Expand Down
5 changes: 5 additions & 0 deletions ghast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#![allow(unused)]

pub mod debug;
pub mod state;
pub mod utils;
16 changes: 4 additions & 12 deletions ghast/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
#![allow(unused)]

use iced::{Application, Settings};
use state::Example;

mod debug;
mod state;
mod utils;
use ghast::state::Emulator;

pub fn main() -> iced::Result {
Example::run(Settings {
antialiasing: true,
..Settings::default()
})
iced::application("Specters - Ghast GBC", Emulator::update, Emulator::view)
.subscription(Emulator::subscription)
.run()
}
86 changes: 32 additions & 54 deletions ghast/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use iced::{
executor,
widget::{column, image::Handle, row, text, Button, Image, Scrollable},
Alignment, Application, Element, Subscription, Theme,
Alignment, Element, Subscription,
};
use spirit::{Gameboy, StartUpSequence};

use crate::debug::{pixel_to_bytes, Debugger};

pub struct Example {
gb: Emulator,
pub struct Emulator {
gb: EmulatorInner,
frame: usize,
count: Option<usize>,
dbg: Debugger,
Expand All @@ -25,36 +24,28 @@ pub enum Message {
}

#[allow(clippy::large_enum_variant)]
enum Emulator {
enum EmulatorInner {
StartUp(Option<Box<StartUpSequence>>),
Ready(Gameboy),
}

impl Emulator {
impl EmulatorInner {
fn gb(&self) -> &Gameboy {
match self {
Emulator::StartUp(seq) => seq.as_ref().unwrap().gb(),
Emulator::Ready(gb) => gb,
}
}

fn is_complete(&self) -> bool {
match self {
Emulator::StartUp(seq) => seq.as_ref().unwrap().is_complete(),
// TODO: This should probably check if the GB is halted...
Emulator::Ready(gb) => gb.is_stopped(),
EmulatorInner::StartUp(seq) => seq.as_ref().unwrap().gb(),
EmulatorInner::Ready(gb) => gb,
}
}

fn frame_step(&mut self) {
match self {
Emulator::StartUp(seq) => {
EmulatorInner::StartUp(seq) => {
seq.as_mut().unwrap().frame_step().complete();
if seq.as_ref().unwrap().is_complete() {
*self = Emulator::Ready(seq.take().unwrap().complete())
*self = EmulatorInner::Ready(seq.take().unwrap().complete())
}
}
Emulator::Ready(gb) => {
EmulatorInner::Ready(gb) => {
if !gb.is_stopped() {
gb.next_frame().complete()
} else {
Expand All @@ -66,13 +57,13 @@ impl Emulator {

fn scanline_step(&mut self) {
match self {
Emulator::StartUp(seq) => {
EmulatorInner::StartUp(seq) => {
seq.as_mut().unwrap().scanline_step();
if seq.as_ref().unwrap().is_complete() {
*self = Emulator::Ready(seq.take().unwrap().complete())
*self = EmulatorInner::Ready(seq.take().unwrap().complete())
}
}
Emulator::Ready(gb) => {
EmulatorInner::Ready(gb) => {
if !gb.is_stopped() {
gb.scanline_step()
}
Expand All @@ -81,7 +72,7 @@ impl Emulator {
}
}

impl Example {
impl Emulator {
fn screen(&self) -> impl Into<Element<Message>> {
let gb = self.gb.gb();
let screen = &gb.ppu.screen;
Expand All @@ -102,30 +93,20 @@ impl Example {
}
}

impl Application for Example {
type Message = Message;
type Executor = executor::Default;
type Theme = Theme;
type Flags = ();

fn new((): ()) -> (Self, iced::Command<Message>) {
impl Default for Emulator {
fn default() -> Self {
let gb = Gameboy::new(include_bytes!("../../spirit/tests/roms/acid/cgb-acid2.gbc"));
(
Self {
gb: Emulator::StartUp(Some(Box::new(gb.start_up()))),
count: Some(0),
frame: 0,
dbg: Debugger(0),
},
iced::Command::none(),
)
}

fn title(&self) -> String {
String::from("GameBoy!!!")
Self {
gb: EmulatorInner::StartUp(Some(Box::new(gb))),
count: Some(0),
frame: 0,
dbg: Debugger(0),
}
}
}

fn update(&mut self, msg: Message) -> iced::Command<Message> {
impl Emulator {
pub fn update(&mut self, msg: Message) {
match msg {
Message::Play => self.count = None,
Message::Pause => self.count = Some(0),
Expand All @@ -147,36 +128,33 @@ impl Application for Example {
self.gb.frame_step()
}
},
Message::ScanLine => {
self.gb.scanline_step()
}
Message::ScanLine => self.gb.scanline_step(),
Message::PaletteInc => self.dbg.inc(),
}
iced::Command::none()
}

fn view(&self) -> Element<Message> {
pub fn view(&self) -> Element<Message> {
column![
row![
Button::new(text(format!("To frame {}", self.frame + 1)))
.on_press(Message::Step(1)),
Button::new(text(format!("To frame {}", self.frame + 10)))
.on_press(Message::Step(10)),
Button::new(text("Next Scanline"))
.on_press(Message::ScanLine),
Button::new(text("Next Scanline")).on_press(Message::ScanLine),
Button::new(text("Run")).on_press(Message::Play),
Button::new(text("Pause")).on_press(Message::Pause),
Button::new(text(format!("Change palette from {}", self.dbg.0))).on_press(Message::PaletteInc),
Button::new(text(format!("Change palette from {}", self.dbg.0)))
.on_press(Message::PaletteInc),
],
self.screen().into(),
]
.padding(20)
.spacing(20)
.align_items(Alignment::Center)
.align_x(Alignment::Center)
.into()
}

fn subscription(&self) -> Subscription<Message> {
pub fn subscription(&self) -> Subscription<Message> {
match self.count {
Some(0) => Subscription::none(),
_ => iced::time::every(std::time::Duration::from_millis(33)).map(|_| Message::Tick),
Expand Down
2 changes: 0 additions & 2 deletions ghast/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


/// Scales an image by a set factor, preserving the original ratio.
fn scale_up_image(image: &[u8], height: usize, width: usize, scale: usize) -> Vec<u8> {
assert_eq!(image.len(), 4 * height * width);
Expand Down
7 changes: 4 additions & 3 deletions tombstone/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use std::fmt::Write;
use std::{error::Error, io::Write as _};

use ratatui::layout::Position;
use ratatui::{
backend::{Backend, CrosstermBackend},
layout::{Constraint, Direction, Layout, Rect},
Expand All @@ -27,7 +28,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let backend = CrosstermBackend::new(std::io::stdout());
let mut term = Terminal::new(backend)?;
term.clear()?;
let mut gb = Gameboy::new(TMP_ROM).start_up();
let mut gb = Gameboy::new(TMP_ROM);
run_until_complete(gb, &mut state, &mut term)?;
println!("Startup sequence complete!");
// run_until_complete(gb, &mut state, &mut term)?;
Expand Down Expand Up @@ -59,7 +60,7 @@ fn render_frame(frame: &mut Frame, state: &mut AppState, gb: &Gameboy) {
let sections = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Fill(1), Constraint::Length(40)])
.split(frame.size());
.split(frame.area());
let left = sections[0];
let right = sections[1];
let left = Layout::default()
Expand Down Expand Up @@ -99,7 +100,7 @@ fn render_cli(frame: &mut Frame, state: &mut AppState, area: Rect) {
.rev()
.map(|s| s.as_str());
let para = Paragraph::new(Text::from_iter(iter)).block(block);
frame.set_cursor(x, cursor_y);
frame.set_cursor_position(Position::new(x, cursor_y));
frame.render_widget(para, area);
}

Expand Down

0 comments on commit 7a6cfb9

Please sign in to comment.