diff --git a/Common/UI/View.h b/Common/UI/View.h index 0a2b4b4137..23f85bd0fd 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -471,6 +471,9 @@ public: const std::string &Tag() const { return tag_; } void SetTag(std::string_view str) { tag_ = str; } + // The group this view was added to, if any. + ViewGroup *Parent() const { return parent_; } + // Fake RTTI virtual bool IsViewGroup() const { return false; } virtual bool ContainsSubview(const View *view) const { return false; } @@ -518,6 +521,9 @@ protected: DialogResult autoResult_ = DR_OK; private: + friend class ViewGroup; // Sets parent_. + ViewGroup *parent_ = nullptr; + std::function enabledFunc_; bool *enabledPtr_ = nullptr; bool enabled_ = true; diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 6835ece25d..e7fcd9c37a 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -164,6 +164,7 @@ bool ViewGroup::ReplaceSubview(View *view, View *newView) { for (int i = 0; i < (int)views_.size(); i++) { if (views_[i] == view) { views_[i] = newView; + SetParentOf(newView); delete view; return true; } @@ -1042,8 +1043,7 @@ CollapsibleSection::CollapsibleSection(std::string_view title, LayoutParams *lay open_ = &localOpen_; SetSpacing(0.0f); - header_ = new CollapsibleHeader(open_, title); - views_.push_back(header_); + header_ = Add(new CollapsibleHeader(open_, title)); header_->OnClick.Add([=](UI::EventParams &) { // Change the visibility of all children except the first one. // Later maybe try something more ambitious. diff --git a/Common/UI/ViewGroup.h b/Common/UI/ViewGroup.h index 7ed8258e8f..8605d3deaa 100644 --- a/Common/UI/ViewGroup.h +++ b/Common/UI/ViewGroup.h @@ -53,11 +53,13 @@ public: template T *Add(T *view) { views_.push_back(view); + SetParentOf(view); return view; } template T *Insert(int index, T *view) { views_.insert(views_.begin() + index, view); + SetParentOf(view); return view; } @@ -108,6 +110,9 @@ protected: std::string DescribeListUnordered(std::string_view heading) const; std::string DescribeListOrdered(std::string_view heading) const; + // Anything that adds to views_ without Add or Insert must call this. + void SetParentOf(View *view) { view->parent_ = this; } + std::vector views_; View *defaultFocusView_ = nullptr; Drawable bg_; diff --git a/Core/Config.cpp b/Core/Config.cpp index 8818631e60..a0586f7799 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -16,10 +16,12 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include #include #include #include #include +#include #include #include @@ -249,11 +251,19 @@ static int DefaultScreenRotation() { #endif } -#define SETTING(a, x) &a, &a.x -#define SETTING_IDX(a, x, i) &a, &a.x[i] +#if defined(__GNUC__) || defined(__clang__) +// offsetof on classes with virtual functions (like ConfigBlock) is conditionally supported, and our compilers do support it. +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + +// The type of the block a setting lives in, from an expression like g_Config or g_Config.gestureControls[0]. +#define CONFIG_BLOCK_TYPE(a) std::remove_reference_t +// Offsets are taken with offsetof, so the tables can be constexpr. +#define SETTING(a, x) ConfigSettingOffset{ (uint32_t)offsetof(CONFIG_BLOCK_TYPE(a), x) } +#define SETTING_IDX(a, x, i) ConfigSettingOffset>{ (uint32_t)(offsetof(CONFIG_BLOCK_TYPE(a), x) + (i) * sizeof(std::remove_extent_t)) } // All relative to g_Config. -static const ConfigSetting generalSettings[] = { +static constexpr ConfigSetting generalSettings[] = { ConfigSetting("FirstRun", SETTING(g_Config, bFirstRun), true, CfgFlag::DEFAULT), ConfigSetting("RunCount", SETTING(g_Config, iRunCount), 0, CfgFlag::DEFAULT), ConfigSetting("Enable Logging", SETTING(g_Config, bEnableLogging), true, CfgFlag::PER_GAME), @@ -405,7 +415,7 @@ static bool DefaultSasThread() { return cpu_info.num_cores > 1; } -static const ConfigSetting achievementSettings[] = { +static constexpr ConfigSetting achievementSettings[] = { // Core settings ConfigSetting("AchievementsEnable", SETTING(g_Config, bAchievementsEnable), false, CfgFlag::PER_GAME), ConfigSetting("AchievementsEnableRAIntegration", SETTING(g_Config, bAchievementsEnableRAIntegration), false, CfgFlag::DEFAULT), @@ -435,7 +445,7 @@ static const ConfigSetting achievementSettings[] = { ConfigSetting("AchievementsUnlockedPos", SETTING(g_Config, iAchievementsUnlockedPos), (int)ScreenEdgePosition::TOP_CENTER, CfgFlag::PER_GAME | CfgFlag::DEFAULT), }; -static const ConfigSetting cpuSettings[] = { +static constexpr ConfigSetting cpuSettings[] = { ConfigSetting("CPUCore", SETTING(g_Config, iCpuCore), &DefaultCpuCore, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("SeparateSASThread", SETTING(g_Config, bSeparateSASThread), &DefaultSasThread, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("IOTimingMethod", SETTING(g_Config, iIOTimingMethod), IOTIMING_FAST, CfgFlag::PER_GAME | CfgFlag::REPORT), @@ -676,7 +686,7 @@ bool DisplayLayoutConfig::ResetToDefault(std::string_view blockName) { // These were previously part of Graphics. // It's instantiated into g_Config.displayLayoutLandscape and g_Config.displayLayoutPortrait. // Defaults are set directly on the struct declaration (and adjusted per instance in ResetToDefault above). -static const ConfigSetting displayLayoutSettings[] = { +static constexpr ConfigSetting displayLayoutSettings[] = { ConfigSetting("BufferFiltering", SETTING(g_Config.displayLayoutLandscape, iDisplayFilter), CfgFlag::PER_GAME), ConfigSetting("DisplayStretch", SETTING(g_Config.displayLayoutLandscape, bDisplayStretch), CfgFlag::PER_GAME), ConfigSetting("DisplayOffsetX", SETTING(g_Config.displayLayoutLandscape, fDisplayOffsetX), CfgFlag::PER_GAME), @@ -703,7 +713,7 @@ bool GestureControlConfig::ResetToDefault(std::string_view blockName) { } // These were previously mostly part of General (which was wrong). -static const ConfigSetting gestureControlSettings[] = { +static constexpr ConfigSetting gestureControlSettings[] = { ConfigSetting("SwipeUp", SETTING(g_Config.gestureControls[0], iSwipeUp), 0, CfgFlag::PER_GAME), ConfigSetting("SwipeDown", SETTING(g_Config.gestureControls[0], iSwipeDown), 0, CfgFlag::PER_GAME), ConfigSetting("SwipeLeft", SETTING(g_Config.gestureControls[0], iSwipeLeft), 0, CfgFlag::PER_GAME), @@ -716,7 +726,24 @@ static const ConfigSetting gestureControlSettings[] = { ConfigSetting("AnalogGestureSensibility", SETTING(g_Config.gestureControls[0], fAnalogGestureSensitivity), 1.0f, CfgFlag::PER_GAME), }; -static const ConfigSetting graphicsSettings[] = { +// The alternative speeds used to be stored as frame rates, out of 60. +static int LegacyFpsLimitToPercent(int fps) { + return fps < 0 ? -1 : (fps * 100 + 30) / 60; +} + +static int DefaultAltSpeedPercent1() { + return LegacyFpsLimitToPercent(g_Config.iLegacyFpsLimit1); +} + +static int DefaultAltSpeedPercent2() { + return LegacyFpsLimitToPercent(g_Config.iLegacyFpsLimit2); +} + +static int DefaultAnalogAltSpeedPercent() { + return LegacyFpsLimitToPercent(g_Config.iLegacyAnalogFpsLimit); +} + +static constexpr ConfigSetting graphicsSettings[] = { ConfigSetting("iShowStatusFlags", SETTING(g_Config, iShowStatusFlags), 0, CfgFlag::PER_GAME), ConfigSetting("GraphicsBackend", SETTING(g_Config, iGPUBackend), &DefaultGPUBackend, &GPUBackendTranslator::To, &GPUBackendTranslator::From, CfgFlag::DEFAULT | CfgFlag::REPORT), #if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64) @@ -742,12 +769,16 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("AndroidHwScale", SETTING(g_Config, iAndroidHwScale), 0, CfgFlag::DEFAULT), ConfigSetting("HighQualityDepth", SETTING(g_Config, bHighQualityDepth), true, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("FrameSkip", SETTING(g_Config, iFrameSkip), 0, CfgFlag::PER_GAME | CfgFlag::REPORT), - ConfigSetting("AutoFrameSkip", SETTING(g_Config, bAutoFrameSkip), IsVREnabled(), CfgFlag::PER_GAME | CfgFlag::REPORT), + ConfigSetting("AutoFrameSkip", SETTING(g_Config, bAutoFrameSkip), false, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("StereoRendering", SETTING(g_Config, bStereoRendering), false, CfgFlag::PER_GAME), ConfigSetting("StereoToMonoShader", SETTING(g_Config, sStereoToMonoShader), "RedBlue", CfgFlag::PER_GAME), - ConfigSetting("FrameRate", SETTING(g_Config, iFpsLimit1), 0, CfgFlag::PER_GAME), - ConfigSetting("FrameRate2", SETTING(g_Config, iFpsLimit2), -1, CfgFlag::PER_GAME), - ConfigSetting("AnalogFrameRate", SETTING(g_Config, iAnalogFpsLimit), 240, CfgFlag::PER_GAME), + // Read before the new settings, which use them as defaults. + ConfigSetting("FrameRate", SETTING(g_Config, iLegacyFpsLimit1), 0, CfgFlag::PER_GAME | CfgFlag::DONT_SAVE), + ConfigSetting("FrameRate2", SETTING(g_Config, iLegacyFpsLimit2), -1, CfgFlag::PER_GAME | CfgFlag::DONT_SAVE), + ConfigSetting("AnalogFrameRate", SETTING(g_Config, iLegacyAnalogFpsLimit), 240, CfgFlag::PER_GAME | CfgFlag::DONT_SAVE), + ConfigSetting("AltSpeedPercent", SETTING(g_Config, iAltSpeedPercent1), &DefaultAltSpeedPercent1, CfgFlag::PER_GAME), + ConfigSetting("AltSpeedPercent2", SETTING(g_Config, iAltSpeedPercent2), &DefaultAltSpeedPercent2, CfgFlag::PER_GAME), + ConfigSetting("AnalogAltSpeedPercent", SETTING(g_Config, iAnalogAltSpeedPercent), &DefaultAnalogAltSpeedPercent, CfgFlag::PER_GAME), #if PPSSPP_PLATFORM(WINDOWS) ConfigSetting("RestartRequired", SETTING(g_Config, bRestartRequired), false, CfgFlag::DONT_SAVE), #endif @@ -803,7 +834,7 @@ static const ConfigSetting graphicsSettings[] = { ConfigSetting("UberShaderVertex", SETTING(g_Config, bUberShaderVertex), true, CfgFlag::DEFAULT), - ConfigSetting("DisplayRefreshRate", SETTING(g_Config, iDisplayRefreshRate), g_Config.iDisplayRefreshRate, CfgFlag::PER_GAME), + ConfigSetting("DisplayRefreshRate", SETTING(g_Config, iDisplayRefreshRate), 60, CfgFlag::PER_GAME), }; static int LegacyVolumeToNewVolume(int legacy, int max) { @@ -844,7 +875,7 @@ bool DefaultAudioMixWithOthers() { #endif } -static const ConfigSetting soundSettings[] = { +static constexpr ConfigSetting soundSettings[] = { ConfigSetting("Enable", SETTING(g_Config, bEnableSound), true, CfgFlag::PER_GAME), ConfigSetting("ExtraAudioBuffering", SETTING(g_Config, bExtraAudioBuffering), false, CfgFlag::DEFAULT), ConfigSetting("AudioBufferSize", SETTING(g_Config, iSDLAudioBufferSize), 256, CfgFlag::DEFAULT), @@ -884,9 +915,9 @@ static bool DefaultShowTouchControls() { } } -static const float defaultControlScale = 1.15f; -static const ConfigTouchPos defaultTouchPosShow = { -1.0f, -1.0f, defaultControlScale, true }; -static const ConfigTouchPos defaultTouchPosHide = { -1.0f, -1.0f, defaultControlScale, false }; +static constexpr float defaultControlScale = 1.15f; +static constexpr ConfigTouchPos defaultTouchPosShow = { -1.0f, -1.0f, defaultControlScale, true }; +static constexpr ConfigTouchPos defaultTouchPosHide = { -1.0f, -1.0f, defaultControlScale, false }; void TouchControlConfig::ResetLayout() { // reset puts the settings in a state so they'll then get properly reinitialized in InitPadLayout. @@ -934,7 +965,7 @@ bool TouchControlConfig::ResetToDefault(std::string_view blockName) { return true; } -static const ConfigSetting touchControlSettings[] = { +static constexpr ConfigSetting touchControlSettings[] = { ConfigSetting("ShowTouchCross", SETTING(g_Config.touchControlsLandscape, bShowTouchCross), true, CfgFlag::PER_GAME), ConfigSetting("ShowTouchCircle", SETTING(g_Config.touchControlsLandscape, bShowTouchCircle), true, CfgFlag::PER_GAME), ConfigSetting("ShowTouchSquare", SETTING(g_Config.touchControlsLandscape, bShowTouchSquare), true, CfgFlag::PER_GAME), @@ -983,7 +1014,7 @@ static const ConfigSetting touchControlSettings[] = { ConfigSetting("HideStickBackground", SETTING(g_Config.touchControlsLandscape, bHideStickBackground), CfgFlag::PER_GAME), }; -static const ConfigSetting controlSettings[] = { +static constexpr ConfigSetting controlSettings[] = { ConfigSetting("HapticFeedback", SETTING(g_Config, bHapticFeedback), false, CfgFlag::PER_GAME), #if PPSSPP_PLATFORM(WINDOWS) @@ -1074,7 +1105,7 @@ static const ConfigSetting controlSettings[] = { static const std::vector emptyList; -static const ConfigSetting networkSettings[] = { +static constexpr ConfigSetting networkSettings[] = { ConfigSetting("EnableWlan", SETTING(g_Config, bEnableWlan), false, CfgFlag::PER_GAME), ConfigSetting("EnableAdhocServer", SETTING(g_Config, bEnableAdhocServer), false, CfgFlag::PER_GAME), ConfigSetting("proAdhocServer", SETTING(g_Config, sProAdhocServer), &DefaultProAdhocServer, CfgFlag::PER_GAME), @@ -1101,14 +1132,14 @@ static const ConfigSetting networkSettings[] = { ConfigSetting("ChatScreenPosition", SETTING(g_Config, iChatScreenPosition), (int)ScreenEdgePosition::BOTTOM_LEFT, CfgFlag::PER_GAME), ConfigSetting("ChatTimestamps", SETTING(g_Config, bChatTimestamps), true, CfgFlag::PER_GAME), ConfigSetting("EnableQuickChat", SETTING(g_Config, bEnableQuickChat), true, CfgFlag::PER_GAME), - ConfigSetting("QuickChat1", SETTING(g_Config, sQuickChat[0]), "Quick Chat 1", CfgFlag::PER_GAME), - ConfigSetting("QuickChat2", SETTING(g_Config, sQuickChat[1]), "Quick Chat 2", CfgFlag::PER_GAME), - ConfigSetting("QuickChat3", SETTING(g_Config, sQuickChat[2]), "Quick Chat 3", CfgFlag::PER_GAME), - ConfigSetting("QuickChat4", SETTING(g_Config, sQuickChat[3]), "Quick Chat 4", CfgFlag::PER_GAME), - ConfigSetting("QuickChat5", SETTING(g_Config, sQuickChat[4]), "Quick Chat 5", CfgFlag::PER_GAME), + ConfigSetting("QuickChat1", SETTING_IDX(g_Config, sQuickChat, 0), "Quick Chat 1", CfgFlag::PER_GAME), + ConfigSetting("QuickChat2", SETTING_IDX(g_Config, sQuickChat, 1), "Quick Chat 2", CfgFlag::PER_GAME), + ConfigSetting("QuickChat3", SETTING_IDX(g_Config, sQuickChat, 2), "Quick Chat 3", CfgFlag::PER_GAME), + ConfigSetting("QuickChat4", SETTING_IDX(g_Config, sQuickChat, 3), "Quick Chat 4", CfgFlag::PER_GAME), + ConfigSetting("QuickChat5", SETTING_IDX(g_Config, sQuickChat, 4), "Quick Chat 5", CfgFlag::PER_GAME), }; -static const ConfigSetting systemParamSettings[] = { +static constexpr ConfigSetting systemParamSettings[] = { ConfigSetting("PSPModel", SETTING(g_Config, iPSPModel), PSP_MODEL_SLIM, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("PSPFirmwareVersion", SETTING(g_Config, iFirmwareVersion), PSP_DEFAULT_FIRMWARE, CfgFlag::PER_GAME | CfgFlag::REPORT), ConfigSetting("NickName", SETTING(g_Config, sNickName), "PPSSPP", CfgFlag::PER_GAME), @@ -1129,7 +1160,7 @@ static const ConfigSetting systemParamSettings[] = { ConfigSetting("FuseID", SETTING(g_Config, sFuseID), "", CfgFlag::DEFAULT), }; -static const ConfigSetting debuggerSettings[] = { +static constexpr ConfigSetting debuggerSettings[] = { ConfigSetting("DisasmWindowX", SETTING(g_Config, iDisasmWindowX), -1, CfgFlag::DEFAULT), ConfigSetting("DisasmWindowY", SETTING(g_Config, iDisasmWindowY), -1, CfgFlag::DEFAULT), ConfigSetting("DisasmWindowW", SETTING(g_Config, iDisasmWindowW), -1, CfgFlag::DEFAULT), @@ -1154,21 +1185,21 @@ static const ConfigSetting debuggerSettings[] = { ConfigSetting("AutoSaveLoadSymbols", SETTING(g_Config, bAutoSaveLoadSymbols), false, CfgFlag::DEFAULT), }; -static const ConfigSetting jitSettings[] = { +static constexpr ConfigSetting jitSettings[] = { ConfigSetting("DiscardRegsOnJRRA", SETTING(g_Config, bDiscardRegsOnJRRA), false, CfgFlag::DONT_SAVE | CfgFlag::REPORT), }; -static const ConfigSetting upgradeSettings[] = { +static constexpr ConfigSetting upgradeSettings[] = { ConfigSetting("UpgradeMessage", SETTING(g_Config, sUpgradeMessage), "", CfgFlag::DEFAULT), ConfigSetting("UpgradeVersion", SETTING(g_Config, sUpgradeVersion), "", CfgFlag::DEFAULT), ConfigSetting("DismissedVersion", SETTING(g_Config, sDismissedVersion), "", CfgFlag::DEFAULT), }; -static const ConfigSetting themeSettings[] = { +static constexpr ConfigSetting themeSettings[] = { ConfigSetting("ThemeName", SETTING(g_Config, sThemeName), "Default", CfgFlag::DEFAULT), }; -static const ConfigSetting vrSettings[] = { +static constexpr ConfigSetting vrSettings[] = { ConfigSetting("VREnable", SETTING(g_Config, bEnableVR), true, CfgFlag::PER_GAME), ConfigSetting("VREnable6DoF", SETTING(g_Config, bEnable6DoF), false, CfgFlag::PER_GAME), ConfigSetting("VREnableStereo", SETTING(g_Config, bEnableStereo), false, CfgFlag::PER_GAME), diff --git a/Core/Config.h b/Core/Config.h index 0e3f7b35fa..5c065dd8b7 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -361,9 +361,14 @@ public: int iTexScalingType; // 0 = xBRZ, 1 = Hybrid bool bTexDeposterize; bool bTexHardwareScaling; - int iFpsLimit1; - int iFpsLimit2; - int iAnalogFpsLimit; + // In percent of normal speed. 0 means unlimited, and negative (not for analog) disabled. + int iAltSpeedPercent1; + int iAltSpeedPercent2; + int iAnalogAltSpeedPercent; + // The old frame rate based settings. Only read, to migrate them. + int iLegacyFpsLimit1; + int iLegacyFpsLimit2; + int iLegacyAnalogFpsLimit; int iMaxRecent; int iCurrentStateSlot; int iRewindSnapshotInterval; @@ -837,6 +842,15 @@ private: std::string CreateRandMAC(); std::string DefaultProAdhocServer(); +// The frame rate limit for an alternative speed. Unlimited (0) and disabled (negative) stay as they are. +inline int AltSpeedPercentToFps(int percent) { + if (percent <= 0) { + return percent; + } + int fps = (percent * 60 + 50) / 100; + return fps < 1 ? 1 : fps; +} + // TODO: Find a better place for this. extern http::RequestManager g_DownloadManager; extern Config g_Config; diff --git a/Core/ConfigSettings.cpp b/Core/ConfigSettings.cpp index 9a866b1ea7..a4a4e1062e 100644 --- a/Core/ConfigSettings.cpp +++ b/Core/ConfigSettings.cpp @@ -139,7 +139,7 @@ bool ConfigSetting::ReadFromIniSection(ConfigBlock *configBlock, const Section * if (defaultCallback_.p) { *target = defaultCallback_.p(); } else { - *target = Path(default_.p); + *target = Path(default_.s); } } return false; @@ -351,8 +351,8 @@ bool ConfigSetting::RestoreToDefault(ConfigBlock *configBlock, bool log) const { if (defaultCallback_.p) { *ptr_path = defaultCallback_.p(); break; - } else if (default_.p) { - *ptr_path = Path(default_.p); + } else if (default_.s) { + *ptr_path = Path(default_.s); } else { ptr_path->clear(); } diff --git a/Core/ConfigSettings.h b/Core/ConfigSettings.h index 81d311f42d..5951608003 100644 --- a/Core/ConfigSettings.h +++ b/Core/ConfigSettings.h @@ -1,7 +1,10 @@ #pragma once #include +#include +#include #include +#include #include "Core/ConfigValues.h" @@ -19,6 +22,12 @@ ENUM_CLASS_BITOPS(CfgFlag); struct ConfigBlock; +// Where a setting is within its ConfigBlock, along with its type. Made by the SETTING macro in Config.cpp. +template +struct ConfigSettingOffset { + uint32_t offset; +}; + struct ConfigSetting { enum class Type { TYPE_TERMINATOR, @@ -34,13 +43,23 @@ struct ConfigSetting { TYPE_CUSTOM_BUTTON }; union DefaultValue { + constexpr DefaultValue() : i(0) {} + constexpr DefaultValue(bool v) : b(v) {} + constexpr DefaultValue(int v) : i(v) {} + constexpr DefaultValue(uint32_t v) : u(v) {} + constexpr DefaultValue(uint64_t v) : lu(v) {} + constexpr DefaultValue(float v) : f(v) {} + constexpr DefaultValue(const char *v) : s(v) {} // Strings and paths. + constexpr DefaultValue(const std::vector *v) : v(v) {} + constexpr DefaultValue(ConfigTouchPos v) : touchPos(v) {} + constexpr DefaultValue(ConfigCustomButton v) : customButton(v) {} + bool b; int i; uint32_t u; uint64_t lu; float f; const char *s; - const char *p; // not sure how much point.. const std::vector *v; ConfigTouchPos touchPos; ConfigCustomButton customButton; @@ -57,6 +76,17 @@ struct ConfigSetting { typedef ConfigCustomButton (*CustomButtonDefaultCallback)(); union DefaultCallback { + constexpr DefaultCallback() : b(nullptr) {} + constexpr DefaultCallback(BoolDefaultCallback cb) : b(cb) {} + constexpr DefaultCallback(IntDefaultCallback cb) : i(cb) {} + constexpr DefaultCallback(Uint32DefaultCallback cb) : u(cb) {} + constexpr DefaultCallback(Uint64DefaultCallback cb) : lu(cb) {} + constexpr DefaultCallback(FloatDefaultCallback cb) : f(cb) {} + constexpr DefaultCallback(StringDefaultCallback cb) : s(cb) {} + constexpr DefaultCallback(PathDefaultCallback cb) : p(cb) {} + constexpr DefaultCallback(TouchPosDefaultCallback cb) : touchPos(cb) {} + constexpr DefaultCallback(CustomButtonDefaultCallback cb) : customButton(cb) {} + BoolDefaultCallback b; IntDefaultCallback i; Uint32DefaultCallback u; @@ -68,125 +98,50 @@ struct ConfigSetting { CustomButtonDefaultCallback customButton; }; - // The configBlock you pass in here is just to be able to calculate the offset of the setting within the block so it can be - // applied to other blocks. - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, bool *v, bool def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_BOOL), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.b = nullptr; - default_.b = def; - } + // The offset says where the setting is within its ConfigBlock, so it can be applied to any block of that type. + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, bool def, CfgFlag flags) noexcept + : type_(Type::TYPE_BOOL), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, CfgFlag flags) noexcept + : type_(Type::TYPE_BOOL), iniKey_(ini), flags_(flags), default_(false), offset_(v.offset) {} // The default is unused with this constructor. + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, int def, CfgFlag flags) noexcept + : type_(Type::TYPE_INT), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, CfgFlag flags) noexcept + : type_(Type::TYPE_INT), iniKey_(ini), flags_(flags), default_(0), offset_(v.offset) {} // The default is unused with this constructor. + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, int def, std::string (*transTo)(int), int (*transFrom)(const std::string &), CfgFlag flags) noexcept + : type_(Type::TYPE_INT), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset), translateTo_(transTo), translateFrom_(transFrom) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, uint32_t def, CfgFlag flags) noexcept + : type_(Type::TYPE_UINT32), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, uint64_t def, CfgFlag flags) noexcept + : type_(Type::TYPE_UINT64), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, float def, CfgFlag flags) noexcept + : type_(Type::TYPE_FLOAT), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, CfgFlag flags) noexcept + : type_(Type::TYPE_FLOAT), iniKey_(ini), flags_(flags), default_(0.0f), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, const char *def, CfgFlag flags) noexcept + : type_(Type::TYPE_STRING), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset> v, const std::vector *def, CfgFlag flags) noexcept + : type_(Type::TYPE_STRING_VECTOR), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, const char *def, CfgFlag flags) noexcept + : type_(Type::TYPE_PATH), iniKey_(ini), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(const char *iniX, const char *iniY, const char *iniScale, const char *iniShow, ConfigSettingOffset v, ConfigTouchPos def, CfgFlag flags) noexcept + : ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(Type::TYPE_TOUCH_POS), iniKey_(iniX), flags_(flags), default_(def), offset_(v.offset) {} + constexpr ConfigSetting(const char *iniKey, const char *iniImage, const char *iniShape, const char *iniToggle, const char *iniRepeat, ConfigSettingOffset v, ConfigCustomButton def, CfgFlag flags) noexcept + : ini2_(iniImage), ini3_(iniShape), ini4_(iniToggle), ini5_(iniRepeat), type_(Type::TYPE_CUSTOM_BUTTON), iniKey_(iniKey), flags_(flags), default_(def), offset_(v.offset) {} - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, bool *v, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_BOOL), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.b = nullptr; - default_.b = false; // unused with this constructor - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, int *v, int def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_INT), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.i = nullptr; - default_.i = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, int *v, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_INT), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.i = nullptr; - default_.i = 0; // unused with this constructor - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, int *v, int def, std::string (*transTo)(int), int (*transFrom)(const std::string &), CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_INT), flags_(flags), translateTo_(transTo), translateFrom_(transFrom), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.i = nullptr; - default_.i = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, uint32_t *v, uint32_t def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_UINT32), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.u = nullptr; - default_.u = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, uint64_t *v, uint64_t def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_UINT64), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.lu = nullptr; - default_.lu = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, float *v, float def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_FLOAT), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.f = nullptr; - default_.f = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, float *v, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_FLOAT), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.f = nullptr; - default_.f = 0.0f; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, std::string *v, const char *def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_STRING), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.s = nullptr; - default_.s = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, std::vector *v, const std::vector *def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_STRING_VECTOR), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - default_.v = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, Path *v, const char *def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_PATH), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.p = nullptr; - default_.p = def; - } - - ConfigSetting(const char *iniX, const char *iniY, const char *iniScale, const char *iniShow, ConfigBlock *configBlock, ConfigTouchPos *v, ConfigTouchPos def, CfgFlag flags) noexcept - : iniKey_(iniX), ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(Type::TYPE_TOUCH_POS), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.touchPos = nullptr; - default_.touchPos = def; - } - - ConfigSetting(const char *iniKey, const char *iniImage, const char *iniShape, const char *iniToggle, const char *iniRepeat, ConfigBlock *configBlock, ConfigCustomButton *v, ConfigCustomButton def, CfgFlag flags) noexcept - : iniKey_(iniKey), ini2_(iniImage), ini3_(iniShape), ini4_(iniToggle), ini5_(iniRepeat), type_(Type::TYPE_CUSTOM_BUTTON), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.customButton = nullptr; - default_.customButton = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, bool *v, BoolDefaultCallback def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_BOOL), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.b = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, int *v, IntDefaultCallback def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_INT), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.i = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, int *v, IntDefaultCallback def, std::string(*transTo)(int), int(*transFrom)(const std::string &), CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_INT), flags_(flags), offset_((const char *)v - (const char *)configBlock), translateTo_(transTo), translateFrom_(transFrom) { - defaultCallback_.i = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, uint32_t *v, Uint32DefaultCallback def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_UINT32), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.u = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, float *v, FloatDefaultCallback def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_FLOAT), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.f = def; - } - - ConfigSetting(std::string_view ini, ConfigBlock *configBlock, std::string *v, StringDefaultCallback def, CfgFlag flags) noexcept - : iniKey_(ini), type_(Type::TYPE_STRING), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.s = def; - } - - ConfigSetting(std::string_view iniX, const char *iniY, const char *iniScale, const char *iniShow, ConfigBlock *configBlock, ConfigTouchPos *v, TouchPosDefaultCallback def, CfgFlag flags) noexcept - : iniKey_(iniX), ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(Type::TYPE_TOUCH_POS), flags_(flags), offset_((const char *)v - (const char *)configBlock) { - defaultCallback_.touchPos = def; - } + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, BoolDefaultCallback def, CfgFlag flags) noexcept + : type_(Type::TYPE_BOOL), iniKey_(ini), flags_(flags), defaultCallback_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, IntDefaultCallback def, CfgFlag flags) noexcept + : type_(Type::TYPE_INT), iniKey_(ini), flags_(flags), defaultCallback_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, IntDefaultCallback def, std::string(*transTo)(int), int(*transFrom)(const std::string &), CfgFlag flags) noexcept + : type_(Type::TYPE_INT), iniKey_(ini), flags_(flags), defaultCallback_(def), offset_(v.offset), translateTo_(transTo), translateFrom_(transFrom) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, Uint32DefaultCallback def, CfgFlag flags) noexcept + : type_(Type::TYPE_UINT32), iniKey_(ini), flags_(flags), defaultCallback_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, FloatDefaultCallback def, CfgFlag flags) noexcept + : type_(Type::TYPE_FLOAT), iniKey_(ini), flags_(flags), defaultCallback_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view ini, ConfigSettingOffset v, StringDefaultCallback def, CfgFlag flags) noexcept + : type_(Type::TYPE_STRING), iniKey_(ini), flags_(flags), defaultCallback_(def), offset_(v.offset) {} + constexpr ConfigSetting(std::string_view iniX, const char *iniY, const char *iniScale, const char *iniShow, ConfigSettingOffset v, TouchPosDefaultCallback def, CfgFlag flags) noexcept + : ini2_(iniY), ini3_(iniScale), ini4_(iniShow), type_(Type::TYPE_TOUCH_POS), iniKey_(iniX), flags_(flags), defaultCallback_(def), offset_(v.offset) {} bool ReadFromIniSection(ConfigBlock *configBlock, const Section *section, bool applyDefaultIfMissing) const; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index d4ea955bf7..05f245e257 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -424,9 +424,9 @@ static int FrameTimingLimit() { return 0; // Can't slow down in hardcore mode. if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) - return fixRate(g_Config.iFpsLimit1); + return fixRate(AltSpeedPercentToFps(g_Config.iAltSpeedPercent1)); if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) - return fixRate(g_Config.iFpsLimit2); + return fixRate(AltSpeedPercentToFps(g_Config.iAltSpeedPercent2)); if (PSP_CoreParameter().fpsLimit == FPSLimit::ANALOG) return fixRate(PSP_CoreParameter().analogFpsLimit); if (PSP_CoreParameter().fpsLimit == FPSLimit::DEBUGGER) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index e401c974f1..8b47928e1e 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -697,14 +697,14 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) { // TODO: We should replace the "fpsLimit" system with a speed factor. static void ShowFpsLimitNotice() { - int fpsLimit = 60; + int percent = 100; switch (PSP_CoreParameter().fpsLimit) { case FPSLimit::CUSTOM1: - fpsLimit = g_Config.iFpsLimit1; + percent = g_Config.iAltSpeedPercent1; break; case FPSLimit::CUSTOM2: - fpsLimit = g_Config.iFpsLimit2; + percent = g_Config.iAltSpeedPercent2; break; default: break; @@ -713,7 +713,7 @@ static void ShowFpsLimitNotice() { // Now display it. char temp[51]; - snprintf(temp, sizeof(temp), "%d%%", (int)((float)fpsLimit / 60.0f * 100.0f)); + snprintf(temp, sizeof(temp), "%d%%", percent); g_OSD.Show(OSDType::STATUS_ICON, temp, "", "I_FAST_FORWARD", 1.5f, "altspeed"); g_OSD.SetFlags("altspeed", OSDMessageFlags::Transparent); } @@ -994,9 +994,9 @@ void EmuScreen::ProcessVKey(VirtKey virtKey, bool down) { if (down) { if (!NetworkWarnUserIfOnlineAndCantSpeed()) { // Cycle through enabled speeds. - if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) { + if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iAltSpeedPercent1 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; - } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit2 >= 0) { + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iAltSpeedPercent2 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 || PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) { PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; @@ -1145,7 +1145,7 @@ void EmuScreen::OnVKeyAnalog(VirtKey virtualKeyCode, float value) { if (limitMode != FPSLimit::NORMAL && limitMode != FPSLimit::ANALOG) return; // Don't even try if the limit is invalid. - if (g_Config.iAnalogFpsLimit <= 0) + if (g_Config.iAnalogAltSpeedPercent <= 0) return; // Apply a small deadzone (against the resting position.) @@ -1153,7 +1153,7 @@ void EmuScreen::OnVKeyAnalog(VirtKey virtualKeyCode, float value) { // If target is above 60, value is how much to speed up over 60. Otherwise, it's how much slower. // So normalize the target. - int target = g_Config.iAnalogFpsLimit - 60; + int target = AltSpeedPercentToFps(g_Config.iAnalogAltSpeedPercent) - 60; PSP_CoreParameter().analogFpsLimit = 60 + (int)(target * value); // If we've reset back to normal, turn it off. diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 87baaed7fa..e74a0c7707 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -131,9 +131,6 @@ GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, void GameSettingsScreen::ReadConfigTemporaries() { // Written back on exit, so it must be read even if the System tab is never opened. enableReports_ = Reporting::IsEnabled(); - iAlternateSpeedPercent1_ = g_Config.iFpsLimit1 < 0 ? -1 : (g_Config.iFpsLimit1 * 100) / 60; - iAlternateSpeedPercent2_ = g_Config.iFpsLimit2 < 0 ? -1 : (g_Config.iFpsLimit2 * 100) / 60; - iAlternateSpeedPercentAnalog_ = (g_Config.iAnalogFpsLimit * 100) / 60; } GameSettingsScreen::~GameSettingsScreen() { @@ -467,28 +464,19 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings) graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control"))); - PopupSliderChoice *altSpeed1 = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent1_, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed", "Alternative speed"), 5, screenManager(), gr->T("%, 0:unlimited"))); + PopupSliderChoice *altSpeed1 = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iAltSpeedPercent1, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed", "Alternative speed"), 5, screenManager(), gr->T("%, 0:unlimited"))); altSpeed1->SetFormat("%i%%"); altSpeed1->SetZeroLabel(gr->T("Unlimited")); altSpeed1->SetNegativeDisable(gr->T("Disabled")); - altSpeed1->OnChange.Add([this](UI::EventParams &) { - g_Config.iFpsLimit1 = iAlternateSpeedPercent1_ < 0 ? -1 : (iAlternateSpeedPercent1_ * 60) / 100; - }); - PopupSliderChoice *altSpeed2 = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercent2_, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed 2", "Alternative speed 2 (in %, 0 = unlimited)"), 5, screenManager(), gr->T("%, 0:unlimited"))); + PopupSliderChoice *altSpeed2 = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iAltSpeedPercent2, 0, 1000, UI::NO_DEFAULT_INT, gr->T("Alternative Speed 2", "Alternative speed 2 (in %, 0 = unlimited)"), 5, screenManager(), gr->T("%, 0:unlimited"))); altSpeed2->SetFormat("%i%%"); altSpeed2->SetZeroLabel(gr->T("Unlimited")); altSpeed2->SetNegativeDisable(gr->T("Disabled")); - altSpeed2->OnChange.Add([this](UI::EventParams &) { - g_Config.iFpsLimit2 = iAlternateSpeedPercent2_ < 0 ? -1 : (iAlternateSpeedPercent2_ * 60) / 100; - }); if (analogSpeedMapped_) { - PopupSliderChoice *analogSpeed = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercentAnalog_, 1, 1000, UI::NO_DEFAULT_INT, gr->T("Analog alternative speed", "Analog alternative speed (in %)"), 5, screenManager(), "%")); + PopupSliderChoice *analogSpeed = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iAnalogAltSpeedPercent, 1, 1000, UI::NO_DEFAULT_INT, gr->T("Analog alternative speed", "Analog alternative speed (in %)"), 5, screenManager(), "%")); analogSpeed->SetFormat("%i%%"); - analogSpeed->OnChange.Add([this](UI::EventParams &) { - g_Config.iAnalogFpsLimit = (iAlternateSpeedPercentAnalog_ * 60) / 100; - }); } graphicsSettings->Add(new ItemHeader(gr->T("Speed Hacks", "Speed Hacks (can cause rendering errors!)"))); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 7c15ca0a44..2d04e0d1f8 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -89,9 +89,6 @@ private: void ReadConfigTemporaries(); // Temporaries to convert setting types, cache enabled, etc. - int iAlternateSpeedPercent1_ = 0; - int iAlternateSpeedPercent2_ = 0; - int iAlternateSpeedPercentAnalog_ = 0; int prevInflightFrames_ = -1; bool enableReports_ = false; bool analogSpeedMapped_ = false;