diff --git a/Cargo.toml b/Cargo.toml index 974041944ff40f1ce55168279fcbcfd3a99782d4..d03d2c3b56592aa751c23f8b5ac9a08205c9a897 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "boytacean" +description = "A Game Boy emulator that is written in Rust." version = "0.1.0" authors = ["João Magalhães <joamag@gmail.com>"] -description = "Game Boy in Rust" license = "Apache" keywords = ["gameboy", "emulator", "rust"] edition = "2018" diff --git a/examples/sdl/src/main.rs b/examples/sdl/src/main.rs index 965230e0d64150d2b87907dd290b1cbab3501b61..437fdbb0fa9863ad431adb3d294b88abff6ba84e 100644 --- a/examples/sdl/src/main.rs +++ b/examples/sdl/src/main.rs @@ -81,7 +81,7 @@ fn main() { // creates a new Game Boy instance and loads both the boot ROM // and the initial game ROM to "start the engine" let mut game_boy = GameBoy::new(); - game_boy.load_boot_static(); + game_boy.load_boot_default(); game_boy.load_rom_file("../../res/roms.prop/tetris.gb"); //game_boy.load_rom_file("../../res/roms.prop/alleyway.gb"); diff --git a/examples/web/index.ts b/examples/web/index.ts index 5f20f7c039382d72f9115ee48b66821a10a25c1b..6149a76e74a1b55424726463fdc67fa26b45f43d 100644 --- a/examples/web/index.ts +++ b/examples/web/index.ts @@ -1,4 +1,4 @@ -import { default as wasm, GameBoy } from "./lib/boytacean.js"; +import { BootRom, default as wasm, GameBoy } from "./lib/boytacean.js"; import info from "./package.json"; const PIXEL_UNSET_COLOR = 0x1b1a17ff; @@ -302,7 +302,7 @@ const start = async ({ // resets the Game Boy engine to restore it into // a valid state ready to be used state.gameBoy.reset(); - state.gameBoy.load_boot_static(); + state.gameBoy.load_boot_default(); state.gameBoy.load_rom(romData); // updates the name of the currently selected engine @@ -534,17 +534,27 @@ const registerButtons = () => { separatorNarrative.style.display = "none"; buttonDebug.classList.add("enabled"); - const canvasTiles = document.getElementById("canvas-tiles") as HTMLCanvasElement; + const canvasTiles = document.getElementById( + "canvas-tiles" + ) as HTMLCanvasElement; const canvasTilesCtx = canvasTiles.getContext("2d"); - const canvasImage = canvasTilesCtx.createImageData(canvasTiles.width, canvasTiles.height); + const canvasImage = canvasTilesCtx.createImageData( + canvasTiles.width, + canvasTiles.height + ); const videoBuff = new DataView(canvasImage.data.buffer); - const drawSprite = (index: number, format: PixelFormat = PixelFormat.RGB) => { + const drawSprite = ( + index: number, + format: PixelFormat = PixelFormat.RGB + ) => { const pixels = state.gameBoy.get_tile_buffer(index); const line = Math.floor(index / 16); const column = index % 16; - let offset = ((line * canvasTiles.width * 8) + (column * 8)) * PixelFormat.RGBA; + let offset = + (line * canvasTiles.width * 8 + column * 8) * + PixelFormat.RGBA; let counter = 0; for (let index = 0; index < pixels.length; index += format) { const color = @@ -553,7 +563,7 @@ const registerButtons = () => { (pixels[index + 2] << 8) | (format == PixelFormat.RGBA ? pixels[index + 3] : 0xff); videoBuff.setUint32(offset, color); - + counter++; if (counter == 8) { counter = 0; @@ -563,7 +573,7 @@ const registerButtons = () => { } } canvasTilesCtx.putImageData(canvasImage, 0, 0); - } + }; for (let index = 0; index < 256; index++) { drawSprite(index); @@ -743,7 +753,10 @@ const initCanvas = async () => { state.videoBuff = new DataView(state.image.data.buffer); }; -const updateCanvas = (pixels: Uint8Array, format: PixelFormat = PixelFormat.RGB) => { +const updateCanvas = ( + pixels: Uint8Array, + format: PixelFormat = PixelFormat.RGB +) => { let offset = 0; for (let index = 0; index < pixels.length; index += format) { const color = diff --git a/src/data.rs b/src/data.rs index ff50d1488682dc41c43751e679eaad67f5303065..c9330da6e7c417932c73e6ade7f54d794db89d5f 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,3 +1,14 @@ +#[cfg(feature = "wasm")] +use wasm_bindgen::prelude::*; + +#[cfg_attr(feature = "wasm", wasm_bindgen)] +pub enum BootRom { + Dmg, + Sgb, + DmgBootix, + MgbBootix, +} + /// Static data corresponding to the DMG boot ROM /// allows freely using the emulator without external dependency. pub const DMG_BOOT: [u8; 256] = [ diff --git a/src/gb.rs b/src/gb.rs index b8fb338da93ddc2f0161604ff23335a3d174148e..715b9600295497ad1b5fc83805c009edfb9905c0 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -1,6 +1,6 @@ use crate::{ cpu::Cpu, - data::{DMG_BOOT, DMG_BOOTIX, MGB_BOOTIX, SGB_BOOT}, + data::{BootRom, DMG_BOOT, DMG_BOOTIX, MGB_BOOTIX, SGB_BOOT}, mmu::Mmu, pad::Pad, ppu::{Ppu, Tile, FRAME_BUFFER_SIZE}, @@ -66,49 +66,35 @@ impl GameBoy { self.cpu.mmu().write_boot(0x0000, data); } - pub fn load_boot_file(&mut self, path: &str) { + pub fn load_boot_path(&mut self, path: &str) { let data = read_file(path); self.load_boot(&data); } - pub fn load_boot_dmg_f(&mut self) { - self.load_boot_file("./res/boot/dmg_boot.bin"); + pub fn load_boot_file(&mut self, boot_rom: BootRom) { + match boot_rom { + BootRom::Dmg => self.load_boot_path("./res/boot/dmg_boot.bin"), + BootRom::Sgb => self.load_boot_path("./res/boot/sgb_boot.bin"), + BootRom::DmgBootix => self.load_boot_path("./res/boot/dmg_bootix.bin"), + BootRom::MgbBootix => self.load_boot_path("./res/boot/mgb_bootix.bin"), + } } - pub fn load_boot_sgb_f(&mut self) { - self.load_boot_file("./res/boot/sgb_boot.bin"); + pub fn load_boot_default_f(&mut self) { + self.load_boot_file(BootRom::DmgBootix); } - pub fn load_boot_dmg_bootix_f(&mut self) { - self.load_boot_file("./res/boot/dmg_bootix.bin"); - } - - pub fn load_boot_mgb_bootix_f(&mut self) { - self.load_boot_file("./res/boot/mgb_bootix.bin"); + pub fn load_boot_static(&mut self, boot_rom: BootRom) { + match boot_rom { + BootRom::Dmg => self.load_boot(&DMG_BOOT), + BootRom::Sgb => self.load_boot(&SGB_BOOT), + BootRom::DmgBootix => self.load_boot(&DMG_BOOTIX), + BootRom::MgbBootix => self.load_boot(&MGB_BOOTIX), + } } pub fn load_boot_default(&mut self) { - self.load_boot_dmg_bootix_f(); - } - - pub fn load_boot_dmg(&mut self) { - self.load_boot(&DMG_BOOT); - } - - pub fn load_boot_sgb(&mut self) { - self.load_boot(&SGB_BOOT); - } - - pub fn load_boot_dmg_bootix(&mut self) { - self.load_boot(&DMG_BOOTIX); - } - - pub fn load_boot_mgb_bootix(&mut self) { - self.load_boot(&MGB_BOOTIX); - } - - pub fn load_boot_static(&mut self) { - self.load_boot_dmg_bootix(); + self.load_boot_static(BootRom::DmgBootix); } pub fn vram_eager(&mut self) -> Vec<u8> { diff --git a/src/pad.rs b/src/pad.rs index 785b8f89ea0aa5a14bfd9c30489544368d96bd2d..f147fb5029b40c8325648ea14881dcebcf535d4d 100644 --- a/src/pad.rs +++ b/src/pad.rs @@ -16,6 +16,17 @@ pub enum PadSelection { Direction, } +pub enum PadKey { + Up, + Down, + Left, + Right, + Start, + Select, + A, + B, +} + impl Pad { pub fn new() -> Self { Self { diff --git a/src/ppu.rs b/src/ppu.rs index 4dc382734fdadbe5e1b7db74568c110394ef6741..b2065dfb9e6158ede31e772c01e095d03082addb 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -290,8 +290,6 @@ impl Ppu { if self.ly == 144 { self.int_vblank = true; self.mode = PpuMode::VBlank; - // self.drawData - // @todo implement this one } else { self.mode = PpuMode::OamRead; }