Skip to content
Snippets Groups Projects
gb.rs 33.2 KiB
Newer Older
  • Learn to ignore specific revisions
  •     pub fn load_boot_path(&mut self, path: &str) -> Result<(), String> {
            let data = read_file(path)?;
    
            self.load_boot(&data);
    
        pub fn load_boot_file(&mut self, boot_rom: BootRom) -> Result<(), String> {
    
            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")?,
                BootRom::Cgb => self.load_boot_path("./res/boot/cgb_boot.bin")?,
    
                BootRom::None => (),
    
        pub fn load_boot_default_f(&mut self) -> Result<(), String> {
            self.load_boot_dmg_f()?;
            Ok(())
    
        pub fn load_boot_dmg_f(&mut self) -> Result<(), String> {
            self.load_boot_file(BootRom::DmgBootix)?;
            Ok(())
    
        pub fn load_boot_cgb_f(&mut self) -> Result<(), String> {
            self.load_boot_file(BootRom::Cgb)?;
            Ok(())
    
        pub fn load_cartridge(&mut self, rom: Cartridge) -> &mut Cartridge {
            self.mmu().set_rom(rom);
    
            self.mmu().rom()
    
        pub fn load_rom(&mut self, data: &[u8], ram_data: Option<&[u8]>) -> &mut Cartridge {
            let mut rom = Cartridge::from_data(data);
    
    João Magalhães's avatar
    João Magalhães committed
            if let Some(ram_data) = ram_data {
                rom.set_ram_data(ram_data)
    
            self.load_cartridge(rom)
    
        pub fn load_rom_file(&mut self, path: &str, ram_path: Option<&str>) -> &mut Cartridge {
    
            let data = read_file(path).unwrap();
    
            match ram_path {
                Some(ram_path) => {
    
                    let ram_data = read_file(ram_path).unwrap();
    
                    self.load_rom(&data, Some(&ram_data))
                }
                None => self.load_rom(&data, None),
            }
    
    
        pub fn attach_serial(&mut self, device: Box<dyn SerialDevice>) {
            self.serial().set_device(device);
        }
    
    
        pub fn set_speed_callback(&mut self, callback: fn(speed: GameBoySpeed)) {
            self.mmu().set_speed_callback(callback);
        }
    
        pub fn reset_cheats(&mut self) {
            self.reset_game_genie();
    
            self.reset_game_shark();
    
        pub fn add_cheat_code(&mut self, code: &str) -> Result<bool, String> {
    
            if GameGenie::is_code(code) {
                return match self.add_game_genie_code(code) {
                    Ok(_) => Ok(true),
                    Err(message) => Err(message),
                };
    
    
            if GameShark::is_code(code) {
                return match self.add_game_shark_code(code) {
                    Ok(_) => Ok(true),
                    Err(message) => Err(message),
                };
            }
    
            Err(String::from("Not a valid cheat code"))
    
        pub fn add_game_genie_code(&mut self, code: &str) -> Result<&GameGenieCode, String> {
            let rom = self.mmu().rom();
            if rom.game_genie().is_none() {
                let game_genie = GameGenie::default();
                rom.attach_genie(game_genie);
            }
            let game_genie = rom.game_genie_mut().as_mut().unwrap();
            game_genie.add_code(code)
        }
    
    
        pub fn add_game_shark_code(&mut self, code: &str) -> Result<&GameSharkCode, String> {
            let rom = self.mmu().rom();
            if rom.game_shark().is_none() {
                let game_shark = GameShark::default();
                rom.attach_shark(game_shark);
            }
            let game_shark = rom.game_shark_mut().as_mut().unwrap();
            game_shark.add_code(code)
        }
    
    
        pub fn reset_game_genie(&mut self) {
            let rom = self.mmu().rom();
            if rom.game_genie().is_some() {
                rom.game_genie_mut().as_mut().unwrap().reset();
            }
        }
    
        pub fn reset_game_shark(&mut self) {
            let rom = self.mmu().rom();
            if rom.game_shark().is_some() {
                rom.game_shark_mut().as_mut().unwrap().reset();
            }
        }
    
    #[cfg(feature = "wasm")]
    
    #[cfg_attr(feature = "wasm", wasm_bindgen)]
    impl GameBoy {
    
        pub fn set_panic_hook_ws() {
            let prev = take_hook();
            set_hook(Box::new(move |info| {
                hook_impl(info);
                prev(info);
            }));
        }
    
        pub fn load_rom_ws(&mut self, data: &[u8]) -> Cartridge {
    
    João Magalhães's avatar
    João Magalhães committed
            let rom = self.load_rom(data, None);
    
            rom.set_rumble_cb(|active| {
                rumble_callback(active);
            });
            rom.clone()
    
        pub fn load_callbacks_ws(&mut self) {
            self.set_speed_callback(|speed| {
                speed_callback(speed);
            });
        }
    
    
        pub fn load_null_ws(&mut self) {
            let null = Box::<NullDevice>::default();
            self.attach_serial(null);
        }
    
        pub fn load_logger_ws(&mut self) {
            let mut logger = Box::<StdoutDevice>::default();
            logger.set_callback(|data| {
                logger_callback(data.to_vec());
            });
            self.attach_serial(logger);
        }
    
    
        pub fn load_printer_ws(&mut self) {
            let mut printer = Box::<PrinterDevice>::default();
            printer.set_callback(|image_buffer| {
                printer_callback(image_buffer.to_vec());
            });
            self.attach_serial(printer);
        }
    
    
        /// Updates the emulation mode using the cartridge
        /// of the provided data to obtain the CGB flag value.
        pub fn infer_mode_ws(&mut self, data: &[u8]) {
            let mode = Cartridge::from_data(data).gb_mode();
            self.set_mode(mode);
        }
    
    
        pub fn set_palette_colors_ws(&mut self, value: Vec<JsValue>) {
            let palette: Palette = value
                .into_iter()
    
                .map(|v| Self::js_to_pixel(&v))
    
                .collect::<Vec<Pixel>>()
    
                .try_into()
                .unwrap();
            self.ppu().set_palette_colors(&palette);
        }
    
    
        pub fn wasm_engine_ws(&self) -> Option<String> {
    
            let dependencies = dependencies_map();
            if !dependencies.contains_key("wasm-bindgen") {
    
            Some(String::from(format!(
    
                "wasm-bindgen/{}",
                *dependencies.get("wasm-bindgen").unwrap()
    
        fn js_to_pixel(value: &JsValue) -> Pixel {
    
            value
                .as_string()
                .unwrap()
                .chars()
                .collect::<Vec<char>>()
                .chunks(2)
                .map(|s| s.iter().collect::<String>())
                .map(|s| u8::from_str_radix(&s, 16).unwrap())
                .collect::<Vec<u8>>()
                .try_into()
                .unwrap()
        }
    
    
    #[cfg(feature = "wasm")]
    #[wasm_bindgen]
    extern "C" {
        #[wasm_bindgen(js_namespace = window)]
    
    João Magalhães's avatar
    João Magalhães committed
        fn panic(message: &str);
    
        #[wasm_bindgen(js_namespace = window, js_name = speedCallback)]
        fn speed_callback(speed: GameBoySpeed);
    
    
        #[wasm_bindgen(js_namespace = window, js_name = loggerCallback)]
        fn logger_callback(data: Vec<u8>);
    
    
        #[wasm_bindgen(js_namespace = window, js_name = printerCallback)]
        fn printer_callback(image_buffer: Vec<u8>);
    
    
        #[wasm_bindgen(js_namespace = window, js_name = rumbleCallback)]
        fn rumble_callback(active: bool);
    
    }
    
    #[cfg(feature = "wasm")]
    pub fn hook_impl(info: &PanicInfo) {
    
    João Magalhães's avatar
    João Magalhães committed
        let message = info.to_string();
        panic(message.as_str());
    
    impl AudioProvider for GameBoy {
    
        fn audio_output(&self) -> u8 {
    
            self.apu_i().output()
    
        fn audio_buffer(&self) -> &VecDeque<u8> {
    
            self.apu_i().audio_buffer()
    
        fn clear_audio_buffer(&mut self) {
    
            self.apu().clear_audio_buffer()
    
    impl Default for GameBoy {
        fn default() -> Self {
    
            Self::new(None)
    
    
    impl Display for GameBoy {
        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
            write!(f, "{}", self.description(9))
        }
    }