mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
Merge branch 'shadps4-emu:main' into main
This commit is contained in:
commit
99000bd5d7
@ -115,9 +115,20 @@ execute_process(
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Default to origin if there's no upstream set or if the command failed
|
||||
# If there's no upstream set or the command failed, check remote.pushDefault
|
||||
if (GIT_BRANCH_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
||||
set(GIT_REMOTE_NAME "origin")
|
||||
execute_process(
|
||||
COMMAND git config --get remote.pushDefault
|
||||
OUTPUT_VARIABLE GIT_REMOTE_NAME
|
||||
RESULT_VARIABLE GIT_PUSH_DEFAULT_RESULT
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# If remote.pushDefault is not set or fails, default to origin
|
||||
if (GIT_PUSH_DEFAULT_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
||||
set(GIT_REMOTE_NAME "origin")
|
||||
endif()
|
||||
else()
|
||||
# Extract remote name if the output contains a remote/branch format
|
||||
string(FIND "${GIT_REMOTE_NAME}" "/" INDEX)
|
||||
@ -475,6 +486,10 @@ set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
|
||||
src/core/libraries/zlib/zlib_error.h
|
||||
)
|
||||
|
||||
set(VR_LIBS src/core/libraries/hmd/hmd.cpp
|
||||
src/core/libraries/hmd/hmd.h
|
||||
)
|
||||
|
||||
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
||||
src/core/libraries/screenshot/screenshot.h
|
||||
src/core/libraries/move/move.cpp
|
||||
@ -652,6 +667,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||
${IME_LIB}
|
||||
${FIBER_LIB}
|
||||
${VDEC_LIB}
|
||||
${VR_LIBS}
|
||||
${DEV_TOOLS}
|
||||
src/core/debug_state.cpp
|
||||
src/core/debug_state.h
|
||||
@ -886,6 +902,9 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
||||
src/qt_gui/cheats_patches.h
|
||||
src/qt_gui/compatibility_info.cpp
|
||||
src/qt_gui/compatibility_info.h
|
||||
src/qt_gui/control_settings.cpp
|
||||
src/qt_gui/control_settings.h
|
||||
src/qt_gui/control_settings.ui
|
||||
src/qt_gui/main_window_ui.h
|
||||
src/qt_gui/main_window.cpp
|
||||
src/qt_gui/main_window.h
|
||||
|
@ -38,6 +38,7 @@ path = [
|
||||
"src/images/list_mode_icon.png",
|
||||
"src/images/pause_icon.png",
|
||||
"src/images/play_icon.png",
|
||||
"src/images/ps4_controller.png",
|
||||
"src/images/refresh_icon.png",
|
||||
"src/images/settings_icon.png",
|
||||
"src/images/stop_icon.png",
|
||||
|
2
dist/net.shadps4.shadPS4.desktop
vendored
2
dist/net.shadps4.shadPS4.desktop
vendored
@ -5,5 +5,5 @@ Terminal=false
|
||||
Type=Application
|
||||
Icon=net.shadps4.shadPS4
|
||||
Comment=PlayStation 4 emulator
|
||||
Categories=Game;
|
||||
Categories=Game;Emulator;
|
||||
StartupWMClass=shadps4;
|
||||
|
@ -95,6 +95,8 @@ std::vector<std::string> m_pkg_viewer;
|
||||
std::vector<std::string> m_elf_viewer;
|
||||
std::vector<std::string> m_recent_files;
|
||||
std::string emulator_language = "en";
|
||||
static int backgroundImageOpacity = 50;
|
||||
static bool showBackgroundImage = true;
|
||||
|
||||
// Language
|
||||
u32 m_language = 1; // english
|
||||
@ -611,6 +613,22 @@ u32 GetLanguage() {
|
||||
return m_language;
|
||||
}
|
||||
|
||||
int getBackgroundImageOpacity() {
|
||||
return backgroundImageOpacity;
|
||||
}
|
||||
|
||||
void setBackgroundImageOpacity(int opacity) {
|
||||
backgroundImageOpacity = std::clamp(opacity, 0, 100);
|
||||
}
|
||||
|
||||
bool getShowBackgroundImage() {
|
||||
return showBackgroundImage;
|
||||
}
|
||||
|
||||
void setShowBackgroundImage(bool show) {
|
||||
showBackgroundImage = show;
|
||||
}
|
||||
|
||||
void load(const std::filesystem::path& path) {
|
||||
// If the configuration file does not exist, create it and return
|
||||
std::error_code error;
|
||||
@ -731,6 +749,8 @@ void load(const std::filesystem::path& path) {
|
||||
m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {});
|
||||
m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0);
|
||||
emulator_language = toml::find_or<std::string>(gui, "emulatorLanguage", "en");
|
||||
backgroundImageOpacity = toml::find_or<int>(gui, "backgroundImageOpacity", 50);
|
||||
showBackgroundImage = toml::find_or<bool>(gui, "showBackgroundImage", true);
|
||||
}
|
||||
|
||||
if (data.contains("Settings")) {
|
||||
@ -821,6 +841,8 @@ void save(const std::filesystem::path& path) {
|
||||
data["GUI"]["addonInstallDir"] =
|
||||
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
||||
data["GUI"]["emulatorLanguage"] = emulator_language;
|
||||
data["GUI"]["backgroundImageOpacity"] = backgroundImageOpacity;
|
||||
data["GUI"]["showBackgroundImage"] = showBackgroundImage;
|
||||
data["Settings"]["consoleLanguage"] = m_language;
|
||||
|
||||
std::ofstream file(path, std::ios::binary);
|
||||
@ -914,6 +936,8 @@ void setDefaultValues() {
|
||||
separateupdatefolder = false;
|
||||
compatibilityData = false;
|
||||
checkCompatibilityOnStartup = false;
|
||||
backgroundImageOpacity = 50;
|
||||
showBackgroundImage = true;
|
||||
}
|
||||
|
||||
constexpr std::string_view GetDefaultKeyboardConfig() {
|
||||
@ -984,8 +1008,8 @@ axis_right_x = axis_right_x
|
||||
axis_right_y = axis_right_y
|
||||
|
||||
# Range of deadzones: 1 (almost none) to 127 (max)
|
||||
analog_deadzone = leftjoystick, 2
|
||||
analog_deadzone = rightjoystick, 2
|
||||
analog_deadzone = leftjoystick, 2, 127
|
||||
analog_deadzone = rightjoystick, 2, 127
|
||||
)";
|
||||
}
|
||||
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) {
|
||||
|
@ -30,6 +30,8 @@ bool getEnableDiscordRPC();
|
||||
bool getSeparateUpdateEnabled();
|
||||
bool getCompatibilityEnabled();
|
||||
bool getCheckCompatibilityOnStartup();
|
||||
int getBackgroundImageOpacity();
|
||||
bool getShowBackgroundImage();
|
||||
|
||||
std::string getLogFilter();
|
||||
std::string getLogType();
|
||||
@ -88,6 +90,8 @@ void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_insta
|
||||
void setSaveDataPath(const std::filesystem::path& path);
|
||||
void setCompatibilityEnabled(bool use);
|
||||
void setCheckCompatibilityOnStartup(bool use);
|
||||
void setBackgroundImageOpacity(int opacity);
|
||||
void setShowBackgroundImage(bool show);
|
||||
|
||||
void setCursorState(s16 cursorState);
|
||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||
|
@ -134,6 +134,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
||||
SUB(Lib, WebBrowserDialog) \
|
||||
SUB(Lib, NpParty) \
|
||||
SUB(Lib, Zlib) \
|
||||
SUB(Lib, Hmd) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Vulkan) \
|
||||
|
@ -23,8 +23,8 @@ std::string FormatLogMessage(const Entry& entry) {
|
||||
const char* class_name = GetLogClassName(entry.log_class);
|
||||
const char* level_name = GetLevelName(entry.log_level);
|
||||
|
||||
return fmt::format("[{}] <{}> {}:{}:{}: {}", class_name, level_name, entry.filename,
|
||||
entry.function, entry.line_num, entry.message);
|
||||
return fmt::format("[{}] <{}> {}:{} {}: {}", class_name, level_name, entry.filename,
|
||||
entry.line_num, entry.function, entry.message);
|
||||
}
|
||||
|
||||
void PrintMessage(const Entry& entry) {
|
||||
|
@ -101,6 +101,7 @@ enum class Class : u8 {
|
||||
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||
Lib_NpParty, ///< The LibSceNpParty implementation
|
||||
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||
Lib_Hmd, ///< The LibSceHmd implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Video Core
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
|
@ -174,7 +174,7 @@ void OnGameLoaded() {
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
MemoryPatcher::PatchMemory(currentPatchName, address, patchValue, false,
|
||||
littleEndian, patchMask);
|
||||
littleEndian, patchMask, maskOffsetValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -278,6 +278,7 @@ void OnGameLoaded() {
|
||||
lineObject["Type"] = attributes.value("Type").toString();
|
||||
lineObject["Address"] = attributes.value("Address").toString();
|
||||
lineObject["Value"] = attributes.value("Value").toString();
|
||||
lineObject["Offset"] = attributes.value("Offset").toString();
|
||||
linesArray.append(lineObject);
|
||||
}
|
||||
}
|
||||
@ -321,7 +322,7 @@ void OnGameLoaded() {
|
||||
|
||||
MemoryPatcher::PatchMemory(currentPatchName, address.toStdString(),
|
||||
patchValue.toStdString(), false,
|
||||
littleEndian, patchMask);
|
||||
littleEndian, patchMask, maskOffsetValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -447,4 +448,4 @@ uintptr_t PatternScan(const std::string& signature) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace MemoryPatcher
|
||||
} // namespace MemoryPatcher
|
||||
|
1219
src/core/libraries/hmd/hmd.cpp
Normal file
1219
src/core/libraries/hmd/hmd.cpp
Normal file
File diff suppressed because it is too large
Load Diff
203
src/core/libraries/hmd/hmd.h
Normal file
203
src/core/libraries/hmd/hmd.h
Normal file
@ -0,0 +1,203 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::Hmd {
|
||||
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStartMultilayer();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionGet2dVrCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionGetCompoundEyeCorrectionCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionGetCorrectionCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionGetWideNearCorrectionCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionGetWorkMemoryAlign();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionGetWorkMemorySize();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionInitialize();
|
||||
s32 PS4_SYSV_ABI sceHmdDistortionSetOutputMinColor();
|
||||
s32 PS4_SYSV_ABI Func_B26430EA74FC3DC0();
|
||||
s32 PS4_SYSV_ABI sceHmdClose();
|
||||
s32 PS4_SYSV_ABI sceHmdGet2DEyeOffset();
|
||||
s32 PS4_SYSV_ABI sceHmdGet2dVrCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdGetAssyError();
|
||||
s32 PS4_SYSV_ABI sceHmdGetDeviceInformation();
|
||||
s32 PS4_SYSV_ABI sceHmdGetDeviceInformationByHandle();
|
||||
s32 PS4_SYSV_ABI sceHmdGetDistortionCorrectionCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdGetDistortionParams();
|
||||
s32 PS4_SYSV_ABI sceHmdGetDistortionWorkMemoryAlign();
|
||||
s32 PS4_SYSV_ABI sceHmdGetDistortionWorkMemorySize();
|
||||
s32 PS4_SYSV_ABI sceHmdGetFieldOfView();
|
||||
s32 PS4_SYSV_ABI sceHmdGetInertialSensorData();
|
||||
s32 PS4_SYSV_ABI sceHmdGetWideNearDistortionCorrectionCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdInitialize();
|
||||
s32 PS4_SYSV_ABI sceHmdInitialize315();
|
||||
s32 PS4_SYSV_ABI sceHmdInternal3dAudioClose();
|
||||
s32 PS4_SYSV_ABI sceHmdInternal3dAudioOpen();
|
||||
s32 PS4_SYSV_ABI sceHmdInternal3dAudioSendData();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenClose();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenGetAudioStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenGetFadeState();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenGetVideoStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenOpen();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenSendAudio();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenSendVideo();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalAnotherScreenSetFadeAndSwitch();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalBindDeviceWithUserId();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCheckDeviceModelMk3();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCheckS3dPassModeAvailable();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCrashReportCancel();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCrashReportClose();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCrashReportOpen();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCrashReportReadData();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCrashReportReadDataSize();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalCreateSharedMemory();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuCheckAfterPvt();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuCheckPartialUpdateAvailable();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuClose();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuGetStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuOpen();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuReset();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuSend();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuSendSize();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuSetMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalDfuStart();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalEventInitialize();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetBrightness();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetCrashDumpInfo();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDebugMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDebugSocialScreenMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDebugTextMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDefaultLedData();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDemoMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDeviceInformation();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDeviceInformationByHandle();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetDeviceStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetEyeStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetHmuOpticalParam();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetHmuPowerStatusForDebug();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetHmuSerialNumber();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetIPD();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetIpdSettingEnableForSystemService();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetPuBuildNumber();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetPuPositionParam();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetPuRevision();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetPUSerialNumber();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetPUVersion();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetRequiredPUPVersion();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetStatusReport();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetTv4kCapability();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetVirtualDisplayDepth();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetVirtualDisplayHeight();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetVirtualDisplaySize();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalGetVr2dData();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalIsCommonDlgMiniAppVr2d();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalIsCommonDlgVr2d();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalIsGameVr2d();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalIsMiniAppVr2d();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalMapSharedMemory();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalMirroringModeSetAspect();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalMirroringModeSetAspectDebug();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalMmapGetCount();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalMmapGetModeId();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalMmapGetSensorCalibrationData();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalMmapIsConnect();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalPushVr2dData();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalRegisterEventCallback();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalResetInertialSensor();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalResetLedForVrTracker();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalResetLedForVsh();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSeparateModeClose();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSeparateModeGetAudioStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSeparateModeGetVideoStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSeparateModeOpen();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSeparateModeSendAudio();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSeparateModeSendVideo();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetBrightness();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetCrashReportCommand();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetDebugGpo();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetDebugMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetDebugSocialScreenMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetDebugTextMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetDefaultLedData();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetDemoMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetDeviceConnection();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetForcedCrash();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetHmuPowerControl();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetHmuPowerControlForDebug();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetIPD();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetIpdSettingEnableForSystemService();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetLedOn();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetM2LedBrightness();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetM2LedOn();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetPortConnection();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetPortStatus();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetS3dPassMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetSidetone();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetUserType();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetVirtualDisplayDepth();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetVirtualDisplayHeight();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetVirtualDisplaySize();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSetVRMode();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSocialScreenGetFadeState();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSocialScreenSetFadeAndSwitch();
|
||||
s32 PS4_SYSV_ABI sceHmdInternalSocialScreenSetOutput();
|
||||
s32 PS4_SYSV_ABI sceHmdOpen();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionAddDisplayBuffer();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionClearUserEventEnd();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionClearUserEventStart();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionDebugGetLastInfo();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionDebugGetLastInfoMultilayer();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionFinalize();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionFinalizeCapture();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionInitialize();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionInitializeCapture();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionQueryGarlicBuffAlign();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionQueryGarlicBuffSize();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionQueryOnionBuffAlign();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionQueryOnionBuffSize();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionSetCallback();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionSetDisplayBuffers();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionSetOutputMinColor();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionSetUserEventEnd();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionSetUserEventStart();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStart();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStart2dVr();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStartCapture();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStartLiveCapture();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStartMultilayer2();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStartWideNear();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStartWideNearWithOverlay();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStartWithOverlay();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStop();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStopCapture();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionStopLiveCapture();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionUnsetCallback();
|
||||
s32 PS4_SYSV_ABI sceHmdReprojectionUnsetDisplayBuffers();
|
||||
s32 PS4_SYSV_ABI sceHmdTerminate();
|
||||
s32 PS4_SYSV_ABI Func_202D0D1A687FCD2F();
|
||||
s32 PS4_SYSV_ABI Func_358DBF818A3D8A12();
|
||||
s32 PS4_SYSV_ABI Func_5CCBADA76FE8F40E();
|
||||
s32 PS4_SYSV_ABI Func_63D403167DC08CF0();
|
||||
s32 PS4_SYSV_ABI Func_69383B2B4E3AEABF();
|
||||
s32 PS4_SYSV_ABI Func_791560C32F4F6D68();
|
||||
s32 PS4_SYSV_ABI Func_7C955961EA85B6D3();
|
||||
s32 PS4_SYSV_ABI Func_9952277839236BA7();
|
||||
s32 PS4_SYSV_ABI Func_9A276E739E54EEAF();
|
||||
s32 PS4_SYSV_ABI Func_9E501994E289CBE7();
|
||||
s32 PS4_SYSV_ABI Func_A31A0320D80EAD99();
|
||||
s32 PS4_SYSV_ABI Func_A31F4DA8B3BD2E12();
|
||||
s32 PS4_SYSV_ABI Func_A92D7C23AC364993();
|
||||
s32 PS4_SYSV_ABI Func_ADCCC25CB876FDBE();
|
||||
s32 PS4_SYSV_ABI Func_B16652641FE69F0E();
|
||||
s32 PS4_SYSV_ABI Func_B614F290B67FB59B();
|
||||
s32 PS4_SYSV_ABI Func_B9A6FA0735EC7E49();
|
||||
s32 PS4_SYSV_ABI Func_FC193BD653F2AF2E();
|
||||
s32 PS4_SYSV_ABI Func_FF2E0E53015FE231();
|
||||
|
||||
void RegisterlibSceHmd(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Hmd
|
@ -84,7 +84,11 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
for (auto& event : m_events) {
|
||||
if (event.event.ident == ident && event.event.filter == filter) {
|
||||
event.Trigger(trigger_data);
|
||||
if (filter == SceKernelEvent::Filter::VideoOut) {
|
||||
event.TriggerDisplay(trigger_data);
|
||||
} else {
|
||||
event.Trigger(trigger_data);
|
||||
}
|
||||
has_found = true;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
|
||||
#include "common/rdtsc.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
@ -81,6 +82,25 @@ struct EqueueEvent {
|
||||
event.data = reinterpret_cast<uintptr_t>(data);
|
||||
}
|
||||
|
||||
void TriggerDisplay(void* data) {
|
||||
is_triggered = true;
|
||||
auto hint = reinterpret_cast<u64>(data);
|
||||
if (hint != 0) {
|
||||
auto hint_h = static_cast<u32>(hint >> 8) & 0xFFFFFF;
|
||||
auto ident_h = static_cast<u32>(event.ident >> 40);
|
||||
if ((static_cast<u32>(hint) & 0xFF) == event.ident && event.ident != 0xFE &&
|
||||
((hint_h ^ ident_h) & 0xFF) == 0) {
|
||||
auto time = Common::FencedRDTSC();
|
||||
auto mask = 0xF000;
|
||||
if ((static_cast<u32>(event.data) & 0xF000) != 0xF000) {
|
||||
mask = (static_cast<u32>(event.data) + 0x1000) & 0xF000;
|
||||
}
|
||||
event.data = (mask | static_cast<u64>(static_cast<u32>(time) & 0xFFF) |
|
||||
(hint & 0xFFFFFFFFFFFF0000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsTriggered() const {
|
||||
return is_triggered;
|
||||
}
|
||||
|
@ -26,17 +26,20 @@ u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize() {
|
||||
|
||||
int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len,
|
||||
u64 alignment, int memoryType, s64* physAddrOut) {
|
||||
if (searchStart < 0 || searchEnd <= searchStart) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
if (searchStart < 0 || searchEnd < 0) {
|
||||
LOG_ERROR(Kernel_Vmm, "Invalid parameters!");
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
const bool is_in_range = searchEnd - searchStart >= len;
|
||||
if (len <= 0 || !Common::Is16KBAligned(len) || !is_in_range) {
|
||||
LOG_ERROR(Kernel_Vmm, "Provided address range is invalid!");
|
||||
if (len <= 0 || !Common::Is16KBAligned(len)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Length {:#x} is invalid!", len);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (alignment != 0 && !Common::Is16KBAligned(alignment)) {
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
|
||||
LOG_ERROR(Kernel_Vmm, "Alignment {:#x} is invalid!", alignment);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (memoryType > 10) {
|
||||
LOG_ERROR(Kernel_Vmm, "Memory type {:#x} is invalid!", memoryType);
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
if (physAddrOut == nullptr) {
|
||||
@ -44,8 +47,21 @@ int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u
|
||||
return ORBIS_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
const bool is_in_range = searchEnd - searchStart >= len;
|
||||
if (searchEnd <= searchStart || searchEnd < len || !is_in_range) {
|
||||
LOG_ERROR(Kernel_Vmm,
|
||||
"Provided address range is too small!"
|
||||
" searchStart = {:#x}, searchEnd = {:#x}, length = {:#x}",
|
||||
searchStart, searchEnd, len);
|
||||
return ORBIS_KERNEL_ERROR_EAGAIN;
|
||||
}
|
||||
|
||||
auto* memory = Core::Memory::Instance();
|
||||
PAddr phys_addr = memory->Allocate(searchStart, searchEnd, len, alignment, memoryType);
|
||||
if (phys_addr == -1) {
|
||||
return ORBIS_KERNEL_ERROR_EAGAIN;
|
||||
}
|
||||
|
||||
*physAddrOut = static_cast<s64>(phys_addr);
|
||||
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
|
@ -13,7 +13,6 @@
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
int PS4_SYSV_ABI sceKernelIsNeoMode() {
|
||||
LOG_DEBUG(Kernel_Sce, "called");
|
||||
return Config::isNeoModeConsole() &&
|
||||
Common::ElfInfo::Instance().GetPSFAttributes().support_neo_mode;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "core/libraries/disc_map/disc_map.h"
|
||||
#include "core/libraries/game_live_streaming/gamelivestreaming.h"
|
||||
#include "core/libraries/gnmdriver/gnmdriver.h"
|
||||
#include "core/libraries/hmd/hmd.h"
|
||||
#include "core/libraries/ime/error_dialog.h"
|
||||
#include "core/libraries/ime/ime.h"
|
||||
#include "core/libraries/ime/ime_dialog.h"
|
||||
@ -113,6 +114,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
||||
Libraries::WebBrowserDialog::RegisterlibSceWebBrowserDialog(sym);
|
||||
Libraries::NpParty::RegisterlibSceNpParty(sym);
|
||||
Libraries::Zlib::RegisterlibSceZlib(sym);
|
||||
Libraries::Hmd::RegisterlibSceHmd(sym);
|
||||
}
|
||||
|
||||
} // namespace Libraries
|
||||
|
@ -185,9 +185,11 @@ void VideoOutDriver::Flip(const Request& req) {
|
||||
// Trigger flip events for the port.
|
||||
for (auto& event : port->flip_events) {
|
||||
if (event != nullptr) {
|
||||
event->TriggerEvent(u64(OrbisVideoOutEventId::Flip),
|
||||
Kernel::SceKernelEvent::Filter::VideoOut,
|
||||
reinterpret_cast<void*>(req.flip_arg));
|
||||
event->TriggerEvent(
|
||||
static_cast<u64>(OrbisVideoOutInternalEventId::Flip),
|
||||
Kernel::SceKernelEvent::Filter::VideoOut,
|
||||
reinterpret_cast<void*>(static_cast<u64>(OrbisVideoOutInternalEventId::Flip) |
|
||||
(req.flip_arg << 16)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,7 +325,7 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||
// Trigger flip events for the port.
|
||||
for (auto& event : main_port.vblank_events) {
|
||||
if (event != nullptr) {
|
||||
event->TriggerEvent(u64(OrbisVideoOutEventId::Vblank),
|
||||
event->TriggerEvent(static_cast<u64>(OrbisVideoOutInternalEventId::Vblank),
|
||||
Kernel::SceKernelEvent::Filter::VideoOut, nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
|
||||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.event.ident = u64(OrbisVideoOutEventId::Flip);
|
||||
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Flip);
|
||||
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
||||
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
||||
event.event.udata = udata;
|
||||
@ -63,6 +63,20 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutDeleteFlipEvent(Kernel::SceKernelEqueue eq, s32 handle) {
|
||||
auto* port = driver->GetPort(handle);
|
||||
if (port == nullptr) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (eq == nullptr) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||
}
|
||||
eq->RemoveEvent(handle, Kernel::SceKernelEvent::Filter::VideoOut);
|
||||
port->flip_events.erase(find(port->flip_events.begin(), port->flip_events.end(), eq));
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata) {
|
||||
LOG_INFO(Lib_VideoOut, "handle = {}", handle);
|
||||
|
||||
@ -76,7 +90,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
|
||||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.event.ident = u64(OrbisVideoOutEventId::Vblank);
|
||||
event.event.ident = static_cast<u64>(OrbisVideoOutInternalEventId::Vblank);
|
||||
event.event.filter = Kernel::SceKernelEvent::Filter::VideoOut;
|
||||
event.event.flags = Kernel::SceKernelEvent::Flags::Add;
|
||||
event.event.udata = udata;
|
||||
@ -156,9 +170,27 @@ int PS4_SYSV_ABI sceVideoOutGetEventId(const Kernel::SceKernelEvent* ev) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
if (ev->filter != Kernel::SceKernelEvent::Filter::VideoOut) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE;
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
|
||||
}
|
||||
|
||||
OrbisVideoOutInternalEventId internal_event_id =
|
||||
static_cast<OrbisVideoOutInternalEventId>(ev->ident);
|
||||
switch (internal_event_id) {
|
||||
case OrbisVideoOutInternalEventId::Flip:
|
||||
return static_cast<s32>(OrbisVideoOutEventId::Flip);
|
||||
case OrbisVideoOutInternalEventId::Vblank:
|
||||
case OrbisVideoOutInternalEventId::SysVblank:
|
||||
return static_cast<s32>(OrbisVideoOutEventId::Vblank);
|
||||
case OrbisVideoOutInternalEventId::PreVblankStart:
|
||||
return static_cast<s32>(OrbisVideoOutEventId::PreVblankStart);
|
||||
case OrbisVideoOutInternalEventId::SetMode:
|
||||
return static_cast<s32>(OrbisVideoOutEventId::SetMode);
|
||||
case OrbisVideoOutInternalEventId::Position:
|
||||
return static_cast<s32>(OrbisVideoOutEventId::Position);
|
||||
default: {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_EVENT;
|
||||
}
|
||||
}
|
||||
return ev->ident;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceVideoOutGetEventData(const Kernel::SceKernelEvent* ev, int64_t* data) {
|
||||
@ -356,6 +388,8 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
sceVideoOutColorSettingsSetGamma);
|
||||
LIB_FUNCTION("pv9CI5VC+R0", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutAdjustColor);
|
||||
LIB_FUNCTION("-Ozn0F1AFRg", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutDeleteFlipEvent);
|
||||
|
||||
// openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1
|
||||
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen);
|
||||
|
@ -40,7 +40,22 @@ constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE = 0;
|
||||
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_VR = 7;
|
||||
constexpr int SCE_VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY = 8;
|
||||
|
||||
enum class OrbisVideoOutEventId : s16 { Flip = 0, Vblank = 1, PreVblankStart = 2 };
|
||||
enum class OrbisVideoOutEventId : s16 {
|
||||
Flip = 0,
|
||||
Vblank = 1,
|
||||
PreVblankStart = 2,
|
||||
SetMode = 8,
|
||||
Position = 12,
|
||||
};
|
||||
|
||||
enum class OrbisVideoOutInternalEventId : s16 {
|
||||
Flip = 0x6,
|
||||
Vblank = 0x7,
|
||||
SetMode = 0x51,
|
||||
Position = 0x58,
|
||||
PreVblankStart = 0x59,
|
||||
SysVblank = 0x63,
|
||||
};
|
||||
|
||||
enum class AspectRatioMode : s32 {
|
||||
Ratio16_9 = 0,
|
||||
|
@ -117,7 +117,10 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size,
|
||||
dmem_area->second.GetEnd() <= search_end) {
|
||||
++dmem_area;
|
||||
}
|
||||
ASSERT_MSG(is_suitable(), "Unable to find free direct memory area: size = {:#x}", size);
|
||||
if (!is_suitable()) {
|
||||
LOG_ERROR(Kernel_Vmm, "Unable to find free direct memory area: size = {:#x}", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Align free position
|
||||
PAddr free_addr = dmem_area->second.base;
|
||||
|
@ -201,12 +201,16 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
||||
window_title = fmt::format("shadPS4 v{} | {}", Common::VERSION, game_title);
|
||||
} else {
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
if (remote_url == "https://github.com/shadps4-emu/shadPS4.git" ||
|
||||
remote_url.length() == 0) {
|
||||
std::string remote_host;
|
||||
try {
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} {} {} | {}", Common::VERSION,
|
||||
Common::g_scm_branch, Common::g_scm_desc, game_title);
|
||||
} else {
|
||||
std::string remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
window_title = fmt::format("shadPS4 v{} {}/{} {} | {}", Common::VERSION, remote_host,
|
||||
Common::g_scm_branch, Common::g_scm_desc, game_title);
|
||||
}
|
||||
|
BIN
src/images/ps4_controller.png
Normal file
BIN
src/images/ps4_controller.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
@ -55,7 +55,8 @@ Don't be an idiot and test only the changed part expecting everything else to no
|
||||
*/
|
||||
|
||||
bool leftjoystick_halfmode = false, rightjoystick_halfmode = false;
|
||||
int leftjoystick_deadzone, rightjoystick_deadzone, lefttrigger_deadzone, righttrigger_deadzone;
|
||||
std::pair<int, int> leftjoystick_deadzone, rightjoystick_deadzone, lefttrigger_deadzone,
|
||||
righttrigger_deadzone;
|
||||
|
||||
std::list<std::pair<InputEvent, bool>> pressed_keys;
|
||||
std::list<InputID> toggled_keys;
|
||||
@ -208,10 +209,10 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
float mouse_speed = 1;
|
||||
float mouse_speed_offset = 0.125;
|
||||
|
||||
leftjoystick_deadzone = 1;
|
||||
rightjoystick_deadzone = 1;
|
||||
lefttrigger_deadzone = 1;
|
||||
righttrigger_deadzone = 1;
|
||||
leftjoystick_deadzone = {1, 127};
|
||||
rightjoystick_deadzone = {1, 127};
|
||||
lefttrigger_deadzone = {1, 127};
|
||||
righttrigger_deadzone = {1, 127};
|
||||
|
||||
int lineCount = 0;
|
||||
|
||||
@ -298,26 +299,45 @@ void ParseInputConfig(const std::string game_id = "") {
|
||||
continue;
|
||||
} else if (output_string == "analog_deadzone") {
|
||||
std::stringstream ss(input_string);
|
||||
std::string device;
|
||||
int deadzone;
|
||||
std::getline(ss, device, ',');
|
||||
ss >> deadzone;
|
||||
if (ss.fail()) {
|
||||
LOG_WARNING(Input, "Failed to parse deadzone config from line: {}", line);
|
||||
std::string device, inner_deadzone_str, outer_deadzone_str;
|
||||
|
||||
if (!std::getline(ss, device, ',') || !std::getline(ss, inner_deadzone_str, ',') ||
|
||||
!std::getline(ss, outer_deadzone_str)) {
|
||||
LOG_WARNING(Input, "Malformed deadzone config at line {}: \"{}\"", lineCount, line);
|
||||
continue;
|
||||
} else {
|
||||
LOG_DEBUG(Input, "Parsed deadzone: {} {}", device, deadzone);
|
||||
}
|
||||
if (device == "leftjoystick") {
|
||||
leftjoystick_deadzone = deadzone;
|
||||
} else if (device == "rightjoystick") {
|
||||
rightjoystick_deadzone = deadzone;
|
||||
} else if (device == "l2") {
|
||||
lefttrigger_deadzone = deadzone;
|
||||
} else if (device == "r2") {
|
||||
righttrigger_deadzone = deadzone;
|
||||
|
||||
auto parseInt = [](const std::string& s) -> std::optional<int> {
|
||||
try {
|
||||
return std::stoi(s);
|
||||
} catch (...) {
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
auto inner_deadzone = parseInt(inner_deadzone_str);
|
||||
auto outer_deadzone = parseInt(outer_deadzone_str);
|
||||
|
||||
if (!inner_deadzone || !outer_deadzone) {
|
||||
LOG_WARNING(Input, "Invalid deadzone values at line {}: \"{}\"", lineCount, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::pair<int, int> deadzone = {*inner_deadzone, *outer_deadzone};
|
||||
|
||||
static std::unordered_map<std::string, std::pair<int, int>&> deadzone_map = {
|
||||
{"leftjoystick", leftjoystick_deadzone},
|
||||
{"rightjoystick", rightjoystick_deadzone},
|
||||
{"l2", lefttrigger_deadzone},
|
||||
{"r2", righttrigger_deadzone},
|
||||
};
|
||||
|
||||
if (auto it = deadzone_map.find(device); it != deadzone_map.end()) {
|
||||
it->second = deadzone;
|
||||
LOG_DEBUG(Input, "Parsed deadzone: {} {} {}", device, inner_deadzone_str,
|
||||
outer_deadzone_str);
|
||||
} else {
|
||||
LOG_WARNING(Input, "Invalid axis name at line: {}, data: \"{}\", skipping line.",
|
||||
LOG_WARNING(Input, "Invalid axis name at line {}: \"{}\", skipping line.",
|
||||
lineCount, line);
|
||||
}
|
||||
continue;
|
||||
@ -493,9 +513,14 @@ void ControllerOutput::FinalizeUpdate() {
|
||||
// avoid double-updating axes, but don't skip directional button bindings
|
||||
float multiplier = 1.0;
|
||||
int deadzone = 0;
|
||||
auto ApplyDeadzone = [](s16* value, int deadzone) {
|
||||
if (std::abs(*value) <= deadzone) {
|
||||
auto ApplyDeadzone = [](s16* value, std::pair<int, int> deadzone) {
|
||||
if (std::abs(*value) <= deadzone.first || deadzone.first == deadzone.second) {
|
||||
*value = 0;
|
||||
} else {
|
||||
*value = (*value >= 0 ? 1 : -1) *
|
||||
std::clamp((int)((128.0 * (std::abs(*value) - deadzone.first)) /
|
||||
(float)(deadzone.second - deadzone.first)),
|
||||
0, 128);
|
||||
}
|
||||
};
|
||||
Axis c_axis = GetAxisFromSDLAxis(axis);
|
||||
|
510
src/qt_gui/control_settings.cpp
Normal file
510
src/qt_gui/control_settings.cpp
Normal file
@ -0,0 +1,510 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fstream>
|
||||
#include <QMessageBox>
|
||||
#include "common/path_util.h"
|
||||
#include "control_settings.h"
|
||||
#include "kbm_config_dialog.h"
|
||||
#include "ui_control_settings.h"
|
||||
|
||||
ControlSettings::ControlSettings(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent)
|
||||
: QDialog(parent), m_game_info(game_info_get), ui(new Ui::ControlSettings) {
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->PerGameCheckBox->setChecked(!Config::GetUseUnifiedInputConfig());
|
||||
|
||||
AddBoxItems();
|
||||
SetUIValuestoMappings();
|
||||
ui->KBMButton->setFocus();
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [this](QAbstractButton* button) {
|
||||
if (button == ui->buttonBox->button(QDialogButtonBox::Save)) {
|
||||
SaveControllerConfig(true);
|
||||
} else if (button == ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)) {
|
||||
SetDefault();
|
||||
} else if (button == ui->buttonBox->button(QDialogButtonBox::Apply)) {
|
||||
SaveControllerConfig(false);
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close);
|
||||
connect(ui->KBMButton, &QPushButton::clicked, this, [this] {
|
||||
auto KBMWindow = new EditorDialog(this);
|
||||
KBMWindow->exec();
|
||||
SetUIValuestoMappings();
|
||||
});
|
||||
connect(ui->ProfileComboBox, &QComboBox::currentTextChanged, this, [this] {
|
||||
GetGameTitle();
|
||||
SetUIValuestoMappings();
|
||||
});
|
||||
|
||||
connect(ui->LeftDeadzoneSlider, &QSlider::valueChanged, this,
|
||||
[this](int value) { ui->LeftDeadzoneValue->setText(QString::number(value)); });
|
||||
connect(ui->RightDeadzoneSlider, &QSlider::valueChanged, this,
|
||||
[this](int value) { ui->RightDeadzoneValue->setText(QString::number(value)); });
|
||||
|
||||
connect(ui->LStickUpBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->LStickDownBox->setCurrentIndex(value); });
|
||||
connect(ui->LStickDownBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->LStickUpBox->setCurrentIndex(value); });
|
||||
connect(ui->LStickRightBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->LStickLeftBox->setCurrentIndex(value); });
|
||||
connect(ui->LStickLeftBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->LStickRightBox->setCurrentIndex(value); });
|
||||
|
||||
connect(ui->RStickUpBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->RStickDownBox->setCurrentIndex(value); });
|
||||
connect(ui->RStickDownBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->RStickUpBox->setCurrentIndex(value); });
|
||||
connect(ui->RStickRightBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->RStickLeftBox->setCurrentIndex(value); });
|
||||
connect(ui->RStickLeftBox, &QComboBox::currentIndexChanged, this,
|
||||
[this](int value) { ui->RStickRightBox->setCurrentIndex(value); });
|
||||
}
|
||||
|
||||
void ControlSettings::SaveControllerConfig(bool CloseOnSave) {
|
||||
QList<QComboBox*> list;
|
||||
list << ui->RStickUpBox << ui->RStickRightBox << ui->LStickUpBox << ui->LStickRightBox;
|
||||
int count_axis_left_x = 0, count_axis_left_y = 0, count_axis_right_x = 0,
|
||||
count_axis_right_y = 0;
|
||||
for (const auto& i : list) {
|
||||
if (i->currentText() == "axis_left_x") {
|
||||
count_axis_left_x = count_axis_left_x + 1;
|
||||
} else if (i->currentText() == "axis_left_y") {
|
||||
count_axis_left_y = count_axis_left_y + 1;
|
||||
} else if (i->currentText() == "axis_right_x") {
|
||||
count_axis_right_x = count_axis_right_x + 1;
|
||||
} else if (i->currentText() == "axis_right_y") {
|
||||
count_axis_right_y = count_axis_right_y + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (count_axis_left_x > 1 | count_axis_left_y > 1 | count_axis_right_x > 1 |
|
||||
count_axis_right_y > 1) {
|
||||
QMessageBox::StandardButton nosave;
|
||||
nosave = QMessageBox::information(this, "Unable to Save",
|
||||
"Cannot bind axis values more than once");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string config_id;
|
||||
config_id = (ui->ProfileComboBox->currentText() == "Common Config")
|
||||
? "default"
|
||||
: ui->ProfileComboBox->currentText().toStdString();
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(config_id);
|
||||
|
||||
int lineCount = 0;
|
||||
std::string line;
|
||||
std::vector<std::string> lines;
|
||||
std::string output_string = "", input_string = "";
|
||||
std::fstream file(config_file);
|
||||
|
||||
while (std::getline(file, line)) {
|
||||
lineCount++;
|
||||
|
||||
std::size_t comment_pos = line.find('#');
|
||||
if (comment_pos != std::string::npos) {
|
||||
if (!line.contains("Range of deadzones"))
|
||||
lines.push_back(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::size_t equal_pos = line.find('=');
|
||||
if (equal_pos == std::string::npos) {
|
||||
lines.push_back(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
output_string = line.substr(0, equal_pos - 1);
|
||||
input_string = line.substr(equal_pos + 2);
|
||||
|
||||
if (std::find(ControllerInputs.begin(), ControllerInputs.end(), input_string) !=
|
||||
ControllerInputs.end() ||
|
||||
output_string == "analog_deadzone") {
|
||||
line.erase();
|
||||
continue;
|
||||
}
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
input_string = "cross";
|
||||
output_string = ui->ABox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "circle";
|
||||
output_string = ui->BBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "square";
|
||||
output_string = ui->XBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "triangle";
|
||||
output_string = ui->YBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
lines.push_back("");
|
||||
|
||||
input_string = "l1";
|
||||
output_string = ui->LBBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "r1";
|
||||
output_string = ui->RBBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "l2";
|
||||
output_string = ui->LTBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "r2";
|
||||
output_string = ui->RTBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "l3";
|
||||
output_string = ui->LClickBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "r3";
|
||||
output_string = ui->RClickBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
lines.push_back("");
|
||||
|
||||
input_string = "back";
|
||||
output_string = ui->BackBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "options";
|
||||
output_string = ui->StartBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
lines.push_back("");
|
||||
|
||||
input_string = "pad_up";
|
||||
output_string = ui->DpadUpBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "pad_down";
|
||||
output_string = ui->DpadDownBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "pad_left";
|
||||
output_string = ui->DpadLeftBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "pad_right";
|
||||
output_string = ui->DpadRightBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
lines.push_back("");
|
||||
|
||||
input_string = "axis_left_x";
|
||||
output_string = ui->LStickRightBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "axis_left_y";
|
||||
output_string = ui->LStickUpBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "axis_right_x";
|
||||
output_string = ui->RStickRightBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
input_string = "axis_right_y";
|
||||
output_string = ui->RStickUpBox->currentText().toStdString();
|
||||
lines.push_back(output_string + " = " + input_string);
|
||||
|
||||
lines.push_back("");
|
||||
lines.push_back("# Range of deadzones: 1 (almost none) to 127 (max)");
|
||||
|
||||
std::string deadzonevalue = std::to_string(ui->LeftDeadzoneSlider->value());
|
||||
lines.push_back("analog_deadzone = leftjoystick, " + deadzonevalue + ", 127");
|
||||
|
||||
deadzonevalue = std::to_string(ui->RightDeadzoneSlider->value());
|
||||
lines.push_back("analog_deadzone = rightjoystick, " + deadzonevalue + ", 127");
|
||||
|
||||
std::vector<std::string> save;
|
||||
bool CurrentLineEmpty = false, LastLineEmpty = false;
|
||||
for (auto const& line : lines) {
|
||||
LastLineEmpty = CurrentLineEmpty ? true : false;
|
||||
CurrentLineEmpty = line.empty() ? true : false;
|
||||
if (!CurrentLineEmpty || !LastLineEmpty)
|
||||
save.push_back(line);
|
||||
}
|
||||
|
||||
std::ofstream output_file(config_file);
|
||||
for (auto const& line : save) {
|
||||
output_file << line << '\n';
|
||||
}
|
||||
output_file.close();
|
||||
|
||||
Config::SetUseUnifiedInputConfig(!ui->PerGameCheckBox->isChecked());
|
||||
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
|
||||
|
||||
if (CloseOnSave)
|
||||
QWidget::close();
|
||||
}
|
||||
|
||||
void ControlSettings::SetDefault() {
|
||||
ui->ABox->setCurrentIndex(0);
|
||||
ui->BBox->setCurrentIndex(1);
|
||||
ui->XBox->setCurrentIndex(2);
|
||||
ui->YBox->setCurrentIndex(3);
|
||||
ui->DpadUpBox->setCurrentIndex(11);
|
||||
ui->DpadDownBox->setCurrentIndex(12);
|
||||
ui->DpadLeftBox->setCurrentIndex(13);
|
||||
ui->DpadRightBox->setCurrentIndex(14);
|
||||
ui->LClickBox->setCurrentIndex(8);
|
||||
ui->RClickBox->setCurrentIndex(9);
|
||||
ui->LBBox->setCurrentIndex(4);
|
||||
ui->RBBox->setCurrentIndex(5);
|
||||
ui->LTBox->setCurrentIndex(6);
|
||||
ui->RTBox->setCurrentIndex(7);
|
||||
ui->StartBox->setCurrentIndex(10);
|
||||
ui->BackBox->setCurrentIndex(15);
|
||||
|
||||
ui->LStickUpBox->setCurrentIndex(1);
|
||||
ui->LStickDownBox->setCurrentIndex(1);
|
||||
ui->LStickLeftBox->setCurrentIndex(0);
|
||||
ui->LStickRightBox->setCurrentIndex(0);
|
||||
ui->RStickUpBox->setCurrentIndex(3);
|
||||
ui->RStickDownBox->setCurrentIndex(3);
|
||||
ui->RStickLeftBox->setCurrentIndex(2);
|
||||
ui->RStickRightBox->setCurrentIndex(2);
|
||||
|
||||
ui->LeftDeadzoneSlider->setValue(2);
|
||||
ui->RightDeadzoneSlider->setValue(2);
|
||||
}
|
||||
|
||||
void ControlSettings::AddBoxItems() {
|
||||
ui->DpadUpBox->addItems(ButtonOutputs);
|
||||
ui->DpadDownBox->addItems(ButtonOutputs);
|
||||
ui->DpadLeftBox->addItems(ButtonOutputs);
|
||||
ui->DpadRightBox->addItems(ButtonOutputs);
|
||||
ui->LBBox->addItems(ButtonOutputs);
|
||||
ui->RBBox->addItems(ButtonOutputs);
|
||||
ui->LTBox->addItems(ButtonOutputs);
|
||||
ui->RTBox->addItems(ButtonOutputs);
|
||||
ui->RClickBox->addItems(ButtonOutputs);
|
||||
ui->LClickBox->addItems(ButtonOutputs);
|
||||
ui->StartBox->addItems(ButtonOutputs);
|
||||
ui->ABox->addItems(ButtonOutputs);
|
||||
ui->BBox->addItems(ButtonOutputs);
|
||||
ui->XBox->addItems(ButtonOutputs);
|
||||
ui->YBox->addItems(ButtonOutputs);
|
||||
ui->BackBox->addItems(ButtonOutputs);
|
||||
|
||||
ui->LStickUpBox->addItems(StickOutputs);
|
||||
ui->LStickDownBox->addItems(StickOutputs);
|
||||
ui->LStickLeftBox->addItems(StickOutputs);
|
||||
ui->LStickRightBox->addItems(StickOutputs);
|
||||
ui->RStickUpBox->addItems(StickOutputs);
|
||||
ui->RStickDownBox->addItems(StickOutputs);
|
||||
ui->RStickLeftBox->addItems(StickOutputs);
|
||||
ui->RStickRightBox->addItems(StickOutputs);
|
||||
|
||||
ui->ProfileComboBox->addItem("Common Config");
|
||||
for (int i = 0; i < m_game_info->m_games.size(); i++) {
|
||||
ui->ProfileComboBox->addItem(QString::fromStdString(m_game_info->m_games[i].serial));
|
||||
}
|
||||
ui->ProfileComboBox->setCurrentText("Common Config");
|
||||
ui->TitleLabel->setText("Common Config");
|
||||
}
|
||||
|
||||
void ControlSettings::SetUIValuestoMappings() {
|
||||
std::string config_id;
|
||||
config_id = (ui->ProfileComboBox->currentText() == "Common Config")
|
||||
? "default"
|
||||
: ui->ProfileComboBox->currentText().toStdString();
|
||||
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(config_id);
|
||||
std::ifstream file(config_file);
|
||||
|
||||
bool CrossExists = false, CircleExists = false, SquareExists = false, TriangleExists = false,
|
||||
L1Exists = false, L2Exists = false, L3Exists = false, R1Exists = false, R2Exists = false,
|
||||
R3Exists = false, DPadUpExists = false, DPadDownExists = false, DPadLeftExists = false,
|
||||
DPadRightExists = false, StartExists = false, BackExists = false, LStickXExists = false,
|
||||
LStickYExists = false, RStickXExists = false, RStickYExists = false;
|
||||
int lineCount = 0;
|
||||
std::string line = "";
|
||||
while (std::getline(file, line)) {
|
||||
lineCount++;
|
||||
|
||||
line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
std::size_t comment_pos = line.find('#');
|
||||
if (comment_pos != std::string::npos)
|
||||
line = line.substr(0, comment_pos);
|
||||
|
||||
std::size_t equal_pos = line.find('=');
|
||||
if (equal_pos == std::string::npos)
|
||||
continue;
|
||||
|
||||
std::string output_string = line.substr(0, equal_pos);
|
||||
std::string input_string = line.substr(equal_pos + 1);
|
||||
|
||||
if (std::find(ControllerInputs.begin(), ControllerInputs.end(), input_string) !=
|
||||
ControllerInputs.end() ||
|
||||
output_string == "analog_deadzone") {
|
||||
if (input_string == "cross") {
|
||||
ui->ABox->setCurrentText(QString::fromStdString(output_string));
|
||||
CrossExists = true;
|
||||
} else if (input_string == "circle") {
|
||||
ui->BBox->setCurrentText(QString::fromStdString(output_string));
|
||||
CircleExists = true;
|
||||
} else if (input_string == "square") {
|
||||
ui->XBox->setCurrentText(QString::fromStdString(output_string));
|
||||
SquareExists = true;
|
||||
} else if (input_string == "triangle") {
|
||||
ui->YBox->setCurrentText(QString::fromStdString(output_string));
|
||||
TriangleExists = true;
|
||||
} else if (input_string == "l1") {
|
||||
ui->LBBox->setCurrentText(QString::fromStdString(output_string));
|
||||
L1Exists = true;
|
||||
} else if (input_string == "l2") {
|
||||
ui->LTBox->setCurrentText(QString::fromStdString(output_string));
|
||||
L2Exists = true;
|
||||
} else if (input_string == "r1") {
|
||||
ui->RBBox->setCurrentText(QString::fromStdString(output_string));
|
||||
R1Exists = true;
|
||||
} else if (input_string == "r2") {
|
||||
ui->RTBox->setCurrentText(QString::fromStdString(output_string));
|
||||
R2Exists = true;
|
||||
} else if (input_string == "l3") {
|
||||
ui->LClickBox->setCurrentText(QString::fromStdString(output_string));
|
||||
L3Exists = true;
|
||||
} else if (input_string == "r3") {
|
||||
ui->RClickBox->setCurrentText(QString::fromStdString(output_string));
|
||||
R3Exists = true;
|
||||
} else if (input_string == "pad_up") {
|
||||
ui->DpadUpBox->setCurrentText(QString::fromStdString(output_string));
|
||||
DPadUpExists = true;
|
||||
} else if (input_string == "pad_down") {
|
||||
ui->DpadDownBox->setCurrentText(QString::fromStdString(output_string));
|
||||
DPadDownExists = true;
|
||||
} else if (input_string == "pad_left") {
|
||||
ui->DpadLeftBox->setCurrentText(QString::fromStdString(output_string));
|
||||
DPadLeftExists = true;
|
||||
} else if (input_string == "pad_right") {
|
||||
ui->DpadRightBox->setCurrentText(QString::fromStdString(output_string));
|
||||
DPadRightExists = true;
|
||||
} else if (input_string == "options") {
|
||||
ui->StartBox->setCurrentText(QString::fromStdString(output_string));
|
||||
StartExists = true;
|
||||
} else if (input_string == "back") {
|
||||
ui->BackBox->setCurrentText(QString::fromStdString(output_string));
|
||||
BackExists = true;
|
||||
} else if (input_string == "axis_left_x") {
|
||||
ui->LStickRightBox->setCurrentText(QString::fromStdString(output_string));
|
||||
ui->LStickLeftBox->setCurrentText(QString::fromStdString(output_string));
|
||||
LStickXExists = true;
|
||||
} else if (input_string == "axis_left_y") {
|
||||
ui->LStickUpBox->setCurrentText(QString::fromStdString(output_string));
|
||||
ui->LStickDownBox->setCurrentText(QString::fromStdString(output_string));
|
||||
LStickYExists = true;
|
||||
} else if (input_string == "axis_right_x") {
|
||||
ui->RStickRightBox->setCurrentText(QString::fromStdString(output_string));
|
||||
ui->RStickLeftBox->setCurrentText(QString::fromStdString(output_string));
|
||||
RStickXExists = true;
|
||||
} else if (input_string == "axis_right_y") {
|
||||
ui->RStickUpBox->setCurrentText(QString::fromStdString(output_string));
|
||||
ui->RStickDownBox->setCurrentText(QString::fromStdString(output_string));
|
||||
RStickYExists = true;
|
||||
} else if (input_string.contains("leftjoystick")) {
|
||||
std::size_t comma_pos = line.find(',');
|
||||
if (comma_pos != std::string::npos) {
|
||||
int deadzonevalue = std::stoi(line.substr(comma_pos + 1));
|
||||
ui->LeftDeadzoneSlider->setValue(deadzonevalue);
|
||||
ui->LeftDeadzoneValue->setText(QString::number(deadzonevalue));
|
||||
} else {
|
||||
ui->LeftDeadzoneSlider->setValue(2);
|
||||
ui->LeftDeadzoneValue->setText("2");
|
||||
}
|
||||
} else if (input_string.contains("rightjoystick")) {
|
||||
std::size_t comma_pos = line.find(',');
|
||||
if (comma_pos != std::string::npos) {
|
||||
int deadzonevalue = std::stoi(line.substr(comma_pos + 1));
|
||||
ui->RightDeadzoneSlider->setValue(deadzonevalue);
|
||||
ui->RightDeadzoneValue->setText(QString::number(deadzonevalue));
|
||||
} else {
|
||||
ui->RightDeadzoneSlider->setValue(2);
|
||||
ui->RightDeadzoneValue->setText("2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If an entry does not exist in the config file, we assume the user wants it unmapped
|
||||
if (!CrossExists)
|
||||
ui->ABox->setCurrentText("unmapped");
|
||||
if (!CircleExists)
|
||||
ui->BBox->setCurrentText("unmapped");
|
||||
if (!SquareExists)
|
||||
ui->XBox->setCurrentText("unmapped");
|
||||
if (!TriangleExists)
|
||||
ui->YBox->setCurrentText("unmapped");
|
||||
if (!L1Exists)
|
||||
ui->LBBox->setCurrentText("unmapped");
|
||||
if (!L2Exists)
|
||||
ui->LTBox->setCurrentText("unmapped");
|
||||
if (!L3Exists)
|
||||
ui->LClickBox->setCurrentText("unmapped");
|
||||
if (!R1Exists)
|
||||
ui->RBBox->setCurrentText("unmapped");
|
||||
if (!R2Exists)
|
||||
ui->RTBox->setCurrentText("unmapped");
|
||||
if (!R3Exists)
|
||||
ui->RClickBox->setCurrentText("unmapped");
|
||||
if (!DPadUpExists)
|
||||
ui->DpadUpBox->setCurrentText("unmapped");
|
||||
if (!DPadDownExists)
|
||||
ui->DpadDownBox->setCurrentText("unmapped");
|
||||
if (!DPadLeftExists)
|
||||
ui->DpadLeftBox->setCurrentText("unmapped");
|
||||
if (!DPadRightExists)
|
||||
ui->DpadRightBox->setCurrentText("unmapped");
|
||||
if (!BackExists)
|
||||
ui->BackBox->setCurrentText("unmapped");
|
||||
if (!StartExists)
|
||||
ui->StartBox->setCurrentText("unmapped");
|
||||
|
||||
if (!LStickXExists) {
|
||||
ui->LStickRightBox->setCurrentText("unmapped");
|
||||
ui->LStickLeftBox->setCurrentText("unmapped");
|
||||
}
|
||||
if (!LStickYExists) {
|
||||
ui->LStickUpBox->setCurrentText("unmapped");
|
||||
ui->LStickDownBox->setCurrentText("unmapped");
|
||||
}
|
||||
if (!RStickXExists) {
|
||||
ui->RStickRightBox->setCurrentText("unmapped");
|
||||
ui->RStickLeftBox->setCurrentText("unmapped");
|
||||
}
|
||||
if (!RStickYExists) {
|
||||
ui->RStickUpBox->setCurrentText("unmapped");
|
||||
ui->RStickDownBox->setCurrentText("unmapped");
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void ControlSettings::GetGameTitle() {
|
||||
if (ui->ProfileComboBox->currentText() == "Common Config") {
|
||||
ui->TitleLabel->setText("Common Config");
|
||||
} else {
|
||||
for (int i = 0; i < m_game_info->m_games.size(); i++) {
|
||||
if (m_game_info->m_games[i].serial ==
|
||||
ui->ProfileComboBox->currentText().toStdString()) {
|
||||
ui->TitleLabel->setText(QString::fromStdString(m_game_info->m_games[i].name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ControlSettings::~ControlSettings() {}
|
52
src/qt_gui/control_settings.h
Normal file
52
src/qt_gui/control_settings.h
Normal file
@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <QDialog>
|
||||
#include "game_info.h"
|
||||
|
||||
namespace Ui {
|
||||
class ControlSettings;
|
||||
}
|
||||
|
||||
class ControlSettings : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ControlSettings(std::shared_ptr<GameInfoClass> game_info_get,
|
||||
QWidget* parent = nullptr);
|
||||
~ControlSettings();
|
||||
|
||||
private Q_SLOTS:
|
||||
void SaveControllerConfig(bool CloseOnSave);
|
||||
void SetDefault();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::ControlSettings> ui;
|
||||
std::shared_ptr<GameInfoClass> m_game_info;
|
||||
|
||||
void AddBoxItems();
|
||||
void SetUIValuestoMappings();
|
||||
void GetGameTitle();
|
||||
|
||||
const std::vector<std::string> ControllerInputs = {
|
||||
"cross", "circle", "square", "triangle", "l1",
|
||||
"r1", "l2", "r2", "l3",
|
||||
|
||||
"r3", "options", "pad_up",
|
||||
|
||||
"pad_down",
|
||||
|
||||
"pad_left", "pad_right", "axis_left_x", "axis_left_y", "axis_right_x",
|
||||
"axis_right_y", "back"};
|
||||
|
||||
const QStringList ButtonOutputs = {"cross", "circle", "square", "triangle", "l1",
|
||||
"r1", "l2", "r2", "l3",
|
||||
|
||||
"r3", "options", "pad_up",
|
||||
|
||||
"pad_down",
|
||||
|
||||
"pad_left", "pad_right", "touchpad", "unmapped"};
|
||||
|
||||
const QStringList StickOutputs = {"axis_left_x", "axis_left_y", "axis_right_x", "axis_right_y",
|
||||
"unmapped"};
|
||||
};
|
1379
src/qt_gui/control_settings.ui
Normal file
1379
src/qt_gui/control_settings.ui
Normal file
File diff suppressed because it is too large
Load Diff
@ -38,17 +38,34 @@ GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get,
|
||||
|
||||
void GameGridFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow,
|
||||
int previousColumn) {
|
||||
crtRow = currentRow;
|
||||
crtColumn = currentColumn;
|
||||
columnCnt = this->columnCount();
|
||||
|
||||
auto itemID = (crtRow * columnCnt) + currentColumn;
|
||||
if (itemID > m_game_info->m_games.count() - 1) {
|
||||
// Early exit for invalid indices
|
||||
if (currentRow < 0 || currentColumn < 0) {
|
||||
cellClicked = false;
|
||||
validCellSelected = false;
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
crtRow = currentRow;
|
||||
crtColumn = currentColumn;
|
||||
columnCnt = this->columnCount();
|
||||
|
||||
// Prevent integer overflow
|
||||
if (columnCnt <= 0 || crtRow > (std::numeric_limits<int>::max() / columnCnt)) {
|
||||
cellClicked = false;
|
||||
validCellSelected = false;
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
auto itemID = (crtRow * columnCnt) + currentColumn;
|
||||
if (itemID < 0 || itemID > m_game_info->m_games.count() - 1) {
|
||||
cellClicked = false;
|
||||
validCellSelected = false;
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
return;
|
||||
}
|
||||
|
||||
cellClicked = true;
|
||||
validCellSelected = true;
|
||||
SetGridBackgroundImage(crtRow, crtColumn);
|
||||
@ -65,6 +82,8 @@ void GameGridFrame::PlayBackgroundMusic(QString path) {
|
||||
}
|
||||
|
||||
void GameGridFrame::PopulateGameGrid(QVector<GameInfo> m_games_search, bool fromSearch) {
|
||||
this->crtRow = -1;
|
||||
this->crtColumn = -1;
|
||||
QVector<GameInfo> m_games_;
|
||||
this->clearContents();
|
||||
if (fromSearch)
|
||||
@ -136,43 +155,48 @@ void GameGridFrame::PopulateGameGrid(QVector<GameInfo> m_games_search, bool from
|
||||
}
|
||||
|
||||
void GameGridFrame::SetGridBackgroundImage(int row, int column) {
|
||||
|
||||
int itemID = (row * this->columnCount()) + column;
|
||||
QWidget* item = this->cellWidget(row, column);
|
||||
if (item) {
|
||||
QString pic1Path;
|
||||
Common::FS::PathToQString(pic1Path, (*m_games_shared)[itemID].pic_path);
|
||||
const auto blurredPic1Path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||
(*m_games_shared)[itemID].serial / "pic1.png";
|
||||
QString blurredPic1PathQt;
|
||||
Common::FS::PathToQString(blurredPic1PathQt, blurredPic1Path);
|
||||
|
||||
backgroundImage = QImage(blurredPic1PathQt);
|
||||
if (backgroundImage.isNull()) {
|
||||
QImage image(pic1Path);
|
||||
backgroundImage = m_game_list_utils.BlurImage(image, image.rect(), 16);
|
||||
|
||||
std::filesystem::path img_path =
|
||||
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||
(*m_games_shared)[itemID].serial;
|
||||
std::filesystem::create_directories(img_path);
|
||||
if (!backgroundImage.save(blurredPic1PathQt, "PNG")) {
|
||||
// qDebug() << "Error: Unable to save image.";
|
||||
}
|
||||
}
|
||||
RefreshGridBackgroundImage();
|
||||
if (!item) {
|
||||
// handle case where no item was clicked
|
||||
return;
|
||||
}
|
||||
|
||||
// If background images are hidden, clear the background image
|
||||
if (!Config::getShowBackgroundImage()) {
|
||||
backgroundImage = QImage();
|
||||
m_last_opacity = -1; // Reset opacity tracking when disabled
|
||||
m_current_game_path.clear(); // Reset current game path
|
||||
RefreshGridBackgroundImage();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& game = (*m_games_shared)[itemID];
|
||||
const int opacity = Config::getBackgroundImageOpacity();
|
||||
|
||||
// Recompute if opacity changed or we switched to a different game
|
||||
if (opacity != m_last_opacity || game.pic_path != m_current_game_path) {
|
||||
QImage original_image(QString::fromStdString(game.pic_path.string()));
|
||||
if (!original_image.isNull()) {
|
||||
backgroundImage = m_game_list_utils.ChangeImageOpacity(
|
||||
original_image, original_image.rect(), opacity / 100.0f);
|
||||
m_last_opacity = opacity;
|
||||
m_current_game_path = game.pic_path;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshGridBackgroundImage();
|
||||
}
|
||||
|
||||
void GameGridFrame::RefreshGridBackgroundImage() {
|
||||
if (!backgroundImage.isNull()) {
|
||||
QPalette palette;
|
||||
QPalette palette;
|
||||
if (!backgroundImage.isNull() && Config::getShowBackgroundImage()) {
|
||||
palette.setBrush(QPalette::Base,
|
||||
QBrush(backgroundImage.scaled(size(), Qt::IgnoreAspectRatio)));
|
||||
QColor transparentColor = QColor(135, 206, 235, 40);
|
||||
palette.setColor(QPalette::Highlight, transparentColor);
|
||||
this->setPalette(palette);
|
||||
}
|
||||
QColor transparentColor = QColor(135, 206, 235, 40);
|
||||
palette.setColor(QPalette::Highlight, transparentColor);
|
||||
this->setPalette(palette);
|
||||
}
|
||||
|
||||
bool GameGridFrame::IsValidCellSelected() {
|
||||
|
@ -33,6 +33,8 @@ private:
|
||||
std::shared_ptr<CompatibilityInfoClass> m_compat_info;
|
||||
std::shared_ptr<QVector<GameInfo>> m_games_shared;
|
||||
bool validCellSelected = false;
|
||||
int m_last_opacity = -1; // Track last opacity to avoid unnecessary recomputation
|
||||
std::filesystem::path m_current_game_path; // Track current game path to detect changes
|
||||
|
||||
public:
|
||||
explicit GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get,
|
||||
|
@ -19,7 +19,10 @@ public:
|
||||
QVector<GameInfo> m_games;
|
||||
|
||||
static bool CompareStrings(GameInfo& a, GameInfo& b) {
|
||||
return a.name < b.name;
|
||||
std::string name_a = a.name, name_b = b.name;
|
||||
std::transform(name_a.begin(), name_a.end(), name_a.begin(), ::tolower);
|
||||
std::transform(name_b.begin(), name_b.end(), name_b.begin(), ::tolower);
|
||||
return name_a < name_b;
|
||||
}
|
||||
|
||||
static GameInfo readGameInfo(const std::filesystem::path& filePath) {
|
||||
@ -72,4 +75,4 @@ public:
|
||||
}
|
||||
return game;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -89,6 +89,7 @@ void GameListFrame::onCurrentCellChanged(int currentRow, int currentColumn, int
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
m_current_item = item; // Store current item
|
||||
SetListBackgroundImage(item);
|
||||
PlayBackgroundMusic(item);
|
||||
}
|
||||
@ -104,6 +105,7 @@ void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
|
||||
}
|
||||
|
||||
void GameListFrame::PopulateGameList(bool isInitialPopulation) {
|
||||
this->m_current_item = nullptr;
|
||||
// Do not show status column if it is not enabled
|
||||
this->setColumnHidden(2, !Config::getCompatibilityEnabled());
|
||||
this->setColumnHidden(6, !Config::GetLoadGameSizeEnabled());
|
||||
@ -167,38 +169,41 @@ void GameListFrame::SetListBackgroundImage(QTableWidgetItem* item) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString pic1Path;
|
||||
Common::FS::PathToQString(pic1Path, m_game_info->m_games[item->row()].pic_path);
|
||||
const auto blurredPic1Path = Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||
m_game_info->m_games[item->row()].serial / "pic1.png";
|
||||
QString blurredPic1PathQt;
|
||||
Common::FS::PathToQString(blurredPic1PathQt, blurredPic1Path);
|
||||
// If background images are hidden, clear the background image
|
||||
if (!Config::getShowBackgroundImage()) {
|
||||
backgroundImage = QImage();
|
||||
m_last_opacity = -1; // Reset opacity tracking when disabled
|
||||
m_current_game_path.clear(); // Reset current game path
|
||||
RefreshListBackgroundImage();
|
||||
return;
|
||||
}
|
||||
|
||||
backgroundImage = QImage(blurredPic1PathQt);
|
||||
if (backgroundImage.isNull()) {
|
||||
QImage image(pic1Path);
|
||||
backgroundImage = m_game_list_utils.BlurImage(image, image.rect(), 16);
|
||||
const auto& game = m_game_info->m_games[item->row()];
|
||||
const int opacity = Config::getBackgroundImageOpacity();
|
||||
|
||||
std::filesystem::path img_path =
|
||||
Common::FS::GetUserPath(Common::FS::PathType::MetaDataDir) /
|
||||
m_game_info->m_games[item->row()].serial;
|
||||
std::filesystem::create_directories(img_path);
|
||||
if (!backgroundImage.save(blurredPic1PathQt, "PNG")) {
|
||||
// qDebug() << "Error: Unable to save image.";
|
||||
// Recompute if opacity changed or we switched to a different game
|
||||
if (opacity != m_last_opacity || game.pic_path != m_current_game_path) {
|
||||
QImage original_image(QString::fromStdString(game.pic_path.string()));
|
||||
if (!original_image.isNull()) {
|
||||
backgroundImage = m_game_list_utils.ChangeImageOpacity(
|
||||
original_image, original_image.rect(), opacity / 100.0f);
|
||||
m_last_opacity = opacity;
|
||||
m_current_game_path = game.pic_path;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshListBackgroundImage();
|
||||
}
|
||||
|
||||
void GameListFrame::RefreshListBackgroundImage() {
|
||||
if (!backgroundImage.isNull()) {
|
||||
QPalette palette;
|
||||
QPalette palette;
|
||||
if (!backgroundImage.isNull() && Config::getShowBackgroundImage()) {
|
||||
palette.setBrush(QPalette::Base,
|
||||
QBrush(backgroundImage.scaled(size(), Qt::IgnoreAspectRatio)));
|
||||
QColor transparentColor = QColor(135, 206, 235, 40);
|
||||
palette.setColor(QPalette::Highlight, transparentColor);
|
||||
this->setPalette(palette);
|
||||
}
|
||||
QColor transparentColor = QColor(135, 206, 235, 40);
|
||||
palette.setColor(QPalette::Highlight, transparentColor);
|
||||
this->setPalette(palette);
|
||||
}
|
||||
|
||||
void GameListFrame::SortNameAscending(int columnIndex) {
|
||||
@ -392,3 +397,7 @@ QString GameListFrame::GetPlayTime(const std::string& serial) {
|
||||
file.close();
|
||||
return playTime;
|
||||
}
|
||||
|
||||
QTableWidgetItem* GameListFrame::GetCurrentItem() {
|
||||
return m_current_item;
|
||||
}
|
@ -44,11 +44,14 @@ private:
|
||||
QList<QAction*> m_columnActs;
|
||||
GameInfoClass* game_inf_get = nullptr;
|
||||
bool ListSortedAsc = true;
|
||||
QTableWidgetItem* m_current_item = nullptr;
|
||||
int m_last_opacity = -1; // Track last opacity to avoid unnecessary recomputation
|
||||
std::filesystem::path m_current_game_path; // Track current game path to detect changes
|
||||
|
||||
public:
|
||||
void PopulateGameList(bool isInitialPopulation = true);
|
||||
void ResizeIcons(int iconSize);
|
||||
|
||||
QTableWidgetItem* GetCurrentItem();
|
||||
QImage backgroundImage;
|
||||
GameListUtils m_game_list_utils;
|
||||
GuiContextMenus m_gui_context_menus;
|
||||
|
@ -201,4 +201,30 @@ public:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Opacity is a float between 0 and 1
|
||||
static QImage ChangeImageOpacity(const QImage& image, const QRect& rect, float opacity) {
|
||||
// Convert to ARGB32 format to ensure alpha channel support
|
||||
QImage result = image.convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
// Ensure opacity is between 0 and 1
|
||||
opacity = std::clamp(opacity, 0.0f, 1.0f);
|
||||
|
||||
// Convert opacity to integer alpha value (0-255)
|
||||
int alpha = static_cast<int>(opacity * 255);
|
||||
|
||||
// Process only the specified rectangle area
|
||||
for (int y = rect.top(); y <= rect.bottom(); ++y) {
|
||||
QRgb* line = reinterpret_cast<QRgb*>(result.scanLine(y));
|
||||
for (int x = rect.left(); x <= rect.right(); ++x) {
|
||||
// Get current pixel
|
||||
QRgb pixel = line[x];
|
||||
// Keep RGB values, but modify alpha while preserving relative transparency
|
||||
int newAlpha = (qAlpha(pixel) * alpha) / 255;
|
||||
line[x] = qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), newAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
@ -77,10 +77,14 @@ public:
|
||||
QMenu* copyMenu = new QMenu(tr("Copy info..."), widget);
|
||||
QAction* copyName = new QAction(tr("Copy Name"), widget);
|
||||
QAction* copySerial = new QAction(tr("Copy Serial"), widget);
|
||||
QAction* copyVersion = new QAction(tr("Copy Version"), widget);
|
||||
QAction* copySize = new QAction(tr("Copy Size"), widget);
|
||||
QAction* copyNameAll = new QAction(tr("Copy All"), widget);
|
||||
|
||||
copyMenu->addAction(copyName);
|
||||
copyMenu->addAction(copySerial);
|
||||
copyMenu->addAction(copyVersion);
|
||||
copyMenu->addAction(copySize);
|
||||
copyMenu->addAction(copyNameAll);
|
||||
|
||||
menu.addMenu(copyMenu);
|
||||
@ -346,6 +350,16 @@ public:
|
||||
clipboard->setText(QString::fromStdString(m_games[itemID].serial));
|
||||
}
|
||||
|
||||
if (selected == copyVersion) {
|
||||
QClipboard* clipboard = QGuiApplication::clipboard();
|
||||
clipboard->setText(QString::fromStdString(m_games[itemID].version));
|
||||
}
|
||||
|
||||
if (selected == copySize) {
|
||||
QClipboard* clipboard = QGuiApplication::clipboard();
|
||||
clipboard->setText(QString::fromStdString(m_games[itemID].size));
|
||||
}
|
||||
|
||||
if (selected == copyNameAll) {
|
||||
QClipboard* clipboard = QGuiApplication::clipboard();
|
||||
QString combinedText = QString("Name:%1 | Serial:%2 | Version:%3 | Size:%4")
|
||||
|
@ -167,9 +167,10 @@ You can find these here, with detailed comments, examples and suggestions for mo
|
||||
You can make an input toggleable with this, for example: Let's say we want to be able to toggle l1 with t. You can then bind l1 to a key you won't use, like kpenter, then bind t to toggle that, so you will end up with this:
|
||||
l1 = kpenter;
|
||||
key_toggle = t, kpenter;
|
||||
'analog_deadzone' = <device>, <value>;
|
||||
value goes from 1 to 127 (no deadzone to max deadzone)
|
||||
devices: leftjoystick, rightjoystick, l2, r2
|
||||
'analog_deadzone' = <device>, <value>, <value>;
|
||||
Values go from 1 to 127 (no deadzone to max deadzone), first is the inner, second is the outer deadzone
|
||||
If you only want inner or outer deadzone, set the other to 1 or 127, respectively
|
||||
Devices: leftjoystick, rightjoystick, l2, r2
|
||||
)";
|
||||
}
|
||||
};
|
@ -16,6 +16,7 @@
|
||||
#include "common/scm_rev.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/version.h"
|
||||
#include "control_settings.h"
|
||||
#include "core/file_format/pkg.h"
|
||||
#include "core/loader.h"
|
||||
#include "game_install_dialog.h"
|
||||
@ -62,12 +63,16 @@ bool MainWindow::Init() {
|
||||
window_title = fmt::format("shadPS4 v{}", Common::VERSION);
|
||||
} else {
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
if (remote_url == "https://github.com/shadps4-emu/shadPS4.git" ||
|
||||
remote_url.length() == 0) {
|
||||
std::string remote_host;
|
||||
try {
|
||||
remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
} catch (...) {
|
||||
remote_host = "unknown";
|
||||
}
|
||||
if (remote_host == "shadps4-emu" || remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} {} {}", Common::VERSION, Common::g_scm_branch,
|
||||
Common::g_scm_desc);
|
||||
} else {
|
||||
std::string remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
window_title = fmt::format("shadPS4 v{} {}/{} {}", Common::VERSION, remote_host,
|
||||
Common::g_scm_branch, Common::g_scm_desc);
|
||||
}
|
||||
@ -292,13 +297,30 @@ void MainWindow::CreateConnects() {
|
||||
connect(settingsDialog, &SettingsDialog::CompatibilityChanged, this,
|
||||
&MainWindow::RefreshGameTable);
|
||||
|
||||
connect(settingsDialog, &SettingsDialog::BackgroundOpacityChanged, this,
|
||||
[this](int opacity) {
|
||||
Config::setBackgroundImageOpacity(opacity);
|
||||
if (m_game_list_frame) {
|
||||
QTableWidgetItem* current = m_game_list_frame->GetCurrentItem();
|
||||
if (current) {
|
||||
m_game_list_frame->SetListBackgroundImage(current);
|
||||
}
|
||||
}
|
||||
if (m_game_grid_frame) {
|
||||
if (m_game_grid_frame->IsValidCellSelected()) {
|
||||
m_game_grid_frame->SetGridBackgroundImage(m_game_grid_frame->crtRow,
|
||||
m_game_grid_frame->crtColumn);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
settingsDialog->exec();
|
||||
});
|
||||
|
||||
// this is the editor for kbm keybinds
|
||||
connect(ui->controllerButton, &QPushButton::clicked, this, [this]() {
|
||||
EditorDialog* editorWindow = new EditorDialog(this);
|
||||
editorWindow->exec(); // Show the editor window modally
|
||||
auto configWindow = new ControlSettings(m_game_info, this);
|
||||
configWindow->exec();
|
||||
});
|
||||
|
||||
#ifdef ENABLE_UPDATER
|
||||
|
@ -72,7 +72,7 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
ui->buttonBox->button(QDialogButtonBox::StandardButton::Close)->setFocus();
|
||||
|
||||
// Add list of available GPUs
|
||||
ui->graphicsAdapterBox->addItem("Auto Select"); // -1, auto selection
|
||||
ui->graphicsAdapterBox->addItem(tr("Auto Select")); // -1, auto selection
|
||||
for (const auto& device : physical_devices) {
|
||||
ui->graphicsAdapterBox->addItem(device);
|
||||
}
|
||||
@ -173,6 +173,9 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
{
|
||||
connect(ui->chooseHomeTabComboBox, &QComboBox::currentTextChanged, this,
|
||||
[](const QString& hometab) { Config::setChooseHomeTab(hometab.toStdString()); });
|
||||
|
||||
connect(ui->showBackgroundImageCheckBox, &QCheckBox::stateChanged, this,
|
||||
[](int state) { Config::setShowBackgroundImage(state == Qt::Checked); });
|
||||
}
|
||||
// Input TAB
|
||||
{
|
||||
@ -251,6 +254,7 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
||||
#ifdef ENABLE_UPDATER
|
||||
ui->updaterGroupBox->installEventFilter(this);
|
||||
#endif
|
||||
ui->GUIBackgroundImageGroupBox->installEventFilter(this);
|
||||
ui->GUIMusicGroupBox->installEventFilter(this);
|
||||
ui->disableTrophycheckBox->installEventFilter(this);
|
||||
ui->enableCompatibilityCheckBox->installEventFilter(this);
|
||||
@ -410,6 +414,8 @@ void SettingsDialog::LoadValuesFromConfig() {
|
||||
|
||||
ui->removeFolderButton->setEnabled(!ui->gameFoldersListWidget->selectedItems().isEmpty());
|
||||
ResetInstallFolders();
|
||||
ui->backgroundImageOpacitySlider->setValue(Config::getBackgroundImageOpacity());
|
||||
ui->showBackgroundImageCheckBox->setChecked(Config::getShowBackgroundImage());
|
||||
}
|
||||
|
||||
void SettingsDialog::InitializeEmulatorLanguages() {
|
||||
@ -504,6 +510,8 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
||||
} else if (elementName == "updaterGroupBox") {
|
||||
text = tr("updaterGroupBox");
|
||||
#endif
|
||||
} else if (elementName == "GUIBackgroundImageGroupBox") {
|
||||
text = tr("GUIBackgroundImageGroupBox");
|
||||
} else if (elementName == "GUIMusicGroupBox") {
|
||||
text = tr("GUIMusicGroupBox");
|
||||
} else if (elementName == "disableTrophycheckBox") {
|
||||
@ -638,6 +646,9 @@ void SettingsDialog::UpdateSettings() {
|
||||
Config::setChooseHomeTab(ui->chooseHomeTabComboBox->currentText().toStdString());
|
||||
Config::setCompatibilityEnabled(ui->enableCompatibilityCheckBox->isChecked());
|
||||
Config::setCheckCompatibilityOnStartup(ui->checkCompatibilityOnStartupCheckBox->isChecked());
|
||||
Config::setBackgroundImageOpacity(ui->backgroundImageOpacitySlider->value());
|
||||
emit BackgroundOpacityChanged(ui->backgroundImageOpacitySlider->value());
|
||||
Config::setShowBackgroundImage(ui->showBackgroundImageCheckBox->isChecked());
|
||||
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
signals:
|
||||
void LanguageChanged(const std::string& locale);
|
||||
void CompatibilityChanged();
|
||||
void BackgroundOpacityChanged(int opacity);
|
||||
|
||||
private:
|
||||
void LoadValuesFromConfig();
|
||||
|
@ -583,6 +583,76 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="GUIBackgroundImageGroupBox">
|
||||
<property name="title">
|
||||
<string>Background Image</string>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="backgroundImageVLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showBackgroundImageCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Background Image</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="opacityLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="backgroundImageOpacityLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Opacity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="backgroundImageOpacitySlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="GUIMusicGroupBox">
|
||||
<property name="sizePolicy">
|
||||
|
@ -128,6 +128,14 @@
|
||||
<source>Copy Serial</source>
|
||||
<translation>Seriennummer kopieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Version</source>
|
||||
<translation>Version kopieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Size</source>
|
||||
<translation>Größe kopieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy All</source>
|
||||
<translation>Alles kopieren</translation>
|
||||
@ -1421,4 +1429,31 @@
|
||||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CompatibilityInfoClass</name>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Unbekannt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>Nichts</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>Startet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>Menüs</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>ImSpiel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>Spielbar</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
@ -124,6 +124,14 @@
|
||||
<source>Copy Serial</source>
|
||||
<translation>Copy Serial</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Version</source>
|
||||
<translation>Copy Version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Size</source>
|
||||
<translation>Copy Size</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy All</source>
|
||||
<translation>Copy All</translation>
|
||||
@ -749,6 +757,18 @@
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Background Image</source>
|
||||
<translation>Background Image</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Background Image</source>
|
||||
<translation>Show Background Image</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Opacity</source>
|
||||
<translation>Opacity</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play title music</source>
|
||||
<translation>Play title music</translation>
|
||||
@ -845,6 +865,10 @@
|
||||
<source>updaterGroupBox</source>
|
||||
<translation>Update:\nRelease: Official versions released every month that may be very outdated, but are more reliable and tested.\nNightly: Development versions that have all the latest features and fixes, but may contain bugs and are less stable.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIBackgroundImageGroupBox</source>
|
||||
<translation>Background Image:\nControl the opacity of the game background image.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIMusicGroupBox</source>
|
||||
<translation>Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI.</translation>
|
||||
|
@ -748,6 +748,18 @@
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Background Image</source>
|
||||
<translation>Imagen de fondo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Background Image</source>
|
||||
<translation>Mostrar Imagen de Fondo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Opacity</source>
|
||||
<translation>Opacidad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play title music</source>
|
||||
<translation>Reproducir la música de apertura</translation>
|
||||
@ -844,6 +856,10 @@
|
||||
<source>updaterGroupBox</source>
|
||||
<translation>Actualización:\nRelease: Versiones oficiales lanzadas cada mes que pueden estar muy desactualizadas, pero son más confiables y están probadas.\nNightly: Versiones de desarrollo que tienen todas las últimas funciones y correcciones, pero pueden contener errores y son menos estables.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIBackgroundImageGroupBox</source>
|
||||
<translation>Imagen de fondo:\nControle la opacidad de la imagen de fondo del juego.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIMusicGroupBox</source>
|
||||
<translation>Reproducir Música del Título:\nSi un juego lo admite, habilita la reproducción de música especial al seleccionar el juego en la interfaz gráfica.</translation>
|
||||
|
@ -742,7 +742,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
<translation>Musique du titre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
@ -958,7 +958,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Diagnostic de crash:\nCrée un fichier .yaml avec des informations sur l'état de Vulkan au moment du crash.\nUtile pour déboguer les erreurs "Device lost". Si cette option est activée, vous devez aussi activer Marqueur de débogage hôte ET invité.\nNe marche pas pour les GPUs Intel.\nVous devez activer le Vulkan Validation Layers ainsi que le Vulkan SDK pour que cela fonctionne.</translation>
|
||||
<translation>Diagnostic de crash:\nCrée un fichier .yaml avec des informations sur l'état de Vulkan au moment du crash.\nUtile pour déboguer les erreurs "Device lost". Si cette option est activée, vous devez aussi activer Marqueur de débogage hôte ET invité.\nNe marche pas pour les GPUs Intel.\nVous devez activer la couche de validation Vulkan ainsi que le Vulkan SDK pour que cela fonctionne.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
@ -1405,4 +1405,31 @@
|
||||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CompatibilityInfoClass</name>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Inconnu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>Rien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>Démarre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>Menu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>En jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>Jouable</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="nb">
|
||||
<!-- SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
<!-- SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later -->
|
||||
<context>
|
||||
<name>AboutDialog</name>
|
||||
@ -15,7 +15,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>shadPS4 is an experimental open-source emulator for the PlayStation 4.</source>
|
||||
<translation>shadPS4 er en eksperimentell åpen kildekode-etterligner for PlayStation 4.</translation>
|
||||
<translation>shadPS4 er en eksperimentell åpen kildekode-emulator for PlayStation 4.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This software should not be used to play games you have not legally obtained.</source>
|
||||
@ -124,6 +124,14 @@
|
||||
<source>Copy Serial</source>
|
||||
<translation>Kopier serienummer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Version</source>
|
||||
<translation>Kopier versjon</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Size</source>
|
||||
<translation>Kopier størrelse</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy All</source>
|
||||
<translation>Kopier alt</translation>
|
||||
@ -530,11 +538,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Emulator Language</source>
|
||||
<translation>Etterlignerspråk</translation>
|
||||
<translation>Emulatorspråk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Emulator</source>
|
||||
<translation>Etterligner</translation>
|
||||
<translation>Emulator</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Fullscreen</source>
|
||||
@ -764,6 +772,18 @@
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Deaktiver trofé hurtigmeny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Background Image</source>
|
||||
<translation>Bakgrunnsbilde</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Background Image</source>
|
||||
<translation>Vis bakgrunnsbilde</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Opacity</source>
|
||||
<translation>Synlighet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play title music</source>
|
||||
<translation>Spill tittelmusikk</translation>
|
||||
@ -818,7 +838,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>emulatorLanguageGroupBox</source>
|
||||
<translation>Etterlignerspråket:\nAngir språket for etterlignerens brukergrensesnitt.</translation>
|
||||
<translation>Emulatorspråket:\nAngir språket for emulatorens brukergrensesnitt.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>fullscreenCheckBox</source>
|
||||
@ -834,11 +854,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>ps4proCheckBox</source>
|
||||
<translation>Er PS4 Pro:\nFår etterligneren til å fungere som en PS4 PRO, noe som kan aktivere spesielle funksjoner i spill som støtter dette.</translation>
|
||||
<translation>Er PS4 Pro:\nFår emulatoren til å fungere som en PS4 PRO, noe som kan aktivere spesielle funksjoner i spill som støtter dette.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>discordRPCCheckbox</source>
|
||||
<translation>Aktiver Discord Rich Presence:\nViser etterlignerikonet og relevant informasjon på Discord-profilen din.</translation>
|
||||
<translation>Aktiver Discord Rich Presence:\nViser emulatorikonet og relevant informasjon på Discord-profilen din.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>userName</source>
|
||||
@ -850,7 +870,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>logTypeGroupBox</source>
|
||||
<translation>Logg type:\nAngir om loggvinduets utdata skal synkroniseres for ytelse. Kan ha negative effekter for etterligneren.</translation>
|
||||
<translation>Logg type:\nAngir om loggvinduets utdata skal synkroniseres for ytelse. Kan ha negative effekter for emulatoren.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>logFilter</source>
|
||||
@ -860,6 +880,10 @@
|
||||
<source>updaterGroupBox</source>
|
||||
<translation>Oppdatering:\nRelease: Offisielle versjoner utgitt hver måned som kan være veldig utdaterte, men er mer pålitelige og testet.\nNightly: Utviklingsversjoner som har alle de nyeste funksjonene og feilrettingene, men som kan inneholde feil og er mindre stabile.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIBackgroundImageGroupBox</source>
|
||||
<translation>Bakgrunnsbilde:\nEndrer synligheten til spillets bakgrunnsbilde.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIMusicGroupBox</source>
|
||||
<translation>Spille tittelmusikk:\nHvis et spill støtter det, så aktiveres det spesiell musikk når du velger spillet i menyen.</translation>
|
||||
@ -922,15 +946,15 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>graphicsAdapterGroupBox</source>
|
||||
<translation>Grafikkenhet:\nI systemer med flere GPU-er, velg GPU-en etterligneren skal bruke fra rullegardinlisten,\neller velg "Auto Select" for å velge automatisk.</translation>
|
||||
<translation>Grafikkenhet:\nI systemer med flere GPU-er, velg GPU-en emulatoren skal bruke fra rullegardinlisten,\neller velg "Auto Select" for å velge automatisk.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>resolutionLayout</source>
|
||||
<translation>Bredde/Høyde:\nAngir størrelsen på etterlignerkvinduet ved oppstart, som kan endres under spillingen.\nDette er forskjellig fra oppløsningen i spillet.</translation>
|
||||
<translation>Bredde/Høyde:\nAngir størrelsen på emulatorvinduet ved oppstart, som kan endres under spillingen.\nDette er forskjellig fra oppløsningen i spillet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>heightDivider</source>
|
||||
<translation>Vblank skillelinje:\nBildehastigheten som etterligneren oppdaterer ved, multipliseres med dette tallet. Endring av dette kan ha negative effekter, som å øke hastigheten av spillet, eller ødelegge kritisk spillfunksjonalitet som ikke forventer at dette endres!</translation>
|
||||
<translation>Vblank skillelinje:\nBildehastigheten som emulatoren oppdaterer ved, multipliseres med dette tallet. Endring av dette kan ha negative effekter, som å øke hastigheten av spillet, eller ødelegge kritisk spillfunksjonalitet som ikke forventer at dette endres!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>dumpShadersCheckBox</source>
|
||||
@ -958,15 +982,15 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>vkValidationCheckBox</source>
|
||||
<translation>Aktiver Vulkan Validation Layers:\nAktiverer et system som validerer tilstanden til Vulkan-gjengiveren og logger informasjon om dens indre tilstand. Dette vil redusere ytelsen og sannsynligvis endre etterlignerens atferd.</translation>
|
||||
<translation>Aktiver Vulkan Validation Layers:\nAktiverer et system som validerer tilstanden til Vulkan-gjengiveren og logger informasjon om dens indre tilstand. Dette vil redusere ytelsen og sannsynligvis endre emulatorens atferd.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>vkSyncValidationCheckBox</source>
|
||||
<translation>Aktiver Vulkan synkronisering validering:\nAktiverer et system som validerer frekvens tiden av Vulkan-gjengivelsensoppgaver. Dette vil redusere ytelsen og sannsynligvis endre etterlignerens atferd.</translation>
|
||||
<translation>Aktiver Vulkan synkronisering validering:\nAktiverer et system som validerer frekvens tiden av Vulkan-gjengivelsensoppgaver. Dette vil redusere ytelsen og sannsynligvis endre emulatorens atferd.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>rdocCheckBox</source>
|
||||
<translation>Aktiver RenderDoc feilsøking:\nHvis aktivert, vil etterligneren gi kompatibilitet med Renderdoc for å tillate opptak og analyse av det nåværende gjengitte bildet.</translation>
|
||||
<translation>Aktiver RenderDoc feilsøking:\nHvis aktivert, vil emulatoren gi kompatibilitet med RenderDoc for å tillate opptak og analyse av det nåværende gjengitte bildet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
@ -982,7 +1006,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Vertsfeilsøkingsmarkører:\nSetter inn etterligner-side informasjon som markører for spesifikke AMDGPU-kommandoer rundt Vulkan-kommandoer, i tillegg til å gi ressurser feilrettingsnavn.\nHvis du har dette aktivert, burde du aktivere krasjdiagnostikk.\nNyttig for programmer som RenderDoc.</translation>
|
||||
<translation>Vertsfeilsøkingsmarkører:\nSetter inn emulator-side informasjon som markører for spesifikke AMDGPU-kommandoer rundt Vulkan-kommandoer, i tillegg til å gi ressurser feilrettingsnavn.\nHvis du har dette aktivert, burde du aktivere krasjdiagnostikk.\nNyttig for programmer som RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
@ -1280,7 +1304,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Game does not initialize properly / crashes the emulator</source>
|
||||
<translation>Spillet initialiseres ikke riktig / krasjer etterligneren</translation>
|
||||
<translation>Spillet initialiseres ikke riktig / krasjer emulatoren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game boots, but only displays a blank screen</source>
|
||||
@ -1298,6 +1322,14 @@
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>Spillet kan fullføres med spillbar ytelse og uten store feil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Click to go to issue</source>
|
||||
<translation>Klikk for å gå til rapporten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Last updated</source>
|
||||
<translation>Sist oppdatert</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheckUpdate</name>
|
||||
@ -1425,4 +1457,43 @@
|
||||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CompatibilityInfoClass</name>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Ukjent</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>Ingenting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>Starter opp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>Meny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>I spill</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>Spillbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fetching compatibility data, please wait</source>
|
||||
<translation>Henter kompatibilitetsdata, vennligst vent</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>Avbryt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading...</source>
|
||||
<translation>Laster...</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -54,6 +54,14 @@
|
||||
<source>Select which directory you want to install to.</source>
|
||||
<translation>Виберіть папку, до якої ви хочете встановити.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Install All Queued to Selected Folder</source>
|
||||
<translation>Встановити все з черги до вибраної папки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete PKG File on Install</source>
|
||||
<translation>Видалити файл PKG під час встановлення</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>GameInstallDialog</name>
|
||||
@ -102,15 +110,19 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Game Folder</source>
|
||||
<translation>Відкрити папку з грою</translation>
|
||||
<translation>Відкрити папку гри</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Update Folder</source>
|
||||
<translation>Відкрити папку оновлень</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Save Data Folder</source>
|
||||
<translation>Відкрити Папку Збережених Даних</translation>
|
||||
<translation>Відкрити папку збережень гри</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Log Folder</source>
|
||||
<translation>Відкрити Папку Логів</translation>
|
||||
<translation>Відкрити папку логів</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy info...</source>
|
||||
@ -118,19 +130,27 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Name</source>
|
||||
<translation>Копіювати Ім’я</translation>
|
||||
<translation>Копіювати назву гри</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Serial</source>
|
||||
<translation>Копіювати серійний номер</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Version</source>
|
||||
<translation>Копіювати версію</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Size</source>
|
||||
<translation>Копіювати розмір</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy All</source>
|
||||
<translation>Копіювати все</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete...</source>
|
||||
<translation>Видалення...</translation>
|
||||
<translation>Видалити...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Game</source>
|
||||
@ -140,25 +160,29 @@
|
||||
<source>Delete Update</source>
|
||||
<translation>Видалити оновлення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Save Data</source>
|
||||
<translation>Видалити збереження</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete DLC</source>
|
||||
<translation>Видалити DLC</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Compatibility...</source>
|
||||
<translation>Compatibility...</translation>
|
||||
<translation>Сумісність...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database</source>
|
||||
<translation>Update database</translation>
|
||||
<translation>Оновити базу даних</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>View report</source>
|
||||
<translation>View report</translation>
|
||||
<translation>Переглянути звіт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Submit a report</source>
|
||||
<translation>Submit a report</translation>
|
||||
<translation>Створити звіт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut creation</source>
|
||||
@ -182,7 +206,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Game</source>
|
||||
<translation>Ігри</translation>
|
||||
<translation>гри</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>requiresEnableSeparateUpdateFolder_MSG</source>
|
||||
@ -192,10 +216,22 @@
|
||||
<source>This game has no update to delete!</source>
|
||||
<translation>Ця гра не має оновлень для видалення!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no update folder to open!</source>
|
||||
<translation>Ця гра не має папки оновленнь, щоб відкрити її!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Оновлення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no save data to delete!</source>
|
||||
<translation>Ця гра не містить збережень, які можна видалити!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Data</source>
|
||||
<translation>Збереження</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no DLC to delete!</source>
|
||||
<translation>Ця гра не має DLC для видалення!</translation>
|
||||
@ -206,11 +242,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete %1</source>
|
||||
<translation>Видалити %1</translation>
|
||||
<translation>Видалення %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to delete %1's %2 directory?</source>
|
||||
<translation>Ви впевнені, що хочете видалити папку %1 з папки %2??</translation>
|
||||
<translation>Ви впевнені, що хочете видалити %1 з папки %2?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -229,7 +265,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Check for Updates</source>
|
||||
<translation>Перевити наявність оновлень</translation>
|
||||
<translation>Перевірити наявність оновлень</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>About shadPS4</source>
|
||||
@ -249,7 +285,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
<translation>Відкрити папку shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
@ -297,15 +333,15 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Elf Viewer</source>
|
||||
<translation>Elf</translation>
|
||||
<translation>Виконуваний файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Install Directory</source>
|
||||
<translation>Каталог встановлення гри</translation>
|
||||
<translation>Каталоги встановлення ігор та оновлень</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Download Cheats/Patches</source>
|
||||
<translation>Завантажити Чити або Патчі</translation>
|
||||
<translation>Завантажити Чити/Патчі</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dump Game List</source>
|
||||
@ -329,7 +365,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Game List Icons</source>
|
||||
<translation>Розмір значків списку игр</translation>
|
||||
<translation>Розмір значків списку ігор</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game List Mode</source>
|
||||
@ -385,7 +421,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Download Cheats For All Installed Games</source>
|
||||
<translation>Завантажити чити для всіх встановлених ігор</translation>
|
||||
<translation>Завантажити чити для усіх встановлених ігор</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Download Patches For All Games</source>
|
||||
@ -397,7 +433,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>You have downloaded cheats for all the games you have installed.</source>
|
||||
<translation>Ви завантажили чити для всіх встановлених ігор.</translation>
|
||||
<translation>Ви завантажили чити для усіх встановлених ігор.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Patches Downloaded Successfully!</source>
|
||||
@ -417,7 +453,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>ELF files (*.bin *.elf *.oelf)</source>
|
||||
<translation>Файл ELF (*.bin *.elf *.oelf)</translation>
|
||||
<translation>Файли ELF (*.bin *.elf *.oelf)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Boot</source>
|
||||
@ -429,7 +465,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>PKG Extraction</source>
|
||||
<translation>Видобуток PKG</translation>
|
||||
<translation>Розпакування PKG</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Patch detected!</source>
|
||||
@ -449,7 +485,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Game is installed: </source>
|
||||
<translation>Гра встановлена: </translation>
|
||||
<translation>Встановлена гра: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to install Patch: </source>
|
||||
@ -461,7 +497,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Would you like to install DLC: %1?</source>
|
||||
<translation>Ви бажаєте встановити DLC: %1??</translation>
|
||||
<translation>Ви бажаєте встановити DLC: %1?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DLC already installed:</source>
|
||||
@ -481,11 +517,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Extracting PKG %1/%2</source>
|
||||
<translation>Вилучення PKG %1/%2</translation>
|
||||
<translation>Витягування PKG %1/%2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Extraction Finished</source>
|
||||
<translation>Вилучення завершено</translation>
|
||||
<translation>Розпакування завершено</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game successfully installed at %1</source>
|
||||
@ -542,8 +578,16 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Fullscreen Mode</source>
|
||||
<translation>Режим Повноекранний</translation>
|
||||
<translation>Тип повноекранного режиму</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Borderless</source>
|
||||
<translation>Без рамок</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>True</source>
|
||||
<translation>Повний екран</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Separate Update Folder</source>
|
||||
<translation>Увімкнути окрему папку оновлень</translation>
|
||||
@ -554,7 +598,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Game Size In List</source>
|
||||
<translation>Показати розмір гри в списку</translation>
|
||||
<translation>Показати розмір гри у списку</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Splash</source>
|
||||
@ -574,11 +618,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Ключ трофеїв</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
<translation>Trophy</translation>
|
||||
<translation>Трофеї</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
@ -588,6 +632,14 @@
|
||||
<source>Log Type</source>
|
||||
<translation>Тип логів</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>async</source>
|
||||
<translation>Асинхронний</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sync</source>
|
||||
<translation>Синхронний</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Log Filter</source>
|
||||
<translation>Фільтр логів</translation>
|
||||
@ -614,7 +666,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>s</source>
|
||||
<translation>s</translation>
|
||||
<translation>сек</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Controller</source>
|
||||
@ -622,14 +674,18 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Back Button Behavior</source>
|
||||
<translation>Поведінка кнопки назад</translation>
|
||||
<translation>Перепризначення кнопки назад</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Motion Controls</source>
|
||||
<translation>Увімкнути керування рухом</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Graphics</source>
|
||||
<translation>Графіка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Gui</source>
|
||||
<source>GUI</source>
|
||||
<translation>Інтерфейс</translation>
|
||||
</message>
|
||||
<message>
|
||||
@ -660,6 +716,10 @@
|
||||
<source>Enable Shaders Dumping</source>
|
||||
<translation>Увімкнути дамп шейдерів</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto Select</source>
|
||||
<translation>Автовибір</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable NULL GPU</source>
|
||||
<translation>Увімкнути NULL GPU</translation>
|
||||
@ -678,8 +738,12 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Remove</source>
|
||||
<translation>Видалити</translation>
|
||||
<translation>Вилучити</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Data Path</source>
|
||||
<translation>Шлях до файлів збережень</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Debug</source>
|
||||
<translation>Налагодження</translation>
|
||||
@ -702,36 +766,45 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
<translation>Увімкнути діагностику збоїв</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
<translation>Збирати шейдери</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
<translation>Копіювати буфери GPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
<translation>Хостові маркери налагодження</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
<translation>Гостьові маркери налагодження</translation>
|
||||
</message>
|
||||
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Оновлення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Check for Updates at Startup</source>
|
||||
<translation>Перевірка оновлень під час запуску</translation>
|
||||
<translation>Перевіряти оновлення під час запуску</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Channel</source>
|
||||
<translation>Канал оновлення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Release</source>
|
||||
<translation>Релізний</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nightly</source>
|
||||
<translation>Тестовий</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Check for Updates</source>
|
||||
<translation>Перевірити оновлення</translation>
|
||||
@ -742,31 +815,43 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
<translation>Титульна музика</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
<translation>Вимкнути спливаючі вікна трофеїв</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Background Image</source>
|
||||
<translation>Фонове зображення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Background Image</source>
|
||||
<translation>Показувати фонове зображення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Opacity</source>
|
||||
<translation>Непрозорість</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play title music</source>
|
||||
<translation>Програвати заголовну музику</translation>
|
||||
<translation>Програвати титульну музику</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database On Startup</source>
|
||||
<translation>Update Compatibility Database On Startup</translation>
|
||||
<translation>Оновлення даних ігрової сумісності під час запуску</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Compatibility</source>
|
||||
<translation>Game Compatibility</translation>
|
||||
<translation>Сумісність з іграми</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Compatibility Data</source>
|
||||
<translation>Display Compatibility Data</translation>
|
||||
<translation>Відображати данні ігрової сумістністі</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database</source>
|
||||
<translation>Update Compatibility Database</translation>
|
||||
<translation>Оновити данні ігрової сумістності</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Volume</source>
|
||||
@ -774,7 +859,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio Backend</source>
|
||||
<translation>Audio Backend</translation>
|
||||
<translation>Аудіосистема</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save</source>
|
||||
@ -826,11 +911,11 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>userName</source>
|
||||
<translation>Ім'я користувача:\nВстановіть ім'я користувача акаунта PS4. Це може відображатися в деяких іграх.</translation>
|
||||
<translation>Ім'я користувача:\nВстановіть ім'я користувача акаунта PS4. Воно може відображатися в деяких іграх.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TrophyKey</source>
|
||||
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
|
||||
<translation>Ключ трофеїв:\nКлюч для розшифровки трофеїв. Може бути отриманий зі зламаної консолі.\nПовинен містити лише шістнадцяткові символи.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>logTypeGroupBox</source>
|
||||
@ -842,19 +927,23 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>updaterGroupBox</source>
|
||||
<translation>Оновлення:\nRelease: Офіційні версії, які випускаються щомісяця і можуть бути дуже старими, але вони більш надійні та перевірені.\nNightly: Версії для розробників, які мають усі найновіші функції та виправлення, але можуть містити помилки та є менш стабільними.</translation>
|
||||
<translation>Оновлення:\nРелізний: Офіційні версії, які випускаються щомісяця і можуть бути дуже старими, але вони більш надійні та перевірені.\nТестовий: Версії для розробників, які мають усі найновіші функції та виправлення, але можуть містити помилки та є менш стабільними.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIBackgroundImageGroupBox</source>
|
||||
<translation>Фонове зображення:\nКерує непрозорістю фонового зображення гри.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIMusicGroupBox</source>
|
||||
<translation>Грати заголовну музику:\nВмикає відтворення спеціальної музики під час вибору гри в списку, якщо вона це підтримує.</translation>
|
||||
<translation>Грати титульну музику:\nВмикає відтворення спеціальної музики під час вибору гри в списку, якщо вона це підтримує.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>disableTrophycheckBox</source>
|
||||
<translation>Disable Trophy Pop-ups:\nDisable in-game trophy notifications. Trophy progress can still be tracked using the Trophy Viewer (right-click the game in the main window).</translation>
|
||||
<translation>Вимкнути спливаючі вікна трофеїв:\nВимикає сповіщення про ігрові трофеї. Прогрес трофея все ще можна відстежувати за допомогою "Перегляд трофеїв" (клацніть правою кнопкою миші на грі у головному вікні).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hideCursorGroupBox</source>
|
||||
<translation>Приховувати курсор:\nВиберіть, коли курсор зникне:\nНіколи: Ви завжди будете бачити мишу.\nПри бездіяльності: Встановіть час, через який курсор зникне в разі бездіяльності.\nЗавжди: Ви ніколи не будете бачити мишу.</translation>
|
||||
<translation>Приховувати курсор:\nВиберіть, коли курсор зникатиме:\nНіколи: Курсор миші завжди буде видимий.\nПри бездіяльності: Встановіть час, через який курсор зникне в разі бездіяльності.\nЗавжди: Курсор миші завжди буде прихований.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>idleTimeoutGroupBox</source>
|
||||
@ -862,19 +951,19 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>backButtonBehaviorGroupBox</source>
|
||||
<translation>Поведінка кнопки «Назад»:\nНалаштовує кнопку «Назад» контролера на емуляцію натискання на зазначену область на сенсорній панелі контролера PS4.</translation>
|
||||
<translation>Перепризначення кнопки «Назад»:\nНалаштовує кнопку «Назад» контролера на емуляцію натискання на зазначену область на сенсорній панелі контролера PS4.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>enableCompatibilityCheckBox</source>
|
||||
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
|
||||
<translation>Відображати данні ігрової сумістністі:\nВідображає інформацію про сумісність ігор у вигляді таблиці. Увімкніть "Оновлення даних ігрової сумісності під час запуску" для отримання актуальної інформації.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>checkCompatibilityOnStartupCheckBox</source>
|
||||
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
|
||||
<translation>Оновлення даних ігрової сумісності під час запуску:\nАвтоматично оновлює базу даних ігрової сумісності під час запуску shadPS4.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>updateCompatibilityButton</source>
|
||||
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
|
||||
<translation>Оновити данні ігрової сумістності:\nНегайно оновить базу даних ігрової сумісності.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Never</source>
|
||||
@ -890,23 +979,23 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Touchpad Left</source>
|
||||
<translation>Тачпад ліворуч</translation>
|
||||
<translation>Ліва сторона тачпаду</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Touchpad Right</source>
|
||||
<translation>Тачпад праворуч</translation>
|
||||
<translation>Права сторона тачпаду</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Touchpad Center</source>
|
||||
<translation>Тачпад по центру </translation>
|
||||
<translation>Середина тачпаду</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
<translation>Ні</translation>
|
||||
<translation>Без змін</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>graphicsAdapterGroupBox</source>
|
||||
<translation>Графічний пристрій:\nУ системах із кількома GPU виберіть з випадаючого списку GPU, який буде використовувати емулятор,\nабо виберіть "Auto Select", щоб визначити його автоматично.</translation>
|
||||
<translation>Графічний пристрій:\nУ системах із кількома GPU виберіть з випадаючого списку GPU, який буде використовувати емулятор,\nабо виберіть "Автовибір", щоб визначити його автоматично.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>resolutionLayout</source>
|
||||
@ -926,7 +1015,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>gameFoldersBox</source>
|
||||
<translation>Ігрові папки:\nСписок папок для перевірки встановлених ігор.</translation>
|
||||
<translation>Ігрові папки:\nСписок папок, що скануватимуться для виявлення ігор.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>addFolderButton</source>
|
||||
@ -934,7 +1023,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>removeFolderButton</source>
|
||||
<translation>Видалити:\nВидалити папку зі списку.</translation>
|
||||
<translation>Вилучити:\nВилучити папку зі списку.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>debugDump</source>
|
||||
@ -954,30 +1043,38 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
<translation>Збирати шейдери:\nВам потрібно увімкнути цю опцію, щоб редагувати шейдери за допомогою меню налагодження (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
<translation>Діагностика збоїв:\nСтворює .yaml файл з інформацією про стан Vulkan на момент збою.\nКорисно для налагодження помилок 'Device lost'. Якщо у вас увімкнено цей параметр, вам слід увімкнути маркери налагодження Хоста ТА Гостя.\nНе працює на графічних процесорах Intel.\nДля цього вам потрібно увімкнути шари валідації Vulkan і мати Vulkan SDK.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
<translation>Копіювати буфери GPU:\nДозволяє обійти проблеми синхронізації, пов'язані з відправленням даних на GPU\nМоже як допомогти, так і не вплинути на збої типу PM4 (тип 0).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
<translation>Хостові маркери налагодження:\nДодає інформацію емулятора, наприклад маркери для конкретних команд AMDGPU у Vulkan, також присвоює ресурсам налагоджувані назви.\nЯкщо ця опція увімкнена, рекомендується також активувати діагностику збоїв.\nКорисно для програм на кшталт RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
<translation>Гостьові маркери налагодження:\nВставляє налагоджувані маркери, які сама гра додала до командного буфера.\nЯкщо ця опція увімкнена, рекомендується також активувати діагностику збоїв.\nКорисно для програм на кшталт RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>saveDataBox</source>
|
||||
<translation>Шлях до файлів збережень:\nПапка, де будуть зберігатися ігрові збереження.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>browseButton</source>
|
||||
<translation>Вибрати:\nВиберіть папку для ігрових збережень.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
<message>
|
||||
<source>Cheats / Patches for </source>
|
||||
<translation>Cheats / Patches for </translation>
|
||||
<translation>Чити та Патчі для </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>defaultTextEdit_MSG</source>
|
||||
@ -1149,7 +1246,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>The game is in version: %1</source>
|
||||
<translation>Гра у версії: %1</translation>
|
||||
<translation>Версія гри: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The downloaded patch only works on version: %1</source>
|
||||
@ -1189,7 +1286,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Name:</source>
|
||||
<translation>Ім'я:</translation>
|
||||
<translation>Назва:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Can't apply cheats before the game is started</source>
|
||||
@ -1212,7 +1309,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
<translation>Сумісність</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Region</source>
|
||||
@ -1240,43 +1337,43 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
<translation>Ніколи не запускалась</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>h</source>
|
||||
<translation>h</translation>
|
||||
<translation>год</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>m</source>
|
||||
<translation>m</translation>
|
||||
<translation>хв</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>s</source>
|
||||
<translation>s</translation>
|
||||
<translation>сек</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Compatibility is untested</source>
|
||||
<translation>Compatibility is untested</translation>
|
||||
<translation>Сумісність не перевірена</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game does not initialize properly / crashes the emulator</source>
|
||||
<translation>Game does not initialize properly / crashes the emulator</translation>
|
||||
<translation>Гра не ініціалізується належним чином або спричиняє збій емулятора.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game boots, but only displays a blank screen</source>
|
||||
<translation>Game boots, but only displays a blank screen</translation>
|
||||
<translation>Гра запускається, але відображає лише чорний екран.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game displays an image but does not go past the menu</source>
|
||||
<translation>Game displays an image but does not go past the menu</translation>
|
||||
<translation>Гра відображає зображення, але не проходить далі меню.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game has game-breaking glitches or unplayable performance</source>
|
||||
<translation>Game has game-breaking glitches or unplayable performance</translation>
|
||||
<translation>У грі є критичні баги або погана продуктивність</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>Game can be completed with playable performance and no major glitches</translation>
|
||||
<translation>Гру можна пройти з хорошою продуктивністю та без серйозних глюків.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1303,7 +1400,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Invalid release data.</source>
|
||||
<translation>Неприпустимі дані релізу.</translation>
|
||||
<translation>Некоректні дані про випуск.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No download URL found for the specified asset.</source>
|
||||
@ -1311,7 +1408,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Your version is already up to date!</source>
|
||||
<translation>Вашу версію вже оновлено!</translation>
|
||||
<translation>У вас актуальна версія!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Available</source>
|
||||
@ -1386,23 +1483,74 @@
|
||||
<name>GameListUtils</name>
|
||||
<message>
|
||||
<source>B</source>
|
||||
<translation>B</translation>
|
||||
<translation>Б</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>KB</source>
|
||||
<translation>KB</translation>
|
||||
<translation>КБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MB</source>
|
||||
<translation>MB</translation>
|
||||
<translation>MБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GB</source>
|
||||
<translation>GB</translation>
|
||||
<translation>ГБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>TB</source>
|
||||
<translation>TB</translation>
|
||||
<translation>ТБ</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
<context>
|
||||
<name>CompatibilityInfoClass</name>
|
||||
<message>
|
||||
<source>Fetching compatibility data, please wait</source>
|
||||
<translation>Отримання даних про сумісність. Будь ласка, зачекайте</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel</source>
|
||||
<translation>Відмінити</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Loading...</source>
|
||||
<translation>Завантаження...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Error</source>
|
||||
<translation>Помилка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to update compatibility data! Try again later.</source>
|
||||
<translation>Не вдалося оновити дані про сумісність! Спробуйте ще раз пізніше.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unable to open compatibility.json for writing.</source>
|
||||
<translation>Не вдалося відкрити файл compatibility.json для запису.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Невідомо</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>Не працює</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>Запускається</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>У меню</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>У грі</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>Іграбельно</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
@ -52,7 +52,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Select which directory you want to install to.</source>
|
||||
<translation>选择你想要安装到的目录。</translation>
|
||||
<translation>选择您想要安装到的目录。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -186,7 +186,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>requiresEnableSeparateUpdateFolder_MSG</source>
|
||||
<translation>这个功能需要“启用单独的更新目录”配置选项才能正常运行,如果你想要使用这个功能,请启用它。</translation>
|
||||
<translation>这个功能需要“启用单独的更新目录”配置选项才能正常运行,如果您想要使用这个功能,请启用它。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no update to delete!</source>
|
||||
@ -210,7 +210,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to delete %1's %2 directory?</source>
|
||||
<translation>你确定要删除 %1 的%2目录?</translation>
|
||||
<translation>您确定要删除 %1 的%2目录?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -702,24 +702,25 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
<translation>启用崩溃诊断</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
<translation>收集着色器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
<translation>复制 GPU 缓冲区</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
<translation>Host 调试标记</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
<translation>Geust 调试标记</translation>
|
||||
</message>
|
||||
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>更新</translation>
|
||||
@ -954,23 +955,23 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
<translation>收集着色器:\n您需要启用此功能才能使用调试菜单(Ctrl + F10)编辑着色器。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
<translation>崩溃诊断:\n创建一个包含崩溃时 Vulkan 状态的 .yaml 文件。\n对于调试“Device lost”错误很有用。如果您启用了此功能,您应该同时启用 Host 和 Guest 调试标记。\n此功能在 Intel 显卡上不可用。\n您需要启用 Vulkan 验证层并安装 Vulkan SDK 才能使用此功能。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
<translation>复制 GPU 缓冲区:\n绕过涉及 GPU 提交的竞态条件。\n对于 PM4 type 0 崩溃可能有帮助,也可能没有帮助。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
<translation>Host 调试标记:\n在 Vulkan 命令周围插入模拟器端信息,如特定 AMD GPU 命令的标记,以及为资源提供调试名称。\n如果您已启用此功能,应同时启用崩溃诊断。\n对 RenderDoc 等程序很有用。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
<translation>Guest 调试标记:\n在命令缓冲区中插入游戏本身添加的任何调试标记。\n如果您已启用此功能,应同时启用崩溃诊断。\n对 RenderDoc 等程序很有用。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>saveDataBox</source>
|
||||
@ -1284,7 +1285,7 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>游戏能在可玩的性能下完成且没有重大 Bug</translation>
|
||||
<translation>游戏能在可玩的性能下通关且没有重大 Bug</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1413,4 +1414,31 @@
|
||||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CompatibilityInfoClass</name>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>未知</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>无法启动</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>可启动</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>可进入菜单</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>可进入游戏内</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>可通关</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
@ -148,41 +148,46 @@ void CFG::EmitDivergenceLabels() {
|
||||
const size_t end_index = GetIndex(end);
|
||||
|
||||
s32 curr_begin = -1;
|
||||
s32 last_exec_idx = -1;
|
||||
for (size_t index = GetIndex(start); index < end_index; index++) {
|
||||
const auto& inst = inst_list[index];
|
||||
const bool is_close = is_close_scope(inst);
|
||||
if ((is_close || index == end_index - 1) && curr_begin != -1) {
|
||||
// If there are no instructions inside scope don't do anything.
|
||||
if (index - curr_begin == 1) {
|
||||
curr_begin = -1;
|
||||
continue;
|
||||
if (curr_begin != -1) {
|
||||
// Keep note of the last instruction that does not ignore exec, so we know where
|
||||
// to end the divergence block without impacting trailing instructions that do.
|
||||
if (!IgnoresExecMask(inst)) {
|
||||
last_exec_idx = index;
|
||||
}
|
||||
// If all instructions in the scope ignore exec masking, we shouldn't insert a
|
||||
// scope.
|
||||
const auto start = inst_list.begin() + curr_begin + 1;
|
||||
if (!std::ranges::all_of(start, inst_list.begin() + index, IgnoresExecMask)) {
|
||||
// Add a label to the instruction right after the open scope call.
|
||||
// It is the start of a new basic block.
|
||||
const auto& save_inst = inst_list[curr_begin];
|
||||
const Label label = index_to_pc[curr_begin] + save_inst.length;
|
||||
AddLabel(label);
|
||||
// Add a label to the close scope instruction.
|
||||
// There are 3 cases where we need to close a scope.
|
||||
// * Close scope instruction inside the block
|
||||
// * Close scope instruction at the end of the block (cbranch or endpgm)
|
||||
// * Normal instruction at the end of the block
|
||||
// For the last case we must NOT add a label as that would cause
|
||||
// the instruction to be separated into its own basic block.
|
||||
if (is_close) {
|
||||
AddLabel(index_to_pc[index]);
|
||||
// Consider a close scope on certain instruction types or at the last instruction
|
||||
// before the next label.
|
||||
if (is_close_scope(inst) || index == end_index - 1) {
|
||||
// Only insert a scope if, since the open-scope instruction, there is at least
|
||||
// one instruction that does not ignore exec.
|
||||
if (index - curr_begin > 1 && last_exec_idx != -1) {
|
||||
// Add a label to the instruction right after the open scope call.
|
||||
// It is the start of a new basic block.
|
||||
const auto& save_inst = inst_list[curr_begin];
|
||||
AddLabel(index_to_pc[curr_begin] + save_inst.length);
|
||||
// Add a label to the close scope instruction.
|
||||
// There are 3 cases where we need to close a scope.
|
||||
// * Close scope instruction inside the block
|
||||
// * Close scope instruction at the end of the block (cbranch or endpgm)
|
||||
// * Normal instruction at the end of the block
|
||||
// If the instruction we want to close the scope at is at the end of the
|
||||
// block, we do not need to insert a new label.
|
||||
if (last_exec_idx != end_index - 1) {
|
||||
// Add the label after the last instruction affected by exec.
|
||||
const auto& last_exec_inst = inst_list[last_exec_idx];
|
||||
AddLabel(index_to_pc[last_exec_idx] + last_exec_inst.length);
|
||||
}
|
||||
}
|
||||
// Reset scope begin.
|
||||
curr_begin = -1;
|
||||
}
|
||||
// Reset scope begin.
|
||||
curr_begin = -1;
|
||||
}
|
||||
// Mark a potential start of an exec scope.
|
||||
if (is_open_scope(inst)) {
|
||||
curr_begin = index;
|
||||
last_exec_idx = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,11 @@ u32 SwizzleMrtComponent(const FragmentRuntimeInfo::PsColorBuffer& color_buffer,
|
||||
|
||||
void Translator::ExportMrtValue(IR::Attribute attribute, u32 comp, const IR::F32& value,
|
||||
const FragmentRuntimeInfo::PsColorBuffer& color_buffer) {
|
||||
const auto converted = ApplyWriteNumberConversion(ir, value, color_buffer.num_conversion);
|
||||
auto converted = ApplyWriteNumberConversion(ir, value, color_buffer.num_conversion);
|
||||
if (color_buffer.needs_unorm_fixup) {
|
||||
// FIXME: Fix-up for GPUs where float-to-unorm rounding is off from expected.
|
||||
converted = ir.FPSub(converted, ir.Imm32(1.f / 127500.f));
|
||||
}
|
||||
ir.SetAttribute(attribute, converted, comp);
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ void FlattenExtendedUserdataPass(IR::Program& program) {
|
||||
};
|
||||
auto base0 = IR::BreadthFirstSearch(ptr_composite->Arg(0), pred);
|
||||
auto base1 = IR::BreadthFirstSearch(ptr_composite->Arg(1), pred);
|
||||
ASSERT_MSG(base0 && base1 && "ReadConst not from constant memory");
|
||||
ASSERT_MSG(base0 && base1, "ReadConst not from constant memory");
|
||||
|
||||
IR::Inst* ptr_lo = base0.value();
|
||||
ptr_lo = pass_info.DeduplicateInstruction(ptr_lo);
|
||||
@ -250,4 +250,4 @@ void FlattenExtendedUserdataPass(IR::Program& program) {
|
||||
info.RefreshFlatBuf();
|
||||
}
|
||||
|
||||
} // namespace Shader::Optimization
|
||||
} // namespace Shader::Optimization
|
||||
|
@ -9,9 +9,10 @@ namespace Shader::IR {
|
||||
|
||||
std::string NameOf(Type type) {
|
||||
static constexpr std::array names{
|
||||
"Opaque", "Label", "Reg", "Pred", "Attribute", "U1", "U8", "U16", "U32",
|
||||
"U64", "F16", "F32", "F64", "U32x2", "U32x3", "U32x4", "F16x2", "F16x3",
|
||||
"F16x4", "F32x2", "F32x3", "F32x4", "F64x2", "F64x3", "F64x4", "StringLiteral"};
|
||||
"Opaque", "ScalarReg", "VectorReg", "Attribute", "Patch", "U1", "U8",
|
||||
"U16", "U32", "U64", "F16", "F32", "F64", "U32x2",
|
||||
"U32x3", "U32x4", "F16x2", "F16x3", "F16x4", "F32x2", "F32x3",
|
||||
"F32x4", "F64x2", "F64x3", "F64x4", "StringLiteral"};
|
||||
const size_t bits{static_cast<size_t>(type)};
|
||||
if (bits == 0) {
|
||||
return "Void";
|
||||
|
@ -185,6 +185,7 @@ struct FragmentRuntimeInfo {
|
||||
AmdGpu::NumberConversion num_conversion;
|
||||
AmdGpu::CompMapping swizzle;
|
||||
AmdGpu::Liverpool::ShaderExportFormat export_format;
|
||||
bool needs_unorm_fixup;
|
||||
|
||||
auto operator<=>(const PsColorBuffer&) const noexcept = default;
|
||||
};
|
||||
|
@ -30,5 +30,6 @@
|
||||
<file>images/ko-fi.png</file>
|
||||
<file>images/youtube.png</file>
|
||||
<file>images/website.png</file>
|
||||
<file>images/ps4_controller.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -330,6 +330,16 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Metal seems to have an issue where 8-bit unorm/snorm/sRGB outputs to render target
|
||||
// need a bias applied to round correctly; detect and set the flag for that here.
|
||||
const auto needs_unorm_fixup = instance.GetDriverID() == vk::DriverId::eMoltenvk &&
|
||||
(col_buf.GetNumberFmt() == AmdGpu::NumberFormat::Unorm ||
|
||||
col_buf.GetNumberFmt() == AmdGpu::NumberFormat::Snorm ||
|
||||
col_buf.GetNumberFmt() == AmdGpu::NumberFormat::Srgb) &&
|
||||
(col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8 ||
|
||||
col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8 ||
|
||||
col_buf.GetDataFmt() == AmdGpu::DataFormat::Format8_8_8_8);
|
||||
|
||||
key.color_formats[remapped_cb] =
|
||||
LiverpoolToVK::SurfaceFormat(col_buf.GetDataFmt(), col_buf.GetNumberFmt());
|
||||
key.color_buffers[remapped_cb] = {
|
||||
@ -337,6 +347,7 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||
.num_conversion = col_buf.GetNumberConversion(),
|
||||
.swizzle = col_buf.Swizzle(),
|
||||
.export_format = regs.color_export_format.GetFormat(cb),
|
||||
.needs_unorm_fixup = needs_unorm_fixup,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ private:
|
||||
cb_descs;
|
||||
std::optional<std::pair<VideoCore::ImageId, VideoCore::TextureCache::DepthTargetDesc>> db_desc;
|
||||
boost::container::static_vector<vk::DescriptorImageInfo, 64> image_infos;
|
||||
boost::container::static_vector<vk::BufferView, 8> buffer_views;
|
||||
boost::container::static_vector<vk::BufferView, 16> buffer_views;
|
||||
boost::container::static_vector<vk::DescriptorBufferInfo, 32> buffer_infos;
|
||||
boost::container::static_vector<VideoCore::ImageId, 64> bound_images;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user