Skip to content
Snippets Groups Projects
main.rs 40.5 KiB
Newer Older
#![allow(clippy::uninlined_format_args)]
pub mod data;
pub mod test;
João Magalhães's avatar
João Magalhães committed
use boytacean::{
    devices::{printer::PrinterDevice, stdout::StdoutDevice},
    error::Error,
    gb::{AudioProvider, GameBoy, GameBoyMode},
    ppu::PaletteInfo,
    serial::{NullDevice, SerialDevice},
    state::StateManager,
    util::{replace_ext, write_file},
use image::{ColorType, ImageBuffer, Rgb};
use sdl::{surface_from_bytes, SdlSystem};
use sdl2::{
    event::Event,
    keyboard::{Keycode, Mod},
    pixels::PixelFormatEnum,
    Sdl,
};
    path::{Path, PathBuf},
    thread,
    time::{Duration, Instant, SystemTime},
};
/// The scale at which the screen is going to be drawn
/// meaning the ratio between Game Boy resolution and
/// the window size to be displayed.
const SCREEN_SCALE: f32 = 3.0;
/// Base audio volume to be used as the basis of the
/// amplification level of the volume
const VOLUME: f32 = 64.0;
/// The rate (in seconds) at which the current battery
/// backed RAM is going to be stored into the file system.
const STORE_RATE: u8 = 5;

/// The path to the default ROM file that is going to be
/// loaded in case no other ROM path is provided.
const DEFAULT_ROM_PATH: &str = "../../res/roms/demo/pocket.gb";

pub struct Benchmark {
    count: usize,
    cpu_only: Option<bool>,
    pub fn new(count: usize, cpu_only: Option<bool>) -> Self {
        Self { count, cpu_only }
    }
}

impl Default for Benchmark {
    fn default() -> Self {
        Self::new(50000000, None)
pub struct EmulatorOptions {
    auto_mode: Option<bool>,
    unlimited: Option<bool>,
    features: Option<Vec<&'static str>>,
}

/// Main structure used to control the logic execution of
/// an emulator in an SDL context.
///
/// The way the structure is defined should be as agnostic
/// as possible to the underlying system, meaning that it
/// should be able to run in different systems without any
/// major changes.
pub struct Emulator {
    /// Reference to the system that is going to be used to
    /// run the emulation.

    /// Flag that controls if the emulator should run in
    /// auto mode, meaning that the mode should be inferred
    /// from the ROM file.

    /// Flag that controls if the emulator should run in an
    /// unlimited mode, meaning that no speed limit is imposed.
    unlimited: bool,

    /// Reference to the SDL system that is going to be used
    /// to render the graphics and handle the input.
    sdl: Option<SdlSystem>,

    /// Reference to the audio provider that is going to be used
    /// to handle the audio output.
    audio: Option<Audio>,

    /// The title of the emulator that is going to be displayed
    /// in the window title.

    /// The path to the ROM file that is going to be loaded into
    /// the emulator.
    rom_path: String,

    /// The path to the RAM file (save state) that is going to be
    /// to load state from.
    ram_path: String,

    /// Path to the directory where storage of files is located, this
    /// value is going to be used to save files.
    ///
    /// Example usage of this directory includes screenshots, save states
    /// and other files that are going to be saved to the file system.

    /// The frequency at which the logic of the emulator is going to
    /// be executed, this value is going to be used to control the
    /// speed of the emulation.
    logic_frequency: u32,

    /// The frequency at which the visual part of the emulator is going
    /// to be executed, this value is going to be used to control the
    /// speed of the visual part of the emulation (eg: 60 FPS).
    visual_frequency: f32,

    /// The time at which the next tick is going to be executed, this
    /// value is expressed in milliseconds.

    /// Integer representation of the `next_tick_time` value.
    next_tick_time_i: u32,

    /// Flag that controls if the emulator is running above its reference
    /// speed.
    fast: bool,

    /// Set of features that are going to be enabled in the emulator, this
    /// value is going to be used to control the behavior of the emulator.
    features: Vec<&'static str>,

    /// Set of palettes that are going to be used to control the color
    /// of the emulator frame buffer.
    palettes: [PaletteInfo; 7],

    /// Index of the current palette controlling the palette being used.
    palette_index: usize,
    pub fn new(system: GameBoy, options: EmulatorOptions) -> Self {
João Magalhães's avatar
João Magalhães committed
            system,
            auto_mode: options.auto_mode.unwrap_or(true),
            unlimited: options.unlimited.unwrap_or(false),
            title: format!("{} v{}", Info::name(), Info::version()),
            rom_path: String::from("invalid"),
            ram_path: String::from("invalid"),
            dir_path: String::from("invalid"),
            logic_frequency: GameBoy::CPU_FREQ,
            visual_frequency: GameBoy::VISUAL_FREQ,
            next_tick_time: 0.0,
            next_tick_time_i: 0,
            fast: false,
            features: options
                .features
João Magalhães's avatar
João Magalhães committed
                .unwrap_or_else(|| vec!["video", "audio", "no-vsync"]),
            palettes: [
                PaletteInfo::new(
                    "basic",
                    [
                        [0xff, 0xff, 0xff],
                        [0xc0, 0xc0, 0xc0],
                        [0x60, 0x60, 0x60],
                        [0x00, 0x00, 0x00],
                    ],
                ),
                PaletteInfo::new(
                    "hogwards",
                    [
                        [0xb6, 0xa5, 0x71],
                        [0x8b, 0x7e, 0x56],
                        [0x55, 0x4d, 0x35],
                        [0x20, 0x1d, 0x13],
                    ],
                ),
                PaletteInfo::new(
                    "christmas",
                    [
Loading
Loading full blame...