From 3ea97b83a8905485d3625d11e2a465bcb21be170 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 4 Jul 2022 13:10:42 -0700 Subject: [PATCH] UI: Add analog speed limit mapping. Only shows up as a setting if mapped, to avoid cluttering settings. --- Core/Config.cpp | 2 ++ Core/Config.h | 2 ++ Core/ConfigValues.h | 6 ++++ Core/ControlMapper.cpp | 63 +++++++++++++++++++++++++++++++++++++ Core/ControlMapper.h | 1 + Core/CoreParameter.h | 2 ++ Core/HLE/sceDisplay.cpp | 2 ++ Core/KeyMap.cpp | 14 +++++++-- Core/KeyMap.h | 2 ++ GPU/GPUCommon.cpp | 9 +++++- UI/ControlMappingScreen.cpp | 3 ++ UI/EmuScreen.cpp | 4 +-- UI/GameSettingsScreen.cpp | 7 +++++ UI/GameSettingsScreen.h | 1 + 14 files changed, 113 insertions(+), 5 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index 81c0be55b886..9e6a17ad8eda 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -862,6 +862,8 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), ConfigSetting("FrameRate", &g_Config.iFpsLimit1, 0, true, true), ConfigSetting("FrameRate2", &g_Config.iFpsLimit2, -1, true, true), + ConfigSetting("AnalogFrameRate", &g_Config.iAnalogFpsLimit, 240, true, true), + ConfigSetting("AnalogFrameRateMode", &g_Config.iAnalogFpsMode, 0, true, true), ConfigSetting("UnthrottlingMode", &g_Config.iFastForwardMode, &DefaultFastForwardMode, &FastForwardModeToString, &FastForwardModeFromString, true, true), #if defined(USING_WIN_UI) ConfigSetting("RestartRequired", &g_Config.bRestartRequired, false, false), diff --git a/Core/Config.h b/Core/Config.h index 92d240c0af7f..b2ea03455529 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -209,6 +209,8 @@ struct Config { bool bTexHardwareScaling; int iFpsLimit1; int iFpsLimit2; + int iAnalogFpsLimit; + int iAnalogFpsMode; // 0 = auto, 1 = single direction, 2 = mapped to opposite int iMaxRecent; int iCurrentStateSlot; int iRewindFlipFrequency; diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index 44653a28fca4..5499a6640528 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -130,3 +130,9 @@ enum class BackgroundAnimation { WAVE = 3, MOVING_BACKGROUND = 4, }; + +enum class AnalogFpsMode { + AUTO = 0, + MAPPED_DIRECTION = 1, + MAPPED_TO_OPPOSITE = 2, +}; diff --git a/Core/ControlMapper.cpp b/Core/ControlMapper.cpp index 44d034a2cb82..25a20470c7cc 100644 --- a/Core/ControlMapper.cpp +++ b/Core/ControlMapper.cpp @@ -7,6 +7,8 @@ #include "Core/KeyMap.h" #include "Core/ControlMapper.h" #include "Core/Config.h" +#include "Core/CoreParameter.h" +#include "Core/System.h" static float MapAxisValue(float v) { const float deadzone = g_Config.fAnalogDeadzone; @@ -334,12 +336,21 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { case VIRTKEY_AXIS_RIGHT_Y_MAX: SetPSPAxis('Y', value, CTRL_STICK_RIGHT); break; + + case VIRTKEY_SPEED_ANALOG: + ProcessAnalogSpeed(axis, false); + break; } } std::vector resultsOpposite; KeyMap::AxisToPspButton(axis.deviceId, axis.axisId, -direction, &resultsOpposite); + for (int result : resultsOpposite) { + if (result == VIRTKEY_SPEED_ANALOG) + ProcessAnalogSpeed(axis, true); + } + int axisState = 0; float threshold = axis.deviceId == DEVICE_ID_MOUSE ? AXIS_BIND_THRESHOLD_MOUSE : AXIS_BIND_THRESHOLD; if (direction == 1 && axis.value >= threshold) { @@ -375,3 +386,55 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) { } } } + +void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) { + FPSLimit &limitMode = PSP_CoreParameter().fpsLimit; + // If we're using an alternate speed already, let that win. + if (limitMode != FPSLimit::NORMAL && limitMode != FPSLimit::ANALOG) + return; + // Don't even try if the limit is invalid. + if (g_Config.iAnalogFpsLimit <= 0) + return; + + AnalogFpsMode mode = (AnalogFpsMode)g_Config.iAnalogFpsMode; + float value = axis.value; + if (mode == AnalogFpsMode::AUTO) { + // TODO: Consider the pad name for better auto? KeyMap::PadName(axis.deviceId); + switch (axis.axisId) { + case JOYSTICK_AXIS_X: + case JOYSTICK_AXIS_Y: + case JOYSTICK_AXIS_Z: + case JOYSTICK_AXIS_RX: + case JOYSTICK_AXIS_RY: + case JOYSTICK_AXIS_RZ: + // These, at least on directinput, can be used for triggers that go from mapped to opposite. + mode = AnalogFpsMode::MAPPED_TO_OPPOSITE; + break; + + default: + // Other axises probably don't go from negative to positive. + mode = AnalogFpsMode::MAPPED_DIRECTION; + break; + } + } + + // Okay, now let's map it as appropriate. + if (mode == AnalogFpsMode::MAPPED_DIRECTION) { + value = fabsf(value); + if (opposite) + return; + } else if (mode == AnalogFpsMode::MAPPED_TO_OPPOSITE) { + value = fabsf(value); + if (opposite) + value = -value; + value = 0.5f - value * 0.5f; + } + + // 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; + PSP_CoreParameter().analogFpsLimit = 60 + (int)(target * value); + + // If we've reset back to normal, turn it off. + limitMode = PSP_CoreParameter().analogFpsLimit == 60 ? FPSLimit::NORMAL : FPSLimit::ANALOG; +} diff --git a/Core/ControlMapper.h b/Core/ControlMapper.h index cb363c7ebcc5..d930c56f8be2 100644 --- a/Core/ControlMapper.h +++ b/Core/ControlMapper.h @@ -33,6 +33,7 @@ class ControlMapper { void setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true); void SetPSPAxis(char axis, float value, int stick); + void ProcessAnalogSpeed(const AxisInput &axis, bool opposite); void onVKeyDown(int vkey); void onVKeyUp(int vkey); diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h index 1e5ef6793533..7e9ea60b2e46 100644 --- a/Core/CoreParameter.h +++ b/Core/CoreParameter.h @@ -33,6 +33,7 @@ enum class FPSLimit { NORMAL = 0, CUSTOM1 = 1, CUSTOM2 = 2, + ANALOG = 3, }; class FileLoader; @@ -76,6 +77,7 @@ struct CoreParameter { // Can be modified at runtime. bool fastForward = false; FPSLimit fpsLimit = FPSLimit::NORMAL; + int analogFpsLimit = 0; bool updateRecent = true; diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 3ebd21046969..bd1de18342d1 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -354,6 +354,8 @@ static int FrameTimingLimit() { return g_Config.iFpsLimit1; if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) return g_Config.iFpsLimit2; + if (PSP_CoreParameter().fpsLimit == FPSLimit::ANALOG) + return PSP_CoreParameter().analogFpsLimit; if (PSP_CoreParameter().fastForward) return 0; return 60; diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index 61b96374c02d..49455d747717 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -368,6 +368,7 @@ const KeyMap_IntStrPair psp_button_names[] = { {VIRTKEY_SPEED_TOGGLE, "SpeedToggle"}, {VIRTKEY_SPEED_CUSTOM1, "Alt speed 1"}, {VIRTKEY_SPEED_CUSTOM2, "Alt speed 2"}, + {VIRTKEY_SPEED_ANALOG, "Analog speed"}, {VIRTKEY_PAUSE, "Pause"}, #ifndef MOBILE_DEVICE {VIRTKEY_FRAME_ADVANCE, "Frame Advance"}, @@ -542,8 +543,10 @@ bool AxisFromPspButton(int btn, int *deviceId, int *axisId, int *direction) { for (auto iter = g_controllerMap.begin(); iter != g_controllerMap.end(); ++iter) { for (auto iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2) { if (iter->first == btn && iter2->keyCode >= AXIS_BIND_NKCODE_START) { - *deviceId = iter2->deviceId; - *axisId = TranslateKeyCodeToAxis(iter2->keyCode, *direction); + if (deviceId) + *deviceId = iter2->deviceId; + if (axisId) + *axisId = TranslateKeyCodeToAxis(iter2->keyCode, *direction); return true; } } @@ -797,6 +800,13 @@ const std::set &GetSeenPads() { return g_seenPads; } +std::string PadName(int deviceId) { + auto it = g_padNames.find(deviceId); + if (it != g_padNames.end()) + return it->second; + return ""; +} + // Swap direction buttons and left analog axis void SwapAxis() { g_swapped_keys = !g_swapped_keys; diff --git a/Core/KeyMap.h b/Core/KeyMap.h index 78f2b95987a8..a8ae9f672a58 100644 --- a/Core/KeyMap.h +++ b/Core/KeyMap.h @@ -67,6 +67,7 @@ enum { VIRTKEY_SCREEN_ROTATION_VERTICAL180 = 0x40000021, VIRTKEY_SCREEN_ROTATION_HORIZONTAL = 0x40000022, VIRTKEY_SCREEN_ROTATION_HORIZONTAL180 = 0x40000023, + VIRTKEY_SPEED_ANALOG = 0x40000024, VIRTKEY_LAST, VIRTKEY_COUNT = VIRTKEY_LAST - VIRTKEY_FIRST }; @@ -163,6 +164,7 @@ namespace KeyMap { bool HasBuiltinController(const std::string &name); const std::set &GetSeenPads(); + std::string PadName(int deviceId); void AutoConfForPad(const std::string &name); bool IsKeyMapped(int device, int key); diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index df978cfb9be6..0d24e004c499 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -505,7 +505,14 @@ void GPUCommon::UpdateVsyncInterval(bool force) { desiredVSyncInterval = 0; } if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) { - int limit = PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 ? g_Config.iFpsLimit1 : g_Config.iFpsLimit2; + int limit; + if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1) + limit = g_Config.iFpsLimit1; + else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) + limit = g_Config.iFpsLimit2; + else + limit = PSP_CoreParameter().analogFpsLimit; + // For an alternative speed that is a clean factor of 60, the user probably still wants vsync. if (limit == 0 || (limit >= 0 && limit != 15 && limit != 30 && limit != 60)) { desiredVSyncInterval = 0; diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 126f2629f3cd..32ada96a0d40 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -337,6 +337,9 @@ bool KeyMappingNewKeyDialog::key(const KeyInput &key) { if (key.keyCode == NKCODE_EXT_MOUSEBUTTON_1) { return true; } + // Only map analog values to this mapping. + if (pspBtn_ == VIRTKEY_SPEED_ANALOG) + return true; mapped_ = true; KeyDef kdf(key.deviceId, key.keyCode); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b2a32c45ec10..4be13c877dfb 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -582,10 +582,10 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) { if (PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL && g_Config.iFpsLimit1 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM1; osm.Show(sc->T("fixed", "Speed: alternate"), 1.0); - } else if (PSP_CoreParameter().fpsLimit != FPSLimit::CUSTOM2 && g_Config.iFpsLimit2 >= 0) { + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && g_Config.iFpsLimit2 >= 0) { PSP_CoreParameter().fpsLimit = FPSLimit::CUSTOM2; osm.Show(sc->T("SpeedCustom2", "Speed: alternate 2"), 1.0); - } else if (PSP_CoreParameter().fpsLimit != FPSLimit::NORMAL) { + } else if (PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM1 && PSP_CoreParameter().fpsLimit == FPSLimit::CUSTOM2) { PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; osm.Show(sc->T("standard", "Speed: standard"), 1.0); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 548daef51127..efbaf39c054a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -201,6 +201,7 @@ void GameSettingsScreen::CreateViews() { 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; bool vertical = UseVerticalLayout(); @@ -335,6 +336,11 @@ void GameSettingsScreen::CreateViews() { altSpeed2->SetZeroLabel(gr->T("Unlimited")); altSpeed2->SetNegativeDisable(gr->T("Disabled")); + if (KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr)) { + PopupSliderChoice *analogSpeed = graphicsSettings->Add(new PopupSliderChoice(&iAlternateSpeedPercentAnalog_, 1, 1000, gr->T("Analog Alternative Speed", "Analog alternative speed (in %)"), 5, screenManager(), gr->T("%"))); + altSpeed2->SetFormat("%i%%"); + } + graphicsSettings->Add(new ItemHeader(gr->T("Postprocessing effect"))); std::set alreadyAddedShader; @@ -1388,6 +1394,7 @@ void GameSettingsScreen::dialogFinished(const Screen *dialog, DialogResult resul if (result == DialogResult::DR_OK) { g_Config.iFpsLimit1 = iAlternateSpeedPercent1_ < 0 ? -1 : (iAlternateSpeedPercent1_ * 60) / 100; g_Config.iFpsLimit2 = iAlternateSpeedPercent2_ < 0 ? -1 : (iAlternateSpeedPercent2_ * 60) / 100; + g_Config.iAnalogFpsLimit = (iAlternateSpeedPercentAnalog_ * 60) / 100; RecreateViews(); } diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 5e3f280f3bc3..2db41e2d9c30 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -137,6 +137,7 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { // Temporaries to convert setting types, cache enabled, etc. int iAlternateSpeedPercent1_; int iAlternateSpeedPercent2_; + int iAlternateSpeedPercentAnalog_; int prevInflightFrames_; bool enableReports_ = false; bool enableReportsSet_ = false;