Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Add analog speed limit mapping #15645

Merged
merged 7 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,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),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this belong to controls section? Related to #15406.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't the button or anything, it's the limit. It's kinda more related to graphics.

-[Unknown]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just wondering if we want to allow different control profile to have different limit or not. Not really interested in the semantic meaning here :)

Not a big deal anyway

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),
Expand Down
2 changes: 2 additions & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,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;
Expand Down
6 changes: 6 additions & 0 deletions Core/ConfigValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,9 @@ enum class BackgroundAnimation {
WAVE = 3,
MOVING_BACKGROUND = 4,
};

enum class AnalogFpsMode {
AUTO = 0,
MAPPED_DIRECTION = 1,
MAPPED_DIR_TO_OPPOSITE_DIR = 2,
};
70 changes: 70 additions & 0 deletions Core/ControlMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<int> 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) {
Expand Down Expand Up @@ -375,3 +386,62 @@ void ControlMapper::processAxis(const AxisInput &axis, int direction) {
}
}
}

void ControlMapper::ProcessAnalogSpeed(const AxisInput &axis, bool opposite) {
static constexpr float DEADZONE_THRESHOLD = 0.15f;
static constexpr float DEADZONE_SCALE = 1.0f / (1.0f - DEADZONE_THRESHOLD);

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_DIR_TO_OPPOSITE_DIR;
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);
// Clamp to 0 in this case if we're processing the opposite direction.
if (opposite)
value = 0.0f;
} else if (mode == AnalogFpsMode::MAPPED_DIR_TO_OPPOSITE_DIR) {
value = fabsf(value);
if (opposite)
value = -value;
value = 0.5f - value * 0.5f;
}

// Apply a small deadzone (against the resting position.)
value = std::max(0.0f, (value - DEADZONE_THRESHOLD) * DEADZONE_SCALE);

// 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;
}
1 change: 1 addition & 0 deletions Core/ControlMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions Core/CoreParameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum class FPSLimit {
NORMAL = 0,
CUSTOM1 = 1,
CUSTOM2 = 2,
ANALOG = 3,
};

class FileLoader;
Expand Down Expand Up @@ -76,6 +77,7 @@ struct CoreParameter {
// Can be modified at runtime.
bool fastForward = false;
FPSLimit fpsLimit = FPSLimit::NORMAL;
int analogFpsLimit = 0;

bool updateRecent = true;

Expand Down
2 changes: 2 additions & 0 deletions Core/HLE/sceDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 15 additions & 3 deletions Core/KeyMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ KeyMapping g_controllerMap;
// Incremented on modification, so we know when to update menus.
int g_controllerMapGeneration = 0;
std::set<std::string> g_seenPads;
std::map<int, std::string> g_padNames;
std::set<int> g_seenDeviceIds;

bool g_swapped_keys = false;
Expand Down Expand Up @@ -368,6 +369,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"},
Expand Down Expand Up @@ -542,8 +544,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;
}
}
Expand Down Expand Up @@ -762,8 +766,9 @@ bool HasBuiltinController(const std::string &name) {
return IsOuya(name) || IsXperiaPlay(name) || IsNvidiaShield(name) || IsMOQII7S(name) || IsRetroid(name);
}

void NotifyPadConnected(const std::string &name) {
void NotifyPadConnected(int deviceId, const std::string &name) {
g_seenPads.insert(name);
g_padNames[deviceId] = name;
}

void AutoConfForPad(const std::string &name) {
Expand Down Expand Up @@ -796,6 +801,13 @@ const std::set<std::string> &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;
Expand Down
4 changes: 3 additions & 1 deletion Core/KeyMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
Expand Down Expand Up @@ -153,7 +154,7 @@ namespace KeyMap {
void SwapAxis();
void UpdateNativeMenuKeys();

void NotifyPadConnected(const std::string &name);
void NotifyPadConnected(int deviceId, const std::string &name);
bool IsNvidiaShield(const std::string &name);
bool IsNvidiaShieldTV(const std::string &name);
bool IsXperiaPlay(const std::string &name);
Expand All @@ -163,6 +164,7 @@ namespace KeyMap {
bool HasBuiltinController(const std::string &name);

const std::set<std::string> &GetSeenPads();
std::string PadName(int deviceId);
void AutoConfForPad(const std::string &name);

bool IsKeyMapped(int device, int key);
Expand Down
9 changes: 8 additions & 1 deletion GPU/GPUCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 12 additions & 3 deletions SDL/SDLJoystick.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "Common/System/System.h"

#include "Core/Config.h"
#include "Core/KeyMap.h"
#include "SDL/SDLJoystick.h"

using namespace std;
Expand Down Expand Up @@ -54,11 +55,12 @@ void SDLJoystick::setUpControllers() {
}

void SDLJoystick::setUpController(int deviceIndex) {
static constexpr int cbGUID = 33;
char pszGUID[cbGUID];

if (!SDL_IsGameController(deviceIndex)) {
cout << "Control pad device " << deviceIndex << " not supported by SDL game controller database, attempting to create default mapping..." << endl;
int cbGUID = 33;
char pszGUID[cbGUID];
SDL_Joystick* joystick = SDL_JoystickOpen(deviceIndex);
SDL_Joystick *joystick = SDL_JoystickOpen(deviceIndex);
if (joystick) {
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), pszGUID, cbGUID);
// create default mapping - this is the PS3 dual shock mapping
Expand All @@ -73,13 +75,20 @@ void SDLJoystick::setUpController(int deviceIndex) {
} else {
cout << "Failed to get joystick identifier. Read-only device? Control pad device " + std::to_string(deviceIndex) << endl;
}
} else {
SDL_Joystick *joystick = SDL_JoystickOpen(deviceIndex);
if (joystick) {
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(joystick), pszGUID, cbGUID);
SDL_JoystickClose(joystick);
}
}
SDL_GameController *controller = SDL_GameControllerOpen(deviceIndex);
if (controller) {
if (SDL_GameControllerGetAttached(controller)) {
controllers.push_back(controller);
controllerDeviceMap[SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))] = deviceIndex;
cout << "found control pad: " << SDL_GameControllerName(controller) << ", loading mapping: ";
KeyMap::NotifyPadConnected(deviceIndex, std::string(pszGUID) + ": " + SDL_GameControllerName(controller));
auto mapping = SDL_GameControllerMapping(controller);
if (mapping == NULL) {
//cout << "FAILED" << endl;
Expand Down
5 changes: 4 additions & 1 deletion UI/ControlMappingScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,14 @@ 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 && !UI::IsEscapeKey(key))
return true;

mapped_ = true;
KeyDef kdf(key.deviceId, key.keyCode);
TriggerFinish(DR_YES);
if (callback_)
if (callback_ && pspBtn_ != VIRTKEY_SPEED_ANALOG)
callback_(kdf);
}
return true;
Expand Down
4 changes: 2 additions & 2 deletions UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,10 +585,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);
}
Expand Down
14 changes: 14 additions & 0 deletions UI/GameSettingsScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID,
: UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), editThenRestore_(editThenRestore) {
lastVertical_ = UseVerticalLayout();
prevInflightFrames_ = g_Config.iInflightFrames;
analogSpeedMapped_ = KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr);
}

bool GameSettingsScreen::UseVerticalLayout() const {
Expand Down Expand Up @@ -201,6 +202,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();

Expand Down Expand Up @@ -335,6 +337,11 @@ void GameSettingsScreen::CreateViews() {
altSpeed2->SetZeroLabel(gr->T("Unlimited"));
altSpeed2->SetNegativeDisable(gr->T("Disabled"));

if (analogSpeedMapped_) {
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<std::string> alreadyAddedShader;
Expand Down Expand Up @@ -1402,7 +1409,14 @@ 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();
}

bool mapped = KeyMap::AxisFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, nullptr, nullptr);
if (mapped != analogSpeedMapped_) {
analogSpeedMapped_ = mapped;
RecreateViews();
}
}
Expand Down
2 changes: 2 additions & 0 deletions UI/GameSettingsScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,11 @@ 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;
bool analogSpeedMapped_ = false;
std::string shaderNames_[256];
std::string searchFilter_;

Expand Down
Loading