config!!!
This commit is contained in:
parent
71bb9f8e6d
commit
d3d2de183c
6 changed files with 338 additions and 135 deletions
44
Cargo.lock
generated
44
Cargo.lock
generated
|
@ -364,6 +364,9 @@ name = "bitflags"
|
|||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
|
@ -975,6 +978,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "directories"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "1.0.2"
|
||||
|
@ -985,6 +997,18 @@ dependencies = [
|
|||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
|
@ -1255,6 +1279,7 @@ dependencies = [
|
|||
"ash-window",
|
||||
"async-ringbuf",
|
||||
"bytemuck",
|
||||
"directories",
|
||||
"futures",
|
||||
"itertools",
|
||||
"librashader",
|
||||
|
@ -1263,6 +1288,7 @@ dependencies = [
|
|||
"pixels",
|
||||
"rand",
|
||||
"raw-window-handle",
|
||||
"ron",
|
||||
"serde",
|
||||
"serde_with",
|
||||
]
|
||||
|
@ -2514,6 +2540,12 @@ version = "1.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.46"
|
||||
|
@ -2887,6 +2919,18 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ron"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitflags 2.4.0",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.14.1"
|
||||
|
|
|
@ -5,13 +5,15 @@ use camera::Webcam;
|
|||
use clap::{ArgGroup, Parser};
|
||||
use debug::Debugger;
|
||||
use gb_emu_lib::{
|
||||
config::ConfigManager,
|
||||
connect::{
|
||||
EmulatorCoreTrait, EmulatorMessage, EmulatorOptions, NoCamera, RomFile, SerialTarget,
|
||||
StdoutType,
|
||||
CgbRomType, EmulatorCoreTrait, EmulatorMessage, EmulatorOptions, NoCamera, RomFile,
|
||||
SerialTarget, SramType, StdoutType,
|
||||
},
|
||||
EmulatorCore,
|
||||
};
|
||||
use gilrs::Gilrs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
sync::mpsc::channel,
|
||||
|
@ -47,14 +49,6 @@ struct Args {
|
|||
#[arg(long)]
|
||||
no_save: bool,
|
||||
|
||||
/// BootROM path
|
||||
#[arg(short, long)]
|
||||
bootrom: Option<String>,
|
||||
|
||||
/// Shader path
|
||||
#[arg(long)]
|
||||
shader: Option<String>,
|
||||
|
||||
/// Output link port to stdout as ASCII
|
||||
#[arg(long)]
|
||||
ascii: bool,
|
||||
|
@ -71,10 +65,6 @@ struct Args {
|
|||
#[arg(long)]
|
||||
layer_window: bool,
|
||||
|
||||
/// Scale display by...
|
||||
#[arg(short, long)]
|
||||
scale_factor: Option<usize>,
|
||||
|
||||
/// Mute audio
|
||||
#[arg(long)]
|
||||
mute: bool,
|
||||
|
@ -82,19 +72,23 @@ struct Args {
|
|||
/// Run debug console
|
||||
#[arg(long)]
|
||||
debug: bool,
|
||||
|
||||
/// Prefer DMG mode
|
||||
#[arg(short, long)]
|
||||
dmg: bool,
|
||||
|
||||
/// Show BootROM
|
||||
#[arg(long)]
|
||||
show_bootrom: bool,
|
||||
// /// Use webcam as Pocket Camera emulation
|
||||
// #[arg(short, long)]
|
||||
// camera: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct StandaloneConfig {
|
||||
scale_factor: usize,
|
||||
}
|
||||
|
||||
impl Default for StandaloneConfig {
|
||||
fn default() -> Self {
|
||||
Self { scale_factor: 3 }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
|
@ -114,8 +108,6 @@ struct EmulatorHandler {
|
|||
|
||||
impl EmulatorHandler {
|
||||
fn run(args: Args) -> ! {
|
||||
let factor = args.scale_factor.unwrap_or(3);
|
||||
|
||||
let (sender, receiver) = channel::<EmulatorMessage>();
|
||||
|
||||
{
|
||||
|
@ -126,52 +118,60 @@ impl EmulatorHandler {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
let config_manager = ConfigManager::get().expect("Could not open config folder");
|
||||
let config = config_manager.load_or_create_base_config();
|
||||
let standalone_config: StandaloneConfig =
|
||||
config_manager.load_or_create_config("standalone");
|
||||
|
||||
let (output, _stream) = audio::create_output(args.mute);
|
||||
let rom = RomFile::Path(args.rom);
|
||||
let rom_file = RomFile::Path(PathBuf::from(args.rom));
|
||||
|
||||
let (rom, camera) = rom_file
|
||||
.load(
|
||||
args.save.map(SramType::File).unwrap_or(SramType::Auto),
|
||||
NoCamera::default(),
|
||||
)
|
||||
.expect("Error parsing rom");
|
||||
|
||||
let shader_path = if rom.rom_type == CgbRomType::CgbOnly || config.prefer_cgb {
|
||||
config.vulkan_config.cgb_shader_path.as_ref()
|
||||
} else {
|
||||
config.vulkan_config.dmg_shader_path.as_ref()
|
||||
}
|
||||
.map(|v| config_manager.dir().join(v));
|
||||
|
||||
let mut window_manager = WindowManager::new(sender);
|
||||
|
||||
let window = window_manager.add(
|
||||
factor,
|
||||
standalone_config.scale_factor,
|
||||
Some(Gilrs::new().unwrap()),
|
||||
args.shader.map(PathBuf::from),
|
||||
shader_path,
|
||||
);
|
||||
|
||||
let tile_window: Option<WindowRenderer> = if args.tile_window {
|
||||
Some(window_manager.add(factor, None, None))
|
||||
Some(window_manager.add(standalone_config.scale_factor, None, None))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let layer_window: Option<WindowRenderer> = if args.layer_window {
|
||||
Some(window_manager.add(factor.min(2), None, None))
|
||||
Some(window_manager.add(standalone_config.scale_factor.min(2), None, None))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let options = EmulatorOptions::new(window, rom, output)
|
||||
.with_save_path(args.save)
|
||||
.with_serial_target(if args.ascii {
|
||||
SerialTarget::Stdout(StdoutType::Ascii)
|
||||
} else if args.hex {
|
||||
SerialTarget::Stdout(StdoutType::Hex)
|
||||
} else {
|
||||
SerialTarget::None
|
||||
})
|
||||
.with_bootrom(
|
||||
args.bootrom
|
||||
.or(if args.dmg {
|
||||
std::env::var("DMG_BOOTROM").ok()
|
||||
} else {
|
||||
std::env::var("CGB_BOOTROM").ok()
|
||||
})
|
||||
.map(RomFile::Path),
|
||||
args.show_bootrom,
|
||||
)
|
||||
.with_no_save(args.no_save)
|
||||
.with_tile_window(tile_window)
|
||||
.with_layer_window(layer_window)
|
||||
.with_cgb_mode(!args.dmg);
|
||||
let options =
|
||||
EmulatorOptions::new_with_config(config, config_manager.dir(), window, rom, output)
|
||||
.with_serial_target(if args.ascii {
|
||||
SerialTarget::Stdout(StdoutType::Ascii)
|
||||
} else if args.hex {
|
||||
SerialTarget::Stdout(StdoutType::Hex)
|
||||
} else {
|
||||
SerialTarget::None
|
||||
})
|
||||
.with_no_save(args.no_save)
|
||||
.with_tile_window(tile_window)
|
||||
.with_layer_window(layer_window);
|
||||
|
||||
// let core: Box<dyn EmulatorCoreTrait> = if args.camera {
|
||||
// Box::new(EmulatorCore::init(receiver, options, Webcam::new()))
|
||||
|
@ -181,7 +181,7 @@ impl EmulatorHandler {
|
|||
|
||||
#[cfg(not(feature = "camera"))]
|
||||
let core: Box<dyn EmulatorCoreTrait> =
|
||||
Box::new(EmulatorCore::init(receiver, options, NoCamera::default()));
|
||||
Box::new(EmulatorCore::init(receiver, options, camera));
|
||||
#[cfg(feature = "camera")]
|
||||
let core = Box::new(EmulatorCore::init(receiver, options, Webcam::new()));
|
||||
|
||||
|
|
113
lib/src/config/mod.rs
Normal file
113
lib/src/config/mod.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use std::{
|
||||
fs,
|
||||
io::{BufReader, BufWriter},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
pub struct ConfigManager {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl ConfigManager {
|
||||
pub fn get() -> Option<Self> {
|
||||
directories::ProjectDirs::from("com", "alexjanka", "TWINC")
|
||||
.map(|v| v.config_dir().to_path_buf())
|
||||
.map(|path| {
|
||||
if let Ok(false) = path.try_exists() {
|
||||
fs::create_dir_all(path.clone()).expect("Failed to create config dir");
|
||||
};
|
||||
Self { path }
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dir(&self) -> PathBuf {
|
||||
self.path.clone()
|
||||
}
|
||||
|
||||
pub fn load_or_create_base_config(&self) -> Config {
|
||||
self.load_or_create_config("base")
|
||||
}
|
||||
|
||||
pub fn load_or_create_config<C>(&self, name: &str) -> C
|
||||
where
|
||||
C: Serialize + DeserializeOwned + Default + Clone,
|
||||
{
|
||||
match self.load_custom_config(name) {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
let config = C::default();
|
||||
if let Ok(true) = self.path.join(name).try_exists() {
|
||||
eprintln!("Failed to load \"{name}\" config, but it exists on disk");
|
||||
} else {
|
||||
let result = self.save_custom_config(name, config.clone());
|
||||
if let Err(e) = result {
|
||||
eprintln!("Failed to save \"{name}\" config: {e:#?}");
|
||||
}
|
||||
}
|
||||
config
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_custom_config<C>(&self, name: &str) -> Option<C>
|
||||
where
|
||||
C: DeserializeOwned + Default,
|
||||
{
|
||||
let path = self.path.join(name);
|
||||
ron::de::from_reader(BufReader::new(fs::File::open(path).ok()?)).ok()
|
||||
}
|
||||
|
||||
pub fn save_custom_config<C>(&self, name: &str, config: C) -> Result<(), ron::Error>
|
||||
where
|
||||
C: Serialize,
|
||||
{
|
||||
let path = self.path.join(name);
|
||||
ron::ser::to_writer_pretty(
|
||||
BufWriter::new(fs::File::create(path)?),
|
||||
&config,
|
||||
Default::default(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct Config {
|
||||
pub dmg_bootrom: Option<String>,
|
||||
pub cgb_bootrom: Option<String>,
|
||||
pub show_bootrom: bool,
|
||||
pub prefer_cgb: bool,
|
||||
pub vulkan_config: VulkanRendererConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(default)]
|
||||
pub struct VulkanRendererConfig {
|
||||
pub dmg_shader_path: Option<String>,
|
||||
pub cgb_shader_path: Option<String>,
|
||||
}
|
||||
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dmg_bootrom: None,
|
||||
cgb_bootrom: None,
|
||||
show_bootrom: false,
|
||||
prefer_cgb: true,
|
||||
vulkan_config: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::derivable_impls)]
|
||||
impl Default for VulkanRendererConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dmg_shader_path: None,
|
||||
cgb_shader_path: None,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
use std::fs;
|
||||
use std::marker::PhantomData;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
pub use crate::processor::memory::mmio::gpu::Colour;
|
||||
pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState};
|
||||
pub use crate::processor::memory::mmio::serial::{SerialTarget, StdoutType};
|
||||
use crate::processor::memory::rom::sram_save::SaveDataLocation;
|
||||
pub use crate::processor::memory::rom::CgbRomType;
|
||||
use crate::processor::memory::Rom;
|
||||
pub use crate::{HEIGHT, WIDTH};
|
||||
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};
|
||||
|
||||
|
@ -18,10 +23,54 @@ pub enum DownsampleType {
|
|||
}
|
||||
|
||||
pub enum RomFile {
|
||||
Path(String),
|
||||
Path(PathBuf),
|
||||
Raw(Vec<u8>),
|
||||
}
|
||||
|
||||
impl RomFile {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn load<C>(
|
||||
self,
|
||||
save: SramType,
|
||||
camera: C,
|
||||
) -> Result<(Rom<C>, Arc<Mutex<CameraWrapper<C>>>), std::io::Error>
|
||||
where
|
||||
C: PocketCamera + Send + 'static,
|
||||
{
|
||||
let camera: CameraWrapperRef<C> = Arc::new(Mutex::new(CameraWrapper::new(camera)));
|
||||
|
||||
match self {
|
||||
RomFile::Path(path) => {
|
||||
let save_location = match save {
|
||||
SramType::File(path) => Some(SaveDataLocation::File(PathBuf::from(path))),
|
||||
SramType::RawBuffer(buf) => Some(SaveDataLocation::Raw(buf)),
|
||||
SramType::Auto => Some(SaveDataLocation::File(path.with_extension("sav"))),
|
||||
SramType::None => None,
|
||||
};
|
||||
|
||||
fs::read(path).map(|data| Rom::load(data, save_location, camera.clone()))
|
||||
}
|
||||
RomFile::Raw(data) => {
|
||||
let save_location = match save {
|
||||
SramType::File(path) => Some(SaveDataLocation::File(PathBuf::from(path))),
|
||||
SramType::RawBuffer(buf) => Some(SaveDataLocation::Raw(buf)),
|
||||
SramType::Auto => None,
|
||||
SramType::None => None,
|
||||
};
|
||||
Ok(Rom::load(data, save_location, camera.clone()))
|
||||
}
|
||||
}
|
||||
.map(|v| (v, camera))
|
||||
}
|
||||
|
||||
pub fn load_data(self) -> Result<Vec<u8>, std::io::Error> {
|
||||
match self {
|
||||
RomFile::Path(path) => std::fs::read(path),
|
||||
RomFile::Raw(data) => Ok(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Renderer<Format: From<Colour>> {
|
||||
fn prepare(&mut self, width: usize, height: usize);
|
||||
|
||||
|
@ -112,7 +161,7 @@ impl PocketCamera for NoCamera {
|
|||
|
||||
pub(crate) type CameraWrapperRef<C> = Arc<Mutex<CameraWrapper<C>>>;
|
||||
|
||||
pub(crate) struct CameraWrapper<C>
|
||||
pub struct CameraWrapper<C>
|
||||
where
|
||||
C: PocketCamera,
|
||||
{
|
||||
|
@ -163,35 +212,40 @@ where
|
|||
pub enum SramType {
|
||||
File(String),
|
||||
RawBuffer(Arc<RwLock<Vec<u8>>>),
|
||||
Auto,
|
||||
None,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct EmulatorOptions<ColourFormat, R>
|
||||
pub struct EmulatorOptions<ColourFormat, R, C>
|
||||
where
|
||||
ColourFormat: From<Colour> + Copy,
|
||||
R: Renderer<ColourFormat>,
|
||||
C: PocketCamera + Send + 'static,
|
||||
{
|
||||
pub(crate) window: R,
|
||||
pub(crate) tile_window: Option<R>,
|
||||
pub(crate) layer_window: Option<R>,
|
||||
pub(crate) rom: RomFile,
|
||||
pub(crate) rom: Rom<C>,
|
||||
pub(crate) output: AudioOutput,
|
||||
pub(crate) save: Option<SramType>,
|
||||
|
||||
pub(crate) no_save: bool,
|
||||
pub(crate) bootrom: Option<RomFile>,
|
||||
pub(crate) dmg_bootrom: Option<RomFile>,
|
||||
pub(crate) cgb_bootrom: Option<RomFile>,
|
||||
pub(crate) show_bootrom: bool,
|
||||
pub(crate) serial_target: SerialTarget,
|
||||
pub(crate) cgb_mode: bool,
|
||||
spooky: PhantomData<ColourFormat>,
|
||||
_spooky: PhantomData<ColourFormat>,
|
||||
}
|
||||
|
||||
impl<ColourFormat, R> EmulatorOptions<ColourFormat, R>
|
||||
impl<ColourFormat, R, C> EmulatorOptions<ColourFormat, R, C>
|
||||
where
|
||||
ColourFormat: From<Colour> + Copy,
|
||||
R: Renderer<ColourFormat>,
|
||||
C: PocketCamera + Send + 'static,
|
||||
{
|
||||
pub fn new(window: R, rom: RomFile, output: AudioOutput) -> Self {
|
||||
pub fn new(window: R, rom: Rom<C>, output: AudioOutput) -> Self {
|
||||
Self {
|
||||
window,
|
||||
tile_window: None,
|
||||
|
@ -200,17 +254,44 @@ where
|
|||
output,
|
||||
save: None,
|
||||
no_save: false,
|
||||
bootrom: None,
|
||||
dmg_bootrom: None,
|
||||
cgb_bootrom: None,
|
||||
show_bootrom: false,
|
||||
serial_target: SerialTarget::None,
|
||||
cgb_mode: true,
|
||||
spooky: PhantomData,
|
||||
_spooky: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_save_path(mut self, path: Option<String>) -> Self {
|
||||
self.save = path.map(SramType::File);
|
||||
self
|
||||
#[cfg(feature = "config")]
|
||||
pub fn new_with_config(
|
||||
config: crate::config::Config,
|
||||
config_dir: PathBuf,
|
||||
window: R,
|
||||
rom: Rom<C>,
|
||||
output: AudioOutput,
|
||||
) -> Self {
|
||||
Self {
|
||||
window,
|
||||
tile_window: None,
|
||||
layer_window: None,
|
||||
rom,
|
||||
output,
|
||||
save: None,
|
||||
no_save: false,
|
||||
dmg_bootrom: config
|
||||
.dmg_bootrom
|
||||
.map(|v| config_dir.join(v))
|
||||
.map(RomFile::Path),
|
||||
cgb_bootrom: config
|
||||
.cgb_bootrom
|
||||
.map(|v| config_dir.join(v))
|
||||
.map(RomFile::Path),
|
||||
show_bootrom: config.show_bootrom,
|
||||
serial_target: SerialTarget::None,
|
||||
cgb_mode: config.prefer_cgb,
|
||||
_spooky: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_sram_buffer(mut self, buffer: Arc<RwLock<Vec<u8>>>) -> Self {
|
||||
|
@ -228,8 +309,17 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_bootrom(mut self, bootrom: Option<RomFile>, show_bootrom: bool) -> Self {
|
||||
self.bootrom = bootrom;
|
||||
pub fn with_dmg_bootrom(mut self, dmg_bootrom: Option<RomFile>) -> Self {
|
||||
self.dmg_bootrom = dmg_bootrom;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_cgb_bootrom(mut self, cgb_bootrom: Option<RomFile>) -> Self {
|
||||
self.cgb_bootrom = cgb_bootrom;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_show_bootrom(mut self, show_bootrom: bool) -> Self {
|
||||
self.show_bootrom = show_bootrom;
|
||||
self
|
||||
}
|
||||
|
|
|
@ -5,24 +5,17 @@ use crate::{
|
|||
util::pause,
|
||||
};
|
||||
use connect::{
|
||||
AudioOutput, CameraWrapper, CameraWrapperRef, EmulatorCoreTrait, EmulatorMessage,
|
||||
EmulatorOptions, PocketCamera, Renderer, RomFile, SramType,
|
||||
AudioOutput, CameraWrapper, EmulatorCoreTrait, EmulatorMessage, EmulatorOptions, PocketCamera,
|
||||
Renderer, RomFile,
|
||||
};
|
||||
use processor::{
|
||||
memory::{
|
||||
mmio::gpu::Colour,
|
||||
rom::{sram_save::SaveDataLocation, CgbRomType},
|
||||
OutputTargets, Rom,
|
||||
},
|
||||
memory::{mmio::gpu::Colour, rom::CgbRomType, OutputTargets},
|
||||
Cpu,
|
||||
};
|
||||
use std::{
|
||||
fs::{self},
|
||||
io::{stdout, Write},
|
||||
marker::PhantomData,
|
||||
path::PathBuf,
|
||||
process::exit,
|
||||
str::FromStr,
|
||||
sync::{mpsc::Receiver, Arc, Mutex},
|
||||
};
|
||||
|
||||
|
@ -35,6 +28,8 @@ compile_error!("select only one rendering backend!");
|
|||
#[cfg_attr(feature = "vulkan-renderer", path = "renderer/vulkan/vulkan.rs")]
|
||||
pub mod renderer;
|
||||
|
||||
#[cfg(feature = "config")]
|
||||
pub mod config;
|
||||
pub mod connect;
|
||||
mod constants;
|
||||
mod processor;
|
||||
|
@ -62,76 +57,37 @@ where
|
|||
{
|
||||
pub fn init(
|
||||
receiver: Receiver<EmulatorMessage>,
|
||||
mut options: EmulatorOptions<ColourFormat, R>,
|
||||
camera: C,
|
||||
mut options: EmulatorOptions<ColourFormat, R, C>,
|
||||
camera: Arc<Mutex<CameraWrapper<C>>>,
|
||||
) -> Self {
|
||||
let camera: CameraWrapperRef<C> = Arc::new(Mutex::new(CameraWrapper::new(camera)));
|
||||
let rom = options.rom;
|
||||
|
||||
let maybe_save = options.save.map(|i| match i {
|
||||
SramType::File(sram_path) => {
|
||||
SaveDataLocation::File(PathBuf::from_str(&sram_path).unwrap())
|
||||
}
|
||||
SramType::RawBuffer(buffer) => SaveDataLocation::Raw(buffer),
|
||||
});
|
||||
|
||||
let rom = match options.rom {
|
||||
RomFile::Path(path) => {
|
||||
let maybe_save = if options.no_save {
|
||||
None
|
||||
} else {
|
||||
Some(maybe_save.unwrap_or(SaveDataLocation::File(
|
||||
PathBuf::from_str(&path).unwrap().with_extension("sav"),
|
||||
)))
|
||||
};
|
||||
|
||||
match fs::read(path) {
|
||||
Ok(data) => Rom::load(data, maybe_save, camera.clone()),
|
||||
Err(e) => {
|
||||
eprintln!("Error reading ROM: {e}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
RomFile::Raw(data) => Rom::load(data, maybe_save, camera.clone()),
|
||||
};
|
||||
|
||||
let (bootrom, cgb) = if let Some(b) = options.bootrom {
|
||||
let bootrom = match b {
|
||||
RomFile::Path(path) => match fs::read(path) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
eprintln!("Error reading bootROM: {e}");
|
||||
exit(1);
|
||||
}
|
||||
},
|
||||
RomFile::Raw(data) => data,
|
||||
};
|
||||
let cgb =
|
||||
rom.rom_type == CgbRomType::CgbOnly || options.cgb_mode || bootrom.len() > 256;
|
||||
(bootrom, cgb)
|
||||
let is_cgb_mode = rom.rom_type == CgbRomType::CgbOnly || options.cgb_mode;
|
||||
let bootrom = if is_cgb_mode {
|
||||
options.cgb_bootrom.unwrap_or(RomFile::Raw(
|
||||
include_bytes!("../../sameboy-bootroms/cgb_boot.bin").to_vec(),
|
||||
))
|
||||
} else {
|
||||
let cgb = rom.rom_type == CgbRomType::CgbOnly || options.cgb_mode;
|
||||
let bootrom = if cgb {
|
||||
include_bytes!("../../sameboy-bootroms/cgb_boot.bin").to_vec()
|
||||
} else {
|
||||
include_bytes!("../../sameboy-bootroms/dmg_boot.bin").to_vec()
|
||||
};
|
||||
(bootrom, cgb)
|
||||
};
|
||||
options.dmg_bootrom.unwrap_or(RomFile::Raw(
|
||||
include_bytes!("../../sameboy-bootroms/dmg_boot.bin").to_vec(),
|
||||
))
|
||||
}
|
||||
.load_data()
|
||||
.expect("Error loading bootrom!");
|
||||
|
||||
options.window.prepare(WIDTH, HEIGHT);
|
||||
options.window.set_title(format!(
|
||||
"{} on {} on {}",
|
||||
rom.get_title(),
|
||||
rom.mbc_type(),
|
||||
if cgb { "CGB" } else { "DMG" }
|
||||
if is_cgb_mode { "CGB" } else { "DMG" }
|
||||
));
|
||||
|
||||
Self::new(
|
||||
receiver,
|
||||
Cpu::new(
|
||||
Memory::init(
|
||||
cgb,
|
||||
is_cgb_mode,
|
||||
bootrom,
|
||||
rom,
|
||||
OutputTargets::new(
|
||||
|
|
|
@ -12,7 +12,7 @@ mod mbcs;
|
|||
pub mod sram_save;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub(crate) enum CgbRomType {
|
||||
pub enum CgbRomType {
|
||||
Dmg,
|
||||
CgbOptional,
|
||||
CgbOnly,
|
||||
|
@ -24,7 +24,7 @@ where
|
|||
{
|
||||
title: String,
|
||||
mbc: Box<dyn Mbc>,
|
||||
pub(crate) rom_type: CgbRomType,
|
||||
pub rom_type: CgbRomType,
|
||||
spooky: PhantomData<C>,
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue