Compare commits
1 commit
433d53d971
...
ee4b414406
Author | SHA1 | Date | |
---|---|---|---|
ee4b414406 |
52 changed files with 509 additions and 1426 deletions
|
@ -10,7 +10,7 @@ if (-not ([bool](net session 2>$null))) {
|
|||
}
|
||||
|
||||
$VSVer = "17"
|
||||
$ExeFile = "vs_community.exe"
|
||||
$ExeFile = "vs_BuildTools.exe"
|
||||
$Uri = "https://aka.ms/vs/$VSVer/release/$ExeFile"
|
||||
$Destination = "./$ExeFile"
|
||||
|
||||
|
@ -19,39 +19,21 @@ $WebClient = New-Object System.Net.WebClient
|
|||
$WebClient.DownloadFile($Uri, $Destination)
|
||||
Write-Host "Finished downloading $ExeFile"
|
||||
|
||||
$VSROOT = "C:/VSBuildTools/$VSVer"
|
||||
$Arguments = @(
|
||||
"--quiet", # Suppress installer UI
|
||||
"--wait", # Wait for installation to complete
|
||||
"--norestart", # Prevent automatic restart
|
||||
"--force", # Force installation even if components are already installed
|
||||
"--add Microsoft.VisualStudio.Workload.NativeDesktop", # Desktop development with C++
|
||||
"--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64", # Core C++ compiler/tools for x86/x64
|
||||
"--add Microsoft.VisualStudio.Component.Windows11SDK.26100",# Windows 11 SDK (26100)
|
||||
"--add Microsoft.VisualStudio.Component.Windows10SDK.19041",# Windows 10 SDK (19041)
|
||||
"--add Microsoft.VisualStudio.Component.VC.Llvm.Clang", # LLVM Clang compiler
|
||||
"--add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset", # LLVM Clang integration toolset
|
||||
"--add Microsoft.VisualStudio.Component.Windows11SDK.22621",# Windows 11 SDK (22621)
|
||||
"--add Microsoft.VisualStudio.Component.VC.CMake.Project", # CMake project support
|
||||
"--add Microsoft.VisualStudio.ComponentGroup.VC.Tools.142.x86.x64", # VC++ 14.2 toolset
|
||||
"--add Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Llvm.Clang" # LLVM Clang for native desktop
|
||||
"--installPath `"$VSROOT`"", # set custom installation path
|
||||
"--quiet", # suppress UI
|
||||
"--wait", # wait for installation to complete
|
||||
"--norestart", # prevent automatic restart
|
||||
"--add Microsoft.VisualStudio.Workload.VCTools", # add C++ build tools workload
|
||||
"--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64", # add core x86/x64 C++ tools
|
||||
"--add Microsoft.VisualStudio.Component.Windows10SDK.19041" # add specific Windows SDK
|
||||
)
|
||||
|
||||
Write-Host "Installing Visual Studio Build Tools"
|
||||
$InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -ArgumentList $Arguments
|
||||
|
||||
# Spinner while installing
|
||||
$Spinner = "|/-\"
|
||||
$i = 0
|
||||
while (-not $InstallProcess.HasExited) {
|
||||
Write-Host -NoNewline ("`rInstalling... " + $Spinner[$i % $Spinner.Length])
|
||||
Start-Sleep -Milliseconds 250
|
||||
$i++
|
||||
}
|
||||
|
||||
# Clear spinner line
|
||||
Write-Host "`rSetup completed! "
|
||||
|
||||
$InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -Wait -ArgumentList $Arguments
|
||||
$ExitCode = $InstallProcess.ExitCode
|
||||
|
||||
if ($ExitCode -ne 0) {
|
||||
Write-Host "Error installing Visual Studio Build Tools (Error: $ExitCode)"
|
||||
Exit $ExitCode
|
||||
|
|
162
CMakeLists.txt
162
CMakeLists.txt
|
@ -139,50 +139,65 @@ endif()
|
|||
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||
cmake_dependent_option(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF)
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF)
|
||||
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
|
||||
endif()
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
|
||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
|
||||
|
||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
CMAKE_DEPENDENT_OPTION(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF)
|
||||
|
||||
set(EXT_DEFAULT OFF)
|
||||
|
||||
if (MSVC OR ANDROID)
|
||||
set(EXT_DEFAULT ON)
|
||||
endif()
|
||||
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
|
||||
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" OFF "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
if (ENABLE_SDL2)
|
||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF)
|
||||
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
|
||||
endif()
|
||||
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
|
||||
|
||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT WIN32 OR NOT ARCHITECTURE_arm64" OFF)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
|
||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
|
||||
|
||||
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF)
|
||||
|
||||
cmake_dependent_option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF "ENABLE_QT" OFF)
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" OFF "NOT WIN32 AND NOT ANDROID" OFF)
|
||||
|
||||
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
|
||||
|
||||
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
|
||||
|
||||
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
|
||||
|
||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF "ENABLE_QT" OFF)
|
||||
|
||||
option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
|
||||
|
||||
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
message(STATUS "Using Precompiled Headers.")
|
||||
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
|
||||
endif()
|
||||
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ${EXT_DEFAULT})
|
||||
|
||||
# TODO(crueter): CI this?
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF)
|
||||
if(YUZU_ENABLE_LTO)
|
||||
include(CheckIPOSupported)
|
||||
|
@ -190,42 +205,17 @@ if(YUZU_ENABLE_LTO)
|
|||
if(NOT COMPILER_SUPPORTS_LTO)
|
||||
message(FATAL_ERROR "Your compiler does not support interprocedural optimization (IPO). Re-run CMake with -DYUZU_ENABLE_LTO=OFF.")
|
||||
endif()
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ${COMPILER_SUPPORTS_LTO})
|
||||
endif()
|
||||
option(USE_CCACHE "Use ccache for compilation" OFF)
|
||||
set(CCACHE_PATH "ccache" CACHE STRING "Path to ccache binary")
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_BINARY ${CCACHE_PATH})
|
||||
if(CCACHE_BINARY)
|
||||
message(STATUS "Found ccache at: ${CCACHE_BINARY}")
|
||||
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_BINARY})
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_BINARY})
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
message(FATAL_ERROR "Precompiled headers are incompatible with ccache. Re-run CMake with -DYUZU_USE_PRECOMPILED_HEADERS=OFF.")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# TODO(crueter): CI this?
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
|
||||
cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
|
||||
|
||||
set(YUZU_TZDB_PATH "" CACHE STRING "Path to a pre-downloaded timezone database")
|
||||
|
||||
cmake_dependent_option(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "LINUX" OFF)
|
||||
|
||||
cmake_dependent_option(YUZU_APPLE_USE_BUNDLED_MONTENVK "Download bundled MoltenVK lib" ON "APPLE" OFF)
|
||||
|
||||
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
|
||||
|
||||
set(DEFAULT_ENABLE_OPENSSL ON)
|
||||
|
@ -238,12 +228,15 @@ if (ANDROID OR WIN32 OR APPLE OR PLATFORM_SUN)
|
|||
# your own copy of it.
|
||||
set(DEFAULT_ENABLE_OPENSSL OFF)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
set(DEFAULT_ENABLE_OPENSSL ON)
|
||||
endif()
|
||||
|
||||
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
|
||||
|
||||
if (ENABLE_OPENSSL)
|
||||
cmake_dependent_option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON)
|
||||
endif()
|
||||
|
||||
if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
|
||||
|
@ -270,6 +263,21 @@ if (ANDROID)
|
|||
set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # Workaround for Oboe
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
if (MSVC AND CCACHE)
|
||||
# buildcache does not properly cache PCH files, leading to compilation errors.
|
||||
# See https://github.com/mbitsnbites/buildcache/discussions/230
|
||||
message(WARNING "buildcache does not properly support Precompiled Headers. Disabling PCH")
|
||||
set(DYNARMIC_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
|
||||
set(YUZU_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
message(STATUS "Using Precompiled Headers.")
|
||||
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
|
||||
endif()
|
||||
|
||||
# Default to a Release build
|
||||
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
|
||||
|
@ -886,47 +894,25 @@ if (MSVC AND CXX_CLANG)
|
|||
link_libraries(llvm-mingw-runtime)
|
||||
endif()
|
||||
|
||||
#[[
|
||||
search order:
|
||||
- gold (GCC only) - the best, generally, but unfortunately not packaged anymore
|
||||
- mold (GCC only) - generally does well on GCC
|
||||
- ldd - preferred on clang
|
||||
- bfd - the final fallback
|
||||
- If none are found (macOS uses ld.prime, etc) just use the default linker
|
||||
]]
|
||||
if (YUZU_USE_FASTER_LD)
|
||||
find_program(LINKER_BFD bfd)
|
||||
if (LINKER_BFD)
|
||||
set(LINKER bfd)
|
||||
endif()
|
||||
# clang should always use lld
|
||||
find_program(LLD lld)
|
||||
|
||||
find_program(LINKER_LLD lld)
|
||||
if (LINKER_LLD)
|
||||
if (LLD)
|
||||
set(LINKER lld)
|
||||
endif()
|
||||
|
||||
# GNU appears to work better with mold
|
||||
# TODO: mold has been slow lately, see if better options exist (search for gold?)
|
||||
if (CXX_GCC)
|
||||
find_program(LINKER_MOLD mold)
|
||||
if (LINKER_MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
|
||||
find_program(MOLD mold)
|
||||
if (MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
|
||||
set(LINKER mold)
|
||||
endif()
|
||||
|
||||
find_program(LINKER_GOLD gold)
|
||||
if (LINKER_GOLD)
|
||||
set(LINKER gold)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LINKER)
|
||||
message(NOTICE "Selecting ${LINKER} as linker")
|
||||
add_link_options("-fuse-ld=${LINKER}")
|
||||
else()
|
||||
message(WARNING "No faster linker found--using default")
|
||||
endif()
|
||||
|
||||
if (LINKER STREQUAL "lld" AND CXX_GCC)
|
||||
message(WARNING "Using lld on GCC may cause issues with certain LTO settings. If the program fails to compile, disable YUZU_USE_FASTER_LD, or install mold or GNU gold.")
|
||||
endif()
|
||||
message(NOTICE "Selecting ${LINKER} as linker")
|
||||
add_link_options("-fuse-ld=${LINKER}")
|
||||
endif()
|
||||
|
||||
# Set runtime library to MD/MDd for all configurations
|
||||
|
|
|
@ -10,7 +10,6 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
|
|||
set(package_base_url "https://github.com/eden-emulator/")
|
||||
set(package_repo "no_platform")
|
||||
set(package_extension "no_platform")
|
||||
set(CACHE_KEY "")
|
||||
|
||||
# TODO(crueter): Need to convert ffmpeg to a CI.
|
||||
if (WIN32 OR FORCE_WIN_ARCHIVES)
|
||||
|
@ -34,9 +33,8 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
|
|||
else()
|
||||
message(FATAL_ERROR "No package available for this platform")
|
||||
endif()
|
||||
string(CONCAT package_url "${package_base_url}" "${package_repo}")
|
||||
string(CONCAT full_url "${package_url}" "${remote_path}" "${lib_name}" "${package_extension}")
|
||||
message(STATUS "Resolved bundled URL: ${full_url}")
|
||||
set(package_url "${package_base_url}${package_repo}")
|
||||
set(full_url ${package_url}${remote_path}${lib_name}${package_extension})
|
||||
|
||||
# TODO(crueter): DELETE THIS ENTIRELY, GLORY BE TO THE CI!
|
||||
AddPackage(
|
||||
|
@ -49,12 +47,26 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
|
|||
# TODO(crueter): hash
|
||||
)
|
||||
|
||||
if (DEFINED ${cpm_key}_SOURCE_DIR)
|
||||
set(${prefix_var} "${${cpm_key}_SOURCE_DIR}" PARENT_SCOPE)
|
||||
message(STATUS "Using bundled binaries at ${${cpm_key}_SOURCE_DIR}")
|
||||
else()
|
||||
message(FATAL_ERROR "AddPackage did not set ${cpm_key}_SOURCE_DIR")
|
||||
set(${prefix_var} "${${cpm_key}_SOURCE_DIR}" PARENT_SCOPE)
|
||||
message(STATUS "Using bundled binaries at ${${cpm_key}_SOURCE_DIR}")
|
||||
endfunction()
|
||||
|
||||
function(download_moltenvk_external platform version)
|
||||
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
|
||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||
if (NOT EXISTS ${MOLTENVK_DIR})
|
||||
if (NOT EXISTS ${MOLTENVK_TAR})
|
||||
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar
|
||||
${MOLTENVK_TAR} SHOW_PROGRESS)
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
||||
endif()
|
||||
|
||||
# Add the MoltenVK library path to the prefix so find_library can locate it.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Determine installation parameters for OS, architecture, and compiler
|
||||
|
@ -96,7 +108,7 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
|
|||
set(host "linux")
|
||||
set(type "desktop")
|
||||
set(arch "linux_gcc_64")
|
||||
set(arch_path "gcc_64")
|
||||
set(arch_path "linux")
|
||||
endif()
|
||||
|
||||
set(${host_out} "${host}" PARENT_SCOPE)
|
||||
|
@ -131,79 +143,56 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
|
|||
set(install_args -c "${CURRENT_MODULE_DIR}/aqt_config.ini")
|
||||
if (tool)
|
||||
set(prefix "${base_path}/Tools")
|
||||
list(APPEND install_args install-tool --outputdir "${base_path}" "${host}" desktop "${target}")
|
||||
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
|
||||
else()
|
||||
set(prefix "${base_path}/${target}/${arch_path}")
|
||||
list(APPEND install_args install-qt --outputdir "${base_path}" "${host}" "${type}" "${target}" "${arch}" -m qt_base)
|
||||
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt_base)
|
||||
|
||||
if (YUZU_USE_QT_MULTIMEDIA)
|
||||
list(APPEND install_args qtmultimedia)
|
||||
set(install_args ${install_args} qtmultimedia)
|
||||
endif()
|
||||
|
||||
if (YUZU_USE_QT_WEB_ENGINE)
|
||||
list(APPEND install_args qtpositioning qtwebchannel qtwebengine)
|
||||
set(install_args ${install_args} qtpositioning qtwebchannel qtwebengine)
|
||||
endif()
|
||||
|
||||
if (NOT "${YUZU_QT_MIRROR}" STREQUAL "")
|
||||
if (NOT ${YUZU_QT_MIRROR} STREQUAL "")
|
||||
message(STATUS "Using Qt mirror ${YUZU_QT_MIRROR}")
|
||||
list(APPEND install_args -b "${YUZU_QT_MIRROR}")
|
||||
set(install_args ${install_args} -b ${YUZU_QT_MIRROR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Install Args: ${install_args}")
|
||||
|
||||
message(STATUS "Install Args ${install_args}")
|
||||
if (NOT EXISTS "${prefix}")
|
||||
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
|
||||
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0")
|
||||
if (WIN32)
|
||||
set(aqt_path "${base_path}/aqt.exe")
|
||||
if (NOT EXISTS "${aqt_path}")
|
||||
file(DOWNLOAD "${AQT_PREBUILD_BASE_URL}/aqt.exe" "${aqt_path}" SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND "${aqt_path}" ${install_args}
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE aqt_res
|
||||
OUTPUT_VARIABLE aqt_out
|
||||
ERROR_VARIABLE aqt_err)
|
||||
if (NOT aqt_res EQUAL 0)
|
||||
message(FATAL_ERROR "aqt.exe failed: ${aqt_err}")
|
||||
file(DOWNLOAD
|
||||
${AQT_PREBUILD_BASE_URL}/aqt.exe
|
||||
${aqt_path} SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND ${aqt_path} ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
elseif (APPLE)
|
||||
set(aqt_path "${base_path}/aqt-macos")
|
||||
if (NOT EXISTS "${aqt_path}")
|
||||
file(DOWNLOAD "${AQT_PREBUILD_BASE_URL}/aqt-macos" "${aqt_path}" SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND chmod +x "${aqt_path}")
|
||||
execute_process(COMMAND "${aqt_path}" ${install_args}
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE aqt_res
|
||||
ERROR_VARIABLE aqt_err)
|
||||
if (NOT aqt_res EQUAL 0)
|
||||
message(FATAL_ERROR "aqt-macos failed: ${aqt_err}")
|
||||
file(DOWNLOAD
|
||||
${AQT_PREBUILD_BASE_URL}/aqt-macos
|
||||
${aqt_path} SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND chmod +x ${aqt_path})
|
||||
execute_process(COMMAND ${aqt_path} ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
else()
|
||||
find_program(PYTHON3_EXECUTABLE python3)
|
||||
if (NOT PYTHON3_EXECUTABLE)
|
||||
message(FATAL_ERROR "python3 is required to install Qt using aqt (pip mode).")
|
||||
endif()
|
||||
set(aqt_install_path "${base_path}/aqt")
|
||||
file(MAKE_DIRECTORY "${aqt_install_path}")
|
||||
|
||||
execute_process(COMMAND "${PYTHON3_EXECUTABLE}" -m pip install --target="${aqt_install_path}" aqtinstall
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE pip_res
|
||||
ERROR_VARIABLE pip_err)
|
||||
if (NOT pip_res EQUAL 0)
|
||||
message(FATAL_ERROR "pip install aqtinstall failed: ${pip_err}")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -E env PYTHONPATH="${aqt_install_path}" "${PYTHON3_EXECUTABLE}" -m aqt ${install_args}
|
||||
WORKING_DIRECTORY "${base_path}"
|
||||
RESULT_VARIABLE aqt_res
|
||||
ERROR_VARIABLE aqt_err)
|
||||
if (NOT aqt_res EQUAL 0)
|
||||
message(FATAL_ERROR "aqt (python) failed: ${aqt_err}")
|
||||
endif()
|
||||
execute_process(COMMAND python3 -m pip install --target=${aqt_install_path} aqtinstall
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${aqt_install_path} python3 -m aqt ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
endif()
|
||||
|
||||
message(STATUS "Downloaded Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path} to ${prefix}")
|
||||
|
@ -221,7 +210,7 @@ endfunction()
|
|||
function(download_qt target)
|
||||
determine_qt_parameters("${target}" host type arch arch_path host_type host_arch host_arch_path)
|
||||
|
||||
set(base_path "${CMAKE_BINARY_DIR}/externals/qt")
|
||||
get_external_prefix(qt base_path)
|
||||
file(MAKE_DIRECTORY "${base_path}")
|
||||
|
||||
download_qt_configuration(prefix "${target}" "${host}" "${type}" "${arch}" "${arch_path}" "${base_path}")
|
||||
|
@ -238,34 +227,26 @@ function(download_qt target)
|
|||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(download_moltenvk version platform)
|
||||
if(NOT version)
|
||||
message(FATAL_ERROR "download_moltenvk: version argument is required")
|
||||
endif()
|
||||
if(NOT platform)
|
||||
message(FATAL_ERROR "download_moltenvk: platform argument is required")
|
||||
endif()
|
||||
function(download_moltenvk)
|
||||
set(MOLTENVK_PLATFORM "macOS")
|
||||
|
||||
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
|
||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
|
||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||
if (NOT EXISTS ${MOLTENVK_DIR})
|
||||
if (NOT EXISTS ${MOLTENVK_TAR})
|
||||
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.10-rc2/MoltenVK-all.tar
|
||||
${MOLTENVK_TAR} SHOW_PROGRESS)
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${MOLTENVK_DIR}")
|
||||
if(NOT EXISTS "${MOLTENVK_TAR}")
|
||||
file(DOWNLOAD "https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar"
|
||||
"${MOLTENVK_TAR}" SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals"
|
||||
RESULT_VARIABLE tar_res
|
||||
ERROR_VARIABLE tar_err
|
||||
)
|
||||
if(NOT tar_res EQUAL 0)
|
||||
message(FATAL_ERROR "Extracting MoltenVK failed: ${tar_err}")
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
# Add the MoltenVK library path to the prefix so find_library can locate it.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${MOLTENVK_PLATFORM}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_external_prefix lib_name prefix_var)
|
||||
set(${prefix_var} "${CMAKE_BINARY_DIR}/externals/${lib_name}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
|
|
@ -4,8 +4,8 @@ To build Eden, you MUST have a C++ compiler.
|
|||
* On Linux, this is usually [GCC](https://gcc.gnu.org/) 11+ or [Clang](https://clang.llvm.org/) v14+
|
||||
- GCC 12 also requires Clang 14+
|
||||
* On Windows, this is either:
|
||||
- **[MSVC](https://visualstudio.microsoft.com/downloads/)** (you should select *Community* option),
|
||||
* *A convenience script to install the Visual Community Studio 2022 with necessary tools is provided in `.ci/windows/install-msvc.ps1`*
|
||||
- **[MSVC](https://visualstudio.microsoft.com/downloads/)**,
|
||||
* *A convenience script to install the **minimal** version (Visual Build Tools) is provided in `.ci/windows/install-msvc.ps1`*
|
||||
- clang-cl - can be downloaded from the MSVC installer,
|
||||
- or **[MSYS2](https://www.msys2.org)**
|
||||
* On macOS, this is Apple Clang
|
||||
|
@ -101,7 +101,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
|
|||
<summary>Ubuntu, Debian, Mint Linux</summary>
|
||||
|
||||
```sh
|
||||
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2t64 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev vulkan-utility-libraries-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev
|
||||
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev
|
||||
```
|
||||
|
||||
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
|
||||
|
@ -211,4 +211,4 @@ Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/l
|
|||
|
||||
## All Done
|
||||
|
||||
You may now return to the **[root build guide](Build.md)**.
|
||||
You may now return to the **[root build guide](Build.md)**.
|
|
@ -36,28 +36,6 @@ Pull requests are only to be merged by core developers when properly tested and
|
|||
- Maintainers are permitted to change namespaces at will.
|
||||
- Commits within PRs are not required to be namespaced, but it is highly recommended.
|
||||
|
||||
## Adding new settings
|
||||
|
||||
When adding new settings, use `tr("Setting:")` if the setting is meant to be a field, otherwise use `tr("Setting")` if the setting is meant to be a Yes/No or checkmark type of setting, see [this short style guide](https://learn.microsoft.com/en-us/style-guide/punctuation/colons#in-ui).
|
||||
|
||||
- The majority of software must work with the default option selected for such setting. Unless the setting significantly degrades performance.
|
||||
- Debug settings must never be turned on by default.
|
||||
- Provide reasonable bounds (for example, a setting controlling the amount of VRAM should never be 0).
|
||||
- The description of the setting must be short and concise, if the setting "does a lot of things" consider splitting the setting into multiple if possible.
|
||||
- Try to avoid excessive/redundant explainations "recommended for most users and games" can just be "(recommended)".
|
||||
- Try to not write "slow/fast" options unless it clearly degrades/increases performance for a given case, as most options may modify behaviour that result in different metrics accross different systems. If for example the option is an "accuracy" option, writing "High" is sufficient to imply "Slow". No need to write "High (Slow)".
|
||||
|
||||
Some examples:
|
||||
- "[...] negatively affecting image quality", "[...] degrading image quality": Same wording but with less filler.
|
||||
- "[...] this may cause some glitches or crashes in some games", "[...] this may cause soft-crashes": Crashes implies there may be glitches (as crashes are technically a form of a fatal glitch). The entire sentence is structured as "may cause [...] on some games", which is redundant, because "may cause [...] in games" has the same semantic meaning ("may" is a chance that it will occur on "some" given set).
|
||||
- "FIFO Relaxed is similar to FIFO [...]", "FIFO Relaxed [...]": The name already implies similarity.
|
||||
- "[...] but may also reduce performance in some cases", "[...] but may degrade performance": Again, "some cases" and "may" implies there is a probability.
|
||||
- "[...] it can [...] in some cases", "[...] it can [...]": Implied probability.
|
||||
|
||||
Before adding a new setting, consider:
|
||||
- Does the piece of code that the setting pertains to, make a significant difference if it's on/off?
|
||||
- Can it be auto-detected?
|
||||
|
||||
# IDE setup
|
||||
|
||||
## VSCode
|
||||
|
|
|
@ -31,7 +31,7 @@ Notes:
|
|||
* Currently, build fails without this
|
||||
- `YUZU_USE_FASTER_LD` (ON) Check if a faster linker is available
|
||||
* Only available on UNIX
|
||||
- `YUZU_APPLE_USE_BUNDLED_MONTENVK` (ON, macOS only) Download bundled MoltenVK lib)
|
||||
- `USE_SYSTEM_MOLTENVK` (OFF, macOS only) Use the system MoltenVK lib (instead of the bundled one)
|
||||
- `YUZU_TZDB_PATH` (string) Path to a pre-downloaded timezone database (useful for nixOS)
|
||||
- `ENABLE_OPENSSL` (ON for Linux and *BSD) Enable OpenSSL backend for the ssl service
|
||||
* Always enabled if the web service is enabled
|
||||
|
|
|
@ -68,9 +68,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
|||
var isActivityRecreated = false
|
||||
private lateinit var nfcReader: NfcReader
|
||||
|
||||
private var touchDownTime: Long = 0
|
||||
private val maxTapDuration = 500L
|
||||
|
||||
private val gyro = FloatArray(3)
|
||||
private val accel = FloatArray(3)
|
||||
private var motionTimestamp: Long = 0
|
||||
|
@ -492,38 +489,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
||||
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
|
||||
val emulationFragment = navHostFragment?.childFragmentManager?.fragments?.firstOrNull() as? org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||
|
||||
emulationFragment?.let { fragment ->
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
touchDownTime = System.currentTimeMillis()
|
||||
// show overlay immediately on touch and cancel timer
|
||||
if (!emulationViewModel.drawerOpen.value) {
|
||||
fragment.handler.removeCallbacksAndMessages(null)
|
||||
fragment.showOverlay()
|
||||
}
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (!emulationViewModel.drawerOpen.value) {
|
||||
val touchDuration = System.currentTimeMillis() - touchDownTime
|
||||
|
||||
if (touchDuration <= maxTapDuration) {
|
||||
fragment.handleScreenTap(false)
|
||||
} else {
|
||||
// just start the auto-hide timer without toggling visibility
|
||||
fragment.handleScreenTap(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.dispatchTouchEvent(event)
|
||||
}
|
||||
|
||||
fun onEmulationStarted() {
|
||||
emulationViewModel.setEmulationStarted(true)
|
||||
}
|
||||
|
|
|
@ -55,8 +55,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||
FRAME_INTERPOLATION("frame_interpolation"),
|
||||
// FRAME_SKIPPING("frame_skipping"),
|
||||
|
||||
ENABLE_INPUT_OVERLAY_AUTO_HIDE("enable_input_overlay_auto_hide"),
|
||||
|
||||
PERF_OVERLAY_BACKGROUND("perf_overlay_background"),
|
||||
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
|
||||
|
||||
|
|
|
@ -59,8 +59,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
|
|||
OFFLINE_WEB_APPLET("offline_web_applet_mode"),
|
||||
LOGIN_SHARE_APPLET("login_share_applet_mode"),
|
||||
WIFI_WEB_AUTH_APPLET("wifi_web_auth_applet_mode"),
|
||||
MY_PAGE_APPLET("my_page_applet_mode"),
|
||||
INPUT_OVERLAY_AUTO_HIDE("input_overlay_auto_hide")
|
||||
MY_PAGE_APPLET("my_page_applet_mode")
|
||||
;
|
||||
|
||||
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)
|
||||
|
|
|
@ -12,7 +12,6 @@ object Settings {
|
|||
SECTION_SYSTEM(R.string.preferences_system),
|
||||
SECTION_RENDERER(R.string.preferences_graphics),
|
||||
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
||||
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
||||
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
||||
SECTION_AUDIO(R.string.preferences_audio),
|
||||
SECTION_INPUT(R.string.preferences_controls),
|
||||
|
|
|
@ -96,7 +96,6 @@ abstract class SettingsItem(
|
|||
const val TYPE_INT_SINGLE_CHOICE = 9
|
||||
const val TYPE_INPUT_PROFILE = 10
|
||||
const val TYPE_STRING_INPUT = 11
|
||||
const val TYPE_SPINBOX = 12
|
||||
|
||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||
|
||||
|
@ -386,22 +385,6 @@ abstract class SettingsItem(
|
|||
warningMessage = R.string.warning_resolution
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE,
|
||||
titleId = R.string.enable_input_overlay_auto_hide,
|
||||
)
|
||||
)
|
||||
put(
|
||||
SpinBoxSetting(
|
||||
IntSetting.INPUT_OVERLAY_AUTO_HIDE,
|
||||
titleId = R.string.overlay_auto_hide,
|
||||
descriptionId = R.string.overlay_auto_hide_description,
|
||||
min = 1,
|
||||
max = 999,
|
||||
valueHint = R.string.seconds
|
||||
)
|
||||
)
|
||||
|
||||
put(
|
||||
SwitchSetting(
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractByteSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
||||
|
||||
class SpinBoxSetting(
|
||||
setting: AbstractSetting,
|
||||
@StringRes titleId: Int = 0,
|
||||
titleString: String = "",
|
||||
@StringRes descriptionId: Int = 0,
|
||||
descriptionString: String = "",
|
||||
val valueHint: Int,
|
||||
val min: Int,
|
||||
val max: Int
|
||||
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
|
||||
override val type = TYPE_SPINBOX
|
||||
|
||||
fun getSelectedValue(needsGlobal: Boolean = false) =
|
||||
when (setting) {
|
||||
is AbstractByteSetting -> setting.getByte(needsGlobal).toInt()
|
||||
is AbstractShortSetting -> setting.getShort(needsGlobal).toInt()
|
||||
is AbstractIntSetting -> setting.getInt(needsGlobal)
|
||||
is AbstractFloatSetting -> setting.getFloat(needsGlobal).toInt()
|
||||
else -> 0
|
||||
}
|
||||
|
||||
fun setSelectedValue(value: Int) =
|
||||
when (setting) {
|
||||
is AbstractByteSetting -> setting.setByte(value.toByte())
|
||||
is AbstractShortSetting -> setting.setShort(value.toShort())
|
||||
is AbstractFloatSetting -> setting.setFloat(value.toFloat())
|
||||
else -> (setting as AbstractIntSetting).setInt(value)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui
|
||||
|
||||
|
@ -61,10 +61,6 @@ class SettingsAdapter(
|
|||
SliderViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SPINBOX -> {
|
||||
SpinBoxViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SUBMENU -> {
|
||||
SubmenuViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||
}
|
||||
|
@ -195,14 +191,6 @@ class SettingsAdapter(
|
|||
position
|
||||
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
|
||||
}
|
||||
fun onSpinBoxClick(item: SpinBoxSetting, position: Int) {
|
||||
SettingsDialogFragment.newInstance(
|
||||
settingsViewModel,
|
||||
item,
|
||||
SettingsItem.TYPE_SPINBOX,
|
||||
position
|
||||
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
|
||||
}
|
||||
|
||||
fun onSubmenuClick(item: SubmenuSetting) {
|
||||
val action = SettingsNavigationDirections.actionGlobalSettingsFragment(item.menuKey, null)
|
||||
|
|
|
@ -14,7 +14,6 @@ import android.text.TextWatcher
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
|
@ -23,7 +22,6 @@ import com.google.android.material.slider.Slider
|
|||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
|
||||
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
|
||||
import org.yuzu.yuzu_emu.databinding.DialogSpinboxBinding
|
||||
import org.yuzu.yuzu_emu.features.input.NativeInput
|
||||
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.AnalogInputSetting
|
||||
|
@ -32,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
|
|||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SpinBoxSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
|
||||
import org.yuzu.yuzu_emu.utils.ParamPackage
|
||||
|
@ -49,7 +46,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||
|
||||
private lateinit var sliderBinding: DialogSliderBinding
|
||||
private lateinit var stringInputBinding: DialogEditTextBinding
|
||||
private lateinit var spinboxBinding: DialogSpinboxBinding
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -146,76 +142,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||
.create()
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_SPINBOX -> {
|
||||
spinboxBinding = DialogSpinboxBinding.inflate(layoutInflater)
|
||||
val item = settingsViewModel.clickedItem as SpinBoxSetting
|
||||
|
||||
val currentValue = item.getSelectedValue()
|
||||
spinboxBinding.editValue.setText(currentValue.toString())
|
||||
spinboxBinding.textInputLayout.hint = getString(item.valueHint)
|
||||
|
||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(item.title)
|
||||
.setView(spinboxBinding.root)
|
||||
.setPositiveButton(android.R.string.ok, this)
|
||||
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
|
||||
.create()
|
||||
|
||||
val updateButtonState = { enabled: Boolean ->
|
||||
dialog.setOnShowListener { dialogInterface ->
|
||||
(dialogInterface as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = enabled
|
||||
}
|
||||
if (dialog.isShowing) {
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
val updateValidity = { value: Int ->
|
||||
val isValid = value in item.min..item.max
|
||||
if (isValid) {
|
||||
spinboxBinding.textInputLayout.error = null
|
||||
} else {
|
||||
spinboxBinding.textInputLayout.error = getString(
|
||||
if (value < item.min) R.string.value_too_low else R.string.value_too_high,
|
||||
if (value < item.min) item.min else item.max
|
||||
)
|
||||
}
|
||||
updateButtonState(isValid)
|
||||
}
|
||||
|
||||
spinboxBinding.buttonDecrement.setOnClickListener {
|
||||
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
|
||||
val newValue = current - 1
|
||||
spinboxBinding.editValue.setText(newValue.toString())
|
||||
updateValidity(newValue)
|
||||
}
|
||||
|
||||
spinboxBinding.buttonIncrement.setOnClickListener {
|
||||
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
|
||||
val newValue = current + 1
|
||||
spinboxBinding.editValue.setText(newValue.toString())
|
||||
updateValidity(newValue)
|
||||
}
|
||||
|
||||
spinboxBinding.editValue.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val value = s.toString().toIntOrNull()
|
||||
if (value != null) {
|
||||
updateValidity(value)
|
||||
} else {
|
||||
spinboxBinding.textInputLayout.error = getString(R.string.invalid_value)
|
||||
updateButtonState(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
updateValidity(currentValue)
|
||||
|
||||
dialog
|
||||
}
|
||||
|
||||
SettingsItem.TYPE_STRING_INPUT -> {
|
||||
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
|
||||
val item = settingsViewModel.clickedItem as StringInputSetting
|
||||
|
@ -355,14 +281,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
|
|||
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
|
||||
}
|
||||
|
||||
is SpinBoxSetting -> {
|
||||
val spinBoxSetting = settingsViewModel.clickedItem as SpinBoxSetting
|
||||
val value = spinboxBinding.editValue.text.toString().toIntOrNull()
|
||||
if (value != null && value in spinBoxSetting.min..spinBoxSetting.max) {
|
||||
spinBoxSetting.setSelectedValue(value)
|
||||
}
|
||||
}
|
||||
|
||||
is StringInputSetting -> {
|
||||
val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
|
||||
stringInputSetting.setSelectedValue(
|
||||
|
|
|
@ -97,7 +97,6 @@ class SettingsFragmentPresenter(
|
|||
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
||||
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
||||
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
||||
MenuTag.SECTION_AUDIO -> addAudioSettings(sl)
|
||||
MenuTag.SECTION_INPUT -> addInputSettings(sl)
|
||||
MenuTag.SECTION_INPUT_PLAYER_ONE -> addInputPlayer(sl, 0)
|
||||
|
@ -157,14 +156,6 @@ class SettingsFragmentPresenter(
|
|||
menuKey = MenuTag.SECTION_SOC_OVERLAY
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
titleId = R.string.input_overlay_options,
|
||||
iconId = R.drawable.ic_controller,
|
||||
descriptionId = R.string.input_overlay_options_description,
|
||||
menuKey = MenuTag.SECTION_INPUT_OVERLAY
|
||||
)
|
||||
)
|
||||
}
|
||||
add(
|
||||
SubmenuSetting(
|
||||
|
@ -273,13 +264,6 @@ class SettingsFragmentPresenter(
|
|||
}
|
||||
}
|
||||
|
||||
private fun addInputOverlaySettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.key)
|
||||
add(IntSetting.INPUT_OVERLAY_AUTO_HIDE.key)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addSocOverlaySettings(sl: ArrayList<SettingsItem>) {
|
||||
sl.apply {
|
||||
add(HeaderSetting(R.string.stats_overlay_customization))
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
|
||||
|
||||
import android.view.View
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
||||
import org.yuzu.yuzu_emu.features.settings.model.view.SpinBoxSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||
|
||||
class SpinBoxViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
|
||||
SettingViewHolder(binding.root, adapter) {
|
||||
private lateinit var setting: SpinBoxSetting
|
||||
|
||||
override fun bind(item: SettingsItem) {
|
||||
setting = item as SpinBoxSetting
|
||||
binding.textSettingName.text = setting.title
|
||||
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
|
||||
binding.textSettingDescription.text = setting.description
|
||||
binding.textSettingValue.setVisible(true)
|
||||
binding.textSettingValue.text = setting.getSelectedValue().toString()
|
||||
|
||||
binding.buttonClear.setVisible(setting.clearable)
|
||||
binding.buttonClear.setOnClickListener {
|
||||
adapter.onClearClick(setting, bindingAdapterPosition)
|
||||
}
|
||||
|
||||
setStyle(setting.isEditable, binding)
|
||||
}
|
||||
override fun onClick(clicked: View) {
|
||||
if (setting.isEditable) {
|
||||
adapter.onSpinBoxClick(setting, bindingAdapterPosition)
|
||||
}
|
||||
}
|
||||
override fun onLongClick(clicked: View): Boolean {
|
||||
if (setting.isEditable) {
|
||||
return adapter.onLongClick(setting, bindingAdapterPosition)
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -96,9 +96,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
private var perfStatsUpdater: (() -> Unit)? = null
|
||||
private var socUpdater: (() -> Unit)? = null
|
||||
|
||||
val handler = Handler(Looper.getMainLooper())
|
||||
private var isOverlayVisible = true
|
||||
|
||||
private var _binding: FragmentEmulationBinding? = null
|
||||
|
||||
private val binding get() = _binding!!
|
||||
|
@ -455,10 +452,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
/**
|
||||
* Ask user if they want to launch with default settings when custom settings fail
|
||||
*/
|
||||
private suspend fun askUserToLaunchWithDefaultSettings(
|
||||
gameTitle: String,
|
||||
errorMessage: String
|
||||
): Boolean {
|
||||
private suspend fun askUserToLaunchWithDefaultSettings(gameTitle: String, errorMessage: String): Boolean {
|
||||
return suspendCoroutine { continuation ->
|
||||
requireActivity().runOnUiThread {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
|
@ -734,8 +728,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
updateShowStatsOverlay()
|
||||
updateSocOverlay()
|
||||
|
||||
initializeOverlayAutoHide()
|
||||
|
||||
// Re update binding when the specs values get initialized properly
|
||||
binding.inGameMenu.getHeaderView(0).apply {
|
||||
val titleView = findViewById<TextView>(R.id.text_game_title)
|
||||
|
@ -925,11 +917,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
updatePauseMenuEntry(emulationState.isPaused)
|
||||
}
|
||||
}
|
||||
|
||||
// if the overlay auto-hide setting is changed while paused,
|
||||
// we need to reinitialize the auto-hide timer
|
||||
initializeOverlayAutoHide()
|
||||
|
||||
}
|
||||
|
||||
private fun resetInputOverlay() {
|
||||
|
@ -937,7 +924,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
IntSetting.OVERLAY_OPACITY.reset()
|
||||
binding.surfaceInputOverlay.post {
|
||||
binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement()
|
||||
binding.surfaceInputOverlay.resetIndividualControlScale()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1048,7 +1034,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
val status = batteryIntent?.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
|
||||
val isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
|
||||
status == BatteryManager.BATTERY_STATUS_FULL
|
||||
status == BatteryManager.BATTERY_STATUS_FULL
|
||||
|
||||
if (isCharging) {
|
||||
sb.append(" ${getString(R.string.charging)}")
|
||||
|
@ -1560,7 +1546,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
|
||||
setControlScale(50)
|
||||
setControlOpacity(100)
|
||||
binding.surfaceInputOverlay.resetIndividualControlScale()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
|
@ -1741,61 +1726,4 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
||||
private val socUpdateHandler = Handler(Looper.myLooper()!!)
|
||||
}
|
||||
|
||||
private fun startOverlayAutoHideTimer(seconds: Int) {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
|
||||
handler.postDelayed({
|
||||
if (isOverlayVisible) {
|
||||
hideOverlay()
|
||||
}
|
||||
}, seconds * 1000L)
|
||||
}
|
||||
|
||||
fun handleScreenTap(isLongTap: Boolean) {
|
||||
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
|
||||
val shouldProceed = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() && BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
|
||||
|
||||
if (!shouldProceed) {
|
||||
return
|
||||
}
|
||||
|
||||
// failsafe
|
||||
if (autoHideSeconds == 0) {
|
||||
showOverlay()
|
||||
return
|
||||
}
|
||||
|
||||
if (!isOverlayVisible && !isLongTap) {
|
||||
showOverlay()
|
||||
}
|
||||
|
||||
startOverlayAutoHideTimer(autoHideSeconds)
|
||||
}
|
||||
|
||||
private fun initializeOverlayAutoHide() {
|
||||
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
|
||||
val autoHideEnabled = BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
|
||||
val showOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
|
||||
|
||||
if (autoHideEnabled && showOverlay) {
|
||||
showOverlay()
|
||||
startOverlayAutoHideTimer(autoHideSeconds)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun showOverlay() {
|
||||
if (!isOverlayVisible) {
|
||||
isOverlayVisible = true
|
||||
ViewUtils.showView(binding.surfaceInputOverlay, 500)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideOverlay() {
|
||||
if (isOverlayVisible) {
|
||||
isOverlayVisible = false
|
||||
ViewUtils.hideView(binding.surfaceInputOverlay, 500)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
|
@ -13,8 +13,6 @@ import android.graphics.Rect
|
|||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.VectorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.AttributeSet
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.MotionEvent
|
||||
|
@ -54,12 +52,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
|
||||
private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
|
||||
|
||||
private var scaleDialog: OverlayScaleDialog? = null
|
||||
private var touchStartX = 0f
|
||||
private var touchStartY = 0f
|
||||
private var hasMoved = false
|
||||
private val moveThreshold = 20f
|
||||
|
||||
private lateinit var windowInsets: WindowInsets
|
||||
|
||||
var layout = OverlayLayout.Landscape
|
||||
|
@ -262,44 +254,23 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
) {
|
||||
buttonBeingConfigured = button
|
||||
buttonBeingConfigured!!.onConfigureTouch(event)
|
||||
touchStartX = event.getX(pointerIndex)
|
||||
touchStartY = event.getY(pointerIndex)
|
||||
hasMoved = false
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> if (buttonBeingConfigured != null) {
|
||||
val moveDistance = kotlin.math.sqrt(
|
||||
(event.getX(pointerIndex) - touchStartX).let { it * it } +
|
||||
(event.getY(pointerIndex) - touchStartY).let { it * it }
|
||||
)
|
||||
|
||||
if (moveDistance > moveThreshold) {
|
||||
hasMoved = true
|
||||
buttonBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
buttonBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) {
|
||||
if (!hasMoved) {
|
||||
showScaleDialog(
|
||||
buttonBeingConfigured,
|
||||
null,
|
||||
null,
|
||||
fingerPositionX,
|
||||
fingerPositionY
|
||||
)
|
||||
} else {
|
||||
saveControlPosition(
|
||||
buttonBeingConfigured!!.overlayControlData.id,
|
||||
buttonBeingConfigured!!.bounds.centerX(),
|
||||
buttonBeingConfigured!!.bounds.centerY(),
|
||||
individuaScale = buttonBeingConfigured!!.overlayControlData.individualScale,
|
||||
layout
|
||||
)
|
||||
}
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(
|
||||
buttonBeingConfigured!!.overlayControlData.id,
|
||||
buttonBeingConfigured!!.bounds.centerX(),
|
||||
buttonBeingConfigured!!.bounds.centerY(),
|
||||
layout
|
||||
)
|
||||
buttonBeingConfigured = null
|
||||
}
|
||||
}
|
||||
|
@ -316,46 +287,23 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
) {
|
||||
dpadBeingConfigured = dpad
|
||||
dpadBeingConfigured!!.onConfigureTouch(event)
|
||||
touchStartX = event.getX(pointerIndex)
|
||||
touchStartY = event.getY(pointerIndex)
|
||||
hasMoved = false
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> if (dpadBeingConfigured != null) {
|
||||
val moveDistance = kotlin.math.sqrt(
|
||||
(event.getX(pointerIndex) - touchStartX).let { it * it } +
|
||||
(event.getY(pointerIndex) - touchStartY).let { it * it }
|
||||
)
|
||||
|
||||
if (moveDistance > moveThreshold) {
|
||||
hasMoved = true
|
||||
dpadBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
dpadBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
return true
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) {
|
||||
if (!hasMoved) {
|
||||
// This was a click, show scale dialog for dpad
|
||||
showScaleDialog(
|
||||
null,
|
||||
dpadBeingConfigured,
|
||||
null,
|
||||
fingerPositionX,
|
||||
fingerPositionY
|
||||
)
|
||||
} else {
|
||||
// This was a move, save position
|
||||
saveControlPosition(
|
||||
OverlayControl.COMBINED_DPAD.id,
|
||||
dpadBeingConfigured!!.bounds.centerX(),
|
||||
dpadBeingConfigured!!.bounds.centerY(),
|
||||
individuaScale = dpadBeingConfigured!!.individualScale,
|
||||
layout
|
||||
)
|
||||
}
|
||||
// Persist button position by saving new place.
|
||||
saveControlPosition(
|
||||
OverlayControl.COMBINED_DPAD.id,
|
||||
dpadBeingConfigured!!.bounds.centerX(),
|
||||
dpadBeingConfigured!!.bounds.centerY(),
|
||||
layout
|
||||
)
|
||||
dpadBeingConfigured = null
|
||||
}
|
||||
}
|
||||
|
@ -369,43 +317,21 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
) {
|
||||
joystickBeingConfigured = joystick
|
||||
joystickBeingConfigured!!.onConfigureTouch(event)
|
||||
touchStartX = event.getX(pointerIndex)
|
||||
touchStartY = event.getY(pointerIndex)
|
||||
hasMoved = false
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> if (joystickBeingConfigured != null) {
|
||||
val moveDistance = kotlin.math.sqrt(
|
||||
(event.getX(pointerIndex) - touchStartX).let { it * it } +
|
||||
(event.getY(pointerIndex) - touchStartY).let { it * it }
|
||||
)
|
||||
|
||||
if (moveDistance > moveThreshold) {
|
||||
hasMoved = true
|
||||
joystickBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
}
|
||||
joystickBeingConfigured!!.onConfigureTouch(event)
|
||||
invalidate()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> if (joystickBeingConfigured != null) {
|
||||
if (!hasMoved) {
|
||||
showScaleDialog(
|
||||
null,
|
||||
null,
|
||||
joystickBeingConfigured,
|
||||
fingerPositionX,
|
||||
fingerPositionY
|
||||
)
|
||||
} else {
|
||||
saveControlPosition(
|
||||
joystickBeingConfigured!!.prefId,
|
||||
joystickBeingConfigured!!.bounds.centerX(),
|
||||
joystickBeingConfigured!!.bounds.centerY(),
|
||||
individuaScale = joystickBeingConfigured!!.individualScale,
|
||||
layout
|
||||
)
|
||||
}
|
||||
saveControlPosition(
|
||||
joystickBeingConfigured!!.prefId,
|
||||
joystickBeingConfigured!!.bounds.centerX(),
|
||||
joystickBeingConfigured!!.bounds.centerY(),
|
||||
layout
|
||||
)
|
||||
joystickBeingConfigured = null
|
||||
}
|
||||
}
|
||||
|
@ -681,117 +607,25 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
invalidate()
|
||||
}
|
||||
|
||||
private fun saveControlPosition(
|
||||
id: String,
|
||||
x: Int,
|
||||
y: Int,
|
||||
individuaScale: Float,
|
||||
layout: OverlayLayout
|
||||
) {
|
||||
private fun saveControlPosition(id: String, x: Int, y: Int, layout: OverlayLayout) {
|
||||
val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight))
|
||||
val min = windowSize.first
|
||||
val max = windowSize.second
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
val data = overlayControlData.firstOrNull { it.id == id }
|
||||
val newPosition = Pair((x - min.x).toDouble() / max.x, (y - min.y).toDouble() / max.y)
|
||||
|
||||
when (layout) {
|
||||
OverlayLayout.Landscape -> data?.landscapePosition = newPosition
|
||||
OverlayLayout.Portrait -> data?.portraitPosition = newPosition
|
||||
OverlayLayout.Foldable -> data?.foldablePosition = newPosition
|
||||
|
||||
}
|
||||
|
||||
data?.individualScale = individuaScale
|
||||
|
||||
NativeConfig.setOverlayControlData(overlayControlData)
|
||||
}
|
||||
|
||||
fun setIsInEditMode(editMode: Boolean) {
|
||||
inEditMode = editMode
|
||||
if (!editMode) {
|
||||
scaleDialog?.dismiss()
|
||||
scaleDialog = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun showScaleDialog(
|
||||
button: InputOverlayDrawableButton?,
|
||||
dpad: InputOverlayDrawableDpad?,
|
||||
joystick: InputOverlayDrawableJoystick?,
|
||||
x: Int, y: Int
|
||||
) {
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
// prevent dialog from being spam opened
|
||||
scaleDialog?.dismiss()
|
||||
|
||||
|
||||
when {
|
||||
button != null -> {
|
||||
val buttonData =
|
||||
overlayControlData.firstOrNull { it.id == button.overlayControlData.id }
|
||||
if (buttonData != null) {
|
||||
scaleDialog =
|
||||
OverlayScaleDialog(context, button.overlayControlData) { newScale ->
|
||||
saveControlPosition(
|
||||
button.overlayControlData.id,
|
||||
button.bounds.centerX(),
|
||||
button.bounds.centerY(),
|
||||
individuaScale = newScale,
|
||||
layout
|
||||
)
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
scaleDialog?.showDialog(x,y, button.bounds.width(), button.bounds.height())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
dpad != null -> {
|
||||
val dpadData =
|
||||
overlayControlData.firstOrNull { it.id == OverlayControl.COMBINED_DPAD.id }
|
||||
if (dpadData != null) {
|
||||
scaleDialog = OverlayScaleDialog(context, dpadData) { newScale ->
|
||||
saveControlPosition(
|
||||
OverlayControl.COMBINED_DPAD.id,
|
||||
dpad.bounds.centerX(),
|
||||
dpad.bounds.centerY(),
|
||||
newScale,
|
||||
layout
|
||||
)
|
||||
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
scaleDialog?.showDialog(x,y, dpad.bounds.width(), dpad.bounds.height())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
joystick != null -> {
|
||||
val joystickData = overlayControlData.firstOrNull { it.id == joystick.prefId }
|
||||
if (joystickData != null) {
|
||||
scaleDialog = OverlayScaleDialog(context, joystickData) { newScale ->
|
||||
saveControlPosition(
|
||||
joystick.prefId,
|
||||
joystick.bounds.centerX(),
|
||||
joystick.bounds.centerY(),
|
||||
individuaScale = newScale,
|
||||
layout
|
||||
)
|
||||
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
scaleDialog?.showDialog(x,y, joystick.bounds.width(), joystick.bounds.height())
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Applies and saves all default values for the overlay
|
||||
*/
|
||||
|
@ -830,24 +664,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
overlayControlData.forEach {
|
||||
it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
|
||||
it.individualScale = OverlayControl.from(it.id)?.defaultIndividualScaleResource!!
|
||||
}
|
||||
NativeConfig.setOverlayControlData(overlayControlData)
|
||||
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
fun resetIndividualControlScale() {
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
overlayControlData.forEach { data ->
|
||||
val defaultControlData = OverlayControl.from(data.id) ?: return@forEach
|
||||
data.individualScale = defaultControlData.defaultIndividualScaleResource
|
||||
}
|
||||
NativeConfig.setOverlayControlData(overlayControlData)
|
||||
NativeConfig.saveGlobalConfig()
|
||||
refreshControls()
|
||||
}
|
||||
|
||||
private fun defaultOverlayPositionByLayout(layout: OverlayLayout) {
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
for (data in overlayControlData) {
|
||||
|
@ -1038,9 +860,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
|
||||
scale /= 100f
|
||||
|
||||
// Apply individual scale
|
||||
scale *= overlayControlData.individualScale
|
||||
|
||||
// Initialize the InputOverlayDrawableButton.
|
||||
val defaultStateBitmap = getBitmap(context, defaultResId, scale)
|
||||
val pressedStateBitmap = getBitmap(context, pressedResId, scale)
|
||||
|
@ -1103,20 +922,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
// Resources handle for fetching the initial Drawable resource.
|
||||
val res = context.resources
|
||||
|
||||
// Get the dpad control data for individual scale
|
||||
val overlayControlData = NativeConfig.getOverlayControlData()
|
||||
val dpadData = overlayControlData.firstOrNull { it.id == OverlayControl.COMBINED_DPAD.id }
|
||||
|
||||
// Decide scale based on button ID and user preference
|
||||
var scale = 0.25f
|
||||
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
|
||||
scale /= 100f
|
||||
|
||||
// Apply individual scale
|
||||
if (dpadData != null) {
|
||||
scale *= dpadData.individualScale
|
||||
}
|
||||
|
||||
// Initialize the InputOverlayDrawableDpad.
|
||||
val defaultStateBitmap =
|
||||
getBitmap(context, defaultResId, scale)
|
||||
|
@ -1190,9 +1000,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
|
|||
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
|
||||
scale /= 100f
|
||||
|
||||
// Apply individual scale
|
||||
scale *= overlayControlData.individualScale
|
||||
|
||||
// Initialize the InputOverlayDrawableJoystick.
|
||||
val bitmapOuter = getBitmap(context, resOuter, scale)
|
||||
val bitmapInnerDefault = getBitmap(context, defaultResInner, 1.0f)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
|
@ -42,8 +42,6 @@ class InputOverlayDrawableDpad(
|
|||
val width: Int
|
||||
val height: Int
|
||||
|
||||
var individualScale: Float = 1.0f
|
||||
|
||||
private val defaultStateBitmap: BitmapDrawable
|
||||
private val pressedOneDirectionStateBitmap: BitmapDrawable
|
||||
private val pressedTwoDirectionsStateBitmap: BitmapDrawable
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
|
@ -51,8 +51,6 @@ class InputOverlayDrawableJoystick(
|
|||
val width: Int
|
||||
val height: Int
|
||||
|
||||
var individualScale: Float = 1.0f
|
||||
|
||||
private var opacity: Int = 0
|
||||
|
||||
private var virtBounds: Rect
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.slider.Slider
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
|
||||
|
||||
class OverlayScaleDialog(
|
||||
context: Context,
|
||||
private val overlayControlData: OverlayControlData,
|
||||
private val onScaleChanged: (Float) -> Unit
|
||||
) : Dialog(context) {
|
||||
|
||||
private var currentScale = overlayControlData.individualScale
|
||||
private val originalScale = overlayControlData.individualScale
|
||||
private lateinit var scaleValueText: TextView
|
||||
private lateinit var scaleSlider: Slider
|
||||
|
||||
init {
|
||||
setupDialog()
|
||||
}
|
||||
|
||||
private fun setupDialog() {
|
||||
val view = LayoutInflater.from(context).inflate(R.layout.dialog_overlay_scale, null)
|
||||
setContentView(view)
|
||||
|
||||
window?.setBackgroundDrawable(null)
|
||||
|
||||
window?.apply {
|
||||
attributes = attributes.apply {
|
||||
flags = flags and WindowManager.LayoutParams.FLAG_DIM_BEHIND.inv()
|
||||
flags = flags or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
}
|
||||
}
|
||||
|
||||
scaleValueText = view.findViewById(R.id.scaleValueText)
|
||||
scaleSlider = view.findViewById(R.id.scaleSlider)
|
||||
val resetButton = view.findViewById<MaterialButton>(R.id.resetButton)
|
||||
val confirmButton = view.findViewById<MaterialButton>(R.id.confirmButton)
|
||||
val cancelButton = view.findViewById<MaterialButton>(R.id.cancelButton)
|
||||
|
||||
scaleValueText.text = String.format("%.1fx", currentScale)
|
||||
scaleSlider.value = currentScale
|
||||
|
||||
scaleSlider.addOnChangeListener { _, value, input ->
|
||||
if (input) {
|
||||
currentScale = value
|
||||
scaleValueText.text = String.format("%.1fx", currentScale)
|
||||
}
|
||||
}
|
||||
|
||||
scaleSlider.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
|
||||
override fun onStartTrackingTouch(slider: Slider) {
|
||||
// pass
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(slider: Slider) {
|
||||
onScaleChanged(currentScale)
|
||||
}
|
||||
})
|
||||
|
||||
resetButton.setOnClickListener {
|
||||
currentScale = 1.0f
|
||||
scaleSlider.value = 1.0f
|
||||
scaleValueText.text = String.format("%.1fx", currentScale)
|
||||
onScaleChanged(currentScale)
|
||||
}
|
||||
|
||||
confirmButton.setOnClickListener {
|
||||
overlayControlData.individualScale = currentScale
|
||||
//slider value is already saved on touch dispatch but just to be sure
|
||||
onScaleChanged(currentScale)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
// both cancel button and back gesture should revert the scale change
|
||||
cancelButton.setOnClickListener {
|
||||
onScaleChanged(originalScale)
|
||||
dismiss()
|
||||
}
|
||||
|
||||
setOnCancelListener {
|
||||
onScaleChanged(originalScale)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
fun showDialog(anchorX: Int, anchorY: Int, anchorHeight: Int, anchorWidth: Int) {
|
||||
show()
|
||||
|
||||
show()
|
||||
|
||||
// TODO: this calculation is a bit rough, improve it later on
|
||||
window?.let { window ->
|
||||
val layoutParams = window.attributes
|
||||
layoutParams.gravity = Gravity.TOP or Gravity.START
|
||||
|
||||
val density = context.resources.displayMetrics.density
|
||||
val dialogWidthPx = (320 * density).toInt()
|
||||
val dialogHeightPx = (400 * density).toInt() // set your estimated dialog height
|
||||
|
||||
val screenHeight = context.resources.displayMetrics.heightPixels
|
||||
|
||||
|
||||
layoutParams.x = anchorX + anchorWidth / 2 - dialogWidthPx / 2
|
||||
layoutParams.y = anchorY + anchorHeight / 2 - dialogHeightPx / 2
|
||||
layoutParams.width = dialogWidthPx
|
||||
|
||||
|
||||
window.attributes = layoutParams
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay.model
|
||||
|
||||
|
@ -12,144 +12,126 @@ enum class OverlayControl(
|
|||
val defaultVisibility: Boolean,
|
||||
@IntegerRes val defaultLandscapePositionResources: Pair<Int, Int>,
|
||||
@IntegerRes val defaultPortraitPositionResources: Pair<Int, Int>,
|
||||
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>,
|
||||
val defaultIndividualScaleResource: Float,
|
||||
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>
|
||||
) {
|
||||
BUTTON_A(
|
||||
"button_a",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_A_X, R.integer.BUTTON_A_Y),
|
||||
Pair(R.integer.BUTTON_A_X_PORTRAIT, R.integer.BUTTON_A_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_B(
|
||||
"button_b",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_B_X, R.integer.BUTTON_B_Y),
|
||||
Pair(R.integer.BUTTON_B_X_PORTRAIT, R.integer.BUTTON_B_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_X(
|
||||
"button_x",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_X_X, R.integer.BUTTON_X_Y),
|
||||
Pair(R.integer.BUTTON_X_X_PORTRAIT, R.integer.BUTTON_X_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_Y(
|
||||
"button_y",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_Y_X, R.integer.BUTTON_Y_Y),
|
||||
Pair(R.integer.BUTTON_Y_X_PORTRAIT, R.integer.BUTTON_Y_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_PLUS(
|
||||
"button_plus",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_PLUS_X, R.integer.BUTTON_PLUS_Y),
|
||||
Pair(R.integer.BUTTON_PLUS_X_PORTRAIT, R.integer.BUTTON_PLUS_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_MINUS(
|
||||
"button_minus",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_MINUS_X, R.integer.BUTTON_MINUS_Y),
|
||||
Pair(R.integer.BUTTON_MINUS_X_PORTRAIT, R.integer.BUTTON_MINUS_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_HOME(
|
||||
"button_home",
|
||||
false,
|
||||
Pair(R.integer.BUTTON_HOME_X, R.integer.BUTTON_HOME_Y),
|
||||
Pair(R.integer.BUTTON_HOME_X_PORTRAIT, R.integer.BUTTON_HOME_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_CAPTURE(
|
||||
"button_capture",
|
||||
false,
|
||||
Pair(R.integer.BUTTON_CAPTURE_X, R.integer.BUTTON_CAPTURE_Y),
|
||||
Pair(R.integer.BUTTON_CAPTURE_X_PORTRAIT, R.integer.BUTTON_CAPTURE_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_L(
|
||||
"button_l",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_L_X, R.integer.BUTTON_L_Y),
|
||||
Pair(R.integer.BUTTON_L_X_PORTRAIT, R.integer.BUTTON_L_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_R(
|
||||
"button_r",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_R_X, R.integer.BUTTON_R_Y),
|
||||
Pair(R.integer.BUTTON_R_X_PORTRAIT, R.integer.BUTTON_R_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_ZL(
|
||||
"button_zl",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_ZL_X, R.integer.BUTTON_ZL_Y),
|
||||
Pair(R.integer.BUTTON_ZL_X_PORTRAIT, R.integer.BUTTON_ZL_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_ZR(
|
||||
"button_zr",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_ZR_X, R.integer.BUTTON_ZR_Y),
|
||||
Pair(R.integer.BUTTON_ZR_X_PORTRAIT, R.integer.BUTTON_ZR_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_STICK_L(
|
||||
"button_stick_l",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_STICK_L_X, R.integer.BUTTON_STICK_L_Y),
|
||||
Pair(R.integer.BUTTON_STICK_L_X_PORTRAIT, R.integer.BUTTON_STICK_L_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE)
|
||||
),
|
||||
BUTTON_STICK_R(
|
||||
"button_stick_r",
|
||||
true,
|
||||
Pair(R.integer.BUTTON_STICK_R_X, R.integer.BUTTON_STICK_R_Y),
|
||||
Pair(R.integer.BUTTON_STICK_R_X_PORTRAIT, R.integer.BUTTON_STICK_R_Y_PORTRAIT),
|
||||
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE)
|
||||
),
|
||||
STICK_L(
|
||||
"stick_l",
|
||||
true,
|
||||
Pair(R.integer.STICK_L_X, R.integer.STICK_L_Y),
|
||||
Pair(R.integer.STICK_L_X_PORTRAIT, R.integer.STICK_L_Y_PORTRAIT),
|
||||
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE)
|
||||
),
|
||||
STICK_R(
|
||||
"stick_r",
|
||||
true,
|
||||
Pair(R.integer.STICK_R_X, R.integer.STICK_R_Y),
|
||||
Pair(R.integer.STICK_R_X_PORTRAIT, R.integer.STICK_R_Y_PORTRAIT),
|
||||
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE)
|
||||
),
|
||||
COMBINED_DPAD(
|
||||
"combined_dpad",
|
||||
true,
|
||||
Pair(R.integer.COMBINED_DPAD_X, R.integer.COMBINED_DPAD_Y),
|
||||
Pair(R.integer.COMBINED_DPAD_X_PORTRAIT, R.integer.COMBINED_DPAD_Y_PORTRAIT),
|
||||
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE),
|
||||
1.0f
|
||||
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE)
|
||||
);
|
||||
|
||||
fun getDefaultPositionForLayout(layout: OverlayLayout): Pair<Double, Double> {
|
||||
|
@ -191,8 +173,7 @@ enum class OverlayControl(
|
|||
defaultVisibility,
|
||||
getDefaultPositionForLayout(OverlayLayout.Landscape),
|
||||
getDefaultPositionForLayout(OverlayLayout.Portrait),
|
||||
getDefaultPositionForLayout(OverlayLayout.Foldable),
|
||||
defaultIndividualScaleResource
|
||||
getDefaultPositionForLayout(OverlayLayout.Foldable)
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.overlay.model
|
||||
|
||||
|
@ -8,8 +8,7 @@ data class OverlayControlData(
|
|||
var enabled: Boolean,
|
||||
var landscapePosition: Pair<Double, Double>,
|
||||
var portraitPosition: Pair<Double, Double>,
|
||||
var foldablePosition: Pair<Double, Double>,
|
||||
var individualScale: Float
|
||||
var foldablePosition: Pair<Double, Double>
|
||||
) {
|
||||
fun positionFromLayout(layout: OverlayLayout): Pair<Double, Double> =
|
||||
when (layout) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.utils
|
||||
|
||||
|
@ -170,8 +170,7 @@ object DirectoryInitialization {
|
|||
buttonEnabled,
|
||||
Pair(landscapeXPosition, landscapeYPosition),
|
||||
Pair(portraitXPosition, portraitYPosition),
|
||||
Pair(foldableXPosition, foldableYPosition),
|
||||
OverlayControl.map[buttonId]?.defaultIndividualScaleResource ?: 1.0f
|
||||
Pair(foldableXPosition, foldableYPosition)
|
||||
)
|
||||
overlayControlDataMap[buttonId] = controlData
|
||||
setOverlayData = true
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <common/logging/log.h>
|
||||
#include <input_common/main.h>
|
||||
|
@ -103,7 +103,6 @@ void AndroidConfig::ReadOverlayValues() {
|
|||
ReadDoubleSetting(std::string("foldable\\x_position"));
|
||||
control_data.foldable_position.second =
|
||||
ReadDoubleSetting(std::string("foldable\\y_position"));
|
||||
control_data.individual_scale = static_cast<float>(ReadDoubleSetting(std::string("individual_scale")));
|
||||
AndroidSettings::values.overlay_control_data.push_back(control_data);
|
||||
}
|
||||
EndArray();
|
||||
|
@ -256,7 +255,6 @@ void AndroidConfig::SaveOverlayValues() {
|
|||
control_data.foldable_position.first);
|
||||
WriteDoubleSetting(std::string("foldable\\y_position"),
|
||||
control_data.foldable_position.second);
|
||||
WriteDoubleSetting(std::string("individual_scale"), static_cast<double>(control_data.individual_scale));
|
||||
}
|
||||
EndArray();
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ namespace AndroidSettings {
|
|||
std::pair<double, double> landscape_position;
|
||||
std::pair<double, double> portrait_position;
|
||||
std::pair<double, double> foldable_position;
|
||||
float individual_scale;
|
||||
};
|
||||
|
||||
struct Values {
|
||||
|
@ -80,15 +79,6 @@ namespace AndroidSettings {
|
|||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Paired, true,
|
||||
true};
|
||||
Settings::Setting<bool> enable_input_overlay_auto_hide{linkage, false,
|
||||
"enable_input_overlay_auto_hide",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true,
|
||||
true,};
|
||||
|
||||
Settings::Setting<u32> input_overlay_auto_hide{linkage, 5, "input_overlay_auto_hide",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true, true, &enable_input_overlay_auto_hide};
|
||||
Settings::Setting<bool> perf_overlay_background{linkage, false, "perf_overlay_background",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -369,9 +369,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JN
|
|||
env->NewObject(Common::Android::GetOverlayControlDataClass(),
|
||||
Common::Android::GetOverlayControlDataConstructor(),
|
||||
Common::Android::ToJString(env, control_data.id), control_data.enabled,
|
||||
jlandscapePosition, jportraitPosition, jfoldablePosition,
|
||||
control_data.individual_scale);
|
||||
|
||||
jlandscapePosition, jportraitPosition, jfoldablePosition);
|
||||
env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData);
|
||||
}
|
||||
return joverlayControlDataArray;
|
||||
|
@ -420,12 +418,9 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData(
|
|||
env,
|
||||
env->GetObjectField(jfoldablePosition, Common::Android::GetPairSecondField())));
|
||||
|
||||
float individual_scale = static_cast<float>(env->GetFloatField(
|
||||
joverlayControlData, Common::Android::GetOverlayControlDataIndividualScaleField()));
|
||||
|
||||
AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{
|
||||
Common::Android::GetJString(env, jidString), enabled, landscape_position,
|
||||
portrait_position, foldable_position, individual_scale});
|
||||
portrait_position, foldable_position});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="320dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="8dp"
|
||||
app:cardBackgroundColor="#CC222222">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/scaleValueText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="1.0x"
|
||||
android:textAppearance="?attr/textAppearanceBody1"
|
||||
android:gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/scaleSlider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:valueFrom="0.5"
|
||||
android:valueTo="4.0"
|
||||
android:stepSize="0.1"
|
||||
android:value="1.0"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:trackColorActive="@color/eden_border_gradient_start"
|
||||
app:trackColorInactive="@color/eden_border_gradient_end"
|
||||
app:tickColor="@color/eden_border_gradient_start"/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resetButton"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reset"
|
||||
android:layout_marginEnd="4dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/cancelButton"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/cancel"
|
||||
android:layout_marginEnd="4dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/confirmButton"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/eden_button_secondary_bg"
|
||||
android:textColor="@color/eden_border_gradient_end"
|
||||
android:text="@string/confirm" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
|
@ -1,55 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginTop="32dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="@dimen/spacing_large"
|
||||
android:paddingRight="@dimen/spacing_large">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_decrement"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/decrement"
|
||||
android:text="-" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/text_input_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/spacing_medlarge"
|
||||
android:layout_marginRight="@dimen/spacing_medlarge"
|
||||
android:layout_weight="1"
|
||||
android:hint="Value">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:textAlignment="textStart"
|
||||
tools:text="0" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_increment"
|
||||
style="@style/Widget.Material3.Button.IconButton.Filled"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/increment"
|
||||
android:text="+" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
|
@ -251,9 +251,7 @@
|
|||
<item>@string/scaling_filter_nearest_neighbor</item>
|
||||
<item>@string/scaling_filter_bilinear</item>
|
||||
<item>@string/scaling_filter_bicubic</item>
|
||||
<item>@string/scaling_filter_spline1</item>
|
||||
<item>@string/scaling_filter_gaussian</item>
|
||||
<item>@string/scaling_filter_lanczos</item>
|
||||
<item>@string/scaling_filter_scale_force</item>
|
||||
<item>@string/scaling_filter_fsr</item>
|
||||
<item>@string/scaling_filter_area</item>
|
||||
|
@ -267,8 +265,6 @@
|
|||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="rendererAntiAliasingNames">
|
||||
|
|
|
@ -12,24 +12,6 @@
|
|||
<string name="app_notification_channel_id" translatable="false">Eden</string>
|
||||
<string name="app_notification_channel_description">Eden Switch emulator notifications</string>
|
||||
<string name="app_notification_running">Eden is Running</string>
|
||||
<string name="seconds">Seconds</string>
|
||||
|
||||
<!-- Spinbox strings -->
|
||||
<string name="increment">Increment</string>
|
||||
<string name="decrement">Decrement</string>
|
||||
<string name="value">Value</string>
|
||||
<string name="value_too_low">Value must be at least %1$d</string>
|
||||
<string name="value_too_high">Value must be at most %1$d</string>
|
||||
<string name="invalid_value">Invalid value</string>
|
||||
|
||||
|
||||
<!-- Input Overlay -->
|
||||
<string name="overlay_auto_hide">Overlay Auto Hide</string>
|
||||
<string name="overlay_auto_hide_description">Automatically hide the touch controls overlay after the specified time of inactivity.</string>
|
||||
<string name="enable_input_overlay_auto_hide">Enable Overlay Auto Hide</string>
|
||||
|
||||
<string name="input_overlay_options">Input Overlay</string>
|
||||
<string name="input_overlay_options_description">Configure on-screen controls</string>
|
||||
|
||||
|
||||
<!-- Stats Overlay settings -->
|
||||
|
@ -873,7 +855,6 @@
|
|||
<string name="touchscreen">Touchscreen</string>
|
||||
<string name="lock_drawer">Lock drawer</string>
|
||||
<string name="unlock_drawer">Unlock drawer</string>
|
||||
<string name="reset">Reset</string>
|
||||
|
||||
<string name="load_settings">Loading settings…</string>
|
||||
|
||||
|
@ -884,12 +865,12 @@
|
|||
<string name="abort_button">Abort</string>
|
||||
<string name="continue_button">Continue</string>
|
||||
<string name="system_archive_not_found">System Archive Not Found</string>
|
||||
<string name="system_archive_not_found_message">%s is missing. Please dump your system archives.\nContinuing emulation may result in crashes.</string>
|
||||
<string name="system_archive_not_found_message">%s is missing. Please dump your system archives.\nContinuing emulation may result in crashes and bugs.</string>
|
||||
<string name="system_archive_general">A system archive</string>
|
||||
<string name="save_load_error">Save/Load Error</string>
|
||||
<string name="fatal_error">Fatal Error</string>
|
||||
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes.</string>
|
||||
<string name="performance_warning">Turning off this setting will significantly degrade performance. It"s recommended that you leave this setting enabled.</string>
|
||||
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string>
|
||||
<string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string>
|
||||
<string name="device_memory_inadequate">Device RAM: %1$s\nRecommended: %2$s</string>
|
||||
<string name="memory_formatted">%1$s %2$s</string>
|
||||
<string name="no_game_present">No bootable game present!</string>
|
||||
|
@ -960,12 +941,12 @@
|
|||
<!-- Renderer Accuracy -->
|
||||
<string name="renderer_accuracy_normal">Normal</string>
|
||||
<string name="renderer_accuracy_high">High</string>
|
||||
<string name="renderer_accuracy_extreme">Extreme</string>
|
||||
<string name="renderer_accuracy_extreme">Extreme (Slow)</string>
|
||||
|
||||
<!-- DMA Accuracy -->
|
||||
<string name="dma_accuracy_default">Default</string>
|
||||
<string name="dma_accuracy_unsafe">Unsafe</string>
|
||||
<string name="dma_accuracy_safe">Safe</string>
|
||||
<string name="dma_accuracy_unsafe">Unsafe (fast)</string>
|
||||
<string name="dma_accuracy_safe">Safe (stable)</string>
|
||||
|
||||
<!-- ASTC Decoding Method -->
|
||||
<string name="accelerate_astc">ASTC Decoding Method</string>
|
||||
|
@ -1011,9 +992,7 @@
|
|||
<string name="scaling_filter_nearest_neighbor">Nearest Neighbor</string>
|
||||
<string name="scaling_filter_bilinear">Bilinear</string>
|
||||
<string name="scaling_filter_bicubic">Bicubic</string>
|
||||
<string name="scaling_filter_spline1">Spline-1</string>
|
||||
<string name="scaling_filter_gaussian">Gaussian</string>
|
||||
<string name="scaling_filter_lanczos">Lanczos</string>
|
||||
<string name="scaling_filter_scale_force">ScaleForce</string>
|
||||
<string name="scaling_filter_fsr">AMD FidelityFX™ Super Resolution</string>
|
||||
<string name="scaling_filter_area">Area</string>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <jni.h>
|
||||
|
@ -46,7 +49,6 @@ static jclass s_overlay_control_data_class;
|
|||
static jmethodID s_overlay_control_data_constructor;
|
||||
static jfieldID s_overlay_control_data_id_field;
|
||||
static jfieldID s_overlay_control_data_enabled_field;
|
||||
static jfieldID s_overlay_control_data_individual_scale_field;
|
||||
static jfieldID s_overlay_control_data_landscape_position_field;
|
||||
static jfieldID s_overlay_control_data_portrait_position_field;
|
||||
static jfieldID s_overlay_control_data_foldable_position_field;
|
||||
|
@ -242,10 +244,6 @@ namespace Common::Android {
|
|||
return s_overlay_control_data_enabled_field;
|
||||
}
|
||||
|
||||
jfieldID GetOverlayControlDataIndividualScaleField() {
|
||||
return s_overlay_control_data_individual_scale_field;
|
||||
}
|
||||
|
||||
jfieldID GetOverlayControlDataLandscapePositionField() {
|
||||
return s_overlay_control_data_landscape_position_field;
|
||||
}
|
||||
|
@ -496,7 +494,7 @@ namespace Common::Android {
|
|||
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
||||
s_overlay_control_data_constructor =
|
||||
env->GetMethodID(overlay_control_data_class, "<init>",
|
||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;)V");
|
||||
s_overlay_control_data_id_field =
|
||||
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
||||
s_overlay_control_data_enabled_field =
|
||||
|
@ -507,8 +505,6 @@ namespace Common::Android {
|
|||
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_foldable_position_field =
|
||||
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
||||
s_overlay_control_data_individual_scale_field =
|
||||
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
||||
env->DeleteLocalRef(overlay_control_data_class);
|
||||
|
||||
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
@ -64,7 +67,6 @@ jclass GetOverlayControlDataClass();
|
|||
jmethodID GetOverlayControlDataConstructor();
|
||||
jfieldID GetOverlayControlDataIdField();
|
||||
jfieldID GetOverlayControlDataEnabledField();
|
||||
jfieldID GetOverlayControlDataIndividualScaleField();
|
||||
jfieldID GetOverlayControlDataLandscapePositionField();
|
||||
jfieldID GetOverlayControlDataPortraitPositionField();
|
||||
jfieldID GetOverlayControlDataFoldablePositionField();
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/fs.h"
|
||||
#ifdef ANDROID
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/fs/fs.h"
|
||||
#ifdef ANDROID
|
||||
#include "common/fs/fs_android.h"
|
||||
|
|
|
@ -178,7 +178,7 @@ struct Values {
|
|||
SwitchableSetting<std::string> audio_input_device_id{
|
||||
linkage, "auto", "input_device", Category::Audio, Specialization::RuntimeList};
|
||||
SwitchableSetting<AudioMode, true> sound_index{
|
||||
linkage, AudioMode::Stereo,
|
||||
linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround,
|
||||
"sound_index", Category::SystemAudio, Specialization::Default, true,
|
||||
true};
|
||||
SwitchableSetting<u8, true> volume{linkage,
|
||||
|
@ -199,6 +199,8 @@ struct Values {
|
|||
SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
|
||||
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
||||
MemoryLayout::Memory_4Gb,
|
||||
MemoryLayout::Memory_4Gb,
|
||||
MemoryLayout::Memory_12Gb,
|
||||
"memory_layout_mode",
|
||||
Category::Core,
|
||||
Specialization::Default,
|
||||
|
@ -238,8 +240,9 @@ struct Values {
|
|||
#endif
|
||||
"cpu_backend",
|
||||
Category::Cpu};
|
||||
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
|
||||
"cpu_accuracy", Category::Cpu};
|
||||
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
|
||||
CpuAccuracy::Auto, CpuAccuracy::Paranoid,
|
||||
"cpu_accuracy", Category::Cpu};
|
||||
|
||||
SwitchableSetting<bool> use_fast_cpu_time{linkage,
|
||||
false,
|
||||
|
@ -321,10 +324,10 @@ struct Values {
|
|||
|
||||
// Renderer
|
||||
SwitchableSetting<RendererBackend, true> renderer_backend{
|
||||
linkage, RendererBackend::Vulkan,
|
||||
linkage, RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Null,
|
||||
"backend", Category::Renderer};
|
||||
SwitchableSetting<ShaderBackend, true> shader_backend{
|
||||
linkage, ShaderBackend::SpirV,
|
||||
linkage, ShaderBackend::SpirV, ShaderBackend::Glsl, ShaderBackend::SpirV,
|
||||
"shader_backend", Category::Renderer, Specialization::RuntimeList};
|
||||
SwitchableSetting<int> vulkan_device{linkage, 0, "vulkan_device", Category::Renderer,
|
||||
Specialization::RuntimeList};
|
||||
|
@ -339,6 +342,8 @@ struct Values {
|
|||
Category::Renderer};
|
||||
SwitchableSetting<SpirvOptimizeMode, true> optimize_spirv_output{linkage,
|
||||
SpirvOptimizeMode::Never,
|
||||
SpirvOptimizeMode::Never,
|
||||
SpirvOptimizeMode::Always,
|
||||
"optimize_spirv_output",
|
||||
Category::Renderer};
|
||||
SwitchableSetting<bool> use_asynchronous_gpu_emulation{
|
||||
|
@ -349,10 +354,12 @@ struct Values {
|
|||
#else
|
||||
AstcDecodeMode::Gpu,
|
||||
#endif
|
||||
AstcDecodeMode::Cpu,
|
||||
AstcDecodeMode::CpuAsynchronous,
|
||||
"accelerate_astc",
|
||||
Category::Renderer};
|
||||
SwitchableSetting<VSyncMode, true> vsync_mode{
|
||||
linkage, VSyncMode::Fifo,
|
||||
linkage, VSyncMode::Fifo, VSyncMode::Immediate, VSyncMode::FifoRelaxed,
|
||||
"use_vsync", Category::Renderer, Specialization::RuntimeList, true,
|
||||
true};
|
||||
SwitchableSetting<NvdecEmulation> nvdec_emulation{linkage, NvdecEmulation::Gpu,
|
||||
|
@ -365,6 +372,8 @@ struct Values {
|
|||
#else
|
||||
FullscreenMode::Exclusive,
|
||||
#endif
|
||||
FullscreenMode::Borderless,
|
||||
FullscreenMode::Exclusive,
|
||||
"fullscreen_mode",
|
||||
Category::Renderer,
|
||||
Specialization::Default,
|
||||
|
@ -372,6 +381,8 @@ struct Values {
|
|||
true};
|
||||
SwitchableSetting<AspectRatio, true> aspect_ratio{linkage,
|
||||
AspectRatio::R16_9,
|
||||
AspectRatio::R16_9,
|
||||
AspectRatio::Stretch,
|
||||
"aspect_ratio",
|
||||
Category::Renderer,
|
||||
Specialization::Default,
|
||||
|
@ -419,6 +430,8 @@ struct Values {
|
|||
#else
|
||||
GpuAccuracy::High,
|
||||
#endif
|
||||
GpuAccuracy::Normal,
|
||||
GpuAccuracy::Extreme,
|
||||
"gpu_accuracy",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
|
@ -429,6 +442,8 @@ struct Values {
|
|||
|
||||
SwitchableSetting<DmaAccuracy, true> dma_accuracy{linkage,
|
||||
DmaAccuracy::Default,
|
||||
DmaAccuracy::Default,
|
||||
DmaAccuracy::Safe,
|
||||
"dma_accuracy",
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
|
@ -441,14 +456,20 @@ struct Values {
|
|||
#else
|
||||
AnisotropyMode::Automatic,
|
||||
#endif
|
||||
AnisotropyMode::Automatic,
|
||||
AnisotropyMode::X16,
|
||||
"max_anisotropy",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||
AstcRecompression::Uncompressed,
|
||||
AstcRecompression::Uncompressed,
|
||||
AstcRecompression::Bc3,
|
||||
"astc_recompression",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
|
||||
VramUsageMode::Conservative,
|
||||
VramUsageMode::Conservative,
|
||||
VramUsageMode::Aggressive,
|
||||
"vram_usage_mode",
|
||||
Category::RendererAdvanced};
|
||||
SwitchableSetting<bool> skip_cpu_inner_invalidation{linkage,
|
||||
|
@ -574,10 +595,14 @@ struct Values {
|
|||
// System
|
||||
SwitchableSetting<Language, true> language_index{linkage,
|
||||
Language::EnglishAmerican,
|
||||
Language::Japanese,
|
||||
Language::Serbian,
|
||||
"language_index",
|
||||
Category::System};
|
||||
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, "region_index", Category::System};
|
||||
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
|
||||
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, Region::Japan,
|
||||
Region::Taiwan, "region_index", Category::System};
|
||||
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
|
||||
TimeZone::Auto, TimeZone::Zulu,
|
||||
"time_zone_index", Category::System};
|
||||
// Measured in seconds since epoch
|
||||
SwitchableSetting<bool> custom_rtc_enabled{
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
|
@ -19,10 +18,8 @@ namespace Settings {
|
|||
|
||||
template <typename T>
|
||||
struct EnumMetadata {
|
||||
static std::vector<std::pair<std::string_view, T>> Canonicalizations();
|
||||
static std::vector<std::pair<std::string, T>> Canonicalizations();
|
||||
static u32 Index();
|
||||
static constexpr T GetFirst();
|
||||
static constexpr T GetLast();
|
||||
};
|
||||
|
||||
#define PAIR_45(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_46(N, __VA_ARGS__))
|
||||
|
@ -72,101 +69,138 @@ struct EnumMetadata {
|
|||
#define PAIR_1(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_2(N, __VA_ARGS__))
|
||||
#define PAIR(N, X, ...) {#X, N::X} __VA_OPT__(, PAIR_1(N, __VA_ARGS__))
|
||||
|
||||
#define PP_HEAD(A, ...) A
|
||||
|
||||
#define ENUM(NAME, ...) \
|
||||
enum class NAME : u32 { __VA_ARGS__ }; \
|
||||
template<> inline std::vector<std::pair<std::string_view, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
|
||||
return {PAIR(NAME, __VA_ARGS__)}; \
|
||||
} \
|
||||
template<> inline u32 EnumMetadata<NAME>::Index() { \
|
||||
return __COUNTER__; \
|
||||
} \
|
||||
template<> inline constexpr NAME EnumMetadata<NAME>::GetFirst() { \
|
||||
return NAME::PP_HEAD(__VA_ARGS__); \
|
||||
} \
|
||||
template<> inline constexpr NAME EnumMetadata<NAME>::GetLast() { \
|
||||
return (std::vector<std::pair<std::string_view, NAME>>{PAIR(NAME, __VA_ARGS__)}).back().second; \
|
||||
#define ENUM(NAME, ...) \
|
||||
enum class NAME : u32 { __VA_ARGS__ }; \
|
||||
template <> \
|
||||
inline std::vector<std::pair<std::string, NAME>> EnumMetadata<NAME>::Canonicalizations() { \
|
||||
return {PAIR(NAME, __VA_ARGS__)}; \
|
||||
} \
|
||||
template <> \
|
||||
inline u32 EnumMetadata<NAME>::Index() { \
|
||||
return __COUNTER__; \
|
||||
}
|
||||
|
||||
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||
// canonicalizations
|
||||
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
||||
enum class AudioEngine : u32 { Auto, Cubeb, Sdl2, Null, Oboe, };
|
||||
template<>
|
||||
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||
enum class AudioEngine : u32 {
|
||||
Auto,
|
||||
Cubeb,
|
||||
Sdl2,
|
||||
Null,
|
||||
Oboe,
|
||||
};
|
||||
|
||||
template <>
|
||||
inline std::vector<std::pair<std::string, AudioEngine>>
|
||||
EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||
return {
|
||||
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2},
|
||||
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||
};
|
||||
}
|
||||
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
|
||||
template<>
|
||||
|
||||
template <>
|
||||
inline u32 EnumMetadata<AudioEngine>::Index() {
|
||||
// This is just a sufficiently large number that is more than the number of other enums declared
|
||||
// here
|
||||
return 100;
|
||||
}
|
||||
template<>
|
||||
inline constexpr AudioEngine EnumMetadata<AudioEngine>::GetFirst() {
|
||||
return AudioEngine::Auto;
|
||||
}
|
||||
template<>
|
||||
inline constexpr AudioEngine EnumMetadata<AudioEngine>::GetLast() {
|
||||
return AudioEngine::Oboe;
|
||||
}
|
||||
|
||||
ENUM(AudioMode, Mono, Stereo, Surround);
|
||||
static_assert(EnumMetadata<AudioMode>::GetFirst() == AudioMode::Mono);
|
||||
static_assert(EnumMetadata<AudioMode>::GetLast() == AudioMode::Surround);
|
||||
|
||||
ENUM(Language, Japanese, EnglishAmerican, French, German, Italian, Spanish, Chinese, Korean, Dutch,
|
||||
Portuguese, Russian, Taiwanese, EnglishBritish, FrenchCanadian, SpanishLatin,
|
||||
ChineseSimplified, ChineseTraditional, PortugueseBrazilian, Serbian);
|
||||
|
||||
ENUM(Region, Japan, Usa, Europe, Australia, China, Korea, Taiwan);
|
||||
|
||||
ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt, Gb, GbEire, Gmt,
|
||||
GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
|
||||
Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
|
||||
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
|
||||
GmtPlusZero, GmtMinusZero, GmtZero, Greenwich, Hongkong, Hst, Iceland, Iran, Israel, Jamaica,
|
||||
Japan, Kwajalein, Libya, Met, Mst, Mst7Mdt, Navajo, Nz, NzChat, Poland, Portugal, Prc, Pst8Pdt,
|
||||
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
|
||||
|
||||
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
|
||||
|
||||
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||
|
||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||
|
||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||
|
||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||
|
||||
ENUM(RendererBackend, OpenGL, Vulkan, Null);
|
||||
|
||||
ENUM(ShaderBackend, Glsl, Glasm, SpirV);
|
||||
|
||||
ENUM(GpuAccuracy, Normal, High, Extreme);
|
||||
|
||||
ENUM(DmaAccuracy, Default, Unsafe, Safe);
|
||||
|
||||
ENUM(CpuBackend, Dynarmic, Nce);
|
||||
|
||||
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid);
|
||||
|
||||
ENUM(CpuClock, Boost, Fast)
|
||||
|
||||
ENUM(MemoryLayout, Memory_4Gb, Memory_6Gb, Memory_8Gb, Memory_10Gb, Memory_12Gb);
|
||||
|
||||
ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
|
||||
|
||||
ENUM(FullscreenMode, Borderless, Exclusive);
|
||||
|
||||
ENUM(NvdecEmulation, Off, Cpu, Gpu);
|
||||
ENUM(ResolutionSetup, Res1_4X, Res1_2X, Res3_4X, Res1X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X);
|
||||
|
||||
ENUM(ResolutionSetup,
|
||||
Res1_4X,
|
||||
Res1_2X,
|
||||
Res3_4X,
|
||||
Res1X,
|
||||
Res3_2X,
|
||||
Res2X,
|
||||
Res3X,
|
||||
Res4X,
|
||||
Res5X,
|
||||
Res6X,
|
||||
Res7X,
|
||||
Res8X);
|
||||
|
||||
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Spline1, Gaussian, Lanczos, ScaleForce, Fsr, Area, MaxEnum);
|
||||
|
||||
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
|
||||
|
||||
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
|
||||
|
||||
ENUM(ConsoleMode, Handheld, Docked);
|
||||
|
||||
ENUM(AppletMode, HLE, LLE);
|
||||
|
||||
ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
|
||||
|
||||
ENUM(GpuOverclock, Low, Medium, High)
|
||||
|
||||
ENUM(TemperatureUnits, Celsius, Fahrenheit)
|
||||
|
||||
template <typename Type>
|
||||
inline std::string_view CanonicalizeEnum(Type id) {
|
||||
inline std::string CanonicalizeEnum(Type id) {
|
||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||
for (auto& [name, value] : group)
|
||||
if (value == id)
|
||||
for (auto& [name, value] : group) {
|
||||
if (value == id) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type ToEnum(const std::string& canonicalization) {
|
||||
const auto group = EnumMetadata<Type>::Canonicalizations();
|
||||
for (auto& [name, value] : group)
|
||||
if (name == canonicalization)
|
||||
for (auto& [name, value] : group) {
|
||||
if (name == canonicalization) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
} // namespace Settings
|
||||
|
|
|
@ -72,17 +72,10 @@ public:
|
|||
u32 specialization_ = Specialization::Default, bool save_ = true,
|
||||
bool runtime_modifiable_ = false, BasicSetting* other_setting_ = nullptr)
|
||||
requires(ranged)
|
||||
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_, other_setting_),
|
||||
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_,
|
||||
other_setting_),
|
||||
value{default_val}, default_value{default_val}, maximum{max_val}, minimum{min_val} {}
|
||||
|
||||
explicit Setting(Linkage& linkage, const Type& default_val,
|
||||
const std::string& name, Category category_,
|
||||
u32 specialization_ = Specialization::Default, bool save_ = true,
|
||||
bool runtime_modifiable_ = false, BasicSetting* other_setting_ = nullptr)
|
||||
requires(ranged && std::is_enum_v<Type>)
|
||||
: BasicSetting(linkage, name, category_, save_, runtime_modifiable_, specialization_, other_setting_),
|
||||
value{default_val}, default_value{default_val}, maximum{EnumMetadata<Type>::GetLast()}, minimum{EnumMetadata<Type>::GetFirst()} {}
|
||||
|
||||
/**
|
||||
* Returns a reference to the setting's value.
|
||||
*
|
||||
|
@ -126,6 +119,9 @@ protected:
|
|||
return value_.has_value() ? std::to_string(*value_) : "none";
|
||||
} else if constexpr (std::is_same_v<Type, bool>) {
|
||||
return value_ ? "true" : "false";
|
||||
} else if constexpr (std::is_same_v<Type, AudioEngine>) {
|
||||
// Compatibility with old AudioEngine setting being a string
|
||||
return CanonicalizeEnum(value_);
|
||||
} else if constexpr (std::is_floating_point_v<Type>) {
|
||||
return fmt::format("{:f}", value_);
|
||||
} else if constexpr (std::is_enum_v<Type>) {
|
||||
|
@ -211,7 +207,7 @@ public:
|
|||
|
||||
[[nodiscard]] std::string Canonicalize() const override final {
|
||||
if constexpr (std::is_enum_v<Type>) {
|
||||
return std::string{CanonicalizeEnum(this->GetValue())};
|
||||
return CanonicalizeEnum(this->GetValue());
|
||||
} else {
|
||||
return ToString(this->GetValue());
|
||||
}
|
||||
|
@ -292,32 +288,41 @@ public:
|
|||
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||
*/
|
||||
template <typename T = BasicSetting>
|
||||
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name, Category category_, u32 specialization_ = Specialization::Default, bool save_ = true, bool runtime_modifiable_ = false, T* other_setting_ = nullptr) requires(!ranged)
|
||||
: Setting<Type, false>{ linkage, default_val, name, category_, specialization_, save_, runtime_modifiable_, other_setting_} {
|
||||
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name,
|
||||
Category category_, u32 specialization_ = Specialization::Default,
|
||||
bool save_ = true, bool runtime_modifiable_ = false,
|
||||
typename std::enable_if<!ranged, T*>::type other_setting_ = nullptr)
|
||||
: Setting<Type, false>{
|
||||
linkage, default_val, name, category_, specialization_,
|
||||
save_, runtime_modifiable_, other_setting_} {
|
||||
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
|
||||
}
|
||||
virtual ~SwitchableSetting() = default;
|
||||
|
||||
/// @brief Sets a default value, minimum value, maximum value, and label.
|
||||
/// @param linkage Setting registry
|
||||
/// @param default_val Initial value of the setting, and default value of the setting
|
||||
/// @param min_val Sets the minimum allowed value of the setting
|
||||
/// @param max_val Sets the maximum allowed value of the setting
|
||||
/// @param name Label for the setting
|
||||
/// @param category_ Category of the setting AKA INI group
|
||||
/// @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||
/// @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||
/// @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||
/// @param other_setting_ A second Setting to associate to this one in metadata
|
||||
/**
|
||||
* Sets a default value, minimum value, maximum value, and label.
|
||||
*
|
||||
* @param linkage Setting registry
|
||||
* @param default_val Initial value of the setting, and default value of the setting
|
||||
* @param min_val Sets the minimum allowed value of the setting
|
||||
* @param max_val Sets the maximum allowed value of the setting
|
||||
* @param name Label for the setting
|
||||
* @param category_ Category of the setting AKA INI group
|
||||
* @param specialization_ Suggestion for how frontend implementations represent this in a config
|
||||
* @param save_ Suggests that this should or should not be saved to a frontend config file
|
||||
* @param runtime_modifiable_ Suggests whether this is modifiable while a guest is loaded
|
||||
* @param other_setting_ A second Setting to associate to this one in metadata
|
||||
*/
|
||||
template <typename T = BasicSetting>
|
||||
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val, const Type& max_val, const std::string& name, Category category_, u32 specialization_ = Specialization::Default, bool save_ = true, bool runtime_modifiable_ = false, T* other_setting_ = nullptr) requires(ranged)
|
||||
: Setting<Type, true>{linkage, default_val, min_val, max_val, name, category_, specialization_, save_, runtime_modifiable_, other_setting_} {
|
||||
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
|
||||
}
|
||||
|
||||
template <typename T = BasicSetting>
|
||||
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const std::string& name, Category category_, u32 specialization_ = Specialization::Default, bool save_ = true, bool runtime_modifiable_ = false, T* other_setting_ = nullptr) requires(ranged)
|
||||
: Setting<Type, true>{linkage, default_val, EnumMetadata<Type>::GetFirst(), EnumMetadata<Type>::GetLast(), name, category_, specialization_, save_, runtime_modifiable_, other_setting_} {
|
||||
explicit SwitchableSetting(Linkage& linkage, const Type& default_val, const Type& min_val,
|
||||
const Type& max_val, const std::string& name, Category category_,
|
||||
u32 specialization_ = Specialization::Default, bool save_ = true,
|
||||
bool runtime_modifiable_ = false,
|
||||
typename std::enable_if<ranged, T*>::type other_setting_ = nullptr)
|
||||
: Setting<Type, true>{linkage, default_val, min_val,
|
||||
max_val, name, category_,
|
||||
specialization_, save_, runtime_modifiable_,
|
||||
other_setting_} {
|
||||
linkage.restore_functions.emplace_back([this]() { this->SetGlobal(true); });
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <stack>
|
||||
|
||||
#include "common/math_util.h"
|
||||
#include "core/hle/service/apm/apm_controller.h"
|
||||
|
@ -24,7 +23,6 @@
|
|||
#include "core/hle/service/am/hid_registration.h"
|
||||
#include "core/hle/service/am/lifecycle_manager.h"
|
||||
#include "core/hle/service/am/process_holder.h"
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
|
@ -99,9 +97,6 @@ struct Applet {
|
|||
std::deque<std::vector<u8>> preselected_user_launch_parameter{};
|
||||
std::deque<std::vector<u8>> friend_invitation_storage_channel{};
|
||||
|
||||
// Context Stack
|
||||
std::stack<SharedPointer<IStorage>> context_stack{};
|
||||
|
||||
// Caller applet
|
||||
std::weak_ptr<Applet> caller_applet{};
|
||||
std::shared_ptr<AppletDataBroker> caller_applet_broker{};
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -18,12 +15,12 @@ IProcessWindingController::IProcessWindingController(Core::System& system_,
|
|||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IProcessWindingController::GetLaunchReason>, "GetLaunchReason"},
|
||||
{11, D<&IProcessWindingController::OpenCallingLibraryApplet>, "OpenCallingLibraryApplet"},
|
||||
{21, D<&IProcessWindingController::PushContext>, "PushContext"},
|
||||
{22, D<&IProcessWindingController::PopContext>, "PopContext"},
|
||||
{23, D<&IProcessWindingController::CancelWindingReservation>, "CancelWindingReservation"},
|
||||
{30, D<&IProcessWindingController::WindAndDoReserved>, "WindAndDoReserved"},
|
||||
{40, D<&IProcessWindingController::ReserveToStartAndWaitAndUnwindThis>, "ReserveToStartAndWaitAndUnwindThis"},
|
||||
{41, D<&IProcessWindingController::ReserveToStartAndWait>, "ReserveToStartAndWait"},
|
||||
{21, nullptr, "PushContext"},
|
||||
{22, nullptr, "PopContext"},
|
||||
{23, nullptr, "CancelWindingReservation"},
|
||||
{30, nullptr, "WindAndDoReserved"},
|
||||
{40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
|
||||
{41, nullptr, "ReserveToStartAndWait"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
@ -54,43 +51,4 @@ Result IProcessWindingController::OpenCallingLibraryApplet(
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::PushContext(SharedPointer<IStorage> context) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
m_applet->context_stack.push(context);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::PopContext(Out<SharedPointer<IStorage>> out_context) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
if (m_applet->context_stack.empty()) {
|
||||
LOG_ERROR(Service_AM, "Context stack is empty");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
*out_context = m_applet->context_stack.top();
|
||||
m_applet->context_stack.pop();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::CancelWindingReservation() {
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::WindAndDoReserved() {
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::ReserveToStartAndWaitAndUnwindThis() {
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IProcessWindingController::ReserveToStartAndWait() {
|
||||
LOG_WARNING(Service_AM, "STUBBED");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
@ -25,12 +21,6 @@ private:
|
|||
Result GetLaunchReason(Out<AppletProcessLaunchReason> out_launch_reason);
|
||||
Result OpenCallingLibraryApplet(
|
||||
Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet);
|
||||
Result PushContext(SharedPointer<IStorage> in_context);
|
||||
Result PopContext(Out<SharedPointer<IStorage>> out_context);
|
||||
Result CancelWindingReservation();
|
||||
Result WindAndDoReserved();
|
||||
Result ReserveToStartAndWaitAndUnwindThis();
|
||||
Result ReserveToStartAndWait();
|
||||
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -70,7 +67,6 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
|
|||
{110, nullptr, "SetApplicationAlbumUserData"},
|
||||
{120, D<&ISelfController::SaveCurrentScreenshot>, "SaveCurrentScreenshot"},
|
||||
{130, D<&ISelfController::SetRecordVolumeMuted>, "SetRecordVolumeMuted"},
|
||||
{230, D<&ISelfController::Unknown230>, "Unknown230"},
|
||||
{1000, nullptr, "GetDebugStorageChannel"},
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -408,12 +404,4 @@ Result ISelfController::SetRecordVolumeMuted(bool muted) {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISelfController::Unknown230(u32 in_val, Out<u16> out_val) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, in_val={}", in_val);
|
||||
|
||||
*out_val = 0;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -66,7 +63,6 @@ private:
|
|||
Result SetAlbumImageTakenNotificationEnabled(bool enabled);
|
||||
Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
|
||||
Result SetRecordVolumeMuted(bool muted);
|
||||
Result Unknown230(u32 in_val, Out<u16> out_val);
|
||||
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
|
|
|
@ -135,8 +135,6 @@ target_include_directories(dynarmic_tests PRIVATE . ../src)
|
|||
target_compile_options(dynarmic_tests PRIVATE ${DYNARMIC_CXX_FLAGS})
|
||||
target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
|
||||
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
target_compile_options(dynarmic_tests PRIVATE -mavx2)
|
||||
endif()
|
||||
target_compile_options(dynarmic_tests PRIVATE -mavx2)
|
||||
|
||||
add_test(dynarmic_tests dynarmic_tests --durations yes)
|
||||
|
|
|
@ -62,20 +62,22 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
Settings,
|
||||
use_multi_core,
|
||||
tr("Multicore CPU Emulation"),
|
||||
tr("This option increases CPU emulation thread use from 1 to the maximum of 4.\n"
|
||||
"This is mainly a debug option and shouldn't be disabled."));
|
||||
tr("This option increases CPU emulation thread use from 1 to the Switch’s maximum of 4.\n"
|
||||
"This is mainly a debug option and shouldn’t be disabled."));
|
||||
INSERT(
|
||||
Settings,
|
||||
memory_layout_mode,
|
||||
tr("Memory Layout"),
|
||||
tr("Increases the amount of emulated RAM from 4GB of the board to the "
|
||||
"devkit 8/6GB.\nDoesn't affect performance/stability but may allow HD texture "
|
||||
"mods to load."));
|
||||
tr("Increases the amount of emulated RAM from the stock 4GB of the retail Switch to the "
|
||||
"developer kit's 8/6GB.\nIt’s doesn’t improve stability or performance and is intended "
|
||||
"to let big texture mods fit in emulated RAM.\nEnabling it will increase memory "
|
||||
"use. It is not recommended to enable unless a specific game with a texture mod needs "
|
||||
"it."));
|
||||
INSERT(Settings, use_speed_limit, QString(), QString());
|
||||
INSERT(Settings,
|
||||
speed_limit,
|
||||
tr("Limit Speed Percent"),
|
||||
tr("Controls the game's maximum rendering speed, but it's up to each game if it runs "
|
||||
tr("Controls the game's maximum rendering speed, but it’s up to each game if it runs "
|
||||
"faster or not.\n200% for a 30 FPS game is 60 FPS, and for a "
|
||||
"60 FPS game it will be 120 FPS.\nDisabling it means unlocking the framerate to the "
|
||||
"maximum your PC can reach."));
|
||||
|
@ -84,13 +86,15 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
tr("Synchronize Core Speed"),
|
||||
tr("Synchronizes CPU core speed with the game's maximum rendering speed to boost FPS "
|
||||
"without affecting game speed (animations, physics, etc.).\n"
|
||||
"Compatibility varies by game; many (especially older ones) may not respond well.\n"
|
||||
"Can help reduce stuttering at lower framerates."));
|
||||
|
||||
// Cpu
|
||||
INSERT(Settings,
|
||||
cpu_accuracy,
|
||||
tr("Accuracy:"),
|
||||
tr("Change the accuracy of the emulated CPU (for debugging only)."));
|
||||
tr("This setting controls the accuracy of the emulated CPU.\nDon't change this unless "
|
||||
"you know what you are doing."));
|
||||
INSERT(Settings, cpu_backend, tr("Backend:"), QString());
|
||||
|
||||
INSERT(Settings, use_fast_cpu_time, QString(), QString());
|
||||
|
@ -106,7 +110,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
cpu_ticks,
|
||||
tr("Custom CPU Ticks"),
|
||||
tr("Set a custom value of CPU ticks. Higher values can increase performance, but may "
|
||||
"cause deadlocks. A range of 77-21000 is recommended."));
|
||||
"also cause the game to freeze. A range of 77–21000 is recommended."));
|
||||
INSERT(Settings, cpu_backend, tr("Backend:"), QString());
|
||||
|
||||
// Cpu Debug
|
||||
|
@ -140,7 +144,8 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
cpuopt_unsafe_fastmem_check,
|
||||
tr("Disable address space checks"),
|
||||
tr("This option improves speed by eliminating a safety check before every memory "
|
||||
"operation.\nDisabling it may allow arbitrary code execution."));
|
||||
"read/write in guest.\nDisabling it may allow a game to read/write the emulator's "
|
||||
"memory."));
|
||||
INSERT(
|
||||
Settings,
|
||||
cpuopt_unsafe_ignore_global_monitor,
|
||||
|
@ -154,31 +159,36 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
Settings,
|
||||
renderer_backend,
|
||||
tr("API:"),
|
||||
tr("Changes the output graphics API.\nVulkan is recommended."));
|
||||
tr("Switches between the available graphics APIs.\nVulkan is recommended in most cases."));
|
||||
INSERT(Settings,
|
||||
vulkan_device,
|
||||
tr("Device:"),
|
||||
tr("This setting selects the GPU to use (Vulkan only)."));
|
||||
tr("This setting selects the GPU to use with the Vulkan backend."));
|
||||
INSERT(Settings,
|
||||
shader_backend,
|
||||
tr("Shader Backend:"),
|
||||
tr("The shader backend to use with OpenGL.\nGLSL is recommended."));
|
||||
tr("The shader backend to use for the OpenGL renderer.\nGLSL is the fastest in "
|
||||
"performance and the best in rendering accuracy.\n"
|
||||
"GLASM is a deprecated NVIDIA-only backend that offers much better shader building "
|
||||
"performance at the cost of FPS and rendering accuracy.\n"
|
||||
"SPIR-V compiles the fastest, but yields poor results on most GPU drivers."));
|
||||
INSERT(Settings,
|
||||
resolution_setup,
|
||||
tr("Resolution:"),
|
||||
tr("Forces to render at a different resolution.\n"
|
||||
"Higher resolutions require more VRAM and bandwidth.\n"
|
||||
"Options lower than 1X can cause artifacts."));
|
||||
tr("Forces the game to render at a different resolution.\nHigher resolutions require "
|
||||
"much more VRAM and bandwidth.\n"
|
||||
"Options lower than 1X can cause rendering issues."));
|
||||
INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QString());
|
||||
INSERT(Settings,
|
||||
fsr_sharpening_slider,
|
||||
tr("FSR Sharpness:"),
|
||||
tr("Determines how sharpened the image will look using FSR's dynamic contrast."));
|
||||
tr("Determines how sharpened the image will look while using FSR’s dynamic contrast."));
|
||||
INSERT(Settings,
|
||||
anti_aliasing,
|
||||
tr("Anti-Aliasing Method:"),
|
||||
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA "
|
||||
"can produce a more stable picture in lower resolutions."));
|
||||
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a "
|
||||
"lower performance impact and can produce a better and more stable picture under "
|
||||
"very low resolutions."));
|
||||
INSERT(Settings,
|
||||
fullscreen_mode,
|
||||
tr("Fullscreen Mode:"),
|
||||
|
@ -189,17 +199,18 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
INSERT(Settings,
|
||||
aspect_ratio,
|
||||
tr("Aspect Ratio:"),
|
||||
tr("Stretches the renderer to fit the specified aspect ratio.\nMost games only support "
|
||||
"16:9, so modifications are required to get other ratios.\nAlso controls the "
|
||||
tr("Stretches the game to fit the specified aspect ratio.\nSwitch games only support "
|
||||
"16:9, so custom game mods are required to get other ratios.\nAlso controls the "
|
||||
"aspect ratio of captured screenshots."));
|
||||
INSERT(Settings,
|
||||
use_disk_shader_cache,
|
||||
tr("Use persistent pipeline cache"),
|
||||
tr("Use disk pipeline cache"),
|
||||
tr("Allows saving shaders to storage for faster loading on following game "
|
||||
"boots.\nDisabling it is only intended for debugging."));
|
||||
"boots.\nDisabling "
|
||||
"it is only intended for debugging."));
|
||||
INSERT(Settings,
|
||||
optimize_spirv_output,
|
||||
tr("Optimize SPIRV output"),
|
||||
tr("Optimize SPIRV output shader"),
|
||||
tr("Runs an additional optimization pass over generated SPIRV shaders.\n"
|
||||
"Will increase time required for shader compilation.\nMay slightly improve "
|
||||
"performance.\nThis feature is experimental."));
|
||||
|
@ -218,35 +229,37 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
accelerate_astc,
|
||||
tr("ASTC Decoding Method:"),
|
||||
tr("This option controls how ASTC textures should be decoded.\n"
|
||||
"CPU: Use the CPU for decoding.\n"
|
||||
"GPU: Use the GPU's compute shaders to decode ASTC textures (recommended).\n"
|
||||
"CPU Asynchronously: Use the CPU to decode ASTC textures on demand. Eliminates"
|
||||
"ASTC decoding\nstuttering but may present artifacts."));
|
||||
"CPU: Use the CPU for decoding, slowest but safest method.\n"
|
||||
"GPU: Use the GPU's compute shaders to decode ASTC textures, recommended for most "
|
||||
"games and users.\n"
|
||||
"CPU Asynchronously: Use the CPU to decode ASTC textures as they arrive. Completely "
|
||||
"eliminates ASTC decoding\nstuttering at the cost of rendering issues while the "
|
||||
"texture is being decoded."));
|
||||
INSERT(
|
||||
Settings,
|
||||
astc_recompression,
|
||||
tr("ASTC Recompression Method:"),
|
||||
tr("Most GPUs lack support for ASTC textures and must decompress to an"
|
||||
"intermediate format: RGBA8.\n"
|
||||
"BC1/BC3: The intermediate format will be recompressed to BC1 or BC3 format,\n"
|
||||
" saving VRAM but degrading image quality."));
|
||||
tr("Almost all desktop and laptop dedicated GPUs lack support for ASTC textures, forcing "
|
||||
"the emulator to decompress to an intermediate format any card supports, RGBA8.\n"
|
||||
"This option recompresses RGBA8 to either the BC1 or BC3 format, saving VRAM but "
|
||||
"negatively affecting image quality."));
|
||||
INSERT(Settings,
|
||||
vram_usage_mode,
|
||||
tr("VRAM Usage Mode:"),
|
||||
tr("Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance.\nAggressive mode may impact performance of other applications such as recording software."));
|
||||
tr("Selects whether the emulator should prefer to conserve memory or make maximum usage of available video memory for performance.\nAggressive mode may severely impact the performance of other applications such as recording software."));
|
||||
INSERT(Settings,
|
||||
skip_cpu_inner_invalidation,
|
||||
tr("Skip CPU Inner Invalidation"),
|
||||
tr("Skips certain cache invalidations during memory updates, reducing CPU usage and "
|
||||
"improving latency. This may cause soft-crashes."));
|
||||
tr("Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and "
|
||||
"improving it's performance. This may cause glitches or crashes on some games."));
|
||||
INSERT(
|
||||
Settings,
|
||||
vsync_mode,
|
||||
tr("VSync Mode:"),
|
||||
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
|
||||
"refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n"
|
||||
"Mailbox can have lower latency than FIFO and does not tear but may drop "
|
||||
"frames.\nImmediate (no synchronization) presents whatever is available and can "
|
||||
"refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from "
|
||||
"a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop "
|
||||
"frames.\nImmediate (no synchronization) just presents whatever is available and can "
|
||||
"exhibit tearing."));
|
||||
INSERT(Settings, bg_red, QString(), QString());
|
||||
INSERT(Settings, bg_green, QString(), QString());
|
||||
|
@ -254,7 +267,7 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
|
||||
// Renderer (Advanced Graphics)
|
||||
INSERT(Settings, sync_memory_operations, tr("Sync Memory Operations"),
|
||||
tr("Ensures data consistency between compute and memory operations.\nThis option fixes issues in games, but may degrade performance.\nUnreal Engine 4 games often see the most significant changes thereof."));
|
||||
tr("Ensures data consistency between compute and memory operations.\nThis option should fix issues in some games, but may also reduce performance in some cases.\nUnreal Engine 4 games often see the most significant changes thereof."));
|
||||
INSERT(Settings,
|
||||
async_presentation,
|
||||
tr("Enable asynchronous presentation (Vulkan only)"),
|
||||
|
@ -268,7 +281,8 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
INSERT(Settings,
|
||||
max_anisotropy,
|
||||
tr("Anisotropic Filtering:"),
|
||||
tr("Controls the quality of texture rendering at oblique angles.\nSafe to set at 16x on most GPUs."));
|
||||
tr("Controls the quality of texture rendering at oblique angles.\nIt’s a light setting "
|
||||
"and safe to set at 16x on most GPUs."));
|
||||
INSERT(Settings,
|
||||
gpu_accuracy,
|
||||
tr("GPU Accuracy:"),
|
||||
|
@ -278,11 +292,11 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
INSERT(Settings,
|
||||
dma_accuracy,
|
||||
tr("DMA Accuracy:"),
|
||||
tr("Controls the DMA precision accuracy. Safe precision fixes issues in some games but may degrade performance."));
|
||||
tr("Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases.\nIf unsure, leave this on Default."));
|
||||
INSERT(Settings,
|
||||
use_asynchronous_shaders,
|
||||
tr("Enable asynchronous shader compilation (Hack)"),
|
||||
tr("May reduce shader stutter."));
|
||||
tr("Use asynchronous shader building (Hack)"),
|
||||
tr("Enables asynchronous shader compilation, which may reduce shader stutter."));
|
||||
INSERT(Settings, use_fast_gpu_time, QString(), QString());
|
||||
INSERT(Settings,
|
||||
fast_gpu_time,
|
||||
|
@ -300,8 +314,8 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
Settings,
|
||||
enable_compute_pipelines,
|
||||
tr("Enable Compute Pipelines (Intel Vulkan Only)"),
|
||||
tr("Required by some games.\nThis setting only exists for Intel "
|
||||
"proprietary drivers and may crash if enabled.\nCompute pipelines are always enabled "
|
||||
tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
|
||||
"proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled "
|
||||
"on all other drivers."));
|
||||
INSERT(
|
||||
Settings,
|
||||
|
@ -329,12 +343,12 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
INSERT(Settings,
|
||||
dyna_state,
|
||||
tr("Extended Dynamic State"),
|
||||
tr("Controls the number of features that can be used in Extended Dynamic State.\nHigher numbers allow for more features and can increase performance, but may cause issues.\nThe default value is per-system."));
|
||||
tr("Controls the number of features that can be used in Extended Dynamic State.\nHigher numbers allow for more features and can increase performance, but may cause issues with some drivers and vendors.\nThe default value may vary depending on your system and hardware capabilities.\nThis value can be changed until stability and a better visual quality are achieved."));
|
||||
|
||||
INSERT(Settings,
|
||||
provoking_vertex,
|
||||
tr("Provoking Vertex"),
|
||||
tr("Improves lighting and vertex handling in some games.\n"
|
||||
tr("Improves lighting and vertex handling in certain games.\n"
|
||||
"Only Vulkan 1.0+ devices support this extension."));
|
||||
|
||||
INSERT(Settings,
|
||||
|
@ -349,8 +363,8 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
sample_shading_fraction,
|
||||
tr("Sample Shading"),
|
||||
tr("Allows the fragment shader to execute per sample in a multi-sampled fragment "
|
||||
"instead of once per fragment. Improves graphics quality at the cost of performance.\n"
|
||||
"Higher values improve quality but degrade performance."));
|
||||
"instead once per fragment. Improves graphics quality at the cost of some performance.\n"
|
||||
"Higher values improve quality more but also reduce performance to a greater extent."));
|
||||
|
||||
// Renderer (Debug)
|
||||
|
||||
|
@ -358,30 +372,31 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
INSERT(Settings,
|
||||
rng_seed,
|
||||
tr("RNG Seed"),
|
||||
tr("Controls the seed of the random number generator.\nMainly used for speedrunning."));
|
||||
tr("Controls the seed of the random number generator.\nMainly used for speedrunning "
|
||||
"purposes."));
|
||||
INSERT(Settings, rng_seed_enabled, QString(), QString());
|
||||
INSERT(Settings, device_name, tr("Device Name"), tr("The name of the console."));
|
||||
INSERT(Settings, device_name, tr("Device Name"), tr("The name of the emulated Switch."));
|
||||
INSERT(Settings,
|
||||
custom_rtc,
|
||||
tr("Custom RTC Date:"),
|
||||
tr("This option allows to change the clock of the console.\n"
|
||||
tr("This option allows to change the emulated clock of the Switch.\n"
|
||||
"Can be used to manipulate time in games."));
|
||||
INSERT(Settings, custom_rtc_enabled, QString(), QString());
|
||||
INSERT(Settings,
|
||||
custom_rtc_offset,
|
||||
QStringLiteral(" "),
|
||||
tr("The number of seconds from the current unix time"));
|
||||
QStringLiteral("The number of seconds from the current unix time"));
|
||||
INSERT(Settings,
|
||||
language_index,
|
||||
tr("Language:"),
|
||||
tr("This option can be overridden when region setting is auto-select"));
|
||||
INSERT(Settings, region_index, tr("Region:"), tr("The region of the console."));
|
||||
INSERT(Settings, time_zone_index, tr("Time Zone:"), tr("The time zone of the console."));
|
||||
tr("Note: this can be overridden when region setting is auto-select"));
|
||||
INSERT(Settings, region_index, tr("Region:"), tr("The region of the emulated Switch."));
|
||||
INSERT(Settings, time_zone_index, tr("Time Zone:"), tr("The time zone of the emulated Switch."));
|
||||
INSERT(Settings, sound_index, tr("Sound Output Mode:"), QString());
|
||||
INSERT(Settings,
|
||||
use_docked_mode,
|
||||
tr("Console Mode:"),
|
||||
tr("Selects if the console is in Docked or Handheld mode.\nGames will change "
|
||||
tr("Selects if the console is emulated in Docked or Handheld mode.\nGames will change "
|
||||
"their resolution, details and supported controllers and depending on this setting.\n"
|
||||
"Setting to Handheld can help improve performance for low end systems."));
|
||||
INSERT(Settings, current_user, QString(), QString());
|
||||
|
@ -403,26 +418,27 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
|||
// Ui General
|
||||
INSERT(UISettings,
|
||||
select_user_on_boot,
|
||||
tr("Prompt for user profile on boot"),
|
||||
tr("Useful if multiple people use the same PC."));
|
||||
tr("Prompt for user on game boot"),
|
||||
tr("Ask to select a user profile on each boot, useful if multiple people use Eden on "
|
||||
"the same PC."));
|
||||
INSERT(UISettings,
|
||||
pause_when_in_background,
|
||||
tr("Pause when not in focus"),
|
||||
tr("Pauses emulation when focusing on other windows."));
|
||||
tr("Pause emulation when in background"),
|
||||
tr("This setting pauses Eden when focusing other windows."));
|
||||
INSERT(UISettings,
|
||||
confirm_before_stopping,
|
||||
tr("Confirm before stopping emulation"),
|
||||
tr("Overrides prompts asking to confirm stopping the emulation.\nEnabling "
|
||||
tr("This setting overrides game prompts asking to confirm stopping the game.\nEnabling "
|
||||
"it bypasses such prompts and directly exits the emulation."));
|
||||
INSERT(UISettings,
|
||||
hide_mouse,
|
||||
tr("Hide mouse on inactivity"),
|
||||
tr("Hides the mouse after 2.5s of inactivity."));
|
||||
tr("This setting hides the mouse after 2.5s of inactivity."));
|
||||
INSERT(UISettings,
|
||||
controller_applet_disabled,
|
||||
tr("Disable controller applet"),
|
||||
tr("Forcibly disables the use of the controller applet in emulated programs.\n"
|
||||
"When a program attempts to open the controller applet, it is immediately closed."));
|
||||
tr("Forcibly disables the use of the controller applet by guests.\nWhen a guest "
|
||||
"attempts to open the controller applet, it is immediately closed."));
|
||||
INSERT(UISettings,
|
||||
check_for_updates,
|
||||
tr("Check for updates"),
|
||||
|
|
|
@ -366,10 +366,10 @@ if (APPLE)
|
|||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE TRUE)
|
||||
set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist)
|
||||
|
||||
if (YUZU_APPLE_USE_BUNDLED_MONTENVK)
|
||||
if (NOT USE_SYSTEM_MOLTENVK)
|
||||
set(MOLTENVK_PLATFORM "macOS")
|
||||
set(MOLTENVK_VERSION "v1.3.0")
|
||||
download_moltenvk(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
|
||||
download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION})
|
||||
endif()
|
||||
find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED)
|
||||
message(STATUS "Using MoltenVK at ${MOLTENVK_LIBRARY}.")
|
||||
|
|
|
@ -45,31 +45,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string></string>
|
||||
<!-- Fixed -->
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.games</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>nsp</string>
|
||||
<string>xci</string>
|
||||
<string>nro</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Switch File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Default</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>True</string>
|
||||
<key>UIDesignRequiresCompatibility</key>
|
||||
<true/> <!-- https://bugreports.qt.io/browse/QTBUG-138942 -->
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -270,8 +270,10 @@ void ConfigureAudio::UpdateAudioDevices(int sink_index) {
|
|||
void ConfigureAudio::InitializeAudioSinkComboBox() {
|
||||
sink_combo_box->clear();
|
||||
sink_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
|
||||
for (const auto& id : AudioCore::Sink::GetSinkIDs())
|
||||
sink_combo_box->addItem(QString::fromStdString(std::string{Settings::CanonicalizeEnum(id)}));
|
||||
|
||||
for (const auto& id : AudioCore::Sink::GetSinkIDs()) {
|
||||
sink_combo_box->addItem(QString::fromStdString(Settings::CanonicalizeEnum(id)));
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureAudio::RetranslateUI() {
|
||||
|
|
|
@ -373,13 +373,13 @@ bool ConfigureProfileManager::LoadAvatarData() {
|
|||
const auto romfs = nca->GetRomFS();
|
||||
if (!romfs) {
|
||||
QMessageBox::warning(this, tr("Error loading archive"),
|
||||
tr("Could not locate RomFS. Your file or decryption keys may be corrupted."));
|
||||
tr("Archive does not contain romfs. It is probably corrupt."));
|
||||
return false;
|
||||
}
|
||||
const auto extracted = FileSys::ExtractRomFS(romfs);
|
||||
if (!extracted) {
|
||||
QMessageBox::warning(this, tr("Error extracting archive"),
|
||||
tr("Could not extract RomFS. Your file or decryption keys may be corrupted."));
|
||||
tr("Archive could not be extracted. It is probably corrupt."));
|
||||
return false;
|
||||
}
|
||||
const auto chara_dir = extracted->GetSubdirectory("chara");
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <QString>
|
||||
#include <QStringLiteral>
|
||||
#include <QWidget>
|
||||
#include <QObject>
|
||||
#include <qobjectdefs.h>
|
||||
#include "qt_common/shared_translation.h"
|
||||
|
||||
|
|
|
@ -58,11 +58,11 @@ class GameList : public QWidget {
|
|||
public:
|
||||
enum {
|
||||
COLUMN_NAME,
|
||||
COLUMN_COMPATIBILITY,
|
||||
COLUMN_ADD_ONS,
|
||||
COLUMN_FILE_TYPE,
|
||||
COLUMN_SIZE,
|
||||
COLUMN_PLAY_TIME,
|
||||
COLUMN_ADD_ONS,
|
||||
COLUMN_COMPATIBILITY,
|
||||
COLUMN_COUNT, // Number of columns
|
||||
};
|
||||
|
||||
|
|
|
@ -204,24 +204,36 @@ QList<QStandardItem*> MakeGameListEntry(const std::string& path,
|
|||
const PlayTime::PlayTimeManager& play_time_manager,
|
||||
const FileSys::PatchManager& patch)
|
||||
{
|
||||
auto const it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
|
||||
// The game list uses 99 as compatibility number for untested games
|
||||
QString compatibility = it != compatibility_list.end() ? it->second.first : QStringLiteral("99");
|
||||
const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
|
||||
|
||||
auto const file_type = loader.GetFileType();
|
||||
auto const file_type_string = QString::fromStdString(Loader::GetFileTypeString(file_type));
|
||||
// The game list uses this as compatibility number for untested games
|
||||
QString compatibility{QStringLiteral("99")};
|
||||
if (it != compatibility_list.end()) {
|
||||
compatibility = it->second.first;
|
||||
}
|
||||
|
||||
QString patch_versions = GetGameListCachedObject(fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
|
||||
return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
|
||||
});
|
||||
return QList<QStandardItem*>{
|
||||
new GameListItemPath(FormatGameName(path), icon, QString::fromStdString(name), file_type_string, program_id),
|
||||
const auto file_type = loader.GetFileType();
|
||||
const auto file_type_string = QString::fromStdString(Loader::GetFileTypeString(file_type));
|
||||
|
||||
QList<QStandardItem*> list{
|
||||
new GameListItemPath(FormatGameName(path), icon, QString::fromStdString(name),
|
||||
file_type_string, program_id),
|
||||
new GameListItemCompat(compatibility),
|
||||
new GameListItem(file_type_string),
|
||||
new GameListItemSize(size),
|
||||
new GameListItemPlayTime(play_time_manager.GetPlayTime(program_id)),
|
||||
new GameListItem(patch_versions),
|
||||
new GameListItemCompat(compatibility),
|
||||
};
|
||||
|
||||
QString patch_versions;
|
||||
|
||||
patch_versions = GetGameListCachedObject(
|
||||
fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] {
|
||||
return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable());
|
||||
});
|
||||
|
||||
list.insert(2, new GameListItem(patch_versions));
|
||||
|
||||
return list;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue