summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-x.ci/scripts/windows/docker.sh5
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt146
-rw-r--r--CMakeModules/CopyYuzuFFmpegDeps.cmake2
-rw-r--r--README.md2
m---------externals/ffmpeg0
-rw-r--r--externals/find-modules/FindFFmpeg.cmake247
-rw-r--r--src/audio_core/stream.cpp9
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/string_util.cpp14
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp4
-rw-r--r--src/core/hle/service/hid/hid.cpp1
-rw-r--r--src/core/hle/service/olsc/olsc.cpp13
-rw-r--r--src/core/settings.h5
-rw-r--r--src/input_common/mouse/mouse_input.cpp32
-rw-r--r--src/input_common/mouse/mouse_input.h7
-rw-r--r--src/input_common/mouse/mouse_poller.cpp3
-rw-r--r--src/input_common/udp/client.cpp4
-rw-r--r--src/input_common/udp/client.h3
-rw-r--r--src/input_common/udp/udp.cpp4
-rw-r--r--src/video_core/CMakeLists.txt11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp3
-rw-r--r--src/video_core/texture_cache/util.cpp34
-rw-r--r--src/yuzu/bootmanager.cpp14
-rw-r--r--src/yuzu/configuration/config.cpp10
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure_input_advanced.cpp5
-rw-r--r--src/yuzu/configuration/configure_input_advanced.ui82
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp279
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h8
-rw-r--r--src/yuzu/main.cpp24
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp3
33 files changed, 665 insertions, 318 deletions
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh
index 2bc9f36ab..192a01fd8 100755
--- a/.ci/scripts/windows/docker.sh
+++ b/.ci/scripts/windows/docker.sh
@@ -42,3 +42,8 @@ done
pip3 install pefile
python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/"
python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/"
+
+# copy FFmpeg libraries
+EXTERNALS_PATH="$(pwd)/build/externals"
+FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin"
+find ${FFMPEG_DLL_PATH} -type f -regex ".*\.dll" -exec cp -v {} package/ ';'
diff --git a/.gitmodules b/.gitmodules
index 41022615b..4962f7bfd 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -37,3 +37,6 @@
[submodule "opus"]
path = externals/opus/opus
url = https://github.com/xiph/opus.git
+[submodule "externals/ffmpeg"]
+ path = externals/ffmpeg
+ url = https://git.ffmpeg.org/ffmpeg.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 27aa56780..c45123139 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,8 @@ CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" ON "EN
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
+CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled yuzu" ON "WIN32" OFF)
+
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON)
@@ -384,19 +386,141 @@ if (NOT LIBUSB_FOUND)
set(LIBUSB_LIBRARIES usb)
endif()
-# Use system installed ffmpeg.
-if (NOT MSVC)
- find_package(FFmpeg REQUIRED)
-else()
- set(FFMPEG_EXT_NAME "ffmpeg-4.2.1")
- set(FFMPEG_PATH "${CMAKE_BINARY_DIR}/externals/${FFMPEG_EXT_NAME}")
- download_bundled_external("ffmpeg/" ${FFMPEG_EXT_NAME} "")
- set(FFMPEG_FOUND YES)
- set(FFMPEG_INCLUDE_DIR "${FFMPEG_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
- set(FFMPEG_LIBRARY_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg library" FORCE)
- set(FFMPEG_DLL_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
+# List of all FFmpeg components required
+set(FFmpeg_COMPONENTS
+ avcodec
+ avutil
+ swscale)
+
+if (NOT YUZU_USE_BUNDLED_FFMPEG)
+ # Use system installed FFmpeg
+ find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
+
+ if (FFmpeg_FOUND)
+ # Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries.
+ # Prevents shipping too many libraries with the AppImage.
+ set(FFmpeg_LIBRARIES "")
+ set(FFmpeg_INCLUDE_DIR "")
+
+ foreach(COMPONENT ${FFmpeg_COMPONENTS})
+ set(FFmpeg_LIBRARIES ${FFmpeg_LIBRARIES} ${FFmpeg_LIBRARY_${COMPONENT}} CACHE PATH "Paths to FFmpeg libraries" FORCE)
+ set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE)
+ endforeach()
+ else()
+ message(WARNING "FFmpeg not found, falling back to externals")
+ set(YUZU_USE_BUNDLED_FFMPEG ON)
+ endif()
+endif()
+
+if (YUZU_USE_BUNDLED_FFMPEG)
+ if (NOT WIN32)
+ # Build FFmpeg from externals
+ message(STATUS "Using FFmpeg from externals")
+
+ # FFmpeg has source that requires one of nasm or yasm to assemble it.
+ # REQUIRED throws an error if not found here during configuration rather than during compilation.
+ find_program(ASSEMBLER NAMES nasm yasm REQUIRED)
+
+ set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg)
+ set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg)
+ set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
+ make_directory(${FFmpeg_BUILD_DIR})
+
+ # Read version string from external
+ file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION)
+ set(FFmpeg_FOUND NO)
+ if (NOT FFmpeg_VERSION STREQUAL "")
+ set(FFmpeg_FOUND YES)
+ endif()
+
+ foreach(COMPONENT ${FFmpeg_COMPONENTS})
+ set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
+ set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
+ set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}")
+
+ set(FFmpeg_LIBRARIES
+ ${FFmpeg_LIBRARIES}
+ ${FFmpeg_${COMPONENT}_LIBRARY}
+ CACHE PATH "Paths to FFmpeg libraries" FORCE)
+ endforeach()
+
+ set(FFmpeg_INCLUDE_DIR
+ ${FFmpeg_PREFIX}
+ CACHE PATH "Path to FFmpeg headers" FORCE)
+
+ # `configure` parameters builds only exactly what yuzu needs from FFmpeg
+ # `--disable-{vaapi,vdpau}` is needed to avoid linking issues
+ add_custom_command(
+ OUTPUT
+ ${FFmpeg_MAKEFILE}
+ COMMAND
+ /bin/bash ${FFmpeg_PREFIX}/configure
+ --disable-avdevice
+ --disable-avfilter
+ --disable-avformat
+ --disable-doc
+ --disable-everything
+ --disable-ffmpeg
+ --disable-ffprobe
+ --disable-network
+ --disable-postproc
+ --disable-swresample
+ --disable-vaapi
+ --disable-vdpau
+ --enable-decoder=h264
+ --enable-decoder=vp9
+ WORKING_DIRECTORY
+ ${FFmpeg_BUILD_DIR}
+ )
+
+ # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
+ # with context of the jobserver. Also helps ninja users.
+ execute_process(
+ COMMAND
+ nproc
+ OUTPUT_VARIABLE
+ SYSTEM_THREADS)
+
+ add_custom_command(
+ OUTPUT
+ ${FFmpeg_LIBRARIES}
+ COMMAND
+ make -j${SYSTEM_THREADS}
+ WORKING_DIRECTORY
+ ${FFmpeg_BUILD_DIR}
+ )
+
+ # ALL makes this custom target build every time
+ # but it won't actually build if the DEPENDS parameter is up to date
+ add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_LIBRARIES})
+ add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
+
+ if (FFmpeg_FOUND)
+ message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
+
+ add_dependencies(ffmpeg-build ffmpeg-configure)
+ else()
+ message(FATAL_ERROR "FFmpeg not found")
+ endif()
+ else() # WIN32
+ # Use yuzu FFmpeg binaries
+ set(FFmpeg_EXT_NAME "ffmpeg-4.2.1")
+ set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
+ download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
+ set(FFmpeg_FOUND YES)
+ set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
+ set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE)
+ set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
+ set(FFmpeg_LIBRARIES
+ ${FFmpeg_LIBRARY_DIR}/swscale.lib
+ ${FFmpeg_LIBRARY_DIR}/avcodec.lib
+ ${FFmpeg_LIBRARY_DIR}/avutil.lib
+ CACHE PATH "Paths to FFmpeg libraries" FORCE)
+ endif()
endif()
+unset(FFmpeg_COMPONENTS)
+
# Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
diff --git a/CMakeModules/CopyYuzuFFmpegDeps.cmake b/CMakeModules/CopyYuzuFFmpegDeps.cmake
index cca1eeeab..b7162cf17 100644
--- a/CMakeModules/CopyYuzuFFmpegDeps.cmake
+++ b/CMakeModules/CopyYuzuFFmpegDeps.cmake
@@ -1,7 +1,7 @@
function(copy_yuzu_FFmpeg_deps target_dir)
include(WindowsCopyFiles)
set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
- windows_copy_files(${target_dir} ${FFMPEG_DLL_DIR} ${DLL_DEST}
+ windows_copy_files(${target_dir} ${FFmpeg_DLL_DIR} ${DLL_DEST}
avcodec-58.dll
avutil-56.dll
swresample-3.dll
diff --git a/README.md b/README.md
index fbf62eb7c..cb1a64d8c 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ If you want to contribute to the user interface translation, please check out th
### Support
-We happily accept monetary donations or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like:
+We happily accept monetary donations, or donated games and hardware. Please see our [donations page](https://yuzu-emu.org/donate/) for more information on how you can contribute to yuzu. Any donations received will go towards things like:
* Switch consoles to explore and reverse-engineer the hardware
* Switch games for testing, reverse-engineering, and implementing new features
* Web hosting and infrastructure setup
diff --git a/externals/ffmpeg b/externals/ffmpeg
new file mode 160000
+Subproject 6b6b9e593dd4d3aaf75f48d40a13ef03bdef9fd
diff --git a/externals/find-modules/FindFFmpeg.cmake b/externals/find-modules/FindFFmpeg.cmake
index 77b331e00..61b6dc8d2 100644
--- a/externals/find-modules/FindFFmpeg.cmake
+++ b/externals/find-modules/FindFFmpeg.cmake
@@ -1,100 +1,187 @@
-# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil)
-# Once done this will define
+# FindFFmpeg
+# ----------
#
-# FFMPEG_FOUND - system has ffmpeg or libav
-# FFMPEG_INCLUDE_DIR - the ffmpeg include directory
-# FFMPEG_LIBRARIES - Link these to use ffmpeg
-# FFMPEG_LIBAVCODEC
-# FFMPEG_LIBAVFORMAT
-# FFMPEG_LIBAVUTIL
+# Copyright 2019 Citra Emulator Project
+# Licensed under GPLv2 or any later version
#
-# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org>
-# Modified for other libraries by Lasse Kärkkäinen <tronic>
-# Modified for Hedgewars by Stepik777
-# Modified for FFmpeg-example Tuukka Pasanen 2018
-# Modified for yuzu toastUnlimted 2020
+# Find the native FFmpeg includes and libraries
#
-# Redistribution and use is allowed according to the terms of the New
-# BSD license.
+# This module defines the following variables:
+#
+# FFmpeg_INCLUDE_<component>: where to find <component>.h
+# FFmpeg_LIBRARY_<component>: where to find the <component> library
+# FFmpeg_INCLUDE_DIR: aggregate all the include paths
+# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
+# FFmpeg_FOUND: True if all components have been found
+#
+# This module defines the following targets, which are prefered over variables:
+#
+# FFmpeg::<component>: Target to use <component> directly, with include path,
+# library and dependencies set up. If you are using a static build, you are
+# responsible for adding any external dependencies (such as zlib, bzlib...).
+#
+# <component> can be one of:
+# avcodec
+# avdevice
+# avfilter
+# avformat
+# avutil
+# postproc
+# swresample
+# swscale
#
-include(FindPackageHandleStandardArgs)
-
-find_package_handle_standard_args(FFMPEG
- FOUND_VAR FFMPEG_FOUND
- REQUIRED_VARS
- FFMPEG_LIBRARY
- FFMPEG_INCLUDE_DIR
- VERSION_VAR FFMPEG_VERSION
+set(_FFmpeg_ALL_COMPONENTS
+ avcodec
+ avdevice
+ avfilter
+ avformat
+ avutil
+ postproc
+ swresample
+ swscale
)
-if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR)
- # in cache already
- set(FFMPEG_FOUND TRUE)
-else()
- # use pkg-config to get the directories and then use these values
- # in the FIND_PATH() and FIND_LIBRARY() calls
- find_package(PkgConfig)
- if(PKG_CONFIG_FOUND)
- pkg_check_modules(_FFMPEG_AVCODEC libavcodec)
- pkg_check_modules(_FFMPEG_AVUTIL libavutil)
- pkg_check_modules(_FFMPEG_SWSCALE libswscale)
+set(_FFmpeg_DEPS_avcodec avutil)
+set(_FFmpeg_DEPS_avdevice avcodec avformat avutil)
+set(_FFmpeg_DEPS_avfilter avutil)
+set(_FFmpeg_DEPS_avformat avcodec avutil)
+set(_FFmpeg_DEPS_postproc avutil)
+set(_FFmpeg_DEPS_swresample avutil)
+set(_FFmpeg_DEPS_swscale avutil)
+
+function(find_ffmpeg LIBNAME)
+ if(DEFINED ENV{FFMPEG_DIR})
+ set(FFMPEG_DIR $ENV{FFMPEG_DIR})
endif()
- find_path(FFMPEG_AVCODEC_INCLUDE_DIR
- NAMES libavcodec/avcodec.h
- PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS}
- /usr/include
- /usr/local/include
- /opt/local/include
- /sw/include
- PATH_SUFFIXES ffmpeg libav)
-
- find_library(FFMPEG_LIBAVCODEC
- NAMES avcodec
- PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS}
- /usr/lib
- /usr/local/lib
- /opt/local/lib
- /sw/lib)
+ if(FFMPEG_DIR)
+ list(APPEND INCLUDE_PATHS
+ ${FFMPEG_DIR}
+ ${FFMPEG_DIR}/ffmpeg
+ ${FFMPEG_DIR}/lib${LIBNAME}
+ ${FFMPEG_DIR}/include/lib${LIBNAME}
+ ${FFMPEG_DIR}/include/ffmpeg
+ ${FFMPEG_DIR}/include
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH
+ )
+ list(APPEND LIB_PATHS
+ ${FFMPEG_DIR}
+ ${FFMPEG_DIR}/lib
+ ${FFMPEG_DIR}/lib${LIBNAME}
+ NO_DEFAULT_PATH
+ NO_CMAKE_FIND_ROOT_PATH
+ )
+ else()
+ list(APPEND INCLUDE_PATHS
+ /usr/local/include/ffmpeg
+ /usr/local/include/lib${LIBNAME}
+ /usr/include/ffmpeg
+ /usr/include/lib${LIBNAME}
+ /usr/include/ffmpeg/lib${LIBNAME}
+ )
- find_library(FFMPEG_LIBAVUTIL
- NAMES avutil
- PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
- /usr/lib
+ list(APPEND LIB_PATHS
/usr/local/lib
- /opt/local/lib
- /sw/lib)
-
- find_library(FFMPEG_LIBSWSCALE
- NAMES swscale
- PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS}
/usr/lib
- /usr/local/lib
- /opt/local/lib
- /sw/lib)
-
- if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVUTIL AND FFMPEG_LIBSWSCALE)
- set(FFMPEG_FOUND TRUE)
+ )
endif()
- if(FFMPEG_FOUND)
- set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR})
- set(FFMPEG_LIBRARIES
- ${FFMPEG_LIBAVCODEC}
- ${FFMPEG_LIBAVUTIL}
- ${FFMPEG_LIBSWSCALE})
+ find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
+ HINTS ${INCLUDE_PATHS}
+ )
+
+ find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
+ HINTS ${LIB_PATHS}
+ )
+
+ if(NOT FFMPEG_DIR AND (NOT FFmpeg_LIBRARY_${LIBNAME} OR NOT FFmpeg_INCLUDE_${LIBNAME}))
+ # Didn't find it in the usual paths, try pkg-config
+ find_package(PkgConfig QUIET)
+ pkg_check_modules(FFmpeg_PKGCONFIG_${LIBNAME} QUIET lib${LIBNAME})
+
+ find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
+ ${FFmpeg_PKGCONFIG_${LIBNAME}_INCLUDE_DIRS}
+ )
+
+ find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
+ ${FFmpeg_PKGCONFIG_${LIBNAME}_LIBRARY_DIRS}
+ )
endif()
- if(FFMPEG_FOUND)
- if(NOT FFMPEG_FIND_QUIETLY)
- message(STATUS
- "Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}")
+ if(FFmpeg_INCLUDE_${LIBNAME} AND FFmpeg_LIBRARY_${LIBNAME})
+ set(FFmpeg_INCLUDE_${LIBNAME} "${FFmpeg_INCLUDE_${LIBNAME}}" PARENT_SCOPE)
+ set(FFmpeg_LIBRARY_${LIBNAME} "${FFmpeg_LIBRARY_${LIBNAME}}" PARENT_SCOPE)
+
+ # Extract FFmpeg version from version.h
+ foreach(v MAJOR MINOR MICRO)
+ set(FFmpeg_${LIBNAME}_VERSION_${v} 0)
+ endforeach()
+ string(TOUPPER ${LIBNAME} LIBNAME_UPPER)
+ file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version.h" _FFmpeg_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_(MAJOR|MINOR|MICRO) ")
+ set(_FFmpeg_VERSION_REGEX "([0-9]+)")
+ foreach(v MAJOR MINOR MICRO)
+ if("${_FFmpeg_VERSION_H_CONTENTS}" MATCHES "#define LIB${LIBNAME_UPPER}_VERSION_${v}[\\t ]+${_FFmpeg_VERSION_REGEX}")
+ set(FFmpeg_${LIBNAME}_VERSION_${v} "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+ set(FFmpeg_${LIBNAME}_VERSION "${FFmpeg_${LIBNAME}_VERSION_MAJOR}.${FFmpeg_${LIBNAME}_VERSION_MINOR}.${FFmpeg_${LIBNAME}_VERSION_MICRO}")
+ set(FFmpeg_${c}_VERSION "${FFmpeg_${LIBNAME}_VERSION}" PARENT_SCOPE)
+ unset(_FFmpeg_VERSION_REGEX)
+ unset(_FFmpeg_VERSION_H_CONTENTS)
+
+ set(FFmpeg_${c}_FOUND TRUE PARENT_SCOPE)
+ if(NOT FFmpeg_FIND_QUIETLY)
+ message("-- Found ${LIBNAME}: ${FFmpeg_INCLUDE_${LIBNAME}} ${FFmpeg_LIBRARY_${LIBNAME}} (version: ${FFmpeg_${LIBNAME}_VERSION})")
endif()
- else()
- if(FFMPEG_FIND_REQUIRED)
- message(FATAL_ERROR
- "Could not find libavcodec or libavutil or libswscale")
+ endif()
+endfunction()
+
+foreach(c ${_FFmpeg_ALL_COMPONENTS})
+ find_ffmpeg(${c})
+endforeach()
+
+foreach(c ${_FFmpeg_ALL_COMPONENTS})
+ if(FFmpeg_${c}_FOUND)
+ list(APPEND FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_${c}})
+ list(APPEND FFmpeg_LIBRARIES ${FFmpeg_LIBRARY_${c}})
+
+ add_library(FFmpeg::${c} IMPORTED UNKNOWN)
+ set_target_properties(FFmpeg::${c} PROPERTIES
+ IMPORTED_LOCATION ${FFmpeg_LIBRARY_${c}}
+ INTERFACE_INCLUDE_DIRECTORIES ${FFmpeg_INCLUDE_${c}}
+ )
+ if(_FFmpeg_DEPS_${c})
+ set(deps)
+ foreach(dep ${_FFmpeg_DEPS_${c}})
+ list(APPEND deps FFmpeg::${dep})
+ endforeach()
+
+ set_target_properties(FFmpeg::${c} PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${deps}"
+ )
+ unset(deps)
endif()
endif()
+endforeach()
+
+if(FFmpeg_INCLUDE_DIR)
+ list(REMOVE_DUPLICATES FFmpeg_INCLUDE_DIR)
endif()
+
+foreach(c ${FFmpeg_FIND_COMPONENTS})
+ list(APPEND _FFmpeg_REQUIRED_VARS FFmpeg_INCLUDE_${c} FFmpeg_LIBRARY_${c})
+endforeach()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FFmpeg
+ REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS}
+ HANDLE_COMPONENTS
+)
+
+foreach(c ${_FFmpeg_ALL_COMPONENTS})
+ unset(_FFmpeg_DEPS_${c})
+endforeach()
+unset(_FFmpeg_ALL_COMPONENTS)
+unset(_FFmpeg_REQUIRED_VARS)
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 5b0b285cd..b0f6f0c34 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -111,7 +111,14 @@ void Stream::PlayNextBuffer(std::chrono::nanoseconds ns_late) {
sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
- core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer) - ns_late, release_event, {});
+ const auto buffer_release_ns = GetBufferReleaseNS(*active_buffer);
+
+ // If ns_late is higher than the update rate ignore the delay
+ if (ns_late > buffer_release_ns) {
+ ns_late = {};
+ }
+
+ core_timing.ScheduleEvent(buffer_release_ns - ns_late, release_event, {});
}
void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) {
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index bfd11e76d..263c457cd 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -206,6 +206,8 @@ if (MSVC)
else()
target_compile_options(common PRIVATE
-Werror
+
+ $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
)
endif()
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 4cba2aaa4..7b614ad89 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -141,27 +141,13 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
}
std::string UTF16ToUTF8(const std::u16string& input) {
-#ifdef _MSC_VER
- // Workaround for missing char16_t/char32_t instantiations in MSVC2017
- std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
- std::basic_string<__int16> tmp_buffer(input.cbegin(), input.cend());
- return convert.to_bytes(tmp_buffer);
-#else
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.to_bytes(input);
-#endif
}
std::u16string UTF8ToUTF16(const std::string& input) {
-#ifdef _MSC_VER
- // Workaround for missing char16_t/char32_t instantiations in MSVC2017
- std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
- auto tmp_buffer = convert.from_bytes(input);
- return std::u16string(tmp_buffer.cbegin(), tmp_buffer.cend());
-#else
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.from_bytes(input);
-#endif
}
#ifdef _WIN32
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 386d7bddf..987076956 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -653,6 +653,8 @@ else()
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
+ $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
+
-Wno-sign-conversion
)
endif()
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index 3022438b1..79b209c6b 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -121,6 +121,10 @@ void SoftwareKeyboard::ExecuteInteractive() {
std::memcpy(&request, data.data(), sizeof(Request));
switch (request) {
+ case Request::Finalize:
+ complete = true;
+ broker.SignalStateChanged();
+ break;
case Request::Calc: {
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1}));
broker.SignalStateChanged();
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 51a010a55..1e2677320 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -110,6 +110,7 @@ void IAppletResource::DeactivateController(HidController controller) {
IAppletResource ::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
+ system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
}
void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
index 4440135ed..e2ac71fa1 100644
--- a/src/core/hle/service/olsc/olsc.cpp
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -17,7 +17,7 @@ public:
static const FunctionInfo functions[] = {
{0, &OLSC::Initialize, "Initialize"},
{10, nullptr, "VerifySaveDataBackupLicenseAsync"},
- {13, nullptr, "GetSaveDataBackupSetting"},
+ {13, &OLSC::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
{14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
{15, nullptr, "SetCustomData"},
{16, nullptr, "DeleteSaveDataBackupSetting"},
@@ -52,6 +52,17 @@ private:
rb.Push(RESULT_SUCCESS);
}
+ void GetSaveDataBackupSetting(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_OLSC, "(STUBBED) called");
+
+ // backup_setting is set to 0 since real value is unknown
+ constexpr u64 backup_setting = 0;
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(backup_setting);
+ }
+
void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_OLSC, "(STUBBED) called");
diff --git a/src/core/settings.h b/src/core/settings.h
index a324530bd..d849dded3 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -181,12 +181,13 @@ struct Values {
std::string motion_device;
std::string udp_input_servers;
- bool emulate_analog_keyboard;
-
+ bool mouse_panning;
+ float mouse_panning_sensitivity;
bool mouse_enabled;
std::string mouse_device;
MouseButtonsRaw mouse_buttons;
+ bool emulate_analog_keyboard;
bool keyboard_enabled;
KeyboardKeysRaw keyboard_keys;
KeyboardModsRaw keyboard_mods;
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp
index 10786a541..67a584d53 100644
--- a/src/input_common/mouse/mouse_input.cpp
+++ b/src/input_common/mouse/mouse_input.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
+#include "core/settings.h"
#include "input_common/mouse/mouse_input.h"
namespace MouseInput {
@@ -36,6 +37,9 @@ void Mouse::UpdateThread() {
if (configuring) {
UpdateYuzuSettings();
}
+ if (mouse_panning_timout++ > 8) {
+ StopPanning();
+ }
std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
}
}
@@ -65,8 +69,34 @@ void Mouse::PressButton(int x, int y, int button_) {
mouse_info[button_index].data.pressed = true;
}
-void Mouse::MouseMove(int x, int y) {
+void Mouse::StopPanning() {
+ for (MouseInfo& info : mouse_info) {
+ if (Settings::values.mouse_panning) {
+ info.data.axis = {};
+ info.tilt_speed = 0;
+ info.last_mouse_change = {};
+ }
+ }
+}
+
+void Mouse::MouseMove(int x, int y, int center_x, int center_y) {
for (MouseInfo& info : mouse_info) {
+ if (Settings::values.mouse_panning) {
+ const auto mouse_change = Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y);
+ mouse_panning_timout = 0;
+
+ if (mouse_change.y == 0 && mouse_change.x == 0) {
+ continue;
+ }
+
+ info.last_mouse_change = (info.last_mouse_change * 0.8f) + (mouse_change * 0.2f);
+ info.data.axis = {static_cast<int>(16 * info.last_mouse_change.x),
+ static_cast<int>(16 * -info.last_mouse_change.y)};
+ info.tilt_direction = info.last_mouse_change;
+ info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity;
+ continue;
+ }
+
if (info.data.pressed) {
const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin;
const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position;
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h
index 58803c1bf..46aa676c1 100644
--- a/src/input_common/mouse/mouse_input.h
+++ b/src/input_common/mouse/mouse_input.h
@@ -57,8 +57,10 @@ public:
* Signals that mouse has moved.
* @param x the x-coordinate of the cursor
* @param y the y-coordinate of the cursor
+ * @param center_x the x-coordinate of the middle of the screen
+ * @param center_y the y-coordinate of the middle of the screen
*/
- void MouseMove(int x, int y);
+ void MouseMove(int x, int y, int center_x, int center_y);
/**
* Signals that a motion sensor tilt has ended.
@@ -74,11 +76,13 @@ public:
private:
void UpdateThread();
void UpdateYuzuSettings();
+ void StopPanning();
struct MouseInfo {
InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
Common::Vec2<int> mouse_origin;
Common::Vec2<int> last_mouse_position;
+ Common::Vec2<float> last_mouse_change;
bool is_tilting = false;
float sensitivity{0.120f};
@@ -94,5 +98,6 @@ private:
Common::SPSCQueue<MouseStatus> mouse_queue;
bool configuring{false};
bool update_thread_running{true};
+ int mouse_panning_timout{};
};
} // namespace MouseInput
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index 3d799b293..bb56787ee 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -6,6 +6,7 @@
#include <utility>
#include "common/threadsafe_queue.h"
+#include "core/settings.h"
#include "input_common/mouse/mouse_input.h"
#include "input_common/mouse/mouse_poller.h"
@@ -71,7 +72,7 @@ public:
std::lock_guard lock{mutex};
const auto axis_value =
static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
- return axis_value / (100.0f * range);
+ return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range);
}
std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index e7e50d789..c4afa4174 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -144,6 +144,10 @@ Client::~Client() {
Reset();
}
+Client::ClientData::ClientData() = default;
+
+Client::ClientData::~ClientData() = default;
+
std::vector<Common::ParamPackage> Client::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
for (std::size_t client = 0; client < clients.size(); client++) {
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h
index 822f9c550..a523f6124 100644
--- a/src/input_common/udp/client.h
+++ b/src/input_common/udp/client.h
@@ -98,6 +98,9 @@ public:
private:
struct ClientData {
+ ClientData();
+ ~ClientData();
+
std::string host{"127.0.0.1"};
u16 port{26760};
std::size_t pad_index{};
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp
index b630281a0..9829da6f0 100644
--- a/src/input_common/udp/udp.cpp
+++ b/src/input_common/udp/udp.cpp
@@ -84,8 +84,8 @@ public:
private:
const std::string ip;
- const u16 port;
- const u16 pad;
+ [[maybe_unused]] const u16 port;
+ [[maybe_unused]] const u16 pad;
CemuhookUDP::Client* client;
mutable std::mutex mutex;
};
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 2cf95937e..dd4c29ed3 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -271,14 +271,13 @@ create_target_directory_groups(video_core)
target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PRIVATE glad xbyak)
-if (MSVC)
- target_include_directories(video_core PRIVATE ${FFMPEG_INCLUDE_DIR})
- target_link_libraries(video_core PUBLIC ${FFMPEG_LIBRARY_DIR}/swscale.lib ${FFMPEG_LIBRARY_DIR}/avcodec.lib ${FFMPEG_LIBRARY_DIR}/avutil.lib)
-else()
- target_include_directories(video_core PRIVATE ${FFMPEG_INCLUDE_DIR})
- target_link_libraries(video_core PRIVATE ${FFMPEG_LIBRARIES})
+if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32)
+ add_dependencies(video_core ffmpeg-build)
endif()
+target_include_directories(video_core PRIVATE ${FFmpeg_INCLUDE_DIR})
+target_link_libraries(video_core PRIVATE ${FFmpeg_LIBRARIES})
+
add_dependencies(video_core host_shaders)
target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 8aa63d329..ea4ca9a82 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -67,9 +67,6 @@ constexpr size_t TOTAL_CONST_BUFFER_BYTES =
constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
constexpr size_t NUM_SUPPORTED_VERTEX_BINDINGS = 16;
-constexpr size_t MAX_TEXTURES = 192;
-constexpr size_t MAX_IMAGES = 48;
-
struct TextureHandle {
constexpr TextureHandle(u32 data, bool via_header_index) {
const Tegra::Texture::TextureHandle handle{data};
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index bb2cdef81..a0bc1f7b6 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -169,40 +169,6 @@ template <u32 GOB_EXTENT>
return Common::DivCeil(AdjustMipSize(size, level), block_size);
}
-[[nodiscard]] constexpr u32 LayerSize(const TICEntry& config, PixelFormat format) {
- return config.Width() * config.Height() * BytesPerBlock(format);
-}
-
-[[nodiscard]] constexpr bool HasTwoDimsPerLayer(TextureType type) {
- switch (type) {
- case TextureType::Texture2D:
- case TextureType::Texture2DArray:
- case TextureType::Texture2DNoMipmap:
- case TextureType::Texture3D:
- case TextureType::TextureCubeArray:
- case TextureType::TextureCubemap:
- return true;
- case TextureType::Texture1D:
- case TextureType::Texture1DArray:
- case TextureType::Texture1DBuffer:
- return false;
- }
- return false;
-}
-
-[[nodiscard]] constexpr bool HasTwoDimsPerLayer(ImageType type) {
- switch (type) {
- case ImageType::e2D:
- case ImageType::e3D:
- case ImageType::Linear:
- return true;
- case ImageType::e1D:
- case ImageType::Buffer:
- return false;
- }
- UNREACHABLE_MSG("Invalid image type={}", static_cast<int>(type));
-}
-
[[nodiscard]] constexpr std::pair<int, int> Samples(int num_samples) {
switch (num_samples) {
case 1:
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index ffdf34a4a..d9a3035cb 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -405,12 +405,17 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
return;
}
-
auto pos = event->pos();
const auto [x, y] = ScaleTouch(pos);
- input_subsystem->GetMouse()->MouseMove(x, y);
+ const int center_x = width() / 2;
+ const int center_y = height() / 2;
+ input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y);
this->TouchMoved(x, y, 0);
+ if (Settings::values.mouse_panning) {
+ QCursor::setPos(mapToGlobal({center_x, center_y}));
+ }
+
emit MouseActivity();
}
@@ -714,6 +719,11 @@ void GRenderWindow::showEvent(QShowEvent* event) {
bool GRenderWindow::eventFilter(QObject* object, QEvent* event) {
if (event->type() == QEvent::HoverMove) {
+ if (Settings::values.mouse_panning) {
+ auto* hover_event = static_cast<QMouseEvent*>(event);
+ mouseMoveEvent(hover_event);
+ return false;
+ }
emit MouseActivity();
}
return false;
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 8d85a1986..8f7458119 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -220,7 +220,7 @@ const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default
// This must be in alphabetical order according to action name as it must have the same order as
// UISetting::values.shortcuts, which is alphabetically ordered.
// clang-format off
-const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{
+const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::ApplicationShortcut}},
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
@@ -235,6 +235,7 @@ const std::array<UISettings::Shortcut, 16> Config::default_hotkeys{{
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
+ {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}},
}};
@@ -507,6 +508,9 @@ void Config::ReadControlValues() {
Settings::values.emulate_analog_keyboard =
ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool();
+ Settings::values.mouse_panning = ReadSetting(QStringLiteral("mouse_panning"), false).toBool();
+ Settings::values.mouse_panning_sensitivity =
+ ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
ReadSettingGlobal(Settings::values.use_docked_mode, QStringLiteral("use_docked_mode"), true);
ReadSettingGlobal(Settings::values.vibration_enabled, QStringLiteral("vibration_enabled"),
@@ -1184,7 +1188,9 @@ void Config::SaveControlValues() {
WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
WriteSetting(QStringLiteral("emulate_analog_keyboard"),
Settings::values.emulate_analog_keyboard, false);
-
+ WriteSetting(QStringLiteral("mouse_panning"), Settings::values.mouse_panning, false);
+ WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
+ Settings::values.mouse_panning_sensitivity, 1.0f);
qt_config->endGroup();
}
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 8a600e19d..949c4eb13 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -42,7 +42,7 @@ public:
default_mouse_buttons;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
- static const std::array<UISettings::Shortcut, 16> default_hotkeys;
+ static const std::array<UISettings::Shortcut, 17> default_hotkeys;
private:
void Initialize(const std::string& config_name);
diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp
index 4e557bc6f..a1a0eb676 100644
--- a/src/yuzu/configuration/configure_input_advanced.cpp
+++ b/src/yuzu/configuration/configure_input_advanced.cpp
@@ -122,6 +122,9 @@ void ConfigureInputAdvanced::ApplyConfiguration() {
Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
Settings::values.emulate_analog_keyboard = ui->emulate_analog_keyboard->isChecked();
+ Settings::values.mouse_panning = ui->mouse_panning->isChecked();
+ Settings::values.mouse_panning_sensitivity =
+ static_cast<float>(ui->mouse_panning_sensitivity->value());
Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
}
@@ -149,6 +152,8 @@ void ConfigureInputAdvanced::LoadConfiguration() {
ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
ui->emulate_analog_keyboard->setChecked(Settings::values.emulate_analog_keyboard);
+ ui->mouse_panning->setChecked(Settings::values.mouse_panning);
+ ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity);
ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
UpdateUIEnabled();
diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui
index f207e5d3b..173130d8d 100644
--- a/src/yuzu/configuration/configure_input_advanced.ui
+++ b/src/yuzu/configuration/configure_input_advanced.ui
@@ -2546,27 +2546,65 @@
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QCheckBox" name="emulate_analog_keyboard">
- <property name="minimumSize">
- <size>
- <width>0</width>
- <height>23</height>
- </size>
- </property>
- <property name="text">
- <string>Emulate Analog with Keyboard Input</string>
- </property>
- </widget>
- </item>
- <item row="5" column="2">
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="emulate_analog_keyboard">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Emulate Analog with Keyboard Input</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="mouse_panning">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>23</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Enable mouse panning</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QDoubleSpinBox" name="mouse_panning_sensitivity">
+ <property name="toolTip">
+ <string>Mouse sensitivity</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="decimals">
+ <number>2</number>
+ </property>
+ <property name="minimum">
+ <double>0.100000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>16.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>0.010000000000000</double>
+ </property>
+ <property name="value">
+ <double>1.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="2">
<widget class="QPushButton" name="touchscreen_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -2582,21 +2620,21 @@
</property>
</spacer>
</item>
- <item row="2" column="2">
+ <item row="3" column="2">
<widget class="QPushButton" name="mouse_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
- <item row="5" column="0">
+ <item row="6" column="0">
<widget class="QCheckBox" name="touchscreen_enabled">
<property name="text">
<string>Touchscreen</string>
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QCheckBox" name="mouse_enabled">
<property name="minimumSize">
<size>
@@ -2609,28 +2647,28 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="8" column="0">
<widget class="QLabel" name="motion_touch">
<property name="text">
<string>Motion / Touch</string>
</property>
</widget>
</item>
- <item row="7" column="2">
+ <item row="8" column="2">
<widget class="QPushButton" name="buttonMotionTouch">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="7" column="0">
<widget class="QCheckBox" name="debug_enabled">
<property name="text">
<string>Debug Controller</string>
</property>
</widget>
</item>
- <item row="6" column="2">
+ <item row="7" column="2">
<widget class="QPushButton" name="debug_configure">
<property name="text">
<string>Configure</string>
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index e3e8bde48..0e8a964d2 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -37,7 +37,8 @@ void PlayerControlPreview::SetPlayerInput(std::size_t index, const ButtonParam&
Input::CreateDevice<Input::AnalogDevice>);
UpdateColors();
}
-void PlayerControlPreview::SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw buttons_,
+void PlayerControlPreview::SetPlayerInputRaw(std::size_t index,
+ const Settings::ButtonsRaw& buttons_,
Settings::AnalogsRaw analogs_) {
player_index = index;
std::transform(buttons_.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
@@ -517,14 +518,15 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
{
// Draw joysticks
using namespace Settings::NativeAnalog;
- DrawJoystick(p, center + QPointF(-65, -65) + (axis_values[LStick].value * 7), 1.62f,
- button_values[Settings::NativeButton::LStick]);
- DrawJoystick(p, center + QPointF(65, 12) + (axis_values[RStick].value * 7), 1.62f,
- button_values[Settings::NativeButton::RStick]);
- DrawRawJoystick(p, center + QPointF(-180, 90), axis_values[LStick].raw_value,
- axis_values[LStick].properties);
- DrawRawJoystick(p, center + QPointF(180, 90), axis_values[RStick].raw_value,
- axis_values[RStick].properties);
+ const auto& l_stick = axis_values[LStick];
+ const auto l_button = button_values[Settings::NativeButton::LStick];
+ const auto& r_stick = axis_values[RStick];
+ const auto r_button = button_values[Settings::NativeButton::RStick];
+
+ DrawJoystick(p, center + QPointF(-65, -65) + (l_stick.value * 7), 1.62f, l_button);
+ DrawJoystick(p, center + QPointF(65, 12) + (r_stick.value * 7), 1.62f, r_button);
+ DrawRawJoystick(p, center + QPointF(-180, 90), l_stick.raw_value, l_stick.properties);
+ DrawRawJoystick(p, center + QPointF(180, 90), r_stick.raw_value, r_stick.properties);
}
using namespace Settings::NativeButton;
@@ -603,14 +605,15 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
{
// Draw joysticks
using namespace Settings::NativeAnalog;
- DrawJoystick(p, center + QPointF(-171, -41) + (axis_values[LStick].value * 4), 1.0f,
- button_values[Settings::NativeButton::LStick]);
- DrawJoystick(p, center + QPointF(171, 8) + (axis_values[RStick].value * 4), 1.0f,
- button_values[Settings::NativeButton::RStick]);
- DrawRawJoystick(p, center + QPointF(-50, 0), axis_values[LStick].raw_value,
- axis_values[LStick].properties);
- DrawRawJoystick(p, center + QPointF(50, 0), axis_values[RStick].raw_value,
- axis_values[RStick].properties);
+ const auto& l_stick = axis_values[LStick];
+ const auto l_button = button_values[Settings::NativeButton::LStick];
+ const auto& r_stick = axis_values[RStick];
+ const auto r_button = button_values[Settings::NativeButton::RStick];
+
+ DrawJoystick(p, center + QPointF(-171, -41) + (l_stick.value * 4), 1.0f, l_button);
+ DrawJoystick(p, center + QPointF(171, 8) + (r_stick.value * 4), 1.0f, r_button);
+ DrawRawJoystick(p, center + QPointF(-50, 0), l_stick.raw_value, l_stick.properties);
+ DrawRawJoystick(p, center + QPointF(50, 0), r_stick.raw_value, r_stick.properties);
}
using namespace Settings::NativeButton;
@@ -699,9 +702,9 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center)
{
// Draw joysticks
using namespace Settings::NativeAnalog;
- DrawProJoystick(p, center + QPointF(-111, -55) + (axis_values[LStick].value * 11),
+ DrawProJoystick(p, center + QPointF(-111, -55), axis_values[LStick].value, 11,
button_values[Settings::NativeButton::LStick]);
- DrawProJoystick(p, center + QPointF(51, 0) + (axis_values[RStick].value * 11),
+ DrawProJoystick(p, center + QPointF(51, 0), axis_values[RStick].value, 11,
button_values[Settings::NativeButton::RStick]);
DrawRawJoystick(p, center + QPointF(-50, 105), axis_values[LStick].raw_value,
axis_values[LStick].properties);
@@ -1002,12 +1005,6 @@ constexpr std::array<float, 3 * 2> up_arrow_symbol = {
0.0f, -3.0f, -3.0f, 2.0f, 3.0f, 2.0f,
};
-constexpr std::array<float, 13 * 2> up_arrow = {
- 9.4f, -9.8f, 9.4f, -10.2f, 8.9f, -29.8f, 8.5f, -30.0f, 8.1f,
- -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f, -29.8f, -9.3f, -29.5f,
- -9.5f, -29.1f, -9.5f, -28.7f, -9.1f, -9.1f, -8.8f, -8.8f,
-};
-
constexpr std::array<float, 64 * 2> trigger_button = {
5.5f, -12.6f, 5.8f, -12.6f, 6.7f, -12.5f, 8.1f, -12.3f, 8.6f, -12.2f, 9.2f, -12.0f,
9.5f, -11.9f, 9.9f, -11.8f, 10.6f, -11.5f, 11.0f, -11.3f, 11.2f, -11.2f, 11.4f, -11.1f,
@@ -1457,15 +1454,18 @@ void PlayerControlPreview::DrawProBody(QPainter& p, const QPointF center) {
constexpr int radius1 = 32;
for (std::size_t point = 0; point < pro_left_handle.size() / 2; ++point) {
- qleft_handle[point] =
- center + QPointF(pro_left_handle[point * 2], pro_left_handle[point * 2 + 1]);
- qright_handle[point] =
- center + QPointF(-pro_left_handle[point * 2], pro_left_handle[point * 2 + 1]);
+ const float left_x = pro_left_handle[point * 2 + 0];
+ const float left_y = pro_left_handle[point * 2 + 1];
+
+ qleft_handle[point] = center + QPointF(left_x, left_y);
+ qright_handle[point] = center + QPointF(-left_x, left_y);
}
for (std::size_t point = 0; point < pro_body.size() / 2; ++point) {
- qbody[point] = center + QPointF(pro_body[point * 2], pro_body[point * 2 + 1]);
- qbody[pro_body.size() - 1 - point] =
- center + QPointF(-pro_body[point * 2], pro_body[point * 2 + 1]);
+ const float body_x = pro_body[point * 2 + 0];
+ const float body_y = pro_body[point * 2 + 1];
+
+ qbody[point] = center + QPointF(body_x, body_y);
+ qbody[pro_body.size() - 1 - point] = center + QPointF(-body_x, body_y);
}
// Draw left handle body
@@ -1496,21 +1496,25 @@ void PlayerControlPreview::DrawGCBody(QPainter& p, const QPointF center) {
constexpr float angle = 2 * 3.1415f / 8;
for (std::size_t point = 0; point < gc_left_body.size() / 2; ++point) {
- qleft_handle[point] =
- center + QPointF(gc_left_body[point * 2], gc_left_body[point * 2 + 1]);
- qright_handle[point] =
- center + QPointF(-gc_left_body[point * 2], gc_left_body[point * 2 + 1]);
+ const float body_x = gc_left_body[point * 2 + 0];
+ const float body_y = gc_left_body[point * 2 + 1];
+
+ qleft_handle[point] = center + QPointF(body_x, body_y);
+ qright_handle[point] = center + QPointF(-body_x, body_y);
}
for (std::size_t point = 0; point < gc_body.size() / 2; ++point) {
- qbody[point] = center + QPointF(gc_body[point * 2], gc_body[point * 2 + 1]);
- qbody[gc_body.size() - 1 - point] =
- center + QPointF(-gc_body[point * 2], gc_body[point * 2 + 1]);
+ const float body_x = gc_body[point * 2 + 0];
+ const float body_y = gc_body[point * 2 + 1];
+
+ qbody[point] = center + QPointF(body_x, body_y);
+ qbody[gc_body.size() - 1 - point] = center + QPointF(-body_x, body_y);
}
for (std::size_t point = 0; point < 8; ++point) {
- left_hex[point] =
- center + QPointF(34 * std::cos(point * angle) - 111, 34 * std::sin(point * angle) - 44);
- right_hex[point] =
- center + QPointF(26 * std::cos(point * angle) + 61, 26 * std::sin(point * angle) + 37);
+ const float point_cos = std::cos(point * angle);
+ const float point_sin = std::sin(point * angle);
+
+ left_hex[point] = center + QPointF(34 * point_cos - 111, 34 * point_sin - 44);
+ right_hex[point] = center + QPointF(26 * point_cos + 61, 26 * point_sin + 37);
}
// Draw body
@@ -1631,32 +1635,36 @@ void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) {
constexpr float offset = 209.3f;
for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) {
- left_joycon[point] = center + QPointF(left_joycon_body[point * 2] * size + offset,
- left_joycon_body[point * 2 + 1] * size - 1);
- right_joycon[point] = center + QPointF(-left_joycon_body[point * 2] * size - offset,
- left_joycon_body[point * 2 + 1] * size - 1);
+ const float body_x = left_joycon_body[point * 2 + 0];
+ const float body_y = left_joycon_body[point * 2 + 1];
+
+ left_joycon[point] = center + QPointF(body_x * size + offset, body_y * size - 1);
+ right_joycon[point] = center + QPointF(-body_x * size - offset, body_y * size - 1);
}
for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) {
- qleft_joycon_slider[point] =
- center + QPointF(left_joycon_slider[point * 2], left_joycon_slider[point * 2 + 1]);
- qright_joycon_slider[point] =
- center + QPointF(-left_joycon_slider[point * 2], left_joycon_slider[point * 2 + 1]);
+ const float slider_x = left_joycon_slider[point * 2 + 0];
+ const float slider_y = left_joycon_slider[point * 2 + 1];
+
+ qleft_joycon_slider[point] = center + QPointF(slider_x, slider_y);
+ qright_joycon_slider[point] = center + QPointF(-slider_x, slider_y);
}
for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) {
+ const float top_view_x = left_joycon_topview[point * 2 + 0];
+ const float top_view_y = left_joycon_topview[point * 2 + 1];
+
qleft_joycon_topview[point] =
- center + QPointF(left_joycon_topview[point * 2] * size2 - 52,
- left_joycon_topview[point * 2 + 1] * size2 - 52);
+ center + QPointF(top_view_x * size2 - 52, top_view_y * size2 - 52);
qright_joycon_topview[point] =
- center + QPointF(-left_joycon_topview[point * 2] * size2 + 52,
- left_joycon_topview[point * 2 + 1] * size2 - 52);
+ center + QPointF(-top_view_x * size2 + 52, top_view_y * size2 - 52);
}
for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) {
+ const float top_view_x = left_joycon_slider_topview[point * 2 + 0];
+ const float top_view_y = left_joycon_slider_topview[point * 2 + 1];
+
qleft_joycon_slider_topview[point] =
- center + QPointF(left_joycon_slider_topview[point * 2] * size2 - 52,
- left_joycon_slider_topview[point * 2 + 1] * size2 - 52);
+ center + QPointF(top_view_x * size2 - 52, top_view_y * size2 - 52);
qright_joycon_slider_topview[point] =
- center + QPointF(-left_joycon_slider_topview[point * 2] * size2 + 52,
- left_joycon_slider_topview[point * 2 + 1] * size2 - 52);
+ center + QPointF(-top_view_x * size2 + 52, top_view_y * size2 - 52);
}
// right joycon body
@@ -1905,18 +1913,19 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bo
std::array<QPointF, pro_body_top.size()> qbody_top;
for (std::size_t point = 0; point < pro_left_trigger.size() / 2; ++point) {
- qleft_trigger[point] =
- center + QPointF(pro_left_trigger[point * 2],
- pro_left_trigger[point * 2 + 1] + (left_pressed ? 2 : 0));
- qright_trigger[point] =
- center + QPointF(-pro_left_trigger[point * 2],
- pro_left_trigger[point * 2 + 1] + (right_pressed ? 2 : 0));
+ const float trigger_x = pro_left_trigger[point * 2 + 0];
+ const float trigger_y = pro_left_trigger[point * 2 + 1];
+
+ qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 2 : 0));
+ qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 2 : 0));
}
for (std::size_t point = 0; point < pro_body_top.size() / 2; ++point) {
- qbody_top[pro_body_top.size() - 1 - point] =
- center + QPointF(-pro_body_top[point * 2], pro_body_top[point * 2 + 1]);
- qbody_top[point] = center + QPointF(pro_body_top[point * 2], pro_body_top[point * 2 + 1]);
+ const float top_x = pro_body_top[point * 2 + 0];
+ const float top_y = pro_body_top[point * 2 + 1];
+
+ qbody_top[pro_body_top.size() - 1 - point] = center + QPointF(-top_x, top_y);
+ qbody_top[point] = center + QPointF(top_x, top_y);
}
// Pro body detail
@@ -1939,12 +1948,11 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, boo
std::array<QPointF, left_gc_trigger.size() / 2> qright_trigger;
for (std::size_t point = 0; point < left_gc_trigger.size() / 2; ++point) {
- qleft_trigger[point] =
- center + QPointF(left_gc_trigger[point * 2],
- left_gc_trigger[point * 2 + 1] + (left_pressed ? 10 : 0));
- qright_trigger[point] =
- center + QPointF(-left_gc_trigger[point * 2],
- left_gc_trigger[point * 2 + 1] + (right_pressed ? 10 : 0));
+ const float trigger_x = left_gc_trigger[point * 2 + 0];
+ const float trigger_y = left_gc_trigger[point * 2 + 1];
+
+ qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 10 : 0));
+ qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 10 : 0));
}
// Left trigger
@@ -1973,12 +1981,13 @@ void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF cente
std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger;
for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
+ const float left_trigger_x = left_joycon_trigger[point * 2 + 0];
+ const float left_trigger_y = left_joycon_trigger[point * 2 + 1];
+
qleft_trigger[point] =
- center + QPointF(left_joycon_trigger[point * 2],
- left_joycon_trigger[point * 2 + 1] + (left_pressed ? 0.5f : 0));
+ center + QPointF(left_trigger_x, left_trigger_y + (left_pressed ? 0.5f : 0));
qright_trigger[point] =
- center + QPointF(-left_joycon_trigger[point * 2],
- left_joycon_trigger[point * 2 + 1] + (right_pressed ? 0.5f : 0));
+ center + QPointF(-left_trigger_x, left_trigger_y + (right_pressed ? 0.5f : 0));
}
// Left trigger
@@ -1998,12 +2007,14 @@ void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, b
constexpr float size = 1.62f;
constexpr float offset = 210.6f;
for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
- qleft_trigger[point] =
- center + QPointF(left_joycon_trigger[point * 2] * size + offset,
- left_joycon_trigger[point * 2 + 1] * size + (left_pressed ? 0.5f : 0));
- qright_trigger[point] = center + QPointF(-left_joycon_trigger[point * 2] * size - offset,
- left_joycon_trigger[point * 2 + 1] * size +
- (right_pressed ? 0.5f : 0));
+ const float left_trigger_x = left_joycon_trigger[point * 2 + 0];
+ const float left_trigger_y = left_joycon_trigger[point * 2 + 1];
+
+ qleft_trigger[point] = center + QPointF(left_trigger_x * size + offset,
+ left_trigger_y * size + (left_pressed ? 0.5f : 0));
+ qright_trigger[point] =
+ center + QPointF(-left_trigger_x * size - offset,
+ left_trigger_y * size + (right_pressed ? 0.5f : 0));
}
// Left trigger
@@ -2023,13 +2034,16 @@ void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF ce
constexpr float size = 0.9f;
for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
- qleft_trigger[point] = center + QPointF(left_joystick_L_topview[point * 2] * size - 50,
- left_joystick_L_topview[point * 2 + 1] * size - 52);
+ const float top_view_x = left_joystick_L_topview[point * 2 + 0];
+ const float top_view_y = left_joystick_L_topview[point * 2 + 1];
+
+ qleft_trigger[point] = center + QPointF(top_view_x * size - 50, top_view_y * size - 52);
}
for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
- qright_trigger[point] =
- center + QPointF(-left_joystick_L_topview[point * 2] * size + 50,
- left_joystick_L_topview[point * 2 + 1] * size - 52);
+ const float top_view_x = left_joystick_L_topview[point * 2 + 0];
+ const float top_view_y = left_joystick_L_topview[point * 2 + 1];
+
+ qright_trigger[point] = center + QPointF(-top_view_x * size + 50, top_view_y * size - 52);
}
p.setPen(colors.outline);
@@ -2273,15 +2287,39 @@ void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF cente
p.drawLine(p2.at(32), p2.at(71));
}
-void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, bool pressed) {
+void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, const QPointF offset,
+ float offset_scalar, bool pressed) {
+ const float radius1 = 24.0f;
+ const float radius2 = 17.0f;
+
+ const QPointF offset_center = center + offset * offset_scalar;
+
+ const auto amplitude = static_cast<float>(
+ 1.0 - std::sqrt((offset.x() * offset.x()) + (offset.y() * offset.y())) * 0.1f);
+
+ const float rotation =
+ ((offset.x() == 0) ? atan(1) * 2 : atan(offset.y() / offset.x())) * (180 / (atan(1) * 4));
+
+ p.save();
+ p.translate(offset_center);
+ p.rotate(rotation);
+
// Outer circle
p.setPen(colors.outline);
p.setBrush(pressed ? colors.highlight : colors.button);
- DrawCircle(p, center, 24.0f);
+ p.drawEllipse(QPointF(0, 0), radius1 * amplitude, radius1);
// Inner circle
p.setBrush(pressed ? colors.highlight2 : colors.button2);
- DrawCircle(p, center, 17.0f);
+
+ const float inner_offset =
+ (radius1 - radius2) * 0.4f * ((offset.x() == 0 && offset.y() < 0) ? -1.0f : 1.0f);
+ const float offset_factor = (1.0f - amplitude) / 0.1f;
+
+ p.drawEllipse(QPointF((offset.x() < 0) ? -inner_offset : inner_offset, 0) * offset_factor,
+ radius2 * amplitude, radius2);
+
+ p.restore();
}
void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, bool pressed) {
@@ -2299,7 +2337,7 @@ void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, boo
}
void PlayerControlPreview::DrawRawJoystick(QPainter& p, const QPointF center, const QPointF value,
- const Input::AnalogProperties properties) {
+ const Input::AnalogProperties& properties) {
constexpr float size = 45.0f;
const float range = size * properties.range;
const float deadzone = size * properties.deadzone;
@@ -2422,17 +2460,16 @@ void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF cen
std::array<QPointF, (arrow_points - 1) * 4> arrow_button_outline;
for (std::size_t point = 0; point < arrow_points - 1; ++point) {
- arrow_button_outline[point] = center + QPointF(up_arrow_button[point * 2] * size,
- up_arrow_button[point * 2 + 1] * size);
+ const float up_arrow_x = up_arrow_button[point * 2 + 0];
+ const float up_arrow_y = up_arrow_button[point * 2 + 1];
+
+ arrow_button_outline[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
arrow_button_outline[(arrow_points - 1) * 2 - point - 1] =
- center +
- QPointF(up_arrow_button[point * 2 + 1] * size, up_arrow_button[point * 2] * size);
+ center + QPointF(up_arrow_y * size, up_arrow_x * size);
arrow_button_outline[(arrow_points - 1) * 2 + point] =
- center +
- QPointF(-up_arrow_button[point * 2] * size, -up_arrow_button[point * 2 + 1] * size);
+ center + QPointF(-up_arrow_x * size, -up_arrow_y * size);
arrow_button_outline[(arrow_points - 1) * 4 - point - 1] =
- center +
- QPointF(-up_arrow_button[point * 2 + 1] * size, -up_arrow_button[point * 2] * size);
+ center + QPointF(-up_arrow_y * size, -up_arrow_x * size);
}
// Draw arrow button outline
p.setPen(colors.outline);
@@ -2446,22 +2483,21 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
QPoint offset;
for (std::size_t point = 0; point < up_arrow_button.size() / 2; ++point) {
+ const float up_arrow_x = up_arrow_button[point * 2 + 0];
+ const float up_arrow_y = up_arrow_button[point * 2 + 1];
+
switch (direction) {
case Direction::Up:
- arrow_button[point] = center + QPointF(up_arrow_button[point * 2] * size,
- up_arrow_button[point * 2 + 1] * size);
+ arrow_button[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
break;
case Direction::Left:
- arrow_button[point] = center + QPointF(up_arrow_button[point * 2 + 1] * size,
- up_arrow_button[point * 2] * size);
+ arrow_button[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size);
break;
case Direction::Right:
- arrow_button[point] = center + QPointF(-up_arrow_button[point * 2 + 1] * size,
- up_arrow_button[point * 2] * size);
+ arrow_button[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size);
break;
case Direction::Down:
- arrow_button[point] = center + QPointF(up_arrow_button[point * 2] * size,
- -up_arrow_button[point * 2 + 1] * size);
+ arrow_button[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size);
break;
case Direction::None:
break;
@@ -2500,17 +2536,17 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center,
const Direction direction, bool pressed) {
std::array<QPointF, trigger_button.size() / 2> qtrigger_button;
- QPoint offset;
for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) {
+ const float trigger_button_x = trigger_button[point * 2 + 0];
+ const float trigger_button_y = trigger_button[point * 2 + 1];
+
switch (direction) {
case Direction::Left:
- qtrigger_button[point] =
- center + QPointF(-trigger_button[point * 2], trigger_button[point * 2 + 1]);
+ qtrigger_button[point] = center + QPointF(-trigger_button_x, trigger_button_y);
break;
case Direction::Right:
- qtrigger_button[point] =
- center + QPointF(trigger_button[point * 2], trigger_button[point * 2 + 1]);
+ qtrigger_button[point] = center + QPointF(trigger_button_x, trigger_button_y);
break;
case Direction::Up:
case Direction::Down:
@@ -2633,22 +2669,21 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di
std::array<QPointF, up_arrow_symbol.size() / 2> arrow_symbol;
for (std::size_t point = 0; point < up_arrow_symbol.size() / 2; ++point) {
+ const float up_arrow_x = up_arrow_symbol[point * 2 + 0];
+ const float up_arrow_y = up_arrow_symbol[point * 2 + 1];
+
switch (direction) {
case Direction::Up:
- arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2] * size,
- up_arrow_symbol[point * 2 + 1] * size);
+ arrow_symbol[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
break;
case Direction::Left:
- arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2 + 1] * size,
- up_arrow_symbol[point * 2] * size);
+ arrow_symbol[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size);
break;
case Direction::Right:
- arrow_symbol[point] = center + QPointF(-up_arrow_symbol[point * 2 + 1] * size,
- up_arrow_symbol[point * 2] * size);
+ arrow_symbol[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size);
break;
case Direction::Down:
- arrow_symbol[point] = center + QPointF(up_arrow_symbol[point * 2] * size,
- -up_arrow_symbol[point * 2 + 1] * size);
+ arrow_symbol[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size);
break;
case Direction::None:
break;
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
index 39565f795..91c3343f1 100644
--- a/src/yuzu/configuration/configure_input_player_widget.h
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -25,7 +25,7 @@ public:
void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param,
const AnalogParam& analogs_param);
- void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw buttons_,
+ void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw& buttons_,
Settings::AnalogsRaw analogs_);
void SetConnectedStatus(bool checked);
void SetControllerType(Settings::ControllerType type);
@@ -138,9 +138,9 @@ private:
// Draw joystick functions
void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed);
void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed);
- void DrawRawJoystick(QPainter& p, QPointF center, const QPointF value,
- const Input::AnalogProperties properties);
- void DrawProJoystick(QPainter& p, QPointF center, bool pressed);
+ void DrawRawJoystick(QPainter& p, QPointF center, QPointF value,
+ const Input::AnalogProperties& properties);
+ void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed);
void DrawGCJoystick(QPainter& p, QPointF center, bool pressed);
// Draw button functions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index ef92c25bc..52218eb70 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -850,6 +850,16 @@ void GMainWindow::InitializeHotkeys() {
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Mute Audio"), this),
&QShortcut::activated, this,
[] { Settings::values.audio_muted = !Settings::values.audio_muted; });
+
+ connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
+ &QShortcut::activated, this, [&] {
+ Settings::values.mouse_panning = !Settings::values.mouse_panning;
+ if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
+ mouse_hide_timer.start();
+ render_window->installEventFilter(render_window);
+ render_window->setAttribute(Qt::WA_Hover, true);
+ }
+ });
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -1197,7 +1207,7 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
multicore_status_button->setDisabled(true);
renderer_status_button->setDisabled(true);
- if (UISettings::values.hide_mouse) {
+ if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
mouse_hide_timer.start();
render_window->installEventFilter(render_window);
render_window->setAttribute(Qt::WA_Hover, true);
@@ -2359,7 +2369,7 @@ void GMainWindow::OnConfigure() {
config->Save();
- if (UISettings::values.hide_mouse && emulation_running) {
+ if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
render_window->installEventFilter(render_window);
render_window->setAttribute(Qt::WA_Hover, true);
mouse_hide_timer.start();
@@ -2600,7 +2610,8 @@ void GMainWindow::UpdateUISettings() {
}
void GMainWindow::HideMouseCursor() {
- if (emu_thread == nullptr || UISettings::values.hide_mouse == false) {
+ if (emu_thread == nullptr ||
+ (!UISettings::values.hide_mouse && !Settings::values.mouse_panning)) {
mouse_hide_timer.stop();
ShowMouseCursor();
return;
@@ -2610,13 +2621,16 @@ void GMainWindow::HideMouseCursor() {
void GMainWindow::ShowMouseCursor() {
render_window->unsetCursor();
- if (emu_thread != nullptr && UISettings::values.hide_mouse) {
+ if (emu_thread != nullptr &&
+ (UISettings::values.hide_mouse || Settings::values.mouse_panning)) {
mouse_hide_timer.start();
}
}
void GMainWindow::OnMouseActivity() {
- ShowMouseCursor();
+ if (!Settings::values.mouse_panning) {
+ ShowMouseCursor();
+ }
}
void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 7843d5167..39841aa28 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -30,7 +30,8 @@ EmuWindow_SDL2::~EmuWindow_SDL2() {
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0);
- input_subsystem->GetMouse()->MouseMove(x, y);
+
+ input_subsystem->GetMouse()->MouseMove(x, y, 0, 0);
}
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {