#include "stdafx.h" #include #include "EmuSettings.h" #include "KeyManager.h" #include "MessageManager.h" #include "Console.h" #include "SpcDisUtils.h" #include "NotificationManager.h" #include "../Utilities/FolderUtilities.h" EmuSettings::EmuSettings(Console* console) { _console = console; _flags = 0; _debuggerFlags = 0; _inputConfigVersion = 0; std::random_device rd; _mt = std::mt19937(rd()); } uint32_t EmuSettings::GetVersion() { //Version 0.4.0 uint16_t major = 0; uint8_t minor = 4; uint8_t revision = 0; return (major << 16) | (minor << 8) | revision; } string EmuSettings::GetVersionString() { uint32_t version = GetVersion(); return std::to_string(version >> 16) + "." + std::to_string((version >> 8) & 0xFF) + "." + std::to_string(version & 0xFF); } void EmuSettings::ProcessString(string & str, const char ** strPointer) { //Make a copy of the string and keep it (the original pointer will not be valid after the call is over) if(*strPointer) { str = *strPointer; } else { str.clear(); } *strPointer = str.c_str(); } void EmuSettings::SetVideoConfig(VideoConfig config) { _video = config; } VideoConfig EmuSettings::GetVideoConfig() { return _video; } void EmuSettings::SetAudioConfig(AudioConfig config) { ProcessString(_audioDevice, &config.AudioDevice); _audio = config; } AudioConfig EmuSettings::GetAudioConfig() { return _audio; } void EmuSettings::SetInputConfig(InputConfig config) { bool controllersChanged = false; for(int i = 0; i < 5; i++) { controllersChanged |= _input.Controllers[i].Type != config.Controllers[i].Type; } _input = config; _inputConfigVersion++; if(controllersChanged) { //Used by net play _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ConfigChanged); } } InputConfig EmuSettings::GetInputConfig() { if(CheckFlag(EmulationFlags::GameboyMode)) { if(_input.Controllers[0].Type != ControllerType::SnesController) { //Force SNES controller for P1 for gameboy-only mode InputConfig input = _input; input.Controllers[0].Type = ControllerType::SnesController; SetInputConfig(input); } } return _input; } uint32_t EmuSettings::GetInputConfigVersion() { return _inputConfigVersion; } void EmuSettings::SetEmulationConfig(EmulationConfig config) { bool prevOverclockEnabled = _emulation.PpuExtraScanlinesAfterNmi > 0 || _emulation.PpuExtraScanlinesBeforeNmi > 0 || _emulation.GsuClockSpeed > 100; bool overclockEnabled = config.PpuExtraScanlinesAfterNmi > 0 || config.PpuExtraScanlinesBeforeNmi > 0 || config.GsuClockSpeed > 100; _emulation = config; if(prevOverclockEnabled != overclockEnabled) { if(overclockEnabled) { MessageManager::DisplayMessage("Overclock", "OverclockEnabled"); } else { MessageManager::DisplayMessage("Overclock", "OverclockDisabled"); } //Used by net play _console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ConfigChanged); } } EmulationConfig EmuSettings::GetEmulationConfig() { return _emulation; } void EmuSettings::SetGameboyConfig(GameboyConfig config) { _gameboy = config; } GameboyConfig EmuSettings::GetGameboyConfig() { return _gameboy; } void EmuSettings::SetPreferences(PreferencesConfig config) { ProcessString(_saveFolder, &config.SaveFolderOverride); ProcessString(_saveStateFolder, &config.SaveStateFolderOverride); ProcessString(_screenshotFolder, &config.ScreenshotFolderOverride); MessageManager::SetOsdState(!config.DisableOsd); FolderUtilities::SetFolderOverrides( _saveFolder, _saveStateFolder, _screenshotFolder, "" ); _preferences = config; } PreferencesConfig EmuSettings::GetPreferences() { return _preferences; } void EmuSettings::ClearShortcutKeys() { _emulatorKeys[0].clear(); _emulatorKeys[1].clear(); _emulatorKeys[2].clear(); _shortcutSupersets[0].clear(); _shortcutSupersets[1].clear(); _shortcutSupersets[2].clear(); //Add Alt-F4 as a fake shortcut to prevent Alt-F4 from triggering Alt or F4 key bindings. (e.g load save state 4) KeyCombination keyComb; keyComb.Key1 = KeyManager::GetKeyCode("Alt"); keyComb.Key2 = KeyManager::GetKeyCode("F4"); SetShortcutKey(EmulatorShortcut::Exit, keyComb, 2); } void EmuSettings::SetShortcutKey(EmulatorShortcut shortcut, KeyCombination keyCombination, int keySetIndex) { _emulatorKeys[keySetIndex][(uint32_t)shortcut] = keyCombination; for(int i = 0; i < 3; i++) { for(std::pair &kvp : _emulatorKeys[i]) { if(keyCombination.IsSubsetOf(kvp.second)) { _shortcutSupersets[keySetIndex][(uint32_t)shortcut].push_back(kvp.second); } else if(kvp.second.IsSubsetOf(keyCombination)) { _shortcutSupersets[i][kvp.first].push_back(keyCombination); } } } } void EmuSettings::SetShortcutKeys(vector shortcuts) { ClearShortcutKeys(); for(ShortcutKeyInfo &shortcut : shortcuts) { if(_emulatorKeys[0][(uint32_t)shortcut.Shortcut].GetKeys().empty()) { SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 0); } else { SetShortcutKey(shortcut.Shortcut, shortcut.Keys, 1); } } } KeyCombination EmuSettings::GetShortcutKey(EmulatorShortcut shortcut, int keySetIndex) { auto result = _emulatorKeys[keySetIndex].find((int)shortcut); if(result != _emulatorKeys[keySetIndex].end()) { return result->second; } return {}; } vector EmuSettings::GetShortcutSupersets(EmulatorShortcut shortcut, int keySetIndex) { return _shortcutSupersets[keySetIndex][(uint32_t)shortcut]; } OverscanDimensions EmuSettings::GetOverscan() { OverscanDimensions overscan; if(CheckFlag(EmulationFlags::GameboyMode)) { //Force overscan values for gameboy-only mode (not SGB) overscan.Left = 0; overscan.Right = 256 - 160; overscan.Top = 0; overscan.Bottom = 239 - 144; } else { overscan.Left = _video.OverscanLeft; overscan.Right = _video.OverscanRight; overscan.Top = _video.OverscanTop; overscan.Bottom = _video.OverscanBottom; } return overscan; } uint32_t EmuSettings::GetRewindBufferSize() { return _preferences.RewindBufferSize; } uint32_t EmuSettings::GetEmulationSpeed() { if(CheckFlag(EmulationFlags::MaximumSpeed)) { return 0; } else if(CheckFlag(EmulationFlags::Turbo)) { return _emulation.TurboSpeed; } else if(CheckFlag(EmulationFlags::Rewind)) { return _emulation.RewindSpeed; } else { return _emulation.EmulationSpeed; } } double EmuSettings::GetAspectRatio(ConsoleRegion region) { switch(_video.AspectRatio) { case VideoAspectRatio::NoStretching: return 0.0; case VideoAspectRatio::Auto: return region == ConsoleRegion::Pal ? (11.0 / 8.0) : (8.0 / 7.0); case VideoAspectRatio::NTSC: return 8.0 / 7.0; case VideoAspectRatio::PAL: return 11.0 / 8.0; case VideoAspectRatio::Standard: return 4.0 / 3.0; case VideoAspectRatio::Widescreen: return 16.0 / 9.0; case VideoAspectRatio::Custom: return _video.CustomAspectRatio; } return 0.0; } void EmuSettings::SetFlag(EmulationFlags flag) { if((_flags & (int)flag) == 0) { _flags |= (int)flag; } } void EmuSettings::SetFlagState(EmulationFlags flag, bool enabled) { if(enabled) { SetFlag(flag); } else { ClearFlag(flag); } } void EmuSettings::ClearFlag(EmulationFlags flag) { if((_flags & (int)flag) != 0) { _flags &= ~(int)flag; } } bool EmuSettings::CheckFlag(EmulationFlags flag) { return (_flags & (int)flag) != 0; } void EmuSettings::SetDebuggerFlag(DebuggerFlags flag, bool enabled) { if(enabled) { if((_debuggerFlags & (int)flag) == 0) { _debuggerFlags |= (int)flag; } } else { if((_debuggerFlags & (int)flag) != 0) { _debuggerFlags &= ~(int)flag; } } } bool EmuSettings::CheckDebuggerFlag(DebuggerFlags flag) { return (_debuggerFlags & (int)flag) != 0; } void EmuSettings::InitializeRam(void* data, uint32_t length) { switch(_emulation.RamPowerOnState) { default: case RamState::AllZeros: memset(data, 0, length); break; case RamState::AllOnes: memset(data, 0xFF, length); break; case RamState::Random: std::uniform_int_distribution<> dist(0, 255); for(uint32_t i = 0; i < length; i++) { ((uint8_t*)data)[i] = dist(_mt); } break; } } int EmuSettings::GetRandomValue(int maxValue) { std::uniform_int_distribution<> dist(0, maxValue); return dist(_mt); } bool EmuSettings::GetRandomBool() { return GetRandomValue(1) == 1; } bool EmuSettings::IsInputEnabled() { return !CheckFlag(EmulationFlags::InBackground) || _preferences.AllowBackgroundInput; } double EmuSettings::GetControllerDeadzoneRatio() { switch(_input.ControllerDeadzoneSize) { case 0: return 0.5; case 1: return 0.75; case 2: return 1; case 3: return 1.25; case 4: return 1.5; } return 1; }