1use crate::config::{CommonConfig, GameBoyConfig}; 2use crate::mainloop::create::{CreatableEmulator, ReadInputResult}; 3use crate::mainloop::{CreatedEmulator, NativeDebugFn, create, file_name_no_ext}; 4use crate::{NativeEmulator, NativeEmulatorError, NativeEmulatorResult, extensions}; 5use gb_core::api::{BootRoms, GameBoyEmulator}; 6use jgenesis_common::frontend::SaveWriter; 7use jgenesis_native_config::common::WindowSize; 8use jgenesis_native_config::input::mappings::ButtonMappingVec; 9use std::fs; 10use std::path::PathBuf; 11 12pub type NativeGameBoyEmulator = NativeEmulator<GameBoyEmulator>; 13 14impl CreatableEmulator for GameBoyEmulator { 15 type NativeConfig = GameBoyConfig; 16 type CreateInput = Vec<u8>; 17 18 fn read_create_input( 19 config: &Self::NativeConfig, 20 ) -> NativeEmulatorResult<ReadInputResult<Self::CreateInput>> { 21 create::read_rom_file(&config.common.rom_file_path, &extensions::GB_GBC) 22 } 23 24 fn create( 25 input: ReadInputResult<Self::CreateInput>, 26 config: &Self::NativeConfig, 27 save_writer: &mut impl SaveWriter, 28 ) -> NativeEmulatorResult<CreatedEmulator<Self>> { 29 let dmg_boot_rom = load_boot_rom( 30 config.dmg_boot_rom, 31 config.dmg_boot_rom_path.as_ref(), 32 NativeEmulatorError::GbNoDmgBootRom, 33 )?; 34 let cgb_boot_rom = load_boot_rom( 35 config.cgb_boot_rom, 36 config.cgb_boot_rom_path.as_ref(), 37 NativeEmulatorError::GbNoCgbBootRom, 38 )?; 39 let boot_roms = BootRoms { dmg: dmg_boot_rom, cgb: cgb_boot_rom }; 40 41 let emulator = 42 GameBoyEmulator::create(input.input, boot_roms, config.emulator_config, save_writer)?; 43 44 let rom_title = file_name_no_ext(&input.rom_path)?; 45 let window_title = format!("gb - {rom_title}"); 46 47 let default_window_size = WindowSize::new_gb(config.common.initial_window_size); 48 49 Ok(CreatedEmulator { emulator, window_title, default_window_size }) 50 } 51 52 fn common_config(config: &Self::NativeConfig) -> &CommonConfig { 53 &config.common 54 } 55 56 fn emulator_config(config: &Self::NativeConfig) -> &Self::Config { 57 &config.emulator_config 58 } 59 60 fn input_mappings(config: &Self::NativeConfig) -> ButtonMappingVec<'_, Self::Button> { 61 config.inputs.to_mapping_vec() 62 } 63 64 fn turbo_input_mappings(config: &Self::NativeConfig) -> ButtonMappingVec<'_, Self::Button> { 65 config.inputs.to_turbo_mapping_vec() 66 } 67 68 fn debug_fn() -> Option<NativeDebugFn<Self>> { 69 Some(|| { 70 jgenesis_debugger_frontend::partial_clone_debug_fn( 71 jgenesis_debugger_frontend::gb::render_fn(), 72 ) 73 }) 74 } 75} 76 77fn load_boot_rom( 78 load: bool, 79 path: Option<&PathBuf>, 80 no_boot_rom_err: NativeEmulatorError, 81) -> NativeEmulatorResult<Option<Vec<u8>>> { 82 if !load { 83 return Ok(None); 84 } 85 86 let Some(path) = path else { return Err(no_boot_rom_err) }; 87 88 let boot_rom = fs::read(path).map_err(NativeEmulatorError::GbBootRomLoad)?; 89 Ok(Some(boot_rom)) 90}