summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--dist/icons/controller/controller.qrc21
-rw-r--r--dist/icons/controller/dual_joycon.pngbin36466 -> 0 bytes
-rw-r--r--dist/icons/controller/dual_joycon_dark.pngbin36261 -> 0 bytes
-rw-r--r--dist/icons/controller/dual_joycon_midnight.pngbin34667 -> 0 bytes
-rw-r--r--dist/icons/controller/handheld.pngbin14108 -> 0 bytes
-rw-r--r--dist/icons/controller/handheld_dark.pngbin13731 -> 0 bytes
-rw-r--r--dist/icons/controller/handheld_midnight.pngbin13366 -> 0 bytes
-rw-r--r--dist/icons/controller/pro_controller.pngbin36710 -> 0 bytes
-rw-r--r--dist/icons/controller/pro_controller_dark.pngbin34897 -> 0 bytes
-rw-r--r--dist/icons/controller/pro_controller_midnight.pngbin35893 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left.pngbin25565 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_dark.pngbin25682 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_midnight.pngbin24405 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical.pngbin24764 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical_dark.pngbin24938 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_left_vertical_midnight.pngbin23681 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right.pngbin28320 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_dark.pngbin28157 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_midnight.pngbin27006 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical.pngbin27655 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical_dark.pngbin27729 -> 0 bytes
-rw-r--r--dist/icons/controller/single_joycon_right_vertical_midnight.pngbin26354 -> 0 bytes
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/frontend/input.h11
-rw-r--r--src/core/hle/kernel/svc.cpp247
-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/lm/lm.cpp16
-rw-r--r--src/core/hle/service/ns/pl_u.cpp9
-rw-r--r--src/core/hle/service/olsc/olsc.cpp13
-rwxr-xr-xsrc/input_common/analog_from_button.cpp4
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp10
-rw-r--r--src/input_common/mouse/mouse_poller.cpp10
-rw-r--r--src/input_common/sdl/sdl_impl.cpp10
-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.txt13
-rw-r--r--src/video_core/morton.cpp0
-rw-r--r--src/video_core/morton.h0
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/texture_cache/util.cpp34
-rw-r--r--src/yuzu/CMakeLists.txt4
-rw-r--r--src/yuzu/bootmanager.cpp31
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp101
-rw-r--r--src/yuzu/configuration/configure_input_player.h2
-rw-r--r--src/yuzu/configuration/configure_input_player.ui74
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp2729
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.h192
-rw-r--r--src/yuzu/debugger/controller.cpp66
-rw-r--r--src/yuzu/debugger/controller.h31
-rw-r--r--src/yuzu/main.cpp7
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp26
65 files changed, 3754 insertions, 362 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
42pip3 install pefile 42pip3 install pefile
43python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/" 43python3 .ci/scripts/windows/scan_dll.py package/*.exe "package/"
44python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/" 44python3 .ci/scripts/windows/scan_dll.py package/imageformats/*.dll "package/"
45
46# copy FFmpeg libraries
47EXTERNALS_PATH="$(pwd)/build/externals"
48FFMPEG_DLL_PATH="$(find ${EXTERNALS_PATH} -maxdepth 1 -type d | grep ffmpeg)/bin"
49find ${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 @@
37[submodule "opus"] 37[submodule "opus"]
38 path = externals/opus/opus 38 path = externals/opus/opus
39 url = https://github.com/xiph/opus.git 39 url = https://github.com/xiph/opus.git
40[submodule "externals/ffmpeg"]
41 path = externals/ffmpeg
42 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
18 18
19option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) 19option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
20 20
21CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled yuzu" ON "WIN32" OFF)
22
21option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) 23option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
22 24
23option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON) 25option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implementation of BCAT" ON)
@@ -384,19 +386,141 @@ if (NOT LIBUSB_FOUND)
384 set(LIBUSB_LIBRARIES usb) 386 set(LIBUSB_LIBRARIES usb)
385endif() 387endif()
386 388
387# Use system installed ffmpeg. 389# List of all FFmpeg components required
388if (NOT MSVC) 390set(FFmpeg_COMPONENTS
389 find_package(FFmpeg REQUIRED) 391 avcodec
390else() 392 avutil
391 set(FFMPEG_EXT_NAME "ffmpeg-4.2.1") 393 swscale)
392 set(FFMPEG_PATH "${CMAKE_BINARY_DIR}/externals/${FFMPEG_EXT_NAME}") 394
393 download_bundled_external("ffmpeg/" ${FFMPEG_EXT_NAME} "") 395if (NOT YUZU_USE_BUNDLED_FFMPEG)
394 set(FFMPEG_FOUND YES) 396 # Use system installed FFmpeg
395 set(FFMPEG_INCLUDE_DIR "${FFMPEG_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE) 397 find_package(FFmpeg REQUIRED COMPONENTS ${FFmpeg_COMPONENTS})
396 set(FFMPEG_LIBRARY_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg library" FORCE) 398
397 set(FFMPEG_DLL_DIR "${FFMPEG_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE) 399 if (FFmpeg_FOUND)
400 # Overwrite aggregate defines from FFmpeg module to avoid over-linking libraries.
401 # Prevents shipping too many libraries with the AppImage.
402 set(FFmpeg_LIBRARIES "")
403 set(FFmpeg_INCLUDE_DIR "")
404
405 foreach(COMPONENT ${FFmpeg_COMPONENTS})
406 set(FFmpeg_LIBRARIES ${FFmpeg_LIBRARIES} ${FFmpeg_LIBRARY_${COMPONENT}} CACHE PATH "Paths to FFmpeg libraries" FORCE)
407 set(FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_DIR} ${FFmpeg_INCLUDE_${COMPONENT}} CACHE PATH "Path to FFmpeg headers" FORCE)
408 endforeach()
409 else()
410 message(WARNING "FFmpeg not found, falling back to externals")
411 set(YUZU_USE_BUNDLED_FFMPEG ON)
412 endif()
413endif()
414
415if (YUZU_USE_BUNDLED_FFMPEG)
416 if (NOT WIN32)
417 # Build FFmpeg from externals
418 message(STATUS "Using FFmpeg from externals")
419
420 # FFmpeg has source that requires one of nasm or yasm to assemble it.
421 # REQUIRED throws an error if not found here during configuration rather than during compilation.
422 find_program(ASSEMBLER NAMES nasm yasm REQUIRED)
423
424 set(FFmpeg_PREFIX ${PROJECT_SOURCE_DIR}/externals/ffmpeg)
425 set(FFmpeg_BUILD_DIR ${PROJECT_BINARY_DIR}/externals/ffmpeg)
426 set(FFmpeg_MAKEFILE ${FFmpeg_BUILD_DIR}/Makefile)
427 make_directory(${FFmpeg_BUILD_DIR})
428
429 # Read version string from external
430 file(READ ${FFmpeg_PREFIX}/RELEASE FFmpeg_VERSION)
431 set(FFmpeg_FOUND NO)
432 if (NOT FFmpeg_VERSION STREQUAL "")
433 set(FFmpeg_FOUND YES)
434 endif()
435
436 foreach(COMPONENT ${FFmpeg_COMPONENTS})
437 set(FFmpeg_${COMPONENT}_PREFIX "${FFmpeg_BUILD_DIR}/lib${COMPONENT}")
438 set(FFmpeg_${COMPONENT}_LIB_NAME "lib${COMPONENT}.a")
439 set(FFmpeg_${COMPONENT}_LIBRARY "${FFmpeg_${COMPONENT}_PREFIX}/${FFmpeg_${COMPONENT}_LIB_NAME}")
440
441 set(FFmpeg_LIBRARIES
442 ${FFmpeg_LIBRARIES}
443 ${FFmpeg_${COMPONENT}_LIBRARY}
444 CACHE PATH "Paths to FFmpeg libraries" FORCE)
445 endforeach()
446
447 set(FFmpeg_INCLUDE_DIR
448 ${FFmpeg_PREFIX}
449 CACHE PATH "Path to FFmpeg headers" FORCE)
450
451 # `configure` parameters builds only exactly what yuzu needs from FFmpeg
452 # `--disable-{vaapi,vdpau}` is needed to avoid linking issues
453 add_custom_command(
454 OUTPUT
455 ${FFmpeg_MAKEFILE}
456 COMMAND
457 /bin/bash ${FFmpeg_PREFIX}/configure
458 --disable-avdevice
459 --disable-avfilter
460 --disable-avformat
461 --disable-doc
462 --disable-everything
463 --disable-ffmpeg
464 --disable-ffprobe
465 --disable-network
466 --disable-postproc
467 --disable-swresample
468 --disable-vaapi
469 --disable-vdpau
470 --enable-decoder=h264
471 --enable-decoder=vp9
472 WORKING_DIRECTORY
473 ${FFmpeg_BUILD_DIR}
474 )
475
476 # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child
477 # with context of the jobserver. Also helps ninja users.
478 execute_process(
479 COMMAND
480 nproc
481 OUTPUT_VARIABLE
482 SYSTEM_THREADS)
483
484 add_custom_command(
485 OUTPUT
486 ${FFmpeg_LIBRARIES}
487 COMMAND
488 make -j${SYSTEM_THREADS}
489 WORKING_DIRECTORY
490 ${FFmpeg_BUILD_DIR}
491 )
492
493 # ALL makes this custom target build every time
494 # but it won't actually build if the DEPENDS parameter is up to date
495 add_custom_target(ffmpeg-build ALL DEPENDS ${FFmpeg_LIBRARIES})
496 add_custom_target(ffmpeg-configure ALL DEPENDS ${FFmpeg_MAKEFILE})
497
498 if (FFmpeg_FOUND)
499 message(STATUS "Found FFmpeg version ${FFmpeg_VERSION}")
500
501 add_dependencies(ffmpeg-build ffmpeg-configure)
502 else()
503 message(FATAL_ERROR "FFmpeg not found")
504 endif()
505 else() # WIN32
506 # Use yuzu FFmpeg binaries
507 set(FFmpeg_EXT_NAME "ffmpeg-4.2.1")
508 set(FFmpeg_PATH "${CMAKE_BINARY_DIR}/externals/${FFmpeg_EXT_NAME}")
509 download_bundled_external("ffmpeg/" ${FFmpeg_EXT_NAME} "")
510 set(FFmpeg_FOUND YES)
511 set(FFmpeg_INCLUDE_DIR "${FFmpeg_PATH}/include" CACHE PATH "Path to FFmpeg headers" FORCE)
512 set(FFmpeg_LIBRARY_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg library directory" FORCE)
513 set(FFmpeg_DLL_DIR "${FFmpeg_PATH}/bin" CACHE PATH "Path to FFmpeg dll's" FORCE)
514 set(FFmpeg_LIBRARIES
515 ${FFmpeg_LIBRARY_DIR}/swscale.lib
516 ${FFmpeg_LIBRARY_DIR}/avcodec.lib
517 ${FFmpeg_LIBRARY_DIR}/avutil.lib
518 CACHE PATH "Paths to FFmpeg libraries" FORCE)
519 endif()
398endif() 520endif()
399 521
522unset(FFmpeg_COMPONENTS)
523
400# Prefer the -pthread flag on Linux. 524# Prefer the -pthread flag on Linux.
401set(THREADS_PREFER_PTHREAD_FLAG ON) 525set(THREADS_PREFER_PTHREAD_FLAG ON)
402find_package(Threads REQUIRED) 526find_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 @@
1function(copy_yuzu_FFmpeg_deps target_dir) 1function(copy_yuzu_FFmpeg_deps target_dir)
2 include(WindowsCopyFiles) 2 include(WindowsCopyFiles)
3 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/") 3 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
4 windows_copy_files(${target_dir} ${FFMPEG_DLL_DIR} ${DLL_DEST} 4 windows_copy_files(${target_dir} ${FFmpeg_DLL_DIR} ${DLL_DEST}
5 avcodec-58.dll 5 avcodec-58.dll
6 avutil-56.dll 6 avutil-56.dll
7 swresample-3.dll 7 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
33 33
34 34
35### Support 35### Support
36We 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: 36We 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:
37* Switch consoles to explore and reverse-engineer the hardware 37* Switch consoles to explore and reverse-engineer the hardware
38* Switch games for testing, reverse-engineering, and implementing new features 38* Switch games for testing, reverse-engineering, and implementing new features
39* Web hosting and infrastructure setup 39* Web hosting and infrastructure setup
diff --git a/dist/icons/controller/controller.qrc b/dist/icons/controller/controller.qrc
index 1c4e960c0..78eae461c 100644
--- a/dist/icons/controller/controller.qrc
+++ b/dist/icons/controller/controller.qrc
@@ -1,26 +1,5 @@
1<RCC> 1<RCC>
2 <qresource prefix="controller"> 2 <qresource prefix="controller">
3 <file alias="dual_joycon">dual_joycon.png</file>
4 <file alias="dual_joycon_dark">dual_joycon_dark.png</file>
5 <file alias="dual_joycon_midnight">dual_joycon_midnight.png</file>
6 <file alias="handheld">handheld.png</file>
7 <file alias="handheld_dark">handheld_dark.png</file>
8 <file alias="handheld_midnight">handheld_midnight.png</file>
9 <file alias="pro_controller">pro_controller.png</file>
10 <file alias="pro_controller_dark">pro_controller_dark.png</file>
11 <file alias="pro_controller_midnight">pro_controller_midnight.png</file>
12 <file alias="single_joycon_left">single_joycon_left.png</file>
13 <file alias="single_joycon_left_dark">single_joycon_left_dark.png</file>
14 <file alias="single_joycon_left_midnight">single_joycon_left_midnight.png</file>
15 <file alias="single_joycon_right">single_joycon_right.png</file>
16 <file alias="single_joycon_right_dark">single_joycon_right_dark.png</file>
17 <file alias="single_joycon_right_midnight">single_joycon_right_midnight.png</file>
18 <file alias="single_joycon_left_vertical">single_joycon_left_vertical.png</file>
19 <file alias="single_joycon_left_vertical_dark">single_joycon_left_vertical_dark.png</file>
20 <file alias="single_joycon_left_vertical_midnight">single_joycon_left_vertical_midnight.png</file>
21 <file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
22 <file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
23 <file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
24 <file alias="applet_dual_joycon">applet_dual_joycon.png</file> 3 <file alias="applet_dual_joycon">applet_dual_joycon.png</file>
25 <file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file> 4 <file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>
26 <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file> 5 <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>
diff --git a/dist/icons/controller/dual_joycon.png b/dist/icons/controller/dual_joycon.png
deleted file mode 100644
index 4230f5f7b..000000000
--- a/dist/icons/controller/dual_joycon.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/dual_joycon_dark.png b/dist/icons/controller/dual_joycon_dark.png
deleted file mode 100644
index 4445db489..000000000
--- a/dist/icons/controller/dual_joycon_dark.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/dual_joycon_midnight.png b/dist/icons/controller/dual_joycon_midnight.png
deleted file mode 100644
index aac8e5321..000000000
--- a/dist/icons/controller/dual_joycon_midnight.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/handheld.png b/dist/icons/controller/handheld.png
deleted file mode 100644
index d009b4a47..000000000
--- a/dist/icons/controller/handheld.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/handheld_dark.png b/dist/icons/controller/handheld_dark.png
deleted file mode 100644
index c80ca9259..000000000
--- a/dist/icons/controller/handheld_dark.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/handheld_midnight.png b/dist/icons/controller/handheld_midnight.png
deleted file mode 100644
index 19de4629b..000000000
--- a/dist/icons/controller/handheld_midnight.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/pro_controller.png b/dist/icons/controller/pro_controller.png
deleted file mode 100644
index 07d65e94a..000000000
--- a/dist/icons/controller/pro_controller.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/pro_controller_dark.png b/dist/icons/controller/pro_controller_dark.png
deleted file mode 100644
index 73efe18f4..000000000
--- a/dist/icons/controller/pro_controller_dark.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/pro_controller_midnight.png b/dist/icons/controller/pro_controller_midnight.png
deleted file mode 100644
index 8d7e63f0d..000000000
--- a/dist/icons/controller/pro_controller_midnight.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left.png b/dist/icons/controller/single_joycon_left.png
deleted file mode 100644
index 547153034..000000000
--- a/dist/icons/controller/single_joycon_left.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_dark.png b/dist/icons/controller/single_joycon_left_dark.png
deleted file mode 100644
index b6ee073cb..000000000
--- a/dist/icons/controller/single_joycon_left_dark.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_midnight.png b/dist/icons/controller/single_joycon_left_midnight.png
deleted file mode 100644
index 34a485c81..000000000
--- a/dist/icons/controller/single_joycon_left_midnight.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_vertical.png b/dist/icons/controller/single_joycon_left_vertical.png
deleted file mode 100644
index 1e6282ad8..000000000
--- a/dist/icons/controller/single_joycon_left_vertical.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_vertical_dark.png b/dist/icons/controller/single_joycon_left_vertical_dark.png
deleted file mode 100644
index a615d995d..000000000
--- a/dist/icons/controller/single_joycon_left_vertical_dark.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_left_vertical_midnight.png b/dist/icons/controller/single_joycon_left_vertical_midnight.png
deleted file mode 100644
index 4cc578216..000000000
--- a/dist/icons/controller/single_joycon_left_vertical_midnight.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right.png b/dist/icons/controller/single_joycon_right.png
deleted file mode 100644
index 8d29173f6..000000000
--- a/dist/icons/controller/single_joycon_right.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_dark.png b/dist/icons/controller/single_joycon_right_dark.png
deleted file mode 100644
index ead2c44e0..000000000
--- a/dist/icons/controller/single_joycon_right_dark.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_midnight.png b/dist/icons/controller/single_joycon_right_midnight.png
deleted file mode 100644
index 89afe022d..000000000
--- a/dist/icons/controller/single_joycon_right_midnight.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_vertical.png b/dist/icons/controller/single_joycon_right_vertical.png
deleted file mode 100644
index 4d7d06547..000000000
--- a/dist/icons/controller/single_joycon_right_vertical.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_vertical_dark.png b/dist/icons/controller/single_joycon_right_vertical_dark.png
deleted file mode 100644
index 9a6eb3013..000000000
--- a/dist/icons/controller/single_joycon_right_vertical_dark.png
+++ /dev/null
Binary files differ
diff --git a/dist/icons/controller/single_joycon_right_vertical_midnight.png b/dist/icons/controller/single_joycon_right_vertical_midnight.png
deleted file mode 100644
index 685249b68..000000000
--- a/dist/icons/controller/single_joycon_right_vertical_midnight.png
+++ /dev/null
Binary files differ
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 @@
1# - Try to find ffmpeg libraries (libavcodec, libavformat and libavutil) 1# FindFFmpeg
2# Once done this will define 2# ----------
3# 3#
4# FFMPEG_FOUND - system has ffmpeg or libav 4# Copyright 2019 Citra Emulator Project
5# FFMPEG_INCLUDE_DIR - the ffmpeg include directory 5# Licensed under GPLv2 or any later version
6# FFMPEG_LIBRARIES - Link these to use ffmpeg
7# FFMPEG_LIBAVCODEC
8# FFMPEG_LIBAVFORMAT
9# FFMPEG_LIBAVUTIL
10# 6#
11# Copyright (c) 2008 Andreas Schneider <mail@cynapses.org> 7# Find the native FFmpeg includes and libraries
12# Modified for other libraries by Lasse Kärkkäinen <tronic>
13# Modified for Hedgewars by Stepik777
14# Modified for FFmpeg-example Tuukka Pasanen 2018
15# Modified for yuzu toastUnlimted 2020
16# 8#
17# Redistribution and use is allowed according to the terms of the New 9# This module defines the following variables:
18# BSD license. 10#
11# FFmpeg_INCLUDE_<component>: where to find <component>.h
12# FFmpeg_LIBRARY_<component>: where to find the <component> library
13# FFmpeg_INCLUDE_DIR: aggregate all the include paths
14# FFmpeg_LIBRARIES: aggregate all the paths to the libraries
15# FFmpeg_FOUND: True if all components have been found
16#
17# This module defines the following targets, which are prefered over variables:
18#
19# FFmpeg::<component>: Target to use <component> directly, with include path,
20# library and dependencies set up. If you are using a static build, you are
21# responsible for adding any external dependencies (such as zlib, bzlib...).
22#
23# <component> can be one of:
24# avcodec
25# avdevice
26# avfilter
27# avformat
28# avutil
29# postproc
30# swresample
31# swscale
19# 32#
20 33
21include(FindPackageHandleStandardArgs) 34set(_FFmpeg_ALL_COMPONENTS
22 35 avcodec
23find_package_handle_standard_args(FFMPEG 36 avdevice
24 FOUND_VAR FFMPEG_FOUND 37 avfilter
25 REQUIRED_VARS 38 avformat
26 FFMPEG_LIBRARY 39 avutil
27 FFMPEG_INCLUDE_DIR 40 postproc
28 VERSION_VAR FFMPEG_VERSION 41 swresample
42 swscale
29) 43)
30 44
31if(FFMPEG_LIBRARIES AND FFMPEG_INCLUDE_DIR) 45set(_FFmpeg_DEPS_avcodec avutil)
32 # in cache already 46set(_FFmpeg_DEPS_avdevice avcodec avformat avutil)
33 set(FFMPEG_FOUND TRUE) 47set(_FFmpeg_DEPS_avfilter avutil)
34else() 48set(_FFmpeg_DEPS_avformat avcodec avutil)
35 # use pkg-config to get the directories and then use these values 49set(_FFmpeg_DEPS_postproc avutil)
36 # in the FIND_PATH() and FIND_LIBRARY() calls 50set(_FFmpeg_DEPS_swresample avutil)
37 find_package(PkgConfig) 51set(_FFmpeg_DEPS_swscale avutil)
38 if(PKG_CONFIG_FOUND) 52
39 pkg_check_modules(_FFMPEG_AVCODEC libavcodec) 53function(find_ffmpeg LIBNAME)
40 pkg_check_modules(_FFMPEG_AVUTIL libavutil) 54 if(DEFINED ENV{FFMPEG_DIR})
41 pkg_check_modules(_FFMPEG_SWSCALE libswscale) 55 set(FFMPEG_DIR $ENV{FFMPEG_DIR})
42 endif() 56 endif()
43 57
44 find_path(FFMPEG_AVCODEC_INCLUDE_DIR 58 if(FFMPEG_DIR)
45 NAMES libavcodec/avcodec.h 59 list(APPEND INCLUDE_PATHS
46 PATHS ${_FFMPEG_AVCODEC_INCLUDE_DIRS} 60 ${FFMPEG_DIR}
47 /usr/include 61 ${FFMPEG_DIR}/ffmpeg
48 /usr/local/include 62 ${FFMPEG_DIR}/lib${LIBNAME}
49 /opt/local/include 63 ${FFMPEG_DIR}/include/lib${LIBNAME}
50 /sw/include 64 ${FFMPEG_DIR}/include/ffmpeg
51 PATH_SUFFIXES ffmpeg libav) 65 ${FFMPEG_DIR}/include
52 66 NO_DEFAULT_PATH
53 find_library(FFMPEG_LIBAVCODEC 67 NO_CMAKE_FIND_ROOT_PATH
54 NAMES avcodec 68 )
55 PATHS ${_FFMPEG_AVCODEC_LIBRARY_DIRS} 69 list(APPEND LIB_PATHS
56 /usr/lib 70 ${FFMPEG_DIR}
57 /usr/local/lib 71 ${FFMPEG_DIR}/lib
58 /opt/local/lib 72 ${FFMPEG_DIR}/lib${LIBNAME}
59 /sw/lib) 73 NO_DEFAULT_PATH
74 NO_CMAKE_FIND_ROOT_PATH
75 )
76 else()
77 list(APPEND INCLUDE_PATHS
78 /usr/local/include/ffmpeg
79 /usr/local/include/lib${LIBNAME}
80 /usr/include/ffmpeg
81 /usr/include/lib${LIBNAME}
82 /usr/include/ffmpeg/lib${LIBNAME}
83 )
60 84
61 find_library(FFMPEG_LIBAVUTIL 85 list(APPEND LIB_PATHS
62 NAMES avutil
63 PATHS ${_FFMPEG_AVUTIL_LIBRARY_DIRS}
64 /usr/lib
65 /usr/local/lib 86 /usr/local/lib
66 /opt/local/lib
67 /sw/lib)
68
69 find_library(FFMPEG_LIBSWSCALE
70 NAMES swscale
71 PATHS ${_FFMPEG_SWSCALE_LIBRARY_DIRS}
72 /usr/lib 87 /usr/lib
73 /usr/local/lib 88 )
74 /opt/local/lib
75 /sw/lib)
76
77 if(FFMPEG_LIBAVCODEC AND FFMPEG_LIBAVUTIL AND FFMPEG_LIBSWSCALE)
78 set(FFMPEG_FOUND TRUE)
79 endif() 89 endif()
80 90
81 if(FFMPEG_FOUND) 91 find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
82 set(FFMPEG_INCLUDE_DIR ${FFMPEG_AVCODEC_INCLUDE_DIR}) 92 HINTS ${INCLUDE_PATHS}
83 set(FFMPEG_LIBRARIES 93 )
84 ${FFMPEG_LIBAVCODEC} 94
85 ${FFMPEG_LIBAVUTIL} 95 find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
86 ${FFMPEG_LIBSWSCALE}) 96 HINTS ${LIB_PATHS}
97 )
98
99 if(NOT FFMPEG_DIR AND (NOT FFmpeg_LIBRARY_${LIBNAME} OR NOT FFmpeg_INCLUDE_${LIBNAME}))
100 # Didn't find it in the usual paths, try pkg-config
101 find_package(PkgConfig QUIET)
102 pkg_check_modules(FFmpeg_PKGCONFIG_${LIBNAME} QUIET lib${LIBNAME})
103
104 find_path(FFmpeg_INCLUDE_${LIBNAME} lib${LIBNAME}/${LIBNAME}.h
105 ${FFmpeg_PKGCONFIG_${LIBNAME}_INCLUDE_DIRS}
106 )
107
108 find_library(FFmpeg_LIBRARY_${LIBNAME} ${LIBNAME}
109 ${FFmpeg_PKGCONFIG_${LIBNAME}_LIBRARY_DIRS}
110 )
87 endif() 111 endif()
88 112
89 if(FFMPEG_FOUND) 113 if(FFmpeg_INCLUDE_${LIBNAME} AND FFmpeg_LIBRARY_${LIBNAME})
90 if(NOT FFMPEG_FIND_QUIETLY) 114 set(FFmpeg_INCLUDE_${LIBNAME} "${FFmpeg_INCLUDE_${LIBNAME}}" PARENT_SCOPE)
91 message(STATUS 115 set(FFmpeg_LIBRARY_${LIBNAME} "${FFmpeg_LIBRARY_${LIBNAME}}" PARENT_SCOPE)
92 "Found FFMPEG or Libav: ${FFMPEG_LIBRARIES}, ${FFMPEG_INCLUDE_DIR}") 116
117 # Extract FFmpeg version from version.h
118 foreach(v MAJOR MINOR MICRO)
119 set(FFmpeg_${LIBNAME}_VERSION_${v} 0)
120 endforeach()
121 string(TOUPPER ${LIBNAME} LIBNAME_UPPER)
122 file(STRINGS "${FFmpeg_INCLUDE_${LIBNAME}}/lib${LIBNAME}/version.h" _FFmpeg_VERSION_H_CONTENTS REGEX "#define LIB${LIBNAME_UPPER}_VERSION_(MAJOR|MINOR|MICRO) ")
123 set(_FFmpeg_VERSION_REGEX "([0-9]+)")
124 foreach(v MAJOR MINOR MICRO)
125 if("${_FFmpeg_VERSION_H_CONTENTS}" MATCHES "#define LIB${LIBNAME_UPPER}_VERSION_${v}[\\t ]+${_FFmpeg_VERSION_REGEX}")
126 set(FFmpeg_${LIBNAME}_VERSION_${v} "${CMAKE_MATCH_1}")
127 endif()
128 endforeach()
129 set(FFmpeg_${LIBNAME}_VERSION "${FFmpeg_${LIBNAME}_VERSION_MAJOR}.${FFmpeg_${LIBNAME}_VERSION_MINOR}.${FFmpeg_${LIBNAME}_VERSION_MICRO}")
130 set(FFmpeg_${c}_VERSION "${FFmpeg_${LIBNAME}_VERSION}" PARENT_SCOPE)
131 unset(_FFmpeg_VERSION_REGEX)
132 unset(_FFmpeg_VERSION_H_CONTENTS)
133
134 set(FFmpeg_${c}_FOUND TRUE PARENT_SCOPE)
135 if(NOT FFmpeg_FIND_QUIETLY)
136 message("-- Found ${LIBNAME}: ${FFmpeg_INCLUDE_${LIBNAME}} ${FFmpeg_LIBRARY_${LIBNAME}} (version: ${FFmpeg_${LIBNAME}_VERSION})")
93 endif() 137 endif()
94 else() 138 endif()
95 if(FFMPEG_FIND_REQUIRED) 139endfunction()
96 message(FATAL_ERROR 140
97 "Could not find libavcodec or libavutil or libswscale") 141foreach(c ${_FFmpeg_ALL_COMPONENTS})
142 find_ffmpeg(${c})
143endforeach()
144
145foreach(c ${_FFmpeg_ALL_COMPONENTS})
146 if(FFmpeg_${c}_FOUND)
147 list(APPEND FFmpeg_INCLUDE_DIR ${FFmpeg_INCLUDE_${c}})
148 list(APPEND FFmpeg_LIBRARIES ${FFmpeg_LIBRARY_${c}})
149
150 add_library(FFmpeg::${c} IMPORTED UNKNOWN)
151 set_target_properties(FFmpeg::${c} PROPERTIES
152 IMPORTED_LOCATION ${FFmpeg_LIBRARY_${c}}
153 INTERFACE_INCLUDE_DIRECTORIES ${FFmpeg_INCLUDE_${c}}
154 )
155 if(_FFmpeg_DEPS_${c})
156 set(deps)
157 foreach(dep ${_FFmpeg_DEPS_${c}})
158 list(APPEND deps FFmpeg::${dep})
159 endforeach()
160
161 set_target_properties(FFmpeg::${c} PROPERTIES
162 INTERFACE_LINK_LIBRARIES "${deps}"
163 )
164 unset(deps)
98 endif() 165 endif()
99 endif() 166 endif()
167endforeach()
168
169if(FFmpeg_INCLUDE_DIR)
170 list(REMOVE_DUPLICATES FFmpeg_INCLUDE_DIR)
100endif() 171endif()
172
173foreach(c ${FFmpeg_FIND_COMPONENTS})
174 list(APPEND _FFmpeg_REQUIRED_VARS FFmpeg_INCLUDE_${c} FFmpeg_LIBRARY_${c})
175endforeach()
176
177include(FindPackageHandleStandardArgs)
178find_package_handle_standard_args(FFmpeg
179 REQUIRED_VARS ${_FFmpeg_REQUIRED_VARS}
180 HANDLE_COMPONENTS
181)
182
183foreach(c ${_FFmpeg_ALL_COMPONENTS})
184 unset(_FFmpeg_DEPS_${c})
185endforeach()
186unset(_FFmpeg_ALL_COMPONENTS)
187unset(_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) {
111 111
112 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples()); 112 sink_stream.EnqueueSamples(GetNumChannels(), active_buffer->GetSamples());
113 113
114 core_timing.ScheduleEvent(GetBufferReleaseNS(*active_buffer) - ns_late, release_event, {}); 114 const auto buffer_release_ns = GetBufferReleaseNS(*active_buffer);
115
116 // If ns_late is higher than the update rate ignore the delay
117 if (ns_late > buffer_release_ns) {
118 ns_late = {};
119 }
120
121 core_timing.ScheduleEvent(buffer_release_ns - ns_late, release_event, {});
115} 122}
116 123
117void Stream::ReleaseActiveBuffer(std::chrono::nanoseconds ns_late) { 124void 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)
206else() 206else()
207 target_compile_options(common PRIVATE 207 target_compile_options(common PRIVATE
208 -Werror 208 -Werror
209
210 $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
209 ) 211 )
210endif() 212endif()
211 213
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
141} 141}
142 142
143std::string UTF16ToUTF8(const std::u16string& input) { 143std::string UTF16ToUTF8(const std::u16string& input) {
144#ifdef _MSC_VER
145 // Workaround for missing char16_t/char32_t instantiations in MSVC2017
146 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
147 std::basic_string<__int16> tmp_buffer(input.cbegin(), input.cend());
148 return convert.to_bytes(tmp_buffer);
149#else
150 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; 144 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
151 return convert.to_bytes(input); 145 return convert.to_bytes(input);
152#endif
153} 146}
154 147
155std::u16string UTF8ToUTF16(const std::string& input) { 148std::u16string UTF8ToUTF16(const std::string& input) {
156#ifdef _MSC_VER
157 // Workaround for missing char16_t/char32_t instantiations in MSVC2017
158 std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
159 auto tmp_buffer = convert.from_bytes(input);
160 return std::u16string(tmp_buffer.cbegin(), tmp_buffer.cend());
161#else
162 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; 149 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
163 return convert.from_bytes(input); 150 return convert.from_bytes(input);
164#endif
165} 151}
166 152
167#ifdef _WIN32 153#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()
653 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> 653 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>
654 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> 654 $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable>
655 655
656 $<$<CXX_COMPILER_ID:Clang>:-fsized-deallocation>
657
656 -Wno-sign-conversion 658 -Wno-sign-conversion
657 ) 659 )
658endif() 660endif()
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index f014dfea3..88ebc6497 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -21,6 +21,11 @@ enum class AnalogDirection : u8 {
21 UP, 21 UP,
22 DOWN, 22 DOWN,
23}; 23};
24struct AnalogProperties {
25 float deadzone;
26 float range;
27 float threshold;
28};
24 29
25/// An abstract class template for an input device (a button, an analog input, etc.). 30/// An abstract class template for an input device (a button, an analog input, etc.).
26template <typename StatusType> 31template <typename StatusType>
@@ -30,6 +35,12 @@ public:
30 virtual StatusType GetStatus() const { 35 virtual StatusType GetStatus() const {
31 return {}; 36 return {};
32 } 37 }
38 virtual StatusType GetRawStatus() const {
39 return GetStatus();
40 }
41 virtual AnalogProperties GetAnalogProperties() const {
42 return {};
43 }
33 virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const { 44 virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
34 return {}; 45 return {};
35 } 46 }
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index edf208eff..26650a513 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -368,7 +368,10 @@ static ResultCode GetThreadId(Core::System& system, u64* out_thread_id, Handle t
368 // Get the thread from its handle. 368 // Get the thread from its handle.
369 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 369 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
370 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 370 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
371 R_UNLESS(thread, Svc::ResultInvalidHandle); 371 if (!thread) {
372 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
373 return ResultInvalidHandle;
374 }
372 375
373 // Get the thread's id. 376 // Get the thread's id.
374 *out_thread_id = thread->GetThreadID(); 377 *out_thread_id = thread->GetThreadID();
@@ -478,7 +481,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
478 // Get the thread from its handle. 481 // Get the thread from its handle.
479 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 482 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
480 std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 483 std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
481 R_UNLESS(thread, Svc::ResultInvalidHandle); 484 if (!thread) {
485 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
486 return ResultInvalidHandle;
487 }
482 488
483 // Cancel the thread's wait. 489 // Cancel the thread's wait.
484 thread->WaitCancel(); 490 thread->WaitCancel();
@@ -496,8 +502,15 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd
496 thread_handle, address, tag); 502 thread_handle, address, tag);
497 503
498 // Validate the input address. 504 // Validate the input address.
499 R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); 505 if (Memory::IsKernelAddress(address)) {
500 R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); 506 LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})",
507 address);
508 return ResultInvalidCurrentMemory;
509 }
510 if (!Common::IsAligned(address, sizeof(u32))) {
511 LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
512 return ResultInvalidAddress;
513 }
501 514
502 return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag); 515 return system.Kernel().CurrentProcess()->WaitForAddress(thread_handle, address, tag);
503} 516}
@@ -512,8 +525,16 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) {
512 LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); 525 LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address);
513 526
514 // Validate the input address. 527 // Validate the input address.
515 R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); 528 if (Memory::IsKernelAddress(address)) {
516 R_UNLESS(Common::IsAligned(address, sizeof(u32)), Svc::ResultInvalidAddress); 529 LOG_ERROR(Kernel_SVC,
530 "Attempting to arbitrate an unlock on a kernel address (address={:08X})",
531 address);
532 return ResultInvalidCurrentMemory;
533 }
534 if (!Common::IsAligned(address, sizeof(u32))) {
535 LOG_ERROR(Kernel_SVC, "Input address must be 4 byte aligned (address: {:08X})", address);
536 return ResultInvalidAddress;
537 }
517 538
518 return system.Kernel().CurrentProcess()->SignalToAddress(address); 539 return system.Kernel().CurrentProcess()->SignalToAddress(address);
519} 540}
@@ -1025,37 +1046,47 @@ static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size
1025 return UnmapPhysicalMemory(system, addr, size); 1046 return UnmapPhysicalMemory(system, addr, size);
1026} 1047}
1027 1048
1028constexpr bool IsValidThreadActivity(Svc::ThreadActivity thread_activity) {
1029 switch (thread_activity) {
1030 case Svc::ThreadActivity::Runnable:
1031 case Svc::ThreadActivity::Paused:
1032 return true;
1033 default:
1034 return false;
1035 }
1036}
1037
1038/// Sets the thread activity 1049/// Sets the thread activity
1039static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle, 1050static ResultCode SetThreadActivity(Core::System& system, Handle thread_handle,
1040 Svc::ThreadActivity thread_activity) { 1051 ThreadActivity thread_activity) {
1041 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle, 1052 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", thread_handle,
1042 thread_activity); 1053 thread_activity);
1043 1054
1044 // Validate the activity. 1055 // Validate the activity.
1045 R_UNLESS(IsValidThreadActivity(thread_activity), Svc::ResultInvalidEnumValue); 1056 constexpr auto IsValidThreadActivity = [](ThreadActivity activity) {
1057 return activity == ThreadActivity::Runnable || activity == ThreadActivity::Paused;
1058 };
1059 if (!IsValidThreadActivity(thread_activity)) {
1060 LOG_ERROR(Kernel_SVC, "Invalid thread activity value provided (activity={})",
1061 thread_activity);
1062 return ResultInvalidEnumValue;
1063 }
1046 1064
1047 // Get the thread from its handle. 1065 // Get the thread from its handle.
1048 auto& kernel = system.Kernel(); 1066 auto& kernel = system.Kernel();
1049 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); 1067 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
1050 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1068 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
1051 R_UNLESS(thread, Svc::ResultInvalidHandle); 1069 if (!thread) {
1070 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
1071 return ResultInvalidHandle;
1072 }
1052 1073
1053 // Check that the activity is being set on a non-current thread for the current process. 1074 // Check that the activity is being set on a non-current thread for the current process.
1054 R_UNLESS(thread->GetOwnerProcess() == kernel.CurrentProcess(), Svc::ResultInvalidHandle); 1075 if (thread->GetOwnerProcess() != kernel.CurrentProcess()) {
1055 R_UNLESS(thread.get() != GetCurrentThreadPointer(kernel), Svc::ResultBusy); 1076 LOG_ERROR(Kernel_SVC, "Invalid owning process for the created thread.");
1077 return ResultInvalidHandle;
1078 }
1079 if (thread.get() == GetCurrentThreadPointer(kernel)) {
1080 LOG_ERROR(Kernel_SVC, "Thread is busy");
1081 return ResultBusy;
1082 }
1056 1083
1057 // Set the activity. 1084 // Set the activity.
1058 R_TRY(thread->SetActivity(thread_activity)); 1085 const auto set_result = thread->SetActivity(thread_activity);
1086 if (set_result.IsError()) {
1087 LOG_ERROR(Kernel_SVC, "Failed to set thread activity.");
1088 return set_result;
1089 }
1059 1090
1060 return RESULT_SUCCESS; 1091 return RESULT_SUCCESS;
1061} 1092}
@@ -1074,16 +1105,29 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand
1074 const auto* current_process = system.Kernel().CurrentProcess(); 1105 const auto* current_process = system.Kernel().CurrentProcess();
1075 const std::shared_ptr<KThread> thread = 1106 const std::shared_ptr<KThread> thread =
1076 current_process->GetHandleTable().Get<KThread>(thread_handle); 1107 current_process->GetHandleTable().Get<KThread>(thread_handle);
1077 R_UNLESS(thread, Svc::ResultInvalidHandle); 1108 if (!thread) {
1109 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={})", thread_handle);
1110 return ResultInvalidHandle;
1111 }
1078 1112
1079 // Require the handle be to a non-current thread in the current process. 1113 // Require the handle be to a non-current thread in the current process.
1080 R_UNLESS(thread->GetOwnerProcess() == current_process, Svc::ResultInvalidHandle); 1114 if (thread->GetOwnerProcess() != current_process) {
1081 R_UNLESS(thread.get() != system.Kernel().CurrentScheduler()->GetCurrentThread(), 1115 LOG_ERROR(Kernel_SVC, "Thread owning process is not the current process.");
1082 Svc::ResultBusy); 1116 return ResultInvalidHandle;
1117 }
1118 if (thread.get() == system.Kernel().CurrentScheduler()->GetCurrentThread()) {
1119 LOG_ERROR(Kernel_SVC, "Current thread is busy.");
1120 return ResultBusy;
1121 }
1083 1122
1084 // Get the thread context. 1123 // Get the thread context.
1085 std::vector<u8> context; 1124 std::vector<u8> context;
1086 R_TRY(thread->GetThreadContext3(context)); 1125 const auto context_result = thread->GetThreadContext3(context);
1126 if (context_result.IsError()) {
1127 LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve thread context (result: {})",
1128 context_result.raw);
1129 return context_result;
1130 }
1087 1131
1088 // Copy the thread context to user space. 1132 // Copy the thread context to user space.
1089 system.Memory().WriteBlock(out_context, context.data(), context.size()); 1133 system.Memory().WriteBlock(out_context, context.data(), context.size());
@@ -1102,7 +1146,10 @@ static ResultCode GetThreadPriority(Core::System& system, u32* out_priority, Han
1102 // Get the thread from its handle. 1146 // Get the thread from its handle.
1103 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1147 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1104 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 1148 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
1105 R_UNLESS(thread, Svc::ResultInvalidHandle); 1149 if (!thread) {
1150 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", handle);
1151 return ResultInvalidHandle;
1152 }
1106 1153
1107 // Get the thread's priority. 1154 // Get the thread's priority.
1108 *out_priority = thread->GetPriority(); 1155 *out_priority = thread->GetPriority();
@@ -1118,13 +1165,18 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri
1118 LOG_TRACE(Kernel_SVC, "called"); 1165 LOG_TRACE(Kernel_SVC, "called");
1119 1166
1120 // Validate the priority. 1167 // Validate the priority.
1121 R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, 1168 if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
1122 Svc::ResultInvalidPriority); 1169 LOG_ERROR(Kernel_SVC, "Invalid thread priority specified (priority={})", priority);
1170 return ResultInvalidPriority;
1171 }
1123 1172
1124 // Get the thread from its handle. 1173 // Get the thread from its handle.
1125 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1174 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1126 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle); 1175 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(handle);
1127 R_UNLESS(thread, Svc::ResultInvalidHandle); 1176 if (!thread) {
1177 LOG_ERROR(Kernel_SVC, "Invalid handle provided (handle={:08X})", handle);
1178 return ResultInvalidHandle;
1179 }
1128 1180
1129 // Set the thread priority. 1181 // Set the thread priority.
1130 thread->SetBasePriority(priority); 1182 thread->SetBasePriority(priority);
@@ -1440,17 +1492,28 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
1440 // Adjust core id, if it's the default magic. 1492 // Adjust core id, if it's the default magic.
1441 auto& kernel = system.Kernel(); 1493 auto& kernel = system.Kernel();
1442 auto& process = *kernel.CurrentProcess(); 1494 auto& process = *kernel.CurrentProcess();
1443 if (core_id == Svc::IdealCoreUseProcessValue) { 1495 if (core_id == IdealCoreUseProcessValue) {
1444 core_id = process.GetIdealCoreId(); 1496 core_id = process.GetIdealCoreId();
1445 } 1497 }
1446 1498
1447 // Validate arguments. 1499 // Validate arguments.
1448 R_UNLESS(IsValidCoreId(core_id), Svc::ResultInvalidCoreId); 1500 if (!IsValidCoreId(core_id)) {
1449 R_UNLESS(((1ULL << core_id) & process.GetCoreMask()) != 0, Svc::ResultInvalidCoreId); 1501 LOG_ERROR(Kernel_SVC, "Invalid Core ID specified (id={})", core_id);
1502 return ResultInvalidCoreId;
1503 }
1504 if (((1ULL << core_id) & process.GetCoreMask()) == 0) {
1505 LOG_ERROR(Kernel_SVC, "Core ID doesn't fall within allowable cores (id={})", core_id);
1506 return ResultInvalidCoreId;
1507 }
1450 1508
1451 R_UNLESS(Svc::HighestThreadPriority <= priority && priority <= Svc::LowestThreadPriority, 1509 if (HighestThreadPriority > priority || priority > LowestThreadPriority) {
1452 Svc::ResultInvalidPriority); 1510 LOG_ERROR(Kernel_SVC, "Invalid priority specified (priority={})", priority);
1453 R_UNLESS(process.CheckThreadPriority(priority), Svc::ResultInvalidPriority); 1511 return ResultInvalidPriority;
1512 }
1513 if (!process.CheckThreadPriority(priority)) {
1514 LOG_ERROR(Kernel_SVC, "Invalid allowable thread priority (priority={})", priority);
1515 return ResultInvalidPriority;
1516 }
1454 1517
1455 ASSERT(process.GetResourceLimit()->Reserve( 1518 ASSERT(process.GetResourceLimit()->Reserve(
1456 LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); 1519 LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000));
@@ -1489,10 +1552,19 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) {
1489 // Get the thread from its handle. 1552 // Get the thread from its handle.
1490 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1553 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1491 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1554 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
1492 R_UNLESS(thread, Svc::ResultInvalidHandle); 1555 if (!thread) {
1556 LOG_ERROR(Kernel_SVC, "Invalid thread handle provided (handle={:08X})", thread_handle);
1557 return ResultInvalidHandle;
1558 }
1493 1559
1494 // Try to start the thread. 1560 // Try to start the thread.
1495 R_TRY(thread->Run()); 1561 const auto run_result = thread->Run();
1562 if (run_result.IsError()) {
1563 LOG_ERROR(Kernel_SVC,
1564 "Unable to successfuly start thread (thread handle={:08X}, result={})",
1565 thread_handle, run_result.raw);
1566 return run_result;
1567 }
1496 1568
1497 return RESULT_SUCCESS; 1569 return RESULT_SUCCESS;
1498} 1570}
@@ -1553,8 +1625,14 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address,
1553 cv_key, tag, timeout_ns); 1625 cv_key, tag, timeout_ns);
1554 1626
1555 // Validate input. 1627 // Validate input.
1556 R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); 1628 if (Memory::IsKernelAddress(address)) {
1557 R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); 1629 LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address);
1630 return ResultInvalidCurrentMemory;
1631 }
1632 if (!Common::IsAligned(address, sizeof(s32))) {
1633 LOG_ERROR(Kernel_SVC, "Address must be 4 byte aligned (address={:08X})", address);
1634 return ResultInvalidAddress;
1635 }
1558 1636
1559 // Convert timeout from nanoseconds to ticks. 1637 // Convert timeout from nanoseconds to ticks.
1560 s64 timeout{}; 1638 s64 timeout{};
@@ -1629,9 +1707,18 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit
1629 address, arb_type, value, timeout_ns); 1707 address, arb_type, value, timeout_ns);
1630 1708
1631 // Validate input. 1709 // Validate input.
1632 R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); 1710 if (Memory::IsKernelAddress(address)) {
1633 R_UNLESS(Common::IsAligned(address, sizeof(int32_t)), Svc::ResultInvalidAddress); 1711 LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address);
1634 R_UNLESS(IsValidArbitrationType(arb_type), Svc::ResultInvalidEnumValue); 1712 return ResultInvalidCurrentMemory;
1713 }
1714 if (!Common::IsAligned(address, sizeof(s32))) {
1715 LOG_ERROR(Kernel_SVC, "Wait address must be 4 byte aligned (address={:08X})", address);
1716 return ResultInvalidAddress;
1717 }
1718 if (!IsValidArbitrationType(arb_type)) {
1719 LOG_ERROR(Kernel_SVC, "Invalid arbitration type specified (type={})", arb_type);
1720 return ResultInvalidEnumValue;
1721 }
1635 1722
1636 // Convert timeout from nanoseconds to ticks. 1723 // Convert timeout from nanoseconds to ticks.
1637 s64 timeout{}; 1724 s64 timeout{};
@@ -1665,9 +1752,18 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign
1665 address, signal_type, value, count); 1752 address, signal_type, value, count);
1666 1753
1667 // Validate input. 1754 // Validate input.
1668 R_UNLESS(!Memory::IsKernelAddress(address), Svc::ResultInvalidCurrentMemory); 1755 if (Memory::IsKernelAddress(address)) {
1669 R_UNLESS(Common::IsAligned(address, sizeof(s32)), Svc::ResultInvalidAddress); 1756 LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address);
1670 R_UNLESS(IsValidSignalType(signal_type), Svc::ResultInvalidEnumValue); 1757 return ResultInvalidCurrentMemory;
1758 }
1759 if (!Common::IsAligned(address, sizeof(s32))) {
1760 LOG_ERROR(Kernel_SVC, "Signaled address must be 4 byte aligned (address={:08X})", address);
1761 return ResultInvalidAddress;
1762 }
1763 if (!IsValidSignalType(signal_type)) {
1764 LOG_ERROR(Kernel_SVC, "Invalid signal type specified (type={})", signal_type);
1765 return ResultInvalidEnumValue;
1766 }
1671 1767
1672 return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value, 1768 return system.Kernel().CurrentProcess()->SignalAddressArbiter(address, signal_type, value,
1673 count); 1769 count);
@@ -1815,10 +1911,17 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle,
1815 // Get the thread from its handle. 1911 // Get the thread from its handle.
1816 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1912 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1817 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1913 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
1818 R_UNLESS(thread, Svc::ResultInvalidHandle); 1914 if (!thread) {
1915 LOG_ERROR(Kernel_SVC, "Invalid thread handle specified (handle={:08X})", thread_handle);
1916 return ResultInvalidHandle;
1917 }
1819 1918
1820 // Get the core mask. 1919 // Get the core mask.
1821 R_TRY(thread->GetCoreMask(out_core_id, out_affinity_mask)); 1920 const auto result = thread->GetCoreMask(out_core_id, out_affinity_mask);
1921 if (result.IsError()) {
1922 LOG_ERROR(Kernel_SVC, "Unable to successfully retrieve core mask (result={})", result.raw);
1923 return result;
1924 }
1822 1925
1823 return RESULT_SUCCESS; 1926 return RESULT_SUCCESS;
1824} 1927}
@@ -1846,26 +1949,46 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle,
1846 } else { 1949 } else {
1847 // Validate the affinity mask. 1950 // Validate the affinity mask.
1848 const u64 process_core_mask = current_process.GetCoreMask(); 1951 const u64 process_core_mask = current_process.GetCoreMask();
1849 R_UNLESS((affinity_mask | process_core_mask) == process_core_mask, 1952 if ((affinity_mask | process_core_mask) != process_core_mask) {
1850 Svc::ResultInvalidCoreId); 1953 LOG_ERROR(Kernel_SVC,
1851 R_UNLESS(affinity_mask != 0, Svc::ResultInvalidCombination); 1954 "Affinity mask does match the process core mask (affinity mask={:016X}, core "
1955 "mask={:016X})",
1956 affinity_mask, process_core_mask);
1957 return ResultInvalidCoreId;
1958 }
1959 if (affinity_mask == 0) {
1960 LOG_ERROR(Kernel_SVC, "Affinity mask is zero.");
1961 return ResultInvalidCombination;
1962 }
1852 1963
1853 // Validate the core id. 1964 // Validate the core id.
1854 if (IsValidCoreId(core_id)) { 1965 if (IsValidCoreId(core_id)) {
1855 R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, Svc::ResultInvalidCombination); 1966 if (((1ULL << core_id) & affinity_mask) == 0) {
1967 LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
1968 return ResultInvalidCombination;
1969 }
1856 } else { 1970 } else {
1857 R_UNLESS(core_id == Svc::IdealCoreNoUpdate || core_id == Svc::IdealCoreDontCare, 1971 if (core_id != IdealCoreNoUpdate && core_id != IdealCoreDontCare) {
1858 Svc::ResultInvalidCoreId); 1972 LOG_ERROR(Kernel_SVC, "Invalid core ID (ID={})", core_id);
1973 return ResultInvalidCoreId;
1974 }
1859 } 1975 }
1860 } 1976 }
1861 1977
1862 // Get the thread from its handle. 1978 // Get the thread from its handle.
1863 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 1979 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
1864 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle); 1980 const std::shared_ptr<KThread> thread = handle_table.Get<KThread>(thread_handle);
1865 R_UNLESS(thread, Svc::ResultInvalidHandle); 1981 if (!thread) {
1982 LOG_ERROR(Kernel_SVC, "Invalid thread handle (handle={:08X})", thread_handle);
1983 return ResultInvalidHandle;
1984 }
1866 1985
1867 // Set the core mask. 1986 // Set the core mask.
1868 R_TRY(thread->SetCoreMask(core_id, affinity_mask)); 1987 const auto set_result = thread->SetCoreMask(core_id, affinity_mask);
1988 if (set_result.IsError()) {
1989 LOG_ERROR(Kernel_SVC, "Unable to successfully set core mask (result={})", set_result.raw);
1990 return set_result;
1991 }
1869 1992
1870 return RESULT_SUCCESS; 1993 return RESULT_SUCCESS;
1871} 1994}
@@ -1884,7 +2007,10 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
1884 2007
1885 // Get the writable event. 2008 // Get the writable event.
1886 auto writable_event = handle_table.Get<KWritableEvent>(event_handle); 2009 auto writable_event = handle_table.Get<KWritableEvent>(event_handle);
1887 R_UNLESS(writable_event, Svc::ResultInvalidHandle); 2010 if (!writable_event) {
2011 LOG_ERROR(Kernel_SVC, "Invalid event handle provided (handle={:08X})", event_handle);
2012 return ResultInvalidHandle;
2013 }
1888 2014
1889 return writable_event->Signal(); 2015 return writable_event->Signal();
1890} 2016}
@@ -1933,7 +2059,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o
1933 2059
1934 // Create a new event. 2060 // Create a new event.
1935 const auto event = KEvent::Create(kernel, "CreateEvent"); 2061 const auto event = KEvent::Create(kernel, "CreateEvent");
1936 R_UNLESS(event != nullptr, Svc::ResultOutOfResource); 2062 if (!event) {
2063 LOG_ERROR(Kernel_SVC, "Unable to create new events. Event creation limit reached.");
2064 return ResultOutOfResource;
2065 }
1937 2066
1938 // Initialize the event. 2067 // Initialize the event.
1939 event->Initialize(); 2068 event->Initialize();
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() {
121 std::memcpy(&request, data.data(), sizeof(Request)); 121 std::memcpy(&request, data.data(), sizeof(Request));
122 122
123 switch (request) { 123 switch (request) {
124 case Request::Finalize:
125 complete = true;
126 broker.SignalStateChanged();
127 break;
124 case Request::Calc: { 128 case Request::Calc: {
125 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1})); 129 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{1}));
126 broker.SignalStateChanged(); 130 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) {
110 110
111IAppletResource ::~IAppletResource() { 111IAppletResource ::~IAppletResource() {
112 system.CoreTiming().UnscheduleEvent(pad_update_event, 0); 112 system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
113 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
113} 114}
114 115
115void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 116void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index 2a6d43d2a..7d7542fc2 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -143,17 +143,19 @@ private:
143 rb.Push(RESULT_SUCCESS); 143 rb.Push(RESULT_SUCCESS);
144 } 144 }
145 145
146 u32 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) { 146 u64 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) {
147 u32 result{}; 147 u64 result{};
148 u32 shift{}; 148 u32 shift{};
149 do { 149
150 result |= (data[offset] & 0x7f) << shift; 150 for (std::size_t i = 0; i < sizeof(u64); i++) {
151 const auto v = data[offset];
152 result |= (static_cast<u64>(v & 0x7f) << shift);
151 shift += 7; 153 shift += 7;
152 offset++; 154 offset++;
153 if (offset >= data.size()) { 155 if (offset >= data.size() || ((v & 0x80) == 0)) {
154 break; 156 break;
155 } 157 }
156 } while ((data[offset] & 0x80) != 0); 158 }
157 return result; 159 return result;
158 } 160 }
159 161
@@ -262,7 +264,7 @@ private:
262 264
263 switch (entry.severity) { 265 switch (entry.severity) {
264 case LogSeverity::Trace: 266 case LogSeverity::Trace:
265 LOG_DEBUG(Service_LM, "LogManager DEBUG ({}):\n{}", DestinationToString(destination), 267 LOG_DEBUG(Service_LM, "LogManager TRACE ({}):\n{}", DestinationToString(destination),
266 output_log); 268 output_log);
267 break; 269 break;
268 case LogSeverity::Info: 270 case LogSeverity::Info:
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 71c7587db..b6ac0a81a 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -65,13 +65,18 @@ static void DecryptSharedFont(const std::vector<u32>& input, Kernel::PhysicalMem
65void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) { 65void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) {
66 ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); 66 ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
67 67
68 if (input.size() < 2) {
69 LOG_ERROR(Service_NS, "Input font is empty");
70 return;
71 }
72
68 const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor 73 const u32 KEY = input[0] ^ EXPECTED_RESULT; // Derive key using an inverse xor
69 std::vector<u32> transformed_font(input.size()); 74 std::vector<u32> transformed_font(input.size());
70 // TODO(ogniK): Figure out a better way to do this 75 // TODO(ogniK): Figure out a better way to do this
71 std::transform(input.begin(), input.end(), transformed_font.begin(), 76 std::transform(input.begin(), input.end(), transformed_font.begin(),
72 [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); }); 77 [&KEY](u32 font_data) { return Common::swap32(font_data ^ KEY); });
73 transformed_font[1] = Common::swap32(transformed_font[1]) ^ KEY; // "re-encrypt" the size 78 std::memcpy(output.data(), transformed_font.data() + 2,
74 std::memcpy(output.data(), transformed_font.data() + 2, transformed_font.size() * sizeof(u32)); 79 (transformed_font.size() - 2) * sizeof(u32));
75} 80}
76 81
77void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, 82void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output,
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:
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, &OLSC::Initialize, "Initialize"}, 18 {0, &OLSC::Initialize, "Initialize"},
19 {10, nullptr, "VerifySaveDataBackupLicenseAsync"}, 19 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
20 {13, nullptr, "GetSaveDataBackupSetting"}, 20 {13, &OLSC::GetSaveDataBackupSetting, "GetSaveDataBackupSetting"},
21 {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"}, 21 {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
22 {15, nullptr, "SetCustomData"}, 22 {15, nullptr, "SetCustomData"},
23 {16, nullptr, "DeleteSaveDataBackupSetting"}, 23 {16, nullptr, "DeleteSaveDataBackupSetting"},
@@ -52,6 +52,17 @@ private:
52 rb.Push(RESULT_SUCCESS); 52 rb.Push(RESULT_SUCCESS);
53 } 53 }
54 54
55 void GetSaveDataBackupSetting(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57
58 // backup_setting is set to 0 since real value is unknown
59 constexpr u64 backup_setting = 0;
60
61 IPC::ResponseBuilder rb{ctx, 4};
62 rb.Push(RESULT_SUCCESS);
63 rb.Push(backup_setting);
64 }
65
55 void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) { 66 void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called"); 67 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57 68
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp
index 07a0fa4a1..770893687 100755
--- a/src/input_common/analog_from_button.cpp
+++ b/src/input_common/analog_from_button.cpp
@@ -139,6 +139,10 @@ public:
139 static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); 139 static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF));
140 } 140 }
141 141
142 Input::AnalogProperties GetAnalogProperties() const override {
143 return {modifier_scale, 1.0f, 0.5f};
144 }
145
142 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 146 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
143 switch (direction) { 147 switch (direction) {
144 case Input::AnalogDirection::RIGHT: 148 case Input::AnalogDirection::RIGHT:
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index 9670bdeb2..1b6ded8d6 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -185,6 +185,16 @@ public:
185 return {0.0f, 0.0f}; 185 return {0.0f, 0.0f};
186 } 186 }
187 187
188 std::tuple<float, float> GetRawStatus() const override {
189 const float x = GetAxis(axis_x);
190 const float y = GetAxis(axis_y);
191 return {x, y};
192 }
193
194 Input::AnalogProperties GetAnalogProperties() const override {
195 return {deadzone, range, 0.5f};
196 }
197
188 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 198 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
189 const auto [x, y] = GetStatus(); 199 const auto [x, y] = GetStatus();
190 const float directional_deadzone = 0.5f; 200 const float directional_deadzone = 0.5f;
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp
index 3d0dd7fc8..bb56787ee 100644
--- a/src/input_common/mouse/mouse_poller.cpp
+++ b/src/input_common/mouse/mouse_poller.cpp
@@ -107,6 +107,16 @@ public:
107 return {0.0f, 0.0f}; 107 return {0.0f, 0.0f};
108 } 108 }
109 109
110 std::tuple<float, float> GetRawStatus() const override {
111 const float x = GetAxis(axis_x);
112 const float y = GetAxis(axis_y);
113 return {x, y};
114 }
115
116 Input::AnalogProperties GetAnalogProperties() const override {
117 return {deadzone, range, 0.5f};
118 }
119
110private: 120private:
111 const u32 button; 121 const u32 button;
112 const u32 axis_x; 122 const u32 axis_x;
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 1b5750937..f67de37e3 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -377,6 +377,16 @@ public:
377 return {}; 377 return {};
378 } 378 }
379 379
380 std::tuple<float, float> GetRawStatus() const override {
381 const float x = joystick->GetAxis(axis_x, range);
382 const float y = joystick->GetAxis(axis_y, range);
383 return {x, -y};
384 }
385
386 Input::AnalogProperties GetAnalogProperties() const override {
387 return {deadzone, range, 0.5f};
388 }
389
380 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { 390 bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
381 const auto [x, y] = GetStatus(); 391 const auto [x, y] = GetStatus();
382 const float directional_deadzone = 0.5f; 392 const float directional_deadzone = 0.5f;
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() {
144 Reset(); 144 Reset();
145} 145}
146 146
147Client::ClientData::ClientData() = default;
148
149Client::ClientData::~ClientData() = default;
150
147std::vector<Common::ParamPackage> Client::GetInputDevices() const { 151std::vector<Common::ParamPackage> Client::GetInputDevices() const {
148 std::vector<Common::ParamPackage> devices; 152 std::vector<Common::ParamPackage> devices;
149 for (std::size_t client = 0; client < clients.size(); client++) { 153 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:
98 98
99private: 99private:
100 struct ClientData { 100 struct ClientData {
101 ClientData();
102 ~ClientData();
103
101 std::string host{"127.0.0.1"}; 104 std::string host{"127.0.0.1"};
102 u16 port{26760}; 105 u16 port{26760};
103 std::size_t pad_index{}; 106 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:
84 84
85private: 85private:
86 const std::string ip; 86 const std::string ip;
87 const u16 port; 87 [[maybe_unused]] const u16 port;
88 const u16 pad; 88 [[maybe_unused]] const u16 pad;
89 CemuhookUDP::Client* client; 89 CemuhookUDP::Client* client;
90 mutable std::mutex mutex; 90 mutable std::mutex mutex;
91}; 91};
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index bb1f8491f..dd4c29ed3 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -67,8 +67,6 @@ add_library(video_core STATIC
67 guest_driver.h 67 guest_driver.h
68 memory_manager.cpp 68 memory_manager.cpp
69 memory_manager.h 69 memory_manager.h
70 morton.cpp
71 morton.h
72 query_cache.h 70 query_cache.h
73 rasterizer_accelerated.cpp 71 rasterizer_accelerated.cpp
74 rasterizer_accelerated.h 72 rasterizer_accelerated.h
@@ -273,14 +271,13 @@ create_target_directory_groups(video_core)
273target_link_libraries(video_core PUBLIC common core) 271target_link_libraries(video_core PUBLIC common core)
274target_link_libraries(video_core PRIVATE glad xbyak) 272target_link_libraries(video_core PRIVATE glad xbyak)
275 273
276if (MSVC) 274if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32)
277 target_include_directories(video_core PRIVATE ${FFMPEG_INCLUDE_DIR}) 275 add_dependencies(video_core ffmpeg-build)
278 target_link_libraries(video_core PUBLIC ${FFMPEG_LIBRARY_DIR}/swscale.lib ${FFMPEG_LIBRARY_DIR}/avcodec.lib ${FFMPEG_LIBRARY_DIR}/avutil.lib)
279else()
280 target_include_directories(video_core PRIVATE ${FFMPEG_INCLUDE_DIR})
281 target_link_libraries(video_core PRIVATE ${FFMPEG_LIBRARIES})
282endif() 276endif()
283 277
278target_include_directories(video_core PRIVATE ${FFmpeg_INCLUDE_DIR})
279target_link_libraries(video_core PRIVATE ${FFmpeg_LIBRARIES})
280
284add_dependencies(video_core host_shaders) 281add_dependencies(video_core host_shaders)
285target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) 282target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
286target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) 283target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp
deleted file mode 100644
index e69de29bb..000000000
--- a/src/video_core/morton.cpp
+++ /dev/null
diff --git a/src/video_core/morton.h b/src/video_core/morton.h
deleted file mode 100644
index e69de29bb..000000000
--- a/src/video_core/morton.h
+++ /dev/null
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 =
67constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16; 67constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
68constexpr size_t NUM_SUPPORTED_VERTEX_BINDINGS = 16; 68constexpr size_t NUM_SUPPORTED_VERTEX_BINDINGS = 16;
69 69
70constexpr size_t MAX_TEXTURES = 192;
71constexpr size_t MAX_IMAGES = 48;
72
73struct TextureHandle { 70struct TextureHandle {
74 constexpr TextureHandle(u32 data, bool via_header_index) { 71 constexpr TextureHandle(u32 data, bool via_header_index) {
75 const Tegra::Texture::TextureHandle handle{data}; 72 const Tegra::Texture::TextureHandle handle{data};
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index dd77a543c..21159e498 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -506,7 +506,7 @@ bool RendererOpenGL::Init() {
506 506
507 AddTelemetryFields(); 507 AddTelemetryFields();
508 508
509 if (!GLAD_GL_VERSION_4_3) { 509 if (!GLAD_GL_VERSION_4_6) {
510 return false; 510 return false;
511 } 511 }
512 512
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>
169 return Common::DivCeil(AdjustMipSize(size, level), block_size); 169 return Common::DivCeil(AdjustMipSize(size, level), block_size);
170} 170}
171 171
172[[nodiscard]] constexpr u32 LayerSize(const TICEntry& config, PixelFormat format) {
173 return config.Width() * config.Height() * BytesPerBlock(format);
174}
175
176[[nodiscard]] constexpr bool HasTwoDimsPerLayer(TextureType type) {
177 switch (type) {
178 case TextureType::Texture2D:
179 case TextureType::Texture2DArray:
180 case TextureType::Texture2DNoMipmap:
181 case TextureType::Texture3D:
182 case TextureType::TextureCubeArray:
183 case TextureType::TextureCubemap:
184 return true;
185 case TextureType::Texture1D:
186 case TextureType::Texture1DArray:
187 case TextureType::Texture1DBuffer:
188 return false;
189 }
190 return false;
191}
192
193[[nodiscard]] constexpr bool HasTwoDimsPerLayer(ImageType type) {
194 switch (type) {
195 case ImageType::e2D:
196 case ImageType::e3D:
197 case ImageType::Linear:
198 return true;
199 case ImageType::e1D:
200 case ImageType::Buffer:
201 return false;
202 }
203 UNREACHABLE_MSG("Invalid image type={}", static_cast<int>(type));
204}
205
206[[nodiscard]] constexpr std::pair<int, int> Samples(int num_samples) { 172[[nodiscard]] constexpr std::pair<int, int> Samples(int num_samples) {
207 switch (num_samples) { 173 switch (num_samples) {
208 case 1: 174 case 1:
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index e1bab2112..fb9967c8f 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -71,6 +71,8 @@ add_executable(yuzu
71 configuration/configure_input_player.cpp 71 configuration/configure_input_player.cpp
72 configuration/configure_input_player.h 72 configuration/configure_input_player.h
73 configuration/configure_input_player.ui 73 configuration/configure_input_player.ui
74 configuration/configure_input_player_widget.cpp
75 configuration/configure_input_player_widget.h
74 configuration/configure_input_profile_dialog.cpp 76 configuration/configure_input_profile_dialog.cpp
75 configuration/configure_input_profile_dialog.h 77 configuration/configure_input_profile_dialog.h
76 configuration/configure_input_profile_dialog.ui 78 configuration/configure_input_profile_dialog.ui
@@ -115,6 +117,8 @@ add_executable(yuzu
115 configuration/input_profiles.h 117 configuration/input_profiles.h
116 debugger/console.cpp 118 debugger/console.cpp
117 debugger/console.h 119 debugger/console.h
120 debugger/controller.cpp
121 debugger/controller.h
118 debugger/profiler.cpp 122 debugger/profiler.cpp
119 debugger/profiler.h 123 debugger/profiler.h
120 debugger/wait_tree.cpp 124 debugger/wait_tree.cpp
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index f278f1439..d9a3035cb 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -126,7 +126,7 @@ public:
126 /// Create the original context that should be shared from 126 /// Create the original context that should be shared from
127 explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { 127 explicit OpenGLSharedContext(QSurface* surface) : surface(surface) {
128 QSurfaceFormat format; 128 QSurfaceFormat format;
129 format.setVersion(4, 3); 129 format.setVersion(4, 6);
130 format.setProfile(QSurfaceFormat::CompatibilityProfile); 130 format.setProfile(QSurfaceFormat::CompatibilityProfile);
131 format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); 131 format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions);
132 if (Settings::values.renderer_debug) { 132 if (Settings::values.renderer_debug) {
@@ -656,10 +656,10 @@ bool GRenderWindow::LoadOpenGL() {
656 const QString renderer = 656 const QString renderer =
657 QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER))); 657 QString::fromUtf8(reinterpret_cast<const char*>(glGetString(GL_RENDERER)));
658 658
659 if (!GLAD_GL_VERSION_4_3) { 659 if (!GLAD_GL_VERSION_4_6) {
660 LOG_ERROR(Frontend, "GPU does not support OpenGL 4.3: {}", renderer.toStdString()); 660 LOG_ERROR(Frontend, "GPU does not support OpenGL 4.6: {}", renderer.toStdString());
661 QMessageBox::warning(this, tr("Error while initializing OpenGL 4.3!"), 661 QMessageBox::warning(this, tr("Error while initializing OpenGL 4.6!"),
662 tr("Your GPU may not support OpenGL 4.3, or you do not have the " 662 tr("Your GPU may not support OpenGL 4.6, or you do not have the "
663 "latest graphics driver.<br><br>GL Renderer:<br>%1") 663 "latest graphics driver.<br><br>GL Renderer:<br>%1")
664 .arg(renderer)); 664 .arg(renderer));
665 return false; 665 return false;
@@ -682,26 +682,13 @@ bool GRenderWindow::LoadOpenGL() {
682QStringList GRenderWindow::GetUnsupportedGLExtensions() const { 682QStringList GRenderWindow::GetUnsupportedGLExtensions() const {
683 QStringList unsupported_ext; 683 QStringList unsupported_ext;
684 684
685 if (!GLAD_GL_ARB_buffer_storage)
686 unsupported_ext.append(QStringLiteral("ARB_buffer_storage"));
687 if (!GLAD_GL_ARB_direct_state_access)
688 unsupported_ext.append(QStringLiteral("ARB_direct_state_access"));
689 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
690 unsupported_ext.append(QStringLiteral("ARB_vertex_type_10f_11f_11f_rev"));
691 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
692 unsupported_ext.append(QStringLiteral("ARB_texture_mirror_clamp_to_edge"));
693 if (!GLAD_GL_ARB_multi_bind)
694 unsupported_ext.append(QStringLiteral("ARB_multi_bind"));
695 if (!GLAD_GL_ARB_clip_control)
696 unsupported_ext.append(QStringLiteral("ARB_clip_control"));
697
698 // Extensions required to support some texture formats. 685 // Extensions required to support some texture formats.
699 if (!GLAD_GL_EXT_texture_compression_s3tc) 686 if (!GLAD_GL_EXT_texture_compression_s3tc) {
700 unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc")); 687 unsupported_ext.append(QStringLiteral("EXT_texture_compression_s3tc"));
701 if (!GLAD_GL_ARB_texture_compression_rgtc) 688 }
689 if (!GLAD_GL_ARB_texture_compression_rgtc) {
702 unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc")); 690 unsupported_ext.append(QStringLiteral("ARB_texture_compression_rgtc"));
703 if (!GLAD_GL_ARB_depth_buffer_float) 691 }
704 unsupported_ext.append(QStringLiteral("ARB_depth_buffer_float"));
705 692
706 if (!unsupported_ext.empty()) { 693 if (!unsupported_ext.empty()) {
707 LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", 694 LOG_ERROR(Frontend, "GPU does not support all required extensions: {}",
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index b40d7c5e2..c9d19c948 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -23,6 +23,7 @@
23#include "ui_configure_input_player.h" 23#include "ui_configure_input_player.h"
24#include "yuzu/configuration/config.h" 24#include "yuzu/configuration/config.h"
25#include "yuzu/configuration/configure_input_player.h" 25#include "yuzu/configuration/configure_input_player.h"
26#include "yuzu/configuration/configure_input_player_widget.h"
26#include "yuzu/configuration/configure_vibration.h" 27#include "yuzu/configuration/configure_vibration.h"
27#include "yuzu/configuration/input_profiles.h" 28#include "yuzu/configuration/input_profiles.h"
28#include "yuzu/util/limitable_input_dialog.h" 29#include "yuzu/util/limitable_input_dialog.h"
@@ -254,11 +255,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
254 analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; 255 analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup};
255 analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; 256 analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
256 257
257 const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param, 258 const auto ConfigureButtonClick = [&](QPushButton* button, std::size_t button_id,
258 int default_val, InputCommon::Polling::DeviceType type) { 259 Common::ParamPackage* param, int default_val,
260 InputCommon::Polling::DeviceType type) {
259 connect(button, &QPushButton::clicked, [=, this] { 261 connect(button, &QPushButton::clicked, [=, this] {
260 HandleClick( 262 HandleClick(
261 button, 263 button, button_id,
262 [=, this](Common::ParamPackage params) { 264 [=, this](Common::ParamPackage params) {
263 // Workaround for ZL & ZR for analog triggers like on XBOX 265 // Workaround for ZL & ZR for analog triggers like on XBOX
264 // controllers. Analog triggers (from controllers like the XBOX 266 // controllers. Analog triggers (from controllers like the XBOX
@@ -286,12 +288,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
286 continue; 288 continue;
287 } 289 }
288 290
289 ConfigureButtonClick(button_map[button_id], &buttons_param[button_id], 291 ConfigureButtonClick(button_map[button_id], button_id, &buttons_param[button_id],
290 Config::default_buttons[button_id], 292 Config::default_buttons[button_id],
291 InputCommon::Polling::DeviceType::Button); 293 InputCommon::Polling::DeviceType::Button);
292 294
293 button->setContextMenuPolicy(Qt::CustomContextMenu); 295 button->setContextMenuPolicy(Qt::CustomContextMenu);
294
295 connect(button, &QPushButton::customContextMenuRequested, 296 connect(button, &QPushButton::customContextMenuRequested,
296 [=, this](const QPoint& menu_location) { 297 [=, this](const QPoint& menu_location) {
297 QMenu context_menu; 298 QMenu context_menu;
@@ -300,6 +301,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
300 button_map[button_id]->setText(tr("[not set]")); 301 button_map[button_id]->setText(tr("[not set]"));
301 }); 302 });
302 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); 303 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
304 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
303 }); 305 });
304 } 306 }
305 307
@@ -309,7 +311,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
309 continue; 311 continue;
310 } 312 }
311 313
312 ConfigureButtonClick(motion_map[motion_id], &motions_param[motion_id], 314 ConfigureButtonClick(motion_map[motion_id], motion_id, &motions_param[motion_id],
313 Config::default_motions[motion_id], 315 Config::default_motions[motion_id],
314 InputCommon::Polling::DeviceType::Motion); 316 InputCommon::Polling::DeviceType::Motion);
315 317
@@ -348,7 +350,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
348 } 350 }
349 } 351 }
350 HandleClick( 352 HandleClick(
351 analog_map_buttons[analog_id][sub_button_id], 353 analog_map_buttons[analog_id][sub_button_id], analog_id,
352 [=, this](const Common::ParamPackage& params) { 354 [=, this](const Common::ParamPackage& params) {
353 SetAnalogParam(params, analogs_param[analog_id], 355 SetAnalogParam(params, analogs_param[analog_id],
354 analog_sub_buttons[sub_button_id]); 356 analog_sub_buttons[sub_button_id]);
@@ -358,41 +360,43 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
358 360
359 analog_button->setContextMenuPolicy(Qt::CustomContextMenu); 361 analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
360 362
361 connect(analog_button, &QPushButton::customContextMenuRequested, 363 connect(
362 [=, this](const QPoint& menu_location) { 364 analog_button, &QPushButton::customContextMenuRequested,
363 QMenu context_menu; 365 [=, this](const QPoint& menu_location) {
364 context_menu.addAction(tr("Clear"), [&] { 366 QMenu context_menu;
365 analogs_param[analog_id].Clear(); 367 context_menu.addAction(tr("Clear"), [&] {
366 analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); 368 analogs_param[analog_id].Clear();
367 }); 369 analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
368 context_menu.addAction(tr("Invert axis"), [&] { 370 });
369 if (sub_button_id == 2 || sub_button_id == 3) { 371 context_menu.addAction(tr("Invert axis"), [&] {
370 const bool invert_value = 372 if (sub_button_id == 2 || sub_button_id == 3) {
371 analogs_param[analog_id].Get("invert_x", "+") == "-"; 373 const bool invert_value =
372 const std::string invert_str = invert_value ? "+" : "-"; 374 analogs_param[analog_id].Get("invert_x", "+") == "-";
373 analogs_param[analog_id].Set("invert_x", invert_str); 375 const std::string invert_str = invert_value ? "+" : "-";
374 } 376 analogs_param[analog_id].Set("invert_x", invert_str);
375 if (sub_button_id == 0 || sub_button_id == 1) { 377 }
376 const bool invert_value = 378 if (sub_button_id == 0 || sub_button_id == 1) {
377 analogs_param[analog_id].Get("invert_y", "+") == "-"; 379 const bool invert_value =
378 const std::string invert_str = invert_value ? "+" : "-"; 380 analogs_param[analog_id].Get("invert_y", "+") == "-";
379 analogs_param[analog_id].Set("invert_y", invert_str); 381 const std::string invert_str = invert_value ? "+" : "-";
380 } 382 analogs_param[analog_id].Set("invert_y", invert_str);
381 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; 383 }
382 ++sub_button_id) { 384 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM;
383 analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( 385 ++sub_button_id) {
384 analogs_param[analog_id], analog_sub_buttons[sub_button_id])); 386 analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
385 } 387 analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
386 }); 388 }
387 context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
388 menu_location));
389 }); 389 });
390 context_menu.exec(
391 analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(menu_location));
392 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
393 });
390 } 394 }
391 395
392 // Handle clicks for the modifier buttons as well. 396 // Handle clicks for the modifier buttons as well.
393 connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] { 397 connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] {
394 HandleClick( 398 HandleClick(
395 analog_map_modifier_button[analog_id], 399 analog_map_modifier_button[analog_id], analog_id,
396 [=, this](const Common::ParamPackage& params) { 400 [=, this](const Common::ParamPackage& params) {
397 analogs_param[analog_id].Set("modifier", params.Serialize()); 401 analogs_param[analog_id].Set("modifier", params.Serialize());
398 }, 402 },
@@ -416,12 +420,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
416 [=, this] { 420 [=, this] {
417 const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); 421 const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
418 analogs_param[analog_id].Set("range", spinbox_value / 100.0f); 422 analogs_param[analog_id].Set("range", spinbox_value / 100.0f);
423 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
419 }); 424 });
420 425
421 connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { 426 connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
422 const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); 427 const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
423 analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); 428 analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
424 analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); 429 analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
430 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
425 }); 431 });
426 432
427 connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { 433 connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
@@ -433,8 +439,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
433 } 439 }
434 440
435 // Player Connected checkbox 441 // Player Connected checkbox
436 connect(ui->groupConnectedController, &QGroupBox::toggled, 442 connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) {
437 [this](bool checked) { emit Connected(checked); }); 443 emit Connected(checked);
444 ui->controllerFrame->SetConnectedStatus(checked);
445 });
438 446
439 if (player_index == 0) { 447 if (player_index == 0) {
440 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), 448 connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged),
@@ -553,6 +561,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
553 561
554 // TODO(wwylele): enable this when we actually emulate it 562 // TODO(wwylele): enable this when we actually emulate it
555 ui->buttonHome->setEnabled(false); 563 ui->buttonHome->setEnabled(false);
564 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
565 ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked());
556} 566}
557 567
558ConfigureInputPlayer::~ConfigureInputPlayer() = default; 568ConfigureInputPlayer::~ConfigureInputPlayer() = default;
@@ -875,6 +885,7 @@ void ConfigureInputPlayer::UpdateUI() {
875 modifier_label->setVisible(!is_controller); 885 modifier_label->setVisible(!is_controller);
876 modifier_slider->setVisible(!is_controller); 886 modifier_slider->setVisible(!is_controller);
877 range_groupbox->setVisible(is_controller); 887 range_groupbox->setVisible(is_controller);
888 ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
878 } 889 }
879} 890}
880 891
@@ -991,8 +1002,8 @@ void ConfigureInputPlayer::UpdateControllerIcon() {
991 return QString{}; 1002 return QString{};
992 } 1003 }
993 }(); 1004 }();
994 1005 ui->controllerFrame->SetControllerType(
995 ui->controllerFrame->setStyleSheet(stylesheet.arg(theme)); 1006 GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()));
996} 1007}
997 1008
998void ConfigureInputPlayer::UpdateControllerAvailableButtons() { 1009void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
@@ -1129,7 +1140,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
1129} 1140}
1130 1141
1131void ConfigureInputPlayer::HandleClick( 1142void ConfigureInputPlayer::HandleClick(
1132 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter, 1143 QPushButton* button, std::size_t button_id,
1144 std::function<void(const Common::ParamPackage&)> new_input_setter,
1133 InputCommon::Polling::DeviceType type) { 1145 InputCommon::Polling::DeviceType type) {
1134 if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) { 1146 if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
1135 button->setText(tr("Shake!")); 1147 button->setText(tr("Shake!"));
@@ -1173,6 +1185,12 @@ void ConfigureInputPlayer::HandleClick(
1173 input_subsystem->GetMouseTouch()->BeginConfiguration(); 1185 input_subsystem->GetMouseTouch()->BeginConfiguration();
1174 } 1186 }
1175 1187
1188 if (type == InputCommon::Polling::DeviceType::Button) {
1189 ui->controllerFrame->BeginMappingButton(button_id);
1190 } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) {
1191 ui->controllerFrame->BeginMappingAnalog(button_id);
1192 }
1193
1176 timeout_timer->start(2500); // Cancel after 2.5 seconds 1194 timeout_timer->start(2500); // Cancel after 2.5 seconds
1177 poll_timer->start(50); // Check for new inputs every 50ms 1195 poll_timer->start(50); // Check for new inputs every 50ms
1178} 1196}
@@ -1203,6 +1221,7 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
1203 1221
1204 UpdateUI(); 1222 UpdateUI();
1205 UpdateInputDeviceCombobox(); 1223 UpdateInputDeviceCombobox();
1224 ui->controllerFrame->EndMapping();
1206 1225
1207 input_setter = std::nullopt; 1226 input_setter = std::nullopt;
1208} 1227}
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h
index c4ae50de7..da2b89136 100644
--- a/src/yuzu/configuration/configure_input_player.h
+++ b/src/yuzu/configuration/configure_input_player.h
@@ -106,7 +106,7 @@ private:
106 void LoadConfiguration(); 106 void LoadConfiguration();
107 107
108 /// Called when the button was pressed. 108 /// Called when the button was pressed.
109 void HandleClick(QPushButton* button, 109 void HandleClick(QPushButton* button, std::size_t button_id,
110 std::function<void(const Common::ParamPackage&)> new_input_setter, 110 std::function<void(const Common::ParamPackage&)> new_input_setter,
111 InputCommon::Polling::DeviceType type); 111 InputCommon::Polling::DeviceType type);
112 112
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index 1e78b4c10..e76aa484f 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -1964,39 +1964,39 @@
1964 </item> 1964 </item>
1965 </layout> 1965 </layout>
1966 </item> 1966 </item>
1967 <item> 1967 <item>
1968 <widget class="QFrame" name="controllerFrame"> 1968 <widget class="PlayerControlPreview" name="controllerFrame">
1969 <property name="sizePolicy"> 1969 <property name="sizePolicy">
1970 <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> 1970 <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
1971 <horstretch>0</horstretch> 1971 <horstretch>0</horstretch>
1972 <verstretch>0</verstretch> 1972 <verstretch>0</verstretch>
1973 </sizepolicy> 1973 </sizepolicy>
1974 </property> 1974 </property>
1975 <property name="font"> 1975 <property name="font">
1976 <font> 1976 <font>
1977 <weight>75</weight> 1977 <weight>75</weight>
1978 <bold>true</bold> 1978 <bold>true</bold>
1979 </font> 1979 </font>
1980 </property> 1980 </property>
1981 <property name="styleSheet"> 1981 <property name="styleSheet">
1982 <string notr="true">image: url(:/controller/pro);</string> 1982 <string notr="true">image: url(:/controller/pro);</string>
1983 </property> 1983 </property>
1984 <layout class="QVBoxLayout" name="verticalLayout_4"> 1984 <layout class="QVBoxLayout" name="verticalLayout_4">
1985 <property name="leftMargin"> 1985 <property name="leftMargin">
1986 <number>0</number> 1986 <number>0</number>
1987 </property> 1987 </property>
1988 <property name="topMargin"> 1988 <property name="topMargin">
1989 <number>0</number> 1989 <number>0</number>
1990 </property> 1990 </property>
1991 <property name="rightMargin"> 1991 <property name="rightMargin">
1992 <number>0</number> 1992 <number>0</number>
1993 </property> 1993 </property>
1994 <property name="bottomMargin"> 1994 <property name="bottomMargin">
1995 <number>0</number> 1995 <number>0</number>
1996 </property> 1996 </property>
1997 </layout> 1997 </layout>
1998 </widget> 1998 </widget>
1999 </item> 1999 </item>
2000 <item> 2000 <item>
2001 <layout class="QHBoxLayout" name="miscButtons"> 2001 <layout class="QHBoxLayout" name="miscButtons">
2002 <property name="spacing"> 2002 <property name="spacing">
@@ -3087,6 +3087,14 @@
3087 </item> 3087 </item>
3088 </layout> 3088 </layout>
3089 </widget> 3089 </widget>
3090 <customwidgets>
3091 <customwidget>
3092 <class>PlayerControlPreview</class>
3093 <extends>QFrame</extends>
3094 <header>yuzu/configuration/configure_input_player_widget.h</header>
3095 <container>1</container>
3096 </customwidget>
3097 </customwidgets>
3090 <resources> 3098 <resources>
3091 <include location="../../../dist/icons/controller/controller.qrc"/> 3099 <include location="../../../dist/icons/controller/controller.qrc"/>
3092 </resources> 3100 </resources>
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
new file mode 100644
index 000000000..0e8a964d2
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -0,0 +1,2729 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <QMenu>
7#include <QPainter>
8#include <QTimer>
9#include "yuzu/configuration/configure_input_player_widget.h"
10
11PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) {
12 UpdateColors();
13 QTimer* timer = new QTimer(this);
14 connect(timer, &QTimer::timeout, this, QOverload<>::of(&PlayerControlPreview::UpdateInput));
15
16 // refresh at 60hz
17 timer->start(16);
18}
19
20PlayerControlPreview::~PlayerControlPreview() = default;
21
22void PlayerControlPreview::SetPlayerInput(std::size_t index, const ButtonParam& buttons_param,
23 const AnalogParam& analogs_param) {
24 player_index = index;
25 Settings::ButtonsRaw buttonss;
26 Settings::AnalogsRaw analogs;
27 std::transform(buttons_param.begin(), buttons_param.end(), buttonss.begin(),
28 [](const Common::ParamPackage& param) { return param.Serialize(); });
29 std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(),
30 [](const Common::ParamPackage& param) { return param.Serialize(); });
31
32 std::transform(buttonss.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
33 buttonss.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(),
34 Input::CreateDevice<Input::ButtonDevice>);
35 std::transform(analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
36 analogs.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(),
37 Input::CreateDevice<Input::AnalogDevice>);
38 UpdateColors();
39}
40void PlayerControlPreview::SetPlayerInputRaw(std::size_t index,
41 const Settings::ButtonsRaw& buttons_,
42 Settings::AnalogsRaw analogs_) {
43 player_index = index;
44 std::transform(buttons_.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
45 buttons_.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(),
46 Input::CreateDevice<Input::ButtonDevice>);
47 std::transform(analogs_.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
48 analogs_.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(),
49 Input::CreateDevice<Input::AnalogDevice>);
50 UpdateColors();
51}
52
53PlayerControlPreview::LedPattern PlayerControlPreview::GetColorPattern(std::size_t index,
54 bool player_on) {
55 if (!player_on) {
56 return {0, 0, 0, 0};
57 }
58
59 switch (index) {
60 case 0:
61 return {1, 0, 0, 0};
62 case 1:
63 return {1, 1, 0, 0};
64 case 2:
65 return {1, 1, 1, 0};
66 case 3:
67 return {1, 1, 1, 1};
68 case 4:
69 return {1, 0, 0, 1};
70 case 5:
71 return {1, 0, 1, 0};
72 case 6:
73 return {1, 0, 1, 1};
74 case 7:
75 return {0, 1, 1, 0};
76 default:
77 return {0, 0, 0, 0};
78 }
79}
80
81void PlayerControlPreview::SetConnectedStatus(bool checked) {
82 LedPattern led_pattern = GetColorPattern(player_index, checked);
83
84 led_color[0] = led_pattern.position1 ? colors.led_on : colors.led_off;
85 led_color[1] = led_pattern.position2 ? colors.led_on : colors.led_off;
86 led_color[2] = led_pattern.position3 ? colors.led_on : colors.led_off;
87 led_color[3] = led_pattern.position4 ? colors.led_on : colors.led_off;
88}
89
90void PlayerControlPreview::SetControllerType(const Settings::ControllerType type) {
91 controller_type = type;
92 UpdateColors();
93}
94
95void PlayerControlPreview::BeginMappingButton(std::size_t index) {
96 button_mapping_index = index;
97 mapping_active = true;
98}
99
100void PlayerControlPreview::BeginMappingAnalog(std::size_t index) {
101 button_mapping_index = Settings::NativeButton::LStick + index;
102 analog_mapping_index = index;
103 mapping_active = true;
104}
105
106void PlayerControlPreview::EndMapping() {
107 button_mapping_index = Settings::NativeButton::BUTTON_NS_END;
108 analog_mapping_index = Settings::NativeAnalog::NumAnalogs;
109 mapping_active = false;
110 blink_counter = 0;
111}
112
113void PlayerControlPreview::UpdateColors() {
114 if (QIcon::themeName().contains(QStringLiteral("dark")) ||
115 QIcon::themeName().contains(QStringLiteral("midnight"))) {
116 colors.primary = QColor(204, 204, 204);
117 colors.button = QColor(35, 38, 41);
118 colors.button2 = QColor(26, 27, 30);
119 colors.slider_arrow = QColor(14, 15, 18);
120 colors.font2 = QColor(255, 255, 255);
121 colors.indicator = QColor(170, 238, 255);
122 colors.deadzone = QColor(204, 136, 136);
123 colors.slider_button = colors.button;
124 }
125
126 if (QIcon::themeName().contains(QStringLiteral("dark"))) {
127 colors.outline = QColor(160, 160, 160);
128 } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
129 colors.outline = QColor(145, 145, 145);
130 } else {
131 colors.outline = QColor(0, 0, 0);
132 colors.primary = QColor(225, 225, 225);
133 colors.button = QColor(109, 111, 114);
134 colors.button2 = QColor(109, 111, 114);
135 colors.button2 = QColor(77, 80, 84);
136 colors.slider_arrow = QColor(65, 68, 73);
137 colors.font2 = QColor(0, 0, 0);
138 colors.indicator = QColor(0, 0, 200);
139 colors.deadzone = QColor(170, 0, 0);
140 colors.slider_button = QColor(153, 149, 149);
141 }
142
143 // Constant colors
144 colors.highlight = QColor(170, 0, 0);
145 colors.highlight2 = QColor(119, 0, 0);
146 colors.slider = QColor(103, 106, 110);
147 colors.transparent = QColor(0, 0, 0, 0);
148 colors.font = QColor(255, 255, 255);
149 colors.led_on = QColor(255, 255, 0);
150 colors.led_off = QColor(170, 238, 255);
151
152 colors.left = colors.primary;
153 colors.right = colors.primary;
154 // Possible alternative to set colors from settings
155 // colors.left = QColor(Settings::values.players.GetValue()[player_index].body_color_left);
156 // colors.right = QColor(Settings::values.players.GetValue()[player_index].body_color_right);
157}
158
159void PlayerControlPreview::UpdateInput() {
160 bool input_changed = false;
161 const auto& button_state = buttons;
162 for (std::size_t index = 0; index < button_values.size(); ++index) {
163 bool value = false;
164 if (index < Settings::NativeButton::BUTTON_NS_END) {
165 value = button_state[index]->GetStatus();
166 }
167 bool blink = mapping_active && index == button_mapping_index;
168 if (analog_mapping_index == Settings::NativeAnalog::NUM_STICKS_HID) {
169 blink &= blink_counter > 25;
170 }
171 if (button_values[index] != value || blink) {
172 input_changed = true;
173 }
174 button_values[index] = value || blink;
175 }
176
177 const auto& analog_state = sticks;
178 for (std::size_t index = 0; index < axis_values.size(); ++index) {
179 const auto [stick_x_f, stick_y_f] = analog_state[index]->GetStatus();
180 const auto [stick_x_rf, stick_y_rf] = analog_state[index]->GetRawStatus();
181
182 if (static_cast<int>(stick_x_rf * 45) !=
183 static_cast<int>(axis_values[index].raw_value.x() * 45) ||
184 static_cast<int>(-stick_y_rf * 45) !=
185 static_cast<int>(axis_values[index].raw_value.y() * 45)) {
186 input_changed = true;
187 }
188
189 axis_values[index].properties = analog_state[index]->GetAnalogProperties();
190 axis_values[index].value = QPointF(stick_x_f, -stick_y_f);
191 axis_values[index].raw_value = QPointF(stick_x_rf, -stick_y_rf);
192
193 const bool blink_analog = mapping_active && index == analog_mapping_index;
194 if (blink_analog) {
195 input_changed = true;
196 axis_values[index].value =
197 QPointF(blink_counter < 25 ? -blink_counter / 25.0f : 0,
198 blink_counter > 25 ? -(blink_counter - 25) / 25.0f : 0);
199 }
200 }
201
202 if (input_changed) {
203 update();
204 }
205
206 if (mapping_active) {
207 blink_counter = (blink_counter + 1) % 50;
208 }
209}
210
211void PlayerControlPreview::paintEvent(QPaintEvent* event) {
212 QFrame::paintEvent(event);
213 QPainter p(this);
214 p.setRenderHint(QPainter::Antialiasing);
215 const QPointF center = rect().center();
216
217 switch (controller_type) {
218 case Settings::ControllerType::Handheld:
219 DrawHandheldController(p, center);
220 break;
221 case Settings::ControllerType::DualJoyconDetached:
222 DrawDualController(p, center);
223 break;
224 case Settings::ControllerType::LeftJoycon:
225 DrawLeftController(p, center);
226 break;
227 case Settings::ControllerType::RightJoycon:
228 DrawRightController(p, center);
229 break;
230 case Settings::ControllerType::ProController:
231 default:
232 DrawProController(p, center);
233 break;
234 }
235}
236
237void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) {
238 {
239 using namespace Settings::NativeButton;
240
241 // Sideview left joystick
242 DrawJoystickSideview(p, center + QPoint(142, -69),
243 -axis_values[Settings::NativeAnalog::LStick].value.y(), 1.15f,
244 button_values[LStick]);
245
246 // Topview D-pad buttons
247 p.setPen(colors.outline);
248 button_color = colors.button;
249 DrawRoundButton(p, center + QPoint(-163, -21), button_values[DLeft], 11, 5, Direction::Up);
250 DrawRoundButton(p, center + QPoint(-117, -21), button_values[DRight], 11, 5, Direction::Up);
251
252 // Topview left joystick
253 DrawJoystickSideview(p, center + QPointF(-140.5f, -28),
254 -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1.15f,
255 button_values[LStick]);
256
257 // Topview minus button
258 p.setPen(colors.outline);
259 button_color = colors.button;
260 DrawRoundButton(p, center + QPoint(-111, -22), button_values[Minus], 8, 4, Direction::Up,
261 1);
262
263 // Left trigger
264 DrawLeftTriggers(p, center, button_values[L]);
265 DrawRoundButton(p, center + QPoint(151, -146), button_values[L], 8, 4, Direction::Down);
266 DrawLeftZTriggers(p, center, button_values[ZL]);
267
268 // Sideview D-pad buttons
269 DrawRoundButton(p, center + QPoint(135, 14), button_values[DLeft], 5, 11, Direction::Right);
270 DrawRoundButton(p, center + QPoint(135, 36), button_values[DDown], 5, 11, Direction::Right);
271 DrawRoundButton(p, center + QPoint(135, -10), button_values[DUp], 5, 11, Direction::Right);
272 DrawRoundButton(p, center + QPoint(135, 14), button_values[DRight], 5, 11,
273 Direction::Right);
274 DrawRoundButton(p, center + QPoint(135, 71), button_values[Screenshot], 3, 8,
275 Direction::Right, 1);
276
277 // Sideview minus button
278 DrawRoundButton(p, center + QPoint(135, -118), button_values[Minus], 4, 2.66f,
279 Direction::Right, 1);
280
281 // Sideview SL and SR buttons
282 button_color = colors.slider_button;
283 DrawRoundButton(p, center + QPoint(59, 52), button_values[SR], 5, 12, Direction::Left);
284 DrawRoundButton(p, center + QPoint(59, -69), button_values[SL], 5, 12, Direction::Left);
285
286 DrawLeftBody(p, center);
287
288 // Left trigger top view
289 DrawLeftTriggersTopView(p, center, button_values[L]);
290 DrawLeftZTriggersTopView(p, center, button_values[ZL]);
291 }
292
293 {
294 // Draw joysticks
295 using namespace Settings::NativeAnalog;
296 DrawJoystick(p, center + QPointF(9, -69) + (axis_values[LStick].value * 8), 1.8f,
297 button_values[Settings::NativeButton::LStick]);
298 DrawRawJoystick(p, center + QPointF(-140, 90), axis_values[LStick].raw_value,
299 axis_values[LStick].properties);
300 }
301
302 using namespace Settings::NativeButton;
303
304 // D-pad constants
305 const QPointF dpad_center = center + QPoint(9, 14);
306 constexpr int dpad_distance = 23;
307 constexpr int dpad_radius = 11;
308 constexpr float dpad_arrow_size = 1.2f;
309
310 // D-pad buttons
311 p.setPen(colors.outline);
312 button_color = colors.button;
313 DrawCircleButton(p, dpad_center + QPoint(dpad_distance, 0), button_values[DRight], dpad_radius);
314 DrawCircleButton(p, dpad_center + QPoint(0, dpad_distance), button_values[DDown], dpad_radius);
315 DrawCircleButton(p, dpad_center + QPoint(0, -dpad_distance), button_values[DUp], dpad_radius);
316 DrawCircleButton(p, dpad_center + QPoint(-dpad_distance, 0), button_values[DLeft], dpad_radius);
317
318 // D-pad arrows
319 p.setPen(colors.font2);
320 p.setBrush(colors.font2);
321 DrawArrow(p, dpad_center + QPoint(dpad_distance, 0), Direction::Right, dpad_arrow_size);
322 DrawArrow(p, dpad_center + QPoint(0, dpad_distance), Direction::Down, dpad_arrow_size);
323 DrawArrow(p, dpad_center + QPoint(0, -dpad_distance), Direction::Up, dpad_arrow_size);
324 DrawArrow(p, dpad_center + QPoint(-dpad_distance, 0), Direction::Left, dpad_arrow_size);
325
326 // SR and SL buttons
327 p.setPen(colors.outline);
328 button_color = colors.slider_button;
329 DrawRoundButton(p, center + QPoint(155, 52), button_values[SR], 5.2f, 12, Direction::None, 4);
330 DrawRoundButton(p, center + QPoint(155, -69), button_values[SL], 5.2f, 12, Direction::None, 4);
331
332 // SR and SL text
333 p.setPen(colors.transparent);
334 p.setBrush(colors.font2);
335 DrawSymbol(p, center + QPointF(155, 52), Symbol::SR, 1.0f);
336 DrawSymbol(p, center + QPointF(155, -69), Symbol::SL, 1.0f);
337
338 // Minus button
339 button_color = colors.button;
340 DrawMinusButton(p, center + QPoint(39, -118), button_values[Minus], 16);
341
342 // Screenshot button
343 DrawRoundButton(p, center + QPoint(26, 71), button_values[Screenshot], 8, 8);
344 p.setPen(colors.font2);
345 p.setBrush(colors.font2);
346 DrawCircle(p, center + QPoint(26, 71), 5);
347}
348
349void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center) {
350 {
351 using namespace Settings::NativeButton;
352
353 // Sideview right joystick
354 DrawJoystickSideview(p, center + QPoint(173 - 315, 11),
355 axis_values[Settings::NativeAnalog::RStick].value.y() + 10.0f, 1.15f,
356 button_values[Settings::NativeButton::RStick]);
357
358 // Topview face buttons
359 p.setPen(colors.outline);
360 button_color = colors.button;
361 DrawRoundButton(p, center + QPoint(163, -21), button_values[A], 11, 5, Direction::Up);
362 DrawRoundButton(p, center + QPoint(117, -21), button_values[Y], 11, 5, Direction::Up);
363
364 // Topview right joystick
365 DrawJoystickSideview(p, center + QPointF(140, -28),
366 -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1.15f,
367 button_values[RStick]);
368
369 // Topview plus button
370 p.setPen(colors.outline);
371 button_color = colors.button;
372 DrawRoundButton(p, center + QPoint(111, -22), button_values[Plus], 8, 4, Direction::Up, 1);
373 DrawRoundButton(p, center + QPoint(111, -22), button_values[Plus], 2.66f, 4, Direction::Up,
374 1);
375
376 // Right trigger
377 p.setPen(colors.outline);
378 button_color = colors.button;
379 DrawRightTriggers(p, center, button_values[R]);
380 DrawRoundButton(p, center + QPoint(-151, -146), button_values[R], 8, 4, Direction::Down);
381 DrawRightZTriggers(p, center, button_values[ZR]);
382
383 // Sideview face buttons
384 DrawRoundButton(p, center + QPoint(-135, -73), button_values[A], 5, 11, Direction::Left);
385 DrawRoundButton(p, center + QPoint(-135, -50), button_values[B], 5, 11, Direction::Left);
386 DrawRoundButton(p, center + QPoint(-135, -95), button_values[X], 5, 11, Direction::Left);
387 DrawRoundButton(p, center + QPoint(-135, -73), button_values[Y], 5, 11, Direction::Left);
388
389 // Sideview home and plus button
390 DrawRoundButton(p, center + QPoint(-135, 66), button_values[Home], 3, 12, Direction::Left);
391 DrawRoundButton(p, center + QPoint(-135, -118), button_values[Plus], 4, 8, Direction::Left,
392 1);
393 DrawRoundButton(p, center + QPoint(-135, -118), button_values[Plus], 4, 2.66f,
394 Direction::Left, 1);
395
396 // Sideview SL and SR buttons
397 button_color = colors.slider_button;
398 DrawRoundButton(p, center + QPoint(-59, 52), button_values[SL], 5, 11, Direction::Right);
399 DrawRoundButton(p, center + QPoint(-59, -69), button_values[SR], 5, 11, Direction::Right);
400
401 DrawRightBody(p, center);
402
403 // Right trigger top view
404 DrawRightTriggersTopView(p, center, button_values[R]);
405 DrawRightZTriggersTopView(p, center, button_values[ZR]);
406 }
407
408 {
409 // Draw joysticks
410 using namespace Settings::NativeAnalog;
411 DrawJoystick(p, center + QPointF(-9, 11) + (axis_values[RStick].value * 8), 1.8f,
412 button_values[Settings::NativeButton::RStick]);
413 DrawRawJoystick(p, center + QPointF(140, 90), axis_values[RStick].raw_value,
414 axis_values[RStick].properties);
415 }
416
417 using namespace Settings::NativeButton;
418
419 // Face buttons constants
420 const QPointF face_center = center + QPoint(-9, -73);
421 constexpr int face_distance = 23;
422 constexpr int face_radius = 11;
423 constexpr float text_size = 1.1f;
424
425 // Face buttons
426 p.setPen(colors.outline);
427 button_color = colors.button;
428 DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius);
429 DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius);
430 DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius);
431 DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
432
433 // Face buttons text
434 p.setPen(colors.transparent);
435 p.setBrush(colors.font);
436 DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
437 DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
438 DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
439 DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
440
441 // SR and SL buttons
442 p.setPen(colors.outline);
443 button_color = colors.slider_button;
444 DrawRoundButton(p, center + QPoint(-155, 52), button_values[SL], 5, 12, Direction::None, 4.0f);
445 DrawRoundButton(p, center + QPoint(-155, -69), button_values[SR], 5, 12, Direction::None, 4.0f);
446
447 // SR and SL text
448 p.setPen(colors.transparent);
449 p.setBrush(colors.font2);
450 p.rotate(-180);
451 DrawSymbol(p, QPointF(-center.x(), -center.y()) + QPointF(155, 69), Symbol::SR, 1.0f);
452 DrawSymbol(p, QPointF(-center.x(), -center.y()) + QPointF(155, -52), Symbol::SL, 1.0f);
453 p.rotate(180);
454
455 // Plus Button
456 DrawPlusButton(p, center + QPoint(-40, -118), button_values[Plus], 16);
457
458 // Home Button
459 p.setPen(colors.outline);
460 button_color = colors.slider_button;
461 DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 12);
462 button_color = colors.button;
463 DrawCircleButton(p, center + QPoint(-26, 66), button_values[Home], 9);
464 p.setPen(colors.transparent);
465 p.setBrush(colors.font2);
466 DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5);
467}
468
469void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) {
470 {
471 using namespace Settings::NativeButton;
472
473 // Left/Right trigger
474 DrawDualTriggers(p, center, button_values[L], button_values[R]);
475
476 // Topview face buttons
477 p.setPen(colors.outline);
478 button_color = colors.button;
479 DrawRoundButton(p, center + QPoint(200, -71), button_values[A], 10, 5, Direction::Up);
480 DrawRoundButton(p, center + QPoint(160, -71), button_values[Y], 10, 5, Direction::Up);
481
482 // Topview right joystick
483 DrawJoystickSideview(p, center + QPointF(180, -78),
484 -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1,
485 button_values[RStick]);
486
487 // Topview plus button
488 p.setPen(colors.outline);
489 button_color = colors.button;
490 DrawRoundButton(p, center + QPoint(154, -72), button_values[Plus], 7, 4, Direction::Up, 1);
491 DrawRoundButton(p, center + QPoint(154, -72), button_values[Plus], 2.33f, 4, Direction::Up,
492 1);
493
494 // Topview D-pad buttons
495 p.setPen(colors.outline);
496 button_color = colors.button;
497 DrawRoundButton(p, center + QPoint(-200, -71), button_values[DLeft], 10, 5, Direction::Up);
498 DrawRoundButton(p, center + QPoint(-160, -71), button_values[DRight], 10, 5, Direction::Up);
499
500 // Topview left joystick
501 DrawJoystickSideview(p, center + QPointF(-180.5f, -78),
502 -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1,
503 button_values[LStick]);
504
505 // Topview minus button
506 p.setPen(colors.outline);
507 button_color = colors.button;
508 DrawRoundButton(p, center + QPoint(-154, -72), button_values[Minus], 7, 4, Direction::Up,
509 1);
510
511 DrawDualBody(p, center);
512
513 // Right trigger top view
514 DrawDualTriggersTopView(p, center, button_values[L], button_values[R]);
515 DrawDualZTriggersTopView(p, center, button_values[ZL], button_values[ZR]);
516 }
517
518 {
519 // Draw joysticks
520 using namespace Settings::NativeAnalog;
521 const auto& l_stick = axis_values[LStick];
522 const auto l_button = button_values[Settings::NativeButton::LStick];
523 const auto& r_stick = axis_values[RStick];
524 const auto r_button = button_values[Settings::NativeButton::RStick];
525
526 DrawJoystick(p, center + QPointF(-65, -65) + (l_stick.value * 7), 1.62f, l_button);
527 DrawJoystick(p, center + QPointF(65, 12) + (r_stick.value * 7), 1.62f, r_button);
528 DrawRawJoystick(p, center + QPointF(-180, 90), l_stick.raw_value, l_stick.properties);
529 DrawRawJoystick(p, center + QPointF(180, 90), r_stick.raw_value, r_stick.properties);
530 }
531
532 using namespace Settings::NativeButton;
533
534 // Face buttons constants
535 const QPointF face_center = center + QPoint(65, -65);
536 constexpr int face_distance = 20;
537 constexpr int face_radius = 10;
538 constexpr float text_size = 1.0f;
539
540 // Face buttons
541 p.setPen(colors.outline);
542 button_color = colors.button;
543 DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius);
544 DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius);
545 DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius);
546 DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
547
548 // Face buttons text
549 p.setPen(colors.transparent);
550 p.setBrush(colors.font);
551 DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
552 DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
553 DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
554 DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
555
556 // D-pad constants
557 const QPointF dpad_center = center + QPoint(-65, 12);
558 constexpr int dpad_distance = 20;
559 constexpr int dpad_radius = 10;
560 constexpr float dpad_arrow_size = 1.1f;
561
562 // D-pad buttons
563 p.setPen(colors.outline);
564 button_color = colors.button;
565 DrawCircleButton(p, dpad_center + QPoint(dpad_distance, 0), button_values[DRight], dpad_radius);
566 DrawCircleButton(p, dpad_center + QPoint(0, dpad_distance), button_values[DDown], dpad_radius);
567 DrawCircleButton(p, dpad_center + QPoint(0, -dpad_distance), button_values[DUp], dpad_radius);
568 DrawCircleButton(p, dpad_center + QPoint(-dpad_distance, 0), button_values[DLeft], dpad_radius);
569
570 // D-pad arrows
571 p.setPen(colors.font2);
572 p.setBrush(colors.font2);
573 DrawArrow(p, dpad_center + QPoint(dpad_distance, 0), Direction::Right, dpad_arrow_size);
574 DrawArrow(p, dpad_center + QPoint(0, dpad_distance), Direction::Down, dpad_arrow_size);
575 DrawArrow(p, dpad_center + QPoint(0, -dpad_distance), Direction::Up, dpad_arrow_size);
576 DrawArrow(p, dpad_center + QPoint(-dpad_distance, 0), Direction::Left, dpad_arrow_size);
577
578 // Minus and Plus button
579 button_color = colors.button;
580 DrawMinusButton(p, center + QPoint(-39, -106), button_values[Minus], 14);
581 DrawPlusButton(p, center + QPoint(39, -106), button_values[Plus], 14);
582
583 // Screenshot button
584 p.setPen(colors.outline);
585 DrawRoundButton(p, center + QPoint(-52, 63), button_values[Screenshot], 8, 8);
586 p.setPen(colors.font2);
587 p.setBrush(colors.font2);
588 DrawCircle(p, center + QPoint(-52, 63), 5);
589
590 // Home Button
591 p.setPen(colors.outline);
592 button_color = colors.slider_button;
593 DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 11);
594 button_color = colors.button;
595 DrawCircleButton(p, center + QPoint(50, 60), button_values[Home], 8.5f);
596 p.setPen(colors.transparent);
597 p.setBrush(colors.font2);
598 DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f);
599}
600
601void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) {
602 DrawHandheldTriggers(p, center, button_values[Settings::NativeButton::L],
603 button_values[Settings::NativeButton::R]);
604 DrawHandheldBody(p, center);
605 {
606 // Draw joysticks
607 using namespace Settings::NativeAnalog;
608 const auto& l_stick = axis_values[LStick];
609 const auto l_button = button_values[Settings::NativeButton::LStick];
610 const auto& r_stick = axis_values[RStick];
611 const auto r_button = button_values[Settings::NativeButton::RStick];
612
613 DrawJoystick(p, center + QPointF(-171, -41) + (l_stick.value * 4), 1.0f, l_button);
614 DrawJoystick(p, center + QPointF(171, 8) + (r_stick.value * 4), 1.0f, r_button);
615 DrawRawJoystick(p, center + QPointF(-50, 0), l_stick.raw_value, l_stick.properties);
616 DrawRawJoystick(p, center + QPointF(50, 0), r_stick.raw_value, r_stick.properties);
617 }
618
619 using namespace Settings::NativeButton;
620
621 // Face buttons constants
622 const QPointF face_center = center + QPoint(171, -41);
623 constexpr float face_distance = 12.8f;
624 constexpr float face_radius = 6.4f;
625 constexpr float text_size = 0.6f;
626
627 // Face buttons
628 p.setPen(colors.outline);
629 button_color = colors.button;
630 DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius);
631 DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius);
632 DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius);
633 DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
634
635 // Face buttons text
636 p.setPen(colors.transparent);
637 p.setBrush(colors.font);
638 DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
639 DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
640 DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
641 DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
642
643 // D-pad constants
644 const QPointF dpad_center = center + QPoint(-171, 8);
645 constexpr float dpad_distance = 12.8f;
646 constexpr float dpad_radius = 6.4f;
647 constexpr float dpad_arrow_size = 0.68f;
648
649 // D-pad buttons
650 p.setPen(colors.outline);
651 button_color = colors.button;
652 DrawCircleButton(p, dpad_center + QPoint(dpad_distance, 0), button_values[DRight], dpad_radius);
653 DrawCircleButton(p, dpad_center + QPoint(0, dpad_distance), button_values[DDown], dpad_radius);
654 DrawCircleButton(p, dpad_center + QPoint(0, -dpad_distance), button_values[DUp], dpad_radius);
655 DrawCircleButton(p, dpad_center + QPoint(-dpad_distance, 0), button_values[DLeft], dpad_radius);
656
657 // D-pad arrows
658 p.setPen(colors.font2);
659 p.setBrush(colors.font2);
660 DrawArrow(p, dpad_center + QPoint(dpad_distance, 0), Direction::Right, dpad_arrow_size);
661 DrawArrow(p, dpad_center + QPoint(0, dpad_distance), Direction::Down, dpad_arrow_size);
662 DrawArrow(p, dpad_center + QPoint(0, -dpad_distance), Direction::Up, dpad_arrow_size);
663 DrawArrow(p, dpad_center + QPoint(-dpad_distance, 0), Direction::Left, dpad_arrow_size);
664
665 // ZL and ZR buttons
666 p.setPen(colors.outline);
667 DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
668 DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
669 p.setPen(colors.transparent);
670 p.setBrush(colors.font);
671 DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
672 DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
673
674 // Minus and Plus button
675 p.setPen(colors.outline);
676 button_color = colors.button;
677 DrawMinusButton(p, center + QPoint(-155, -67), button_values[Minus], 8);
678 DrawPlusButton(p, center + QPoint(155, -67), button_values[Plus], 8);
679
680 // Screenshot button
681 p.setPen(colors.outline);
682 DrawRoundButton(p, center + QPoint(-162, 39), button_values[Screenshot], 5, 5);
683 p.setPen(colors.font2);
684 p.setBrush(colors.font2);
685 DrawCircle(p, center + QPoint(-162, 39), 3);
686
687 // Home Button
688 p.setPen(colors.outline);
689 button_color = colors.slider_button;
690 DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 7);
691 button_color = colors.button;
692 DrawCircleButton(p, center + QPoint(161, 37), button_values[Home], 5);
693 p.setPen(colors.transparent);
694 p.setBrush(colors.font2);
695 DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f);
696}
697
698void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) {
699 DrawProTriggers(p, center, button_values[Settings::NativeButton::L],
700 button_values[Settings::NativeButton::R]);
701 DrawProBody(p, center);
702 {
703 // Draw joysticks
704 using namespace Settings::NativeAnalog;
705 DrawProJoystick(p, center + QPointF(-111, -55), axis_values[LStick].value, 11,
706 button_values[Settings::NativeButton::LStick]);
707 DrawProJoystick(p, center + QPointF(51, 0), axis_values[RStick].value, 11,
708 button_values[Settings::NativeButton::RStick]);
709 DrawRawJoystick(p, center + QPointF(-50, 105), axis_values[LStick].raw_value,
710 axis_values[LStick].properties);
711 DrawRawJoystick(p, center + QPointF(50, 105), axis_values[RStick].raw_value,
712 axis_values[RStick].properties);
713 }
714
715 using namespace Settings::NativeButton;
716
717 // Face buttons constants
718 const QPointF face_center = center + QPoint(105, -56);
719 constexpr int face_distance = 31;
720 constexpr int face_radius = 15;
721 constexpr float text_size = 1.5f;
722
723 // Face buttons
724 p.setPen(colors.outline);
725 button_color = colors.button;
726 DrawCircleButton(p, face_center + QPoint(face_distance, 0), button_values[A], face_radius);
727 DrawCircleButton(p, face_center + QPoint(0, face_distance), button_values[B], face_radius);
728 DrawCircleButton(p, face_center + QPoint(0, -face_distance), button_values[X], face_radius);
729 DrawCircleButton(p, face_center + QPoint(-face_distance, 0), button_values[Y], face_radius);
730
731 // Face buttons text
732 p.setPen(colors.transparent);
733 p.setBrush(colors.font);
734 DrawSymbol(p, face_center + QPoint(face_distance, 0), Symbol::A, text_size);
735 DrawSymbol(p, face_center + QPoint(0, face_distance), Symbol::B, text_size);
736 DrawSymbol(p, face_center + QPoint(0, -face_distance), Symbol::X, text_size);
737 DrawSymbol(p, face_center + QPoint(-face_distance, 1), Symbol::Y, text_size);
738
739 // D-pad buttons
740 const QPointF dpad_postion = center + QPoint(-61, 0);
741 DrawArrowButton(p, dpad_postion, Direction::Up, button_values[DUp]);
742 DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft]);
743 DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight]);
744 DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown]);
745 DrawArrowButtonOutline(p, dpad_postion);
746
747 // ZL and ZR buttons
748 p.setPen(colors.outline);
749 DrawTriggerButton(p, center + QPoint(-210, -130), Direction::Left, button_values[ZL]);
750 DrawTriggerButton(p, center + QPoint(210, -130), Direction::Right, button_values[ZR]);
751 p.setPen(colors.transparent);
752 p.setBrush(colors.font);
753 DrawSymbol(p, center + QPoint(-210, -130), Symbol::ZL, 1.5f);
754 DrawSymbol(p, center + QPoint(210, -130), Symbol::ZR, 1.5f);
755
756 // Minus and Plus buttons
757 p.setPen(colors.outline);
758 DrawCircleButton(p, center + QPoint(-50, -86), button_values[Minus], 9);
759 DrawCircleButton(p, center + QPoint(50, -86), button_values[Plus], 9);
760
761 // Minus and Plus symbols
762 p.setPen(colors.font2);
763 p.setBrush(colors.font2);
764 DrawRectangle(p, center + QPoint(-50, -86), 9, 1.5f);
765 DrawRectangle(p, center + QPoint(50, -86), 9, 1.5f);
766 DrawRectangle(p, center + QPoint(50, -86), 1.5f, 9);
767
768 // Screenshot button
769 p.setPen(colors.outline);
770 DrawRoundButton(p, center + QPoint(-29, -56), button_values[Screenshot], 7, 7);
771 p.setPen(colors.font2);
772 p.setBrush(colors.font2);
773 DrawCircle(p, center + QPoint(-29, -56), 4.5f);
774
775 // Home Button
776 p.setPen(colors.outline);
777 button_color = colors.slider_button;
778 DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 10.0f);
779 button_color = colors.button;
780 DrawCircleButton(p, center + QPoint(29, -56), button_values[Home], 7.1f);
781 p.setPen(colors.transparent);
782 p.setBrush(colors.font2);
783 DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f);
784}
785
786void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) {
787 DrawGCTriggers(p, center, button_values[Settings::NativeButton::ZL],
788 button_values[Settings::NativeButton::ZR]);
789 DrawGCButtonZ(p, center, button_values[Settings::NativeButton::R]);
790 DrawGCBody(p, center);
791 {
792 // Draw joysticks
793 using namespace Settings::NativeAnalog;
794 DrawGCJoystick(p, center + QPointF(-111, -44) + (axis_values[LStick].value * 10), false);
795 button_color = colors.button2;
796 DrawCircleButton(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), false,
797 15);
798 p.setPen(colors.transparent);
799 p.setBrush(colors.font);
800 DrawSymbol(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), Symbol::C,
801 1.0f);
802 DrawRawJoystick(p, center + QPointF(-198, -125), axis_values[LStick].raw_value,
803 axis_values[LStick].properties);
804 DrawRawJoystick(p, center + QPointF(198, -125), axis_values[RStick].raw_value,
805 axis_values[RStick].properties);
806 }
807
808 using namespace Settings::NativeButton;
809
810 // Face buttons constants
811 constexpr float text_size = 1.1f;
812
813 // Face buttons
814 p.setPen(colors.outline);
815 button_color = colors.button;
816 DrawCircleButton(p, center + QPoint(111, -44), button_values[A], 21);
817 DrawCircleButton(p, center + QPoint(70, -23), button_values[B], 13);
818 DrawGCButtonX(p, center, button_values[Settings::NativeButton::X]);
819 DrawGCButtonY(p, center, button_values[Settings::NativeButton::Y]);
820
821 // Face buttons text
822 p.setPen(colors.transparent);
823 p.setBrush(colors.font);
824 DrawSymbol(p, center + QPoint(111, -44), Symbol::A, 1.5f);
825 DrawSymbol(p, center + QPoint(70, -23), Symbol::B, text_size);
826 DrawSymbol(p, center + QPoint(151, -53), Symbol::X, text_size);
827 DrawSymbol(p, center + QPoint(100, -83), Symbol::Y, text_size);
828
829 // D-pad buttons
830 const QPointF dpad_postion = center + QPoint(-61, 37);
831 const float dpad_size = 0.8f;
832 DrawArrowButton(p, dpad_postion, Direction::Up, button_values[DUp], dpad_size);
833 DrawArrowButton(p, dpad_postion, Direction::Left, button_values[DLeft], dpad_size);
834 DrawArrowButton(p, dpad_postion, Direction::Right, button_values[DRight], dpad_size);
835 DrawArrowButton(p, dpad_postion, Direction::Down, button_values[DDown], dpad_size);
836 DrawArrowButtonOutline(p, dpad_postion, dpad_size);
837
838 // Minus and Plus buttons
839 p.setPen(colors.outline);
840 DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8);
841}
842
843constexpr std::array<float, 13 * 2> symbol_a = {
844 -1.085f, -5.2f, 1.085f, -5.2f, 5.085f, 5.0f, 2.785f, 5.0f, 1.785f,
845 2.65f, -1.785f, 2.65f, -2.785f, 5.0f, -5.085f, 5.0f, -1.4f, 1.0f,
846 0.0f, -2.8f, 1.4f, 1.0f, -1.4f, 1.0f, -5.085f, 5.0f,
847};
848constexpr std::array<float, 134 * 2> symbol_b = {
849 -4.0f, 0.0f, -4.0f, 0.0f, -4.0f, -0.1f, -3.8f, -5.1f, 1.8f, -5.0f, 2.3f, -4.9f, 2.6f,
850 -4.8f, 2.8f, -4.7f, 2.9f, -4.6f, 3.1f, -4.5f, 3.2f, -4.4f, 3.4f, -4.3f, 3.4f, -4.2f,
851 3.5f, -4.1f, 3.7f, -4.0f, 3.7f, -3.9f, 3.8f, -3.8f, 3.8f, -3.7f, 3.9f, -3.6f, 3.9f,
852 -3.5f, 4.0f, -3.4f, 4.0f, -3.3f, 4.1f, -3.1f, 4.1f, -3.0f, 4.0f, -2.0f, 4.0f, -1.9f,
853 3.9f, -1.7f, 3.9f, -1.6f, 3.8f, -1.5f, 3.8f, -1.4f, 3.7f, -1.3f, 3.7f, -1.2f, 3.6f,
854 -1.1f, 3.6f, -1.0f, 3.5f, -0.9f, 3.3f, -0.8f, 3.3f, -0.7f, 3.2f, -0.6f, 3.0f, -0.5f,
855 2.9f, -0.4f, 2.7f, -0.3f, 2.9f, -0.2f, 3.2f, -0.1f, 3.3f, 0.0f, 3.5f, 0.1f, 3.6f,
856 0.2f, 3.8f, 0.3f, 3.9f, 0.4f, 4.0f, 0.6f, 4.1f, 0.7f, 4.3f, 0.8f, 4.3f, 0.9f,
857 4.4f, 1.0f, 4.4f, 1.1f, 4.5f, 1.3f, 4.5f, 1.4f, 4.6f, 1.6f, 4.6f, 1.7f, 4.5f,
858 2.8f, 4.5f, 2.9f, 4.4f, 3.1f, 4.4f, 3.2f, 4.3f, 3.4f, 4.3f, 3.5f, 4.2f, 3.6f,
859 4.2f, 3.7f, 4.1f, 3.8f, 4.1f, 3.9f, 4.0f, 4.0f, 3.9f, 4.2f, 3.8f, 4.3f, 3.6f,
860 4.4f, 3.6f, 4.5f, 3.4f, 4.6f, 3.3f, 4.7f, 3.1f, 4.8f, 2.8f, 4.9f, 2.6f, 5.0f,
861 2.1f, 5.1f, -4.0f, 5.0f, -4.0f, 4.9f,
862
863 -4.0f, 0.0f, 1.1f, 3.4f, 1.1f, 3.4f, 1.5f, 3.3f, 1.8f, 3.2f, 2.0f, 3.1f, 2.1f,
864 3.0f, 2.3f, 2.9f, 2.3f, 2.8f, 2.4f, 2.7f, 2.4f, 2.6f, 2.5f, 2.3f, 2.5f, 2.2f,
865 2.4f, 1.7f, 2.4f, 1.6f, 2.3f, 1.4f, 2.3f, 1.3f, 2.2f, 1.2f, 2.2f, 1.1f, 2.1f,
866 1.0f, 1.9f, 0.9f, 1.6f, 0.8f, 1.4f, 0.7f, -1.9f, 0.6f, -1.9f, 0.7f, -1.8f, 3.4f,
867 1.1f, 3.4f, -4.0f, 0.0f,
868
869 0.3f, -1.1f, 0.3f, -1.1f, 1.3f, -1.2f, 1.5f, -1.3f, 1.8f, -1.4f, 1.8f, -1.5f, 1.9f,
870 -1.6f, 2.0f, -1.8f, 2.0f, -1.9f, 2.1f, -2.0f, 2.1f, -2.1f, 2.0f, -2.7f, 2.0f, -2.8f,
871 1.9f, -2.9f, 1.9f, -3.0f, 1.8f, -3.1f, 1.6f, -3.2f, 1.6f, -3.3f, 1.3f, -3.4f, -1.9f,
872 -3.3f, -1.9f, -3.2f, -1.8f, -1.0f, 0.2f, -1.1f, 0.3f, -1.1f, -4.0f, 0.0f,
873};
874
875constexpr std::array<float, 9 * 2> symbol_y = {
876 -4.79f, -4.9f, -2.44f, -4.9f, 0.0f, -0.9f, 2.44f, -4.9f, 4.79f,
877 -4.9f, 1.05f, 1.0f, 1.05f, 5.31f, -1.05f, 5.31f, -1.05f, 1.0f,
878
879};
880
881constexpr std::array<float, 12 * 2> symbol_x = {
882 -4.4f, -5.0f, -2.0f, -5.0f, 0.0f, -1.7f, 2.0f, -5.0f, 4.4f, -5.0f, 1.2f, 0.0f,
883 4.4f, 5.0f, 2.0f, 5.0f, 0.0f, 1.7f, -2.0f, 5.0f, -4.4f, 5.0f, -1.2f, 0.0f,
884
885};
886
887constexpr std::array<float, 7 * 2> symbol_l = {
888 2.4f, -3.23f, 2.4f, 2.1f, 5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f,
889};
890
891constexpr std::array<float, 98 * 2> symbol_r = {
892 1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f, -2.9f,
893 5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f, 6.2f, -2.1f,
894 6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f, -0.5f, 6.0f, -0.4f,
895 6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f, 5.4f, 0.2f, 5.1f, 0.3f,
896 4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f, 0.8f, 5.2f, 0.9f, 5.3f, 1.0f,
897 5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f, 5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f,
898 6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f, 2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f,
899 6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f, 6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f,
900 5.1f, 2.9f, 5.0f, 2.7f, 4.9f, 2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f,
901 4.4f, 1.8f, 4.3f, 1.7f, 4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f,
902 3.6f, 0.8f, 3.5f, 0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f,
903 1.0f, 3.2f, 1.0f, 3.1f, 1.0f, 0.0f,
904
905 4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f, -1.1f, 5.0f, -1.2f,
906 4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f, 4.3f, -2.2f, 2.3f, -2.1f,
907 2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f,
908};
909
910constexpr std::array<float, 18 * 2> symbol_zl = {
911 -2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f,
912 -0.7f, 2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f, 2.4f, -3.23f, 2.4f, 2.1f,
913 5.43f, 2.1f, 5.43f, 3.22f, 0.98f, 3.22f, 0.98f, -3.23f, 2.4f, -3.23f, -6.0f, 2.12f,
914};
915
916constexpr std::array<float, 57 * 2> symbol_sl = {
917 -3.0f, -3.65f, -2.76f, -4.26f, -2.33f, -4.76f, -1.76f, -5.09f, -1.13f, -5.26f, -0.94f,
918 -4.77f, -0.87f, -4.11f, -1.46f, -3.88f, -1.91f, -3.41f, -2.05f, -2.78f, -1.98f, -2.13f,
919 -1.59f, -1.61f, -0.96f, -1.53f, -0.56f, -2.04f, -0.38f, -2.67f, -0.22f, -3.31f, 0.0f,
920 -3.93f, 0.34f, -4.49f, 0.86f, -4.89f, 1.49f, -5.05f, 2.14f, -4.95f, 2.69f, -4.6f,
921 3.07f, -4.07f, 3.25f, -3.44f, 3.31f, -2.78f, 3.25f, -2.12f, 3.07f, -1.49f, 2.7f,
922 -0.95f, 2.16f, -0.58f, 1.52f, -0.43f, 1.41f, -0.99f, 1.38f, -1.65f, 1.97f, -1.91f,
923 2.25f, -2.49f, 2.25f, -3.15f, 1.99f, -3.74f, 1.38f, -3.78f, 1.06f, -3.22f, 0.88f,
924 -2.58f, 0.71f, -1.94f, 0.49f, -1.32f, 0.13f, -0.77f, -0.4f, -0.4f, -1.04f, -0.25f,
925 -1.69f, -0.32f, -2.28f, -0.61f, -2.73f, -1.09f, -2.98f, -1.69f, -3.09f, -2.34f,
926
927 3.23f, 2.4f, -2.1f, 2.4f, -2.1f, 5.43f, -3.22f, 5.43f, -3.22f, 0.98f, 3.23f,
928 0.98f, 3.23f, 2.4f, -3.09f, -2.34f,
929};
930constexpr std::array<float, 109 * 2> symbol_zr = {
931 -2.6f, -2.13f, -5.6f, -2.13f, -5.6f, -3.23f, -0.8f, -3.23f, -0.8f, -2.13f, -4.4f, 2.12f, -0.7f,
932 2.12f, -0.7f, 3.22f, -6.0f, 3.22f, -6.0f, 2.12f,
933
934 1.0f, 0.0f, 1.0f, -0.1f, 1.1f, -3.3f, 4.3f, -3.2f, 5.1f, -3.1f, 5.4f, -3.0f, 5.6f,
935 -2.9f, 5.7f, -2.8f, 5.9f, -2.7f, 5.9f, -2.6f, 6.0f, -2.5f, 6.1f, -2.3f, 6.2f, -2.2f,
936 6.2f, -2.1f, 6.3f, -2.0f, 6.3f, -1.9f, 6.2f, -0.8f, 6.2f, -0.7f, 6.1f, -0.6f, 6.1f,
937 -0.5f, 6.0f, -0.4f, 6.0f, -0.3f, 5.9f, -0.2f, 5.7f, -0.1f, 5.7f, 0.0f, 5.6f, 0.1f,
938 5.4f, 0.2f, 5.1f, 0.3f, 4.7f, 0.4f, 4.7f, 0.5f, 4.9f, 0.6f, 5.0f, 0.7f, 5.2f,
939 0.8f, 5.2f, 0.9f, 5.3f, 1.0f, 5.5f, 1.1f, 5.5f, 1.2f, 5.6f, 1.3f, 5.7f, 1.5f,
940 5.8f, 1.6f, 5.9f, 1.8f, 6.0f, 1.9f, 6.1f, 2.1f, 6.2f, 2.2f, 6.2f, 2.3f, 6.3f,
941 2.4f, 6.4f, 2.6f, 6.5f, 2.7f, 6.6f, 2.9f, 6.7f, 3.0f, 6.7f, 3.1f, 6.8f, 3.2f,
942 6.8f, 3.3f, 5.3f, 3.2f, 5.2f, 3.1f, 5.2f, 3.0f, 5.1f, 2.9f, 5.0f, 2.7f, 4.9f,
943 2.6f, 4.8f, 2.4f, 4.7f, 2.3f, 4.6f, 2.1f, 4.5f, 2.0f, 4.4f, 1.8f, 4.3f, 1.7f,
944 4.1f, 1.4f, 4.0f, 1.3f, 3.9f, 1.1f, 3.8f, 1.0f, 3.6f, 0.9f, 3.6f, 0.8f, 3.5f,
945 0.7f, 3.3f, 0.6f, 2.9f, 0.5f, 2.3f, 0.6f, 2.3f, 0.7f, 2.2f, 3.3f, 1.0f, 3.2f,
946 1.0f, 3.1f, 1.0f, 0.0f,
947
948 4.2f, -0.5f, 4.4f, -0.6f, 4.7f, -0.7f, 4.8f, -0.8f, 4.9f, -1.0f, 5.0f, -1.1f, 5.0f,
949 -1.2f, 4.9f, -1.7f, 4.9f, -1.8f, 4.8f, -1.9f, 4.8f, -2.0f, 4.6f, -2.1f, 4.3f, -2.2f,
950 2.3f, -2.1f, 2.3f, -2.0f, 2.4f, -0.5f, 4.2f, -0.5f, 1.0f, 0.0f, -6.0f, 2.12f,
951};
952
953constexpr std::array<float, 148 * 2> symbol_sr = {
954 -3.0f, -3.65f, -2.76f, -4.26f, -2.33f, -4.76f, -1.76f, -5.09f, -1.13f, -5.26f, -0.94f, -4.77f,
955 -0.87f, -4.11f, -1.46f, -3.88f, -1.91f, -3.41f, -2.05f, -2.78f, -1.98f, -2.13f, -1.59f, -1.61f,
956 -0.96f, -1.53f, -0.56f, -2.04f, -0.38f, -2.67f, -0.22f, -3.31f, 0.0f, -3.93f, 0.34f, -4.49f,
957 0.86f, -4.89f, 1.49f, -5.05f, 2.14f, -4.95f, 2.69f, -4.6f, 3.07f, -4.07f, 3.25f, -3.44f,
958 3.31f, -2.78f, 3.25f, -2.12f, 3.07f, -1.49f, 2.7f, -0.95f, 2.16f, -0.58f, 1.52f, -0.43f,
959 1.41f, -0.99f, 1.38f, -1.65f, 1.97f, -1.91f, 2.25f, -2.49f, 2.25f, -3.15f, 1.99f, -3.74f,
960 1.38f, -3.78f, 1.06f, -3.22f, 0.88f, -2.58f, 0.71f, -1.94f, 0.49f, -1.32f, 0.13f, -0.77f,
961 -0.4f, -0.4f, -1.04f, -0.25f, -1.69f, -0.32f, -2.28f, -0.61f, -2.73f, -1.09f, -2.98f, -1.69f,
962 -3.09f, -2.34f,
963
964 -1.0f, 0.0f, 0.1f, 1.0f, 3.3f, 1.1f, 3.2f, 4.3f, 3.1f, 5.1f, 3.0f, 5.4f,
965 2.9f, 5.6f, 2.8f, 5.7f, 2.7f, 5.9f, 2.6f, 5.9f, 2.5f, 6.0f, 2.3f, 6.1f,
966 2.2f, 6.2f, 2.1f, 6.2f, 2.0f, 6.3f, 1.9f, 6.3f, 0.8f, 6.2f, 0.7f, 6.2f,
967 0.6f, 6.1f, 0.5f, 6.1f, 0.4f, 6.0f, 0.3f, 6.0f, 0.2f, 5.9f, 0.1f, 5.7f,
968 0.0f, 5.7f, -0.1f, 5.6f, -0.2f, 5.4f, -0.3f, 5.1f, -0.4f, 4.7f, -0.5f, 4.7f,
969 -0.6f, 4.9f, -0.7f, 5.0f, -0.8f, 5.2f, -0.9f, 5.2f, -1.0f, 5.3f, -1.1f, 5.5f,
970 -1.2f, 5.5f, -1.3f, 5.6f, -1.5f, 5.7f, -1.6f, 5.8f, -1.8f, 5.9f, -1.9f, 6.0f,
971 -2.1f, 6.1f, -2.2f, 6.2f, -2.3f, 6.2f, -2.4f, 6.3f, -2.6f, 6.4f, -2.7f, 6.5f,
972 -2.9f, 6.6f, -3.0f, 6.7f, -3.1f, 6.7f, -3.2f, 6.8f, -3.3f, 6.8f, -3.2f, 5.3f,
973 -3.1f, 5.2f, -3.0f, 5.2f, -2.9f, 5.1f, -2.7f, 5.0f, -2.6f, 4.9f, -2.4f, 4.8f,
974 -2.3f, 4.7f, -2.1f, 4.6f, -2.0f, 4.5f, -1.8f, 4.4f, -1.7f, 4.3f, -1.4f, 4.1f,
975 -1.3f, 4.0f, -1.1f, 3.9f, -1.0f, 3.8f, -0.9f, 3.6f, -0.8f, 3.6f, -0.7f, 3.5f,
976 -0.6f, 3.3f, -0.5f, 2.9f, -0.6f, 2.3f, -0.7f, 2.3f, -3.3f, 2.2f, -3.2f, 1.0f,
977 -3.1f, 1.0f, 0.0f, 1.0f,
978
979 0.5f, 4.2f, 0.6f, 4.4f, 0.7f, 4.7f, 0.8f, 4.8f, 1.0f, 4.9f, 1.1f, 5.0f,
980 1.2f, 5.0f, 1.7f, 4.9f, 1.8f, 4.9f, 1.9f, 4.8f, 2.0f, 4.8f, 2.1f, 4.6f,
981 2.2f, 4.3f, 2.1f, 2.3f, 2.0f, 2.3f, 0.5f, 2.4f, 0.5f, 4.2f, -0.0f, 1.0f,
982 -3.09f, -2.34f,
983
984};
985
986constexpr std::array<float, 30 * 2> symbol_c = {
987 2.86f, 7.57f, 0.99f, 7.94f, -0.91f, 7.87f, -2.73f, 7.31f, -4.23f, 6.14f, -5.2f, 4.51f,
988 -5.65f, 2.66f, -5.68f, 0.75f, -5.31f, -1.12f, -4.43f, -2.81f, -3.01f, -4.08f, -1.24f, -4.78f,
989 0.66f, -4.94f, 2.54f, -4.67f, 4.33f, -4.0f, 4.63f, -2.27f, 3.37f, -2.7f, 1.6f, -3.4f,
990 -0.3f, -3.5f, -2.09f, -2.87f, -3.34f, -1.45f, -3.91f, 0.37f, -3.95f, 2.27f, -3.49f, 4.12f,
991 -2.37f, 5.64f, -0.65f, 6.44f, 1.25f, 6.47f, 3.06f, 5.89f, 4.63f, 4.92f, 4.63f, 6.83f,
992};
993
994constexpr std::array<float, 12 * 2> house = {
995 -1.3f, 0.0f, -0.93f, 0.0f, -0.93f, 1.15f, 0.93f, 1.15f, 0.93f, 0.0f, 1.3f, 0.0f,
996 0.0f, -1.2f, -1.3f, 0.0f, -0.43f, 0.0f, -0.43f, .73f, 0.43f, .73f, 0.43f, 0.0f,
997};
998
999constexpr std::array<float, 11 * 2> up_arrow_button = {
1000 9.1f, -9.1f, 9.1f, -30.0f, 8.1f, -30.1f, 7.7f, -30.1f, -8.6f, -30.0f, -9.0f,
1001 -29.8f, -9.3f, -29.5f, -9.5f, -29.1f, -9.1f, -28.7f, -9.1f, -9.1f, 0.0f, 0.6f,
1002};
1003
1004constexpr std::array<float, 3 * 2> up_arrow_symbol = {
1005 0.0f, -3.0f, -3.0f, 2.0f, 3.0f, 2.0f,
1006};
1007
1008constexpr std::array<float, 64 * 2> trigger_button = {
1009 5.5f, -12.6f, 5.8f, -12.6f, 6.7f, -12.5f, 8.1f, -12.3f, 8.6f, -12.2f, 9.2f, -12.0f,
1010 9.5f, -11.9f, 9.9f, -11.8f, 10.6f, -11.5f, 11.0f, -11.3f, 11.2f, -11.2f, 11.4f, -11.1f,
1011 11.8f, -10.9f, 12.0f, -10.8f, 12.2f, -10.7f, 12.4f, -10.5f, 12.6f, -10.4f, 12.8f, -10.3f,
1012 13.6f, -9.7f, 13.8f, -9.6f, 13.9f, -9.4f, 14.1f, -9.3f, 14.8f, -8.6f, 15.0f, -8.5f,
1013 15.1f, -8.3f, 15.6f, -7.8f, 15.7f, -7.6f, 16.1f, -7.0f, 16.3f, -6.8f, 16.4f, -6.6f,
1014 16.5f, -6.4f, 16.8f, -6.0f, 16.9f, -5.8f, 17.0f, -5.6f, 17.1f, -5.4f, 17.2f, -5.2f,
1015 17.3f, -5.0f, 17.4f, -4.8f, 17.5f, -4.6f, 17.6f, -4.4f, 17.7f, -4.1f, 17.8f, -3.9f,
1016 17.9f, -3.5f, 18.0f, -3.3f, 18.1f, -3.0f, 18.2f, -2.6f, 18.2f, -2.3f, 18.3f, -2.1f,
1017 18.3f, -1.9f, 18.4f, -1.4f, 18.5f, -1.2f, 18.6f, -0.3f, 18.6f, 0.0f, 18.3f, 13.9f,
1018 -17.0f, 13.8f, -17.0f, 13.6f, -16.4f, -11.4f, -16.3f, -11.6f, -16.1f, -11.8f, -15.7f, -12.0f,
1019 -15.5f, -12.1f, -15.1f, -12.3f, -14.6f, -12.4f, -13.4f, -12.5f,
1020};
1021
1022constexpr std::array<float, 36 * 2> pro_left_trigger = {
1023 -65.2f, -132.6f, -68.2f, -134.1f, -71.3f, -135.5f, -74.4f, -136.7f, -77.6f,
1024 -137.6f, -80.9f, -138.1f, -84.3f, -138.3f, -87.6f, -138.3f, -91.0f, -138.1f,
1025 -94.3f, -137.8f, -97.6f, -137.3f, -100.9f, -136.7f, -107.5f, -135.3f, -110.7f,
1026 -134.5f, -120.4f, -131.8f, -123.6f, -130.8f, -126.8f, -129.7f, -129.9f, -128.5f,
1027 -132.9f, -127.1f, -135.9f, -125.6f, -138.8f, -123.9f, -141.6f, -122.0f, -144.1f,
1028 -119.8f, -146.3f, -117.3f, -148.4f, -114.7f, -150.4f, -112.0f, -152.3f, -109.2f,
1029 -155.3f, -104.0f, -152.0f, -104.3f, -148.7f, -104.5f, -145.3f, -104.8f, -35.5f,
1030 -117.2f, -38.5f, -118.7f, -41.4f, -120.3f, -44.4f, -121.8f, -50.4f, -124.9f,
1031};
1032
1033constexpr std::array<float, 14 * 2> pro_body_top = {
1034 0.0f, -115.4f, -4.4f, -116.1f, -69.7f, -131.3f, -66.4f, -131.9f, -63.1f, -132.3f,
1035 -56.4f, -133.0f, -53.1f, -133.3f, -49.8f, -133.5f, -43.1f, -133.8f, -39.8f, -134.0f,
1036 -36.5f, -134.1f, -16.4f, -134.4f, -13.1f, -134.4f, 0.0f, -134.1f,
1037};
1038
1039constexpr std::array<float, 145 * 2> pro_left_handle = {
1040 -178.7f, -47.5f, -179.0f, -46.1f, -179.3f, -44.6f, -182.0f, -29.8f, -182.3f, -28.4f,
1041 -182.6f, -26.9f, -182.8f, -25.4f, -183.1f, -23.9f, -183.3f, -22.4f, -183.6f, -21.0f,
1042 -183.8f, -19.5f, -184.1f, -18.0f, -184.3f, -16.5f, -184.6f, -15.1f, -184.8f, -13.6f,
1043 -185.1f, -12.1f, -185.3f, -10.6f, -185.6f, -9.1f, -185.8f, -7.7f, -186.1f, -6.2f,
1044 -186.3f, -4.7f, -186.6f, -3.2f, -186.8f, -1.7f, -187.1f, -0.3f, -187.3f, 1.2f,
1045 -187.6f, 2.7f, -187.8f, 4.2f, -188.3f, 7.1f, -188.5f, 8.6f, -188.8f, 10.1f,
1046 -189.0f, 11.6f, -189.3f, 13.1f, -189.5f, 14.5f, -190.0f, 17.5f, -190.2f, 19.0f,
1047 -190.5f, 20.5f, -190.7f, 21.9f, -191.2f, 24.9f, -191.4f, 26.4f, -191.7f, 27.9f,
1048 -191.9f, 29.3f, -192.4f, 32.3f, -192.6f, 33.8f, -193.1f, 36.8f, -193.3f, 38.2f,
1049 -193.8f, 41.2f, -194.0f, 42.7f, -194.7f, 47.1f, -194.9f, 48.6f, -199.0f, 82.9f,
1050 -199.1f, 84.4f, -199.1f, 85.9f, -199.2f, 87.4f, -199.2f, 88.9f, -199.1f, 94.9f,
1051 -198.9f, 96.4f, -198.8f, 97.8f, -198.5f, 99.3f, -198.3f, 100.8f, -198.0f, 102.3f,
1052 -197.7f, 103.7f, -197.4f, 105.2f, -197.0f, 106.7f, -196.6f, 108.1f, -195.7f, 111.0f,
1053 -195.2f, 112.4f, -194.1f, 115.2f, -193.5f, 116.5f, -192.8f, 117.9f, -192.1f, 119.2f,
1054 -190.6f, 121.8f, -189.8f, 123.1f, -188.9f, 124.3f, -187.0f, 126.6f, -186.0f, 127.7f,
1055 -183.9f, 129.8f, -182.7f, 130.8f, -180.3f, 132.6f, -179.1f, 133.4f, -177.8f, 134.1f,
1056 -176.4f, 134.8f, -175.1f, 135.5f, -173.7f, 136.0f, -169.4f, 137.3f, -167.9f, 137.7f,
1057 -166.5f, 138.0f, -165.0f, 138.3f, -163.5f, 138.4f, -162.0f, 138.4f, -160.5f, 138.3f,
1058 -159.0f, 138.0f, -157.6f, 137.7f, -156.1f, 137.3f, -154.7f, 136.9f, -153.2f, 136.5f,
1059 -151.8f, 136.0f, -150.4f, 135.4f, -149.1f, 134.8f, -147.7f, 134.1f, -146.5f, 133.3f,
1060 -145.2f, 132.5f, -144.0f, 131.6f, -142.8f, 130.6f, -141.7f, 129.6f, -139.6f, 127.5f,
1061 -138.6f, 126.4f, -137.7f, 125.2f, -135.1f, 121.5f, -134.3f, 120.3f, -133.5f, 119.0f,
1062 -131.9f, 116.5f, -131.1f, 115.2f, -128.8f, 111.3f, -128.0f, 110.1f, -127.2f, 108.8f,
1063 -126.5f, 107.5f, -125.7f, 106.2f, -125.0f, 104.9f, -124.2f, 103.6f, -123.5f, 102.3f,
1064 -122.0f, 99.6f, -121.3f, 98.3f, -115.8f, 87.7f, -115.1f, 86.4f, -114.4f, 85.0f,
1065 -113.7f, 83.7f, -112.3f, 81.0f, -111.6f, 79.7f, -110.1f, 77.1f, -109.4f, 75.8f,
1066 -108.0f, 73.1f, -107.2f, 71.8f, -106.4f, 70.6f, -105.7f, 69.3f, -104.8f, 68.0f,
1067 -104.0f, 66.8f, -103.1f, 65.6f, -101.1f, 63.3f, -100.0f, 62.3f, -98.8f, 61.4f,
1068 -97.6f, 60.6f, -97.9f, 59.5f, -98.8f, 58.3f, -101.5f, 54.6f, -102.4f, 53.4f,
1069};
1070
1071constexpr std::array<float, 245 * 2> pro_body = {
1072 -0.7f, -129.1f, -54.3f, -129.1f, -55.0f, -129.1f, -57.8f, -129.0f, -58.5f, -129.0f,
1073 -60.7f, -128.9f, -61.4f, -128.9f, -62.8f, -128.8f, -63.5f, -128.8f, -65.7f, -128.7f,
1074 -66.4f, -128.7f, -67.8f, -128.6f, -68.5f, -128.6f, -69.2f, -128.5f, -70.0f, -128.5f,
1075 -70.7f, -128.4f, -71.4f, -128.4f, -72.1f, -128.3f, -72.8f, -128.3f, -73.5f, -128.2f,
1076 -74.2f, -128.2f, -74.9f, -128.1f, -75.7f, -128.1f, -76.4f, -128.0f, -77.1f, -128.0f,
1077 -77.8f, -127.9f, -78.5f, -127.9f, -79.2f, -127.8f, -80.6f, -127.7f, -81.4f, -127.6f,
1078 -82.1f, -127.5f, -82.8f, -127.5f, -83.5f, -127.4f, -84.9f, -127.3f, -85.6f, -127.2f,
1079 -87.0f, -127.1f, -87.7f, -127.0f, -88.5f, -126.9f, -89.2f, -126.8f, -89.9f, -126.8f,
1080 -90.6f, -126.7f, -94.1f, -126.3f, -94.8f, -126.2f, -113.2f, -123.3f, -113.9f, -123.2f,
1081 -114.6f, -123.0f, -115.3f, -122.9f, -116.7f, -122.6f, -117.4f, -122.5f, -118.1f, -122.3f,
1082 -118.8f, -122.2f, -119.5f, -122.0f, -120.9f, -121.7f, -121.6f, -121.5f, -122.3f, -121.4f,
1083 -122.9f, -121.2f, -123.6f, -121.0f, -126.4f, -120.3f, -127.1f, -120.1f, -127.8f, -119.8f,
1084 -128.4f, -119.6f, -129.1f, -119.4f, -131.2f, -118.7f, -132.5f, -118.3f, -133.2f, -118.0f,
1085 -133.8f, -117.7f, -134.5f, -117.4f, -135.1f, -117.2f, -135.8f, -116.9f, -136.4f, -116.5f,
1086 -137.0f, -116.2f, -137.7f, -115.8f, -138.3f, -115.4f, -138.9f, -115.1f, -139.5f, -114.7f,
1087 -160.0f, -100.5f, -160.5f, -100.0f, -162.5f, -97.9f, -162.9f, -97.4f, -163.4f, -96.8f,
1088 -163.8f, -96.2f, -165.3f, -93.8f, -165.7f, -93.2f, -166.0f, -92.6f, -166.4f, -91.9f,
1089 -166.7f, -91.3f, -167.3f, -90.0f, -167.6f, -89.4f, -167.8f, -88.7f, -168.1f, -88.0f,
1090 -168.4f, -87.4f, -168.6f, -86.7f, -168.9f, -86.0f, -169.1f, -85.4f, -169.3f, -84.7f,
1091 -169.6f, -84.0f, -169.8f, -83.3f, -170.2f, -82.0f, -170.4f, -81.3f, -172.8f, -72.3f,
1092 -173.0f, -71.6f, -173.5f, -69.5f, -173.7f, -68.8f, -173.9f, -68.2f, -174.0f, -67.5f,
1093 -174.2f, -66.8f, -174.5f, -65.4f, -174.7f, -64.7f, -174.8f, -64.0f, -175.0f, -63.3f,
1094 -175.3f, -61.9f, -175.5f, -61.2f, -175.8f, -59.8f, -176.0f, -59.1f, -176.1f, -58.4f,
1095 -176.3f, -57.7f, -176.6f, -56.3f, -176.8f, -55.6f, -176.9f, -54.9f, -177.1f, -54.2f,
1096 -177.3f, -53.6f, -177.4f, -52.9f, -177.6f, -52.2f, -177.9f, -50.8f, -178.1f, -50.1f,
1097 -178.2f, -49.4f, -178.2f, -48.7f, -177.8f, -48.1f, -177.1f, -46.9f, -176.7f, -46.3f,
1098 -176.4f, -45.6f, -176.0f, -45.0f, -175.3f, -43.8f, -174.9f, -43.2f, -174.2f, -42.0f,
1099 -173.4f, -40.7f, -173.1f, -40.1f, -172.7f, -39.5f, -172.0f, -38.3f, -171.6f, -37.7f,
1100 -170.5f, -35.9f, -170.1f, -35.3f, -169.7f, -34.6f, -169.3f, -34.0f, -168.6f, -32.8f,
1101 -168.2f, -32.2f, -166.3f, -29.2f, -165.9f, -28.6f, -163.2f, -24.4f, -162.8f, -23.8f,
1102 -141.8f, 6.8f, -141.4f, 7.4f, -139.4f, 10.3f, -139.0f, 10.9f, -138.5f, 11.5f,
1103 -138.1f, 12.1f, -137.3f, 13.2f, -136.9f, 13.8f, -136.0f, 15.0f, -135.6f, 15.6f,
1104 -135.2f, 16.1f, -134.8f, 16.7f, -133.9f, 17.9f, -133.5f, 18.4f, -133.1f, 19.0f,
1105 -131.8f, 20.7f, -131.4f, 21.3f, -130.1f, 23.0f, -129.7f, 23.6f, -128.4f, 25.3f,
1106 -128.0f, 25.9f, -126.7f, 27.6f, -126.3f, 28.2f, -125.4f, 29.3f, -125.0f, 29.9f,
1107 -124.1f, 31.0f, -123.7f, 31.6f, -122.8f, 32.7f, -122.4f, 33.3f, -121.5f, 34.4f,
1108 -121.1f, 35.0f, -120.6f, 35.6f, -120.2f, 36.1f, -119.7f, 36.7f, -119.3f, 37.2f,
1109 -118.9f, 37.8f, -118.4f, 38.4f, -118.0f, 38.9f, -117.5f, 39.5f, -117.1f, 40.0f,
1110 -116.6f, 40.6f, -116.2f, 41.1f, -115.7f, 41.7f, -115.2f, 42.2f, -114.8f, 42.8f,
1111 -114.3f, 43.3f, -113.9f, 43.9f, -113.4f, 44.4f, -112.4f, 45.5f, -112.0f, 46.0f,
1112 -111.5f, 46.5f, -110.5f, 47.6f, -110.0f, 48.1f, -109.6f, 48.6f, -109.1f, 49.2f,
1113 -108.6f, 49.7f, -107.7f, 50.8f, -107.2f, 51.3f, -105.7f, 52.9f, -105.3f, 53.4f,
1114 -104.8f, 53.9f, -104.3f, 54.5f, -103.8f, 55.0f, -100.7f, 58.0f, -100.2f, 58.4f,
1115 -99.7f, 58.9f, -99.1f, 59.3f, -97.2f, 60.3f, -96.5f, 60.1f, -95.9f, 59.7f,
1116 -95.3f, 59.4f, -94.6f, 59.1f, -93.9f, 58.9f, -92.6f, 58.5f, -91.9f, 58.4f,
1117 -91.2f, 58.2f, -90.5f, 58.1f, -89.7f, 58.0f, -89.0f, 57.9f, -86.2f, 57.6f,
1118 -85.5f, 57.5f, -84.1f, 57.4f, -83.4f, 57.3f, -82.6f, 57.3f, -81.9f, 57.2f,
1119 -81.2f, 57.2f, -80.5f, 57.1f, -79.8f, 57.1f, -78.4f, 57.0f, -77.7f, 57.0f,
1120 -75.5f, 56.9f, -74.8f, 56.9f, -71.9f, 56.8f, -71.2f, 56.8f, 0.0f, 56.8f,
1121};
1122
1123constexpr std::array<float, 199 * 2> gc_body = {
1124 0.0f, -138.03f, -4.91f, -138.01f, -8.02f, -137.94f, -11.14f, -137.82f, -14.25f,
1125 -137.67f, -17.37f, -137.48f, -20.48f, -137.25f, -23.59f, -137.0f, -26.69f, -136.72f,
1126 -29.8f, -136.41f, -32.9f, -136.07f, -35.99f, -135.71f, -39.09f, -135.32f, -42.18f,
1127 -134.91f, -45.27f, -134.48f, -48.35f, -134.03f, -51.43f, -133.55f, -54.51f, -133.05f,
1128 -57.59f, -132.52f, -60.66f, -131.98f, -63.72f, -131.41f, -66.78f, -130.81f, -69.84f,
1129 -130.2f, -72.89f, -129.56f, -75.94f, -128.89f, -78.98f, -128.21f, -82.02f, -127.49f,
1130 -85.05f, -126.75f, -88.07f, -125.99f, -91.09f, -125.19f, -94.1f, -124.37f, -97.1f,
1131 -123.52f, -100.09f, -122.64f, -103.07f, -121.72f, -106.04f, -120.77f, -109.0f, -119.79f,
1132 -111.95f, -118.77f, -114.88f, -117.71f, -117.8f, -116.61f, -120.7f, -115.46f, -123.58f,
1133 -114.27f, -126.44f, -113.03f, -129.27f, -111.73f, -132.08f, -110.38f, -134.86f, -108.96f,
1134 -137.6f, -107.47f, -140.3f, -105.91f, -142.95f, -104.27f, -145.55f, -102.54f, -148.07f,
1135 -100.71f, -150.51f, -98.77f, -152.86f, -96.71f, -155.09f, -94.54f, -157.23f, -92.27f,
1136 -159.26f, -89.9f, -161.2f, -87.46f, -163.04f, -84.94f, -164.78f, -82.35f, -166.42f,
1137 -79.7f, -167.97f, -77.0f, -169.43f, -74.24f, -170.8f, -71.44f, -172.09f, -68.6f,
1138 -173.29f, -65.72f, -174.41f, -62.81f, -175.45f, -59.87f, -176.42f, -56.91f, -177.31f,
1139 -53.92f, -178.14f, -50.91f, -178.9f, -47.89f, -179.6f, -44.85f, -180.24f, -41.8f,
1140 -180.82f, -38.73f, -181.34f, -35.66f, -181.8f, -32.57f, -182.21f, -29.48f, -182.57f,
1141 -26.38f, -182.88f, -23.28f, -183.15f, -20.17f, -183.36f, -17.06f, -183.54f, -13.95f,
1142 -183.71f, -10.84f, -184.0f, -7.73f, -184.23f, -4.62f, -184.44f, -1.51f, -184.62f,
1143 1.6f, -184.79f, 4.72f, -184.95f, 7.83f, -185.11f, 10.95f, -185.25f, 14.06f,
1144 -185.38f, 17.18f, -185.51f, 20.29f, -185.63f, 23.41f, -185.74f, 26.53f, -185.85f,
1145 29.64f, -185.95f, 32.76f, -186.04f, 35.88f, -186.12f, 39.0f, -186.19f, 42.11f,
1146 -186.26f, 45.23f, -186.32f, 48.35f, -186.37f, 51.47f, -186.41f, 54.59f, -186.44f,
1147 57.7f, -186.46f, 60.82f, -186.46f, 63.94f, -186.44f, 70.18f, -186.41f, 73.3f,
1148 -186.36f, 76.42f, -186.3f, 79.53f, -186.22f, 82.65f, -186.12f, 85.77f, -185.99f,
1149 88.88f, -185.84f, 92.0f, -185.66f, 95.11f, -185.44f, 98.22f, -185.17f, 101.33f,
1150 -184.85f, 104.43f, -184.46f, 107.53f, -183.97f, 110.61f, -183.37f, 113.67f, -182.65f,
1151 116.7f, -181.77f, 119.69f, -180.71f, 122.62f, -179.43f, 125.47f, -177.89f, 128.18f,
1152 -176.05f, 130.69f, -173.88f, 132.92f, -171.36f, 134.75f, -168.55f, 136.1f, -165.55f,
1153 136.93f, -162.45f, 137.29f, -156.23f, 137.03f, -153.18f, 136.41f, -150.46f, 134.9f,
1154 -148.14f, 132.83f, -146.14f, 130.43f, -144.39f, 127.85f, -142.83f, 125.16f, -141.41f,
1155 122.38f, -140.11f, 119.54f, -138.9f, 116.67f, -137.77f, 113.76f, -136.7f, 110.84f,
1156 -135.68f, 107.89f, -134.71f, 104.93f, -133.77f, 101.95f, -132.86f, 98.97f, -131.97f,
1157 95.98f, -131.09f, 92.99f, -130.23f, 89.99f, -129.36f, 86.99f, -128.49f, 84.0f,
1158 -127.63f, 81.0f, -126.76f, 78.01f, -125.9f, 75.01f, -124.17f, 69.02f, -123.31f,
1159 66.02f, -121.59f, 60.03f, -120.72f, 57.03f, -119.86f, 54.03f, -118.13f, 48.04f,
1160 -117.27f, 45.04f, -115.55f, 39.05f, -114.68f, 36.05f, -113.82f, 33.05f, -112.96f,
1161 30.06f, -110.4f, 28.29f, -107.81f, 26.55f, -105.23f, 24.8f, -97.48f, 19.55f,
1162 -94.9f, 17.81f, -92.32f, 16.06f, -87.15f, 12.56f, -84.57f, 10.81f, -81.99f,
1163 9.07f, -79.4f, 7.32f, -76.82f, 5.57f, -69.07f, 0.33f, -66.49f, -1.42f,
1164 -58.74f, -6.66f, -56.16f, -8.41f, -48.4f, -13.64f, -45.72f, -15.22f, -42.93f,
1165 -16.62f, -40.07f, -17.86f, -37.15f, -18.96f, -34.19f, -19.94f, -31.19f, -20.79f,
1166 -28.16f, -21.55f, -25.12f, -22.21f, -22.05f, -22.79f, -18.97f, -23.28f, -15.88f,
1167 -23.7f, -12.78f, -24.05f, -9.68f, -24.33f, -6.57f, -24.55f, -3.45f, -24.69f,
1168 0.0f, -24.69f,
1169};
1170
1171constexpr std::array<float, 99 * 2> gc_left_body = {
1172 -74.59f, -97.22f, -70.17f, -94.19f, -65.95f, -90.89f, -62.06f, -87.21f, -58.58f,
1173 -83.14f, -55.58f, -78.7f, -53.08f, -73.97f, -51.05f, -69.01f, -49.46f, -63.89f,
1174 -48.24f, -58.67f, -47.36f, -53.39f, -46.59f, -48.09f, -45.7f, -42.8f, -44.69f,
1175 -37.54f, -43.54f, -32.31f, -42.25f, -27.11f, -40.8f, -21.95f, -39.19f, -16.84f,
1176 -37.38f, -11.8f, -35.34f, -6.84f, -33.04f, -2.0f, -30.39f, 2.65f, -27.26f,
1177 7.0f, -23.84f, 11.11f, -21.19f, 15.76f, -19.18f, 20.73f, -17.73f, 25.88f,
1178 -16.82f, 31.16f, -16.46f, 36.5f, -16.7f, 41.85f, -17.63f, 47.13f, -19.31f,
1179 52.21f, -21.8f, 56.95f, -24.91f, 61.3f, -28.41f, 65.36f, -32.28f, 69.06f,
1180 -36.51f, 72.35f, -41.09f, 75.13f, -45.97f, 77.32f, -51.1f, 78.86f, -56.39f,
1181 79.7f, -61.74f, 79.84f, -67.07f, 79.3f, -72.3f, 78.15f, -77.39f, 76.48f,
1182 -82.29f, 74.31f, -86.76f, 71.37f, -90.7f, 67.75f, -94.16f, 63.66f, -97.27f,
1183 59.3f, -100.21f, 54.81f, -103.09f, 50.3f, -106.03f, 45.82f, -109.11f, 41.44f,
1184 -112.37f, 37.19f, -115.85f, 33.11f, -119.54f, 29.22f, -123.45f, 25.56f, -127.55f,
1185 22.11f, -131.77f, 18.81f, -136.04f, 15.57f, -140.34f, 12.37f, -144.62f, 9.15f,
1186 -148.86f, 5.88f, -153.03f, 2.51f, -157.05f, -1.03f, -160.83f, -4.83f, -164.12f,
1187 -9.05f, -166.71f, -13.73f, -168.91f, -18.62f, -170.77f, -23.64f, -172.3f, -28.78f,
1188 -173.49f, -34.0f, -174.3f, -39.3f, -174.72f, -44.64f, -174.72f, -49.99f, -174.28f,
1189 -55.33f, -173.37f, -60.61f, -172.0f, -65.79f, -170.17f, -70.82f, -167.79f, -75.62f,
1190 -164.84f, -80.09f, -161.43f, -84.22f, -157.67f, -88.03f, -153.63f, -91.55f, -149.37f,
1191 -94.81f, -144.94f, -97.82f, -140.37f, -100.61f, -135.65f, -103.16f, -130.73f, -105.26f,
1192 -125.62f, -106.86f, -120.37f, -107.95f, -115.05f, -108.56f, -109.7f, -108.69f, -104.35f,
1193 -108.36f, -99.05f, -107.6f, -93.82f, -106.41f, -88.72f, -104.79f, -83.78f, -102.7f,
1194};
1195
1196constexpr std::array<float, 47 * 2> left_gc_trigger = {
1197 -99.69f, -125.04f, -101.81f, -126.51f, -104.02f, -127.85f, -106.3f, -129.06f, -108.65f,
1198 -130.12f, -111.08f, -130.99f, -113.58f, -131.62f, -116.14f, -131.97f, -121.26f, -131.55f,
1199 -123.74f, -130.84f, -126.17f, -129.95f, -128.53f, -128.9f, -130.82f, -127.71f, -133.03f,
1200 -126.38f, -135.15f, -124.92f, -137.18f, -123.32f, -139.11f, -121.6f, -140.91f, -119.75f,
1201 -142.55f, -117.77f, -144.0f, -115.63f, -145.18f, -113.34f, -146.17f, -110.95f, -147.05f,
1202 -108.53f, -147.87f, -106.08f, -148.64f, -103.61f, -149.37f, -101.14f, -149.16f, -100.12f,
1203 -147.12f, -101.71f, -144.99f, -103.16f, -142.8f, -104.53f, -140.57f, -105.83f, -138.31f,
1204 -107.08f, -136.02f, -108.27f, -133.71f, -109.42f, -131.38f, -110.53f, -129.04f, -111.61f,
1205 -126.68f, -112.66f, -124.31f, -113.68f, -121.92f, -114.67f, -119.53f, -115.64f, -117.13f,
1206 -116.58f, -114.72f, -117.51f, -112.3f, -118.41f, -109.87f, -119.29f, -107.44f, -120.16f,
1207 -105.0f, -121.0f, -100.11f, -122.65f,
1208};
1209
1210constexpr std::array<float, 50 * 2> gc_button_x = {
1211 142.1f, -50.67f, 142.44f, -48.65f, 142.69f, -46.62f, 142.8f, -44.57f, 143.0f, -42.54f,
1212 143.56f, -40.57f, 144.42f, -38.71f, 145.59f, -37.04f, 147.08f, -35.64f, 148.86f, -34.65f,
1213 150.84f, -34.11f, 152.88f, -34.03f, 154.89f, -34.38f, 156.79f, -35.14f, 158.49f, -36.28f,
1214 159.92f, -37.74f, 161.04f, -39.45f, 161.85f, -41.33f, 162.4f, -43.3f, 162.72f, -45.32f,
1215 162.85f, -47.37f, 162.82f, -49.41f, 162.67f, -51.46f, 162.39f, -53.48f, 162.0f, -55.5f,
1216 161.51f, -57.48f, 160.9f, -59.44f, 160.17f, -61.35f, 159.25f, -63.18f, 158.19f, -64.93f,
1217 157.01f, -66.61f, 155.72f, -68.2f, 154.31f, -69.68f, 152.78f, -71.04f, 151.09f, -72.2f,
1218 149.23f, -73.04f, 147.22f, -73.36f, 145.19f, -73.11f, 143.26f, -72.42f, 141.51f, -71.37f,
1219 140.0f, -69.99f, 138.82f, -68.32f, 138.13f, -66.4f, 138.09f, -64.36f, 138.39f, -62.34f,
1220 139.05f, -60.41f, 139.91f, -58.55f, 140.62f, -56.63f, 141.21f, -54.67f, 141.67f, -52.67f,
1221};
1222
1223constexpr std::array<float, 50 * 2> gc_button_y = {
1224 104.02f, -75.23f, 106.01f, -75.74f, 108.01f, -76.15f, 110.04f, -76.42f, 112.05f, -76.78f,
1225 113.97f, -77.49f, 115.76f, -78.49f, 117.33f, -79.79f, 118.6f, -81.39f, 119.46f, -83.25f,
1226 119.84f, -85.26f, 119.76f, -87.3f, 119.24f, -89.28f, 118.33f, -91.11f, 117.06f, -92.71f,
1227 115.49f, -94.02f, 113.7f, -95.01f, 111.77f, -95.67f, 109.76f, -96.05f, 107.71f, -96.21f,
1228 105.67f, -96.18f, 103.63f, -95.99f, 101.61f, -95.67f, 99.61f, -95.24f, 97.63f, -94.69f,
1229 95.69f, -94.04f, 93.79f, -93.28f, 91.94f, -92.4f, 90.19f, -91.34f, 88.53f, -90.14f,
1230 86.95f, -88.84f, 85.47f, -87.42f, 84.1f, -85.9f, 82.87f, -84.26f, 81.85f, -82.49f,
1231 81.15f, -80.57f, 81.0f, -78.54f, 81.41f, -76.54f, 82.24f, -74.67f, 83.43f, -73.01f,
1232 84.92f, -71.61f, 86.68f, -70.57f, 88.65f, -70.03f, 90.69f, -70.15f, 92.68f, -70.61f,
1233 94.56f, -71.42f, 96.34f, -72.43f, 98.2f, -73.29f, 100.11f, -74.03f, 102.06f, -74.65f,
1234};
1235
1236constexpr std::array<float, 47 * 2> gc_button_z = {
1237 95.74f, -126.41f, 98.34f, -126.38f, 100.94f, -126.24f, 103.53f, -126.01f, 106.11f, -125.7f,
1238 108.69f, -125.32f, 111.25f, -124.87f, 113.8f, -124.34f, 116.33f, -123.73f, 118.84f, -123.05f,
1239 121.33f, -122.3f, 123.79f, -121.47f, 126.23f, -120.56f, 128.64f, -119.58f, 131.02f, -118.51f,
1240 133.35f, -117.37f, 135.65f, -116.14f, 137.9f, -114.84f, 140.1f, -113.46f, 142.25f, -111.99f,
1241 144.35f, -110.45f, 146.38f, -108.82f, 148.35f, -107.13f, 150.25f, -105.35f, 151.89f, -103.38f,
1242 151.43f, -100.86f, 149.15f, -100.15f, 146.73f, -101.06f, 144.36f, -102.12f, 141.98f, -103.18f,
1243 139.6f, -104.23f, 137.22f, -105.29f, 134.85f, -106.35f, 132.47f, -107.41f, 127.72f, -109.53f,
1244 125.34f, -110.58f, 122.96f, -111.64f, 120.59f, -112.7f, 118.21f, -113.76f, 113.46f, -115.88f,
1245 111.08f, -116.93f, 108.7f, -117.99f, 106.33f, -119.05f, 103.95f, -120.11f, 99.2f, -122.23f,
1246 96.82f, -123.29f, 94.44f, -124.34f,
1247};
1248
1249constexpr std::array<float, 84 * 2> left_joycon_body = {
1250 -145.0f, -78.9f, -145.0f, -77.9f, -145.0f, 85.6f, -145.0f, 85.6f, -168.3f, 85.5f,
1251 -169.3f, 85.4f, -171.3f, 85.1f, -172.3f, 84.9f, -173.4f, 84.7f, -174.3f, 84.5f,
1252 -175.3f, 84.2f, -176.3f, 83.8f, -177.3f, 83.5f, -178.2f, 83.1f, -179.2f, 82.7f,
1253 -180.1f, 82.2f, -181.0f, 81.8f, -181.9f, 81.3f, -182.8f, 80.7f, -183.7f, 80.2f,
1254 -184.5f, 79.6f, -186.2f, 78.3f, -186.9f, 77.7f, -187.7f, 77.0f, -189.2f, 75.6f,
1255 -189.9f, 74.8f, -190.6f, 74.1f, -191.3f, 73.3f, -191.9f, 72.5f, -192.5f, 71.6f,
1256 -193.1f, 70.8f, -193.7f, 69.9f, -194.3f, 69.1f, -194.8f, 68.2f, -196.2f, 65.5f,
1257 -196.6f, 64.5f, -197.0f, 63.6f, -197.4f, 62.6f, -198.1f, 60.7f, -198.4f, 59.7f,
1258 -198.6f, 58.7f, -199.2f, 55.6f, -199.3f, 54.6f, -199.5f, 51.5f, -199.5f, 50.5f,
1259 -199.5f, -49.4f, -199.4f, -50.5f, -199.3f, -51.5f, -199.1f, -52.5f, -198.2f, -56.5f,
1260 -197.9f, -57.5f, -197.2f, -59.4f, -196.8f, -60.4f, -196.4f, -61.3f, -195.9f, -62.2f,
1261 -194.3f, -64.9f, -193.7f, -65.7f, -193.1f, -66.6f, -192.5f, -67.4f, -191.8f, -68.2f,
1262 -191.2f, -68.9f, -190.4f, -69.7f, -188.2f, -71.8f, -187.4f, -72.5f, -186.6f, -73.1f,
1263 -185.8f, -73.8f, -185.0f, -74.4f, -184.1f, -74.9f, -183.2f, -75.5f, -182.4f, -76.0f,
1264 -181.5f, -76.5f, -179.6f, -77.5f, -178.7f, -77.9f, -177.8f, -78.4f, -176.8f, -78.8f,
1265 -175.9f, -79.1f, -174.9f, -79.5f, -173.9f, -79.8f, -170.9f, -80.6f, -169.9f, -80.8f,
1266 -167.9f, -81.1f, -166.9f, -81.2f, -165.8f, -81.2f, -145.0f, -80.9f,
1267};
1268
1269constexpr std::array<float, 84 * 2> left_joycon_trigger = {
1270 -166.8f, -83.3f, -167.9f, -83.2f, -168.9f, -83.1f, -170.0f, -83.0f, -171.0f, -82.8f,
1271 -172.1f, -82.6f, -173.1f, -82.4f, -174.2f, -82.1f, -175.2f, -81.9f, -176.2f, -81.5f,
1272 -177.2f, -81.2f, -178.2f, -80.8f, -180.1f, -80.0f, -181.1f, -79.5f, -182.0f, -79.0f,
1273 -183.0f, -78.5f, -183.9f, -78.0f, -184.8f, -77.4f, -185.7f, -76.9f, -186.6f, -76.3f,
1274 -187.4f, -75.6f, -188.3f, -75.0f, -189.1f, -74.3f, -192.2f, -71.5f, -192.9f, -70.7f,
1275 -193.7f, -69.9f, -194.3f, -69.1f, -195.0f, -68.3f, -195.6f, -67.4f, -196.8f, -65.7f,
1276 -197.3f, -64.7f, -197.8f, -63.8f, -198.2f, -62.8f, -198.9f, -60.8f, -198.6f, -59.8f,
1277 -197.6f, -59.7f, -196.6f, -60.0f, -195.6f, -60.5f, -194.7f, -60.9f, -193.7f, -61.4f,
1278 -192.8f, -61.9f, -191.8f, -62.4f, -190.9f, -62.8f, -189.9f, -63.3f, -189.0f, -63.8f,
1279 -187.1f, -64.8f, -186.2f, -65.2f, -185.2f, -65.7f, -184.3f, -66.2f, -183.3f, -66.7f,
1280 -182.4f, -67.1f, -181.4f, -67.6f, -180.5f, -68.1f, -179.5f, -68.6f, -178.6f, -69.0f,
1281 -177.6f, -69.5f, -176.7f, -70.0f, -175.7f, -70.5f, -174.8f, -70.9f, -173.8f, -71.4f,
1282 -172.9f, -71.9f, -171.9f, -72.4f, -171.0f, -72.8f, -170.0f, -73.3f, -169.1f, -73.8f,
1283 -168.1f, -74.3f, -167.2f, -74.7f, -166.2f, -75.2f, -165.3f, -75.7f, -164.3f, -76.2f,
1284 -163.4f, -76.6f, -162.4f, -77.1f, -161.5f, -77.6f, -160.5f, -78.1f, -159.6f, -78.5f,
1285 -158.7f, -79.0f, -157.7f, -79.5f, -156.8f, -80.0f, -155.8f, -80.4f, -154.9f, -80.9f,
1286 -154.2f, -81.6f, -154.3f, -82.6f, -155.2f, -83.3f, -156.2f, -83.3f,
1287};
1288
1289constexpr std::array<float, 70 * 2> handheld_body = {
1290 -137.3f, -81.9f, -137.6f, -81.8f, -137.8f, -81.6f, -138.0f, -81.3f, -138.1f, -81.1f,
1291 -138.1f, -80.8f, -138.2f, -78.7f, -138.2f, -78.4f, -138.3f, -78.1f, -138.7f, -77.3f,
1292 -138.9f, -77.0f, -139.0f, -76.8f, -139.2f, -76.5f, -139.5f, -76.3f, -139.7f, -76.1f,
1293 -139.9f, -76.0f, -140.2f, -75.8f, -140.5f, -75.7f, -140.7f, -75.6f, -141.0f, -75.5f,
1294 -141.9f, -75.3f, -142.2f, -75.3f, -142.5f, -75.2f, -143.0f, -74.9f, -143.2f, -74.7f,
1295 -143.3f, -74.4f, -143.0f, -74.1f, -143.0f, 85.3f, -143.0f, 85.6f, -142.7f, 85.8f,
1296 -142.4f, 85.9f, -142.2f, 85.9f, 143.0f, 85.6f, 143.1f, 85.4f, 143.3f, 85.1f,
1297 143.0f, 84.8f, 143.0f, -74.9f, 142.8f, -75.1f, 142.5f, -75.2f, 141.9f, -75.3f,
1298 141.6f, -75.3f, 141.3f, -75.4f, 141.1f, -75.4f, 140.8f, -75.5f, 140.5f, -75.7f,
1299 140.2f, -75.8f, 140.0f, -76.0f, 139.7f, -76.1f, 139.5f, -76.3f, 139.1f, -76.8f,
1300 138.9f, -77.0f, 138.6f, -77.5f, 138.4f, -77.8f, 138.3f, -78.1f, 138.3f, -78.3f,
1301 138.2f, -78.6f, 138.2f, -78.9f, 138.1f, -79.2f, 138.1f, -79.5f, 138.0f, -81.3f,
1302 137.8f, -81.6f, 137.6f, -81.8f, 137.3f, -81.9f, 137.1f, -81.9f, 120.0f, -70.0f,
1303 -120.0f, -70.0f, -120.0f, 70.0f, 120.0f, 70.0f, 120.0f, -70.0f, 137.1f, -81.9f,
1304};
1305
1306constexpr std::array<float, 40 * 2> handheld_bezel = {
1307 -131.4f, -75.9f, -132.2f, -75.7f, -132.9f, -75.3f, -134.2f, -74.3f, -134.7f, -73.6f,
1308 -135.1f, -72.8f, -135.4f, -72.0f, -135.5f, -71.2f, -135.5f, -70.4f, -135.2f, 76.7f,
1309 -134.8f, 77.5f, -134.3f, 78.1f, -133.7f, 78.8f, -133.1f, 79.2f, -132.3f, 79.6f,
1310 -131.5f, 79.9f, -130.7f, 80.0f, -129.8f, 80.0f, 132.2f, 79.7f, 133.0f, 79.3f,
1311 133.7f, 78.8f, 134.3f, 78.3f, 134.8f, 77.6f, 135.1f, 76.8f, 135.5f, 75.2f,
1312 135.5f, 74.3f, 135.2f, -72.7f, 134.8f, -73.5f, 134.4f, -74.2f, 133.8f, -74.8f,
1313 133.1f, -75.3f, 132.3f, -75.6f, 130.7f, -76.0f, 129.8f, -76.0f, -112.9f, -62.2f,
1314 112.9f, -62.2f, 112.9f, 62.2f, -112.9f, 62.2f, -112.9f, -62.2f, 129.8f, -76.0f,
1315};
1316
1317constexpr std::array<float, 58 * 2> handheld_buttons = {
1318 -82.48f, -82.95f, -82.53f, -82.95f, -106.69f, -82.96f, -106.73f, -82.98f, -106.78f, -83.01f,
1319 -106.81f, -83.05f, -106.83f, -83.1f, -106.83f, -83.15f, -106.82f, -83.93f, -106.81f, -83.99f,
1320 -106.8f, -84.04f, -106.78f, -84.08f, -106.76f, -84.13f, -106.73f, -84.18f, -106.7f, -84.22f,
1321 -106.6f, -84.34f, -106.56f, -84.37f, -106.51f, -84.4f, -106.47f, -84.42f, -106.42f, -84.45f,
1322 -106.37f, -84.47f, -106.32f, -84.48f, -106.17f, -84.5f, -98.9f, -84.48f, -98.86f, -84.45f,
1323 -98.83f, -84.41f, -98.81f, -84.36f, -98.8f, -84.31f, -98.8f, -84.26f, -98.79f, -84.05f,
1324 -90.26f, -84.1f, -90.26f, -84.15f, -90.25f, -84.36f, -90.23f, -84.41f, -90.2f, -84.45f,
1325 -90.16f, -84.48f, -90.11f, -84.5f, -82.79f, -84.49f, -82.74f, -84.48f, -82.69f, -84.46f,
1326 -82.64f, -84.45f, -82.59f, -84.42f, -82.55f, -84.4f, -82.5f, -84.37f, -82.46f, -84.33f,
1327 -82.42f, -84.3f, -82.39f, -84.26f, -82.3f, -84.13f, -82.28f, -84.08f, -82.25f, -83.98f,
1328 -82.24f, -83.93f, -82.23f, -83.83f, -82.23f, -83.78f, -82.24f, -83.1f, -82.26f, -83.05f,
1329 -82.29f, -83.01f, -82.33f, -82.97f, -82.38f, -82.95f,
1330};
1331
1332constexpr std::array<float, 47 * 2> left_joycon_slider = {
1333 -23.7f, -118.2f, -23.7f, -117.3f, -23.7f, 96.6f, -22.8f, 96.6f, -21.5f, 97.2f, -21.5f,
1334 98.1f, -21.2f, 106.7f, -20.8f, 107.5f, -20.1f, 108.2f, -19.2f, 108.2f, -16.4f, 108.1f,
1335 -15.8f, 107.5f, -15.8f, 106.5f, -15.8f, 62.8f, -16.3f, 61.9f, -15.8f, 61.0f, -17.3f,
1336 60.3f, -19.1f, 58.9f, -19.1f, 58.1f, -19.1f, 57.2f, -19.1f, 34.5f, -17.9f, 33.9f,
1337 -17.2f, 33.2f, -16.6f, 32.4f, -16.2f, 31.6f, -15.8f, 30.7f, -15.8f, 29.7f, -15.8f,
1338 28.8f, -15.8f, -46.4f, -16.3f, -47.3f, -15.8f, -48.1f, -17.4f, -48.8f, -19.1f, -49.4f,
1339 -19.1f, -50.1f, -19.1f, -51.0f, -19.1f, -51.9f, -19.1f, -73.7f, -19.1f, -74.5f, -17.5f,
1340 -75.2f, -16.4f, -76.7f, -16.0f, -77.6f, -15.8f, -78.5f, -15.8f, -79.4f, -15.8f, -80.4f,
1341 -15.8f, -118.2f, -15.8f, -118.2f, -18.3f, -118.2f,
1342};
1343
1344constexpr std::array<float, 66 * 2> left_joycon_sideview = {
1345 -158.8f, -133.5f, -159.8f, -133.5f, -173.5f, -133.3f, -174.5f, -133.0f, -175.4f, -132.6f,
1346 -176.2f, -132.1f, -177.0f, -131.5f, -177.7f, -130.9f, -178.3f, -130.1f, -179.4f, -128.5f,
1347 -179.8f, -127.6f, -180.4f, -125.7f, -180.6f, -124.7f, -180.7f, -123.8f, -180.7f, -122.8f,
1348 -180.0f, 128.8f, -179.6f, 129.7f, -179.1f, 130.5f, -177.9f, 132.1f, -177.2f, 132.7f,
1349 -176.4f, 133.3f, -175.6f, 133.8f, -174.7f, 134.3f, -173.8f, 134.6f, -172.8f, 134.8f,
1350 -170.9f, 135.0f, -169.9f, 135.0f, -156.1f, 134.8f, -155.2f, 134.6f, -154.2f, 134.3f,
1351 -153.3f, 134.0f, -152.4f, 133.6f, -151.6f, 133.1f, -150.7f, 132.6f, -149.9f, 132.0f,
1352 -149.2f, 131.4f, -148.5f, 130.7f, -147.1f, 129.2f, -146.5f, 128.5f, -146.0f, 127.7f,
1353 -145.5f, 126.8f, -145.0f, 126.0f, -144.6f, 125.1f, -144.2f, 124.1f, -143.9f, 123.2f,
1354 -143.7f, 122.2f, -143.6f, 121.3f, -143.5f, 120.3f, -143.5f, 119.3f, -144.4f, -123.4f,
1355 -144.8f, -124.3f, -145.3f, -125.1f, -145.8f, -126.0f, -146.3f, -126.8f, -147.0f, -127.5f,
1356 -147.6f, -128.3f, -148.3f, -129.0f, -149.0f, -129.6f, -149.8f, -130.3f, -150.6f, -130.8f,
1357 -151.4f, -131.4f, -152.2f, -131.9f, -153.1f, -132.3f, -155.9f, -133.3f, -156.8f, -133.5f,
1358 -157.8f, -133.5f,
1359};
1360
1361constexpr std::array<float, 40 * 2> left_joycon_body_trigger = {
1362 -146.1f, -124.3f, -146.0f, -122.0f, -145.8f, -119.7f, -145.7f, -117.4f, -145.4f, -112.8f,
1363 -145.3f, -110.5f, -145.0f, -105.9f, -144.9f, -103.6f, -144.6f, -99.1f, -144.5f, -96.8f,
1364 -144.5f, -89.9f, -144.5f, -87.6f, -144.5f, -83.0f, -144.5f, -80.7f, -144.5f, -80.3f,
1365 -142.4f, -82.4f, -141.4f, -84.5f, -140.2f, -86.4f, -138.8f, -88.3f, -137.4f, -90.1f,
1366 -134.5f, -93.6f, -133.0f, -95.3f, -130.0f, -98.8f, -128.5f, -100.6f, -127.1f, -102.4f,
1367 -125.8f, -104.3f, -124.7f, -106.3f, -123.9f, -108.4f, -125.1f, -110.2f, -127.4f, -110.3f,
1368 -129.7f, -110.3f, -134.2f, -110.5f, -136.4f, -111.4f, -138.1f, -112.8f, -139.4f, -114.7f,
1369 -140.5f, -116.8f, -141.4f, -118.9f, -143.3f, -123.1f, -144.6f, -124.9f, -146.2f, -126.0f,
1370};
1371
1372constexpr std::array<float, 49 * 2> left_joycon_topview = {
1373 -184.8f, -20.8f, -185.6f, -21.1f, -186.4f, -21.5f, -187.1f, -22.1f, -187.8f, -22.6f,
1374 -188.4f, -23.2f, -189.6f, -24.5f, -190.2f, -25.2f, -190.7f, -25.9f, -191.1f, -26.7f,
1375 -191.4f, -27.5f, -191.6f, -28.4f, -191.7f, -29.2f, -191.7f, -30.1f, -191.5f, -47.7f,
1376 -191.2f, -48.5f, -191.0f, -49.4f, -190.7f, -50.2f, -190.3f, -51.0f, -190.0f, -51.8f,
1377 -189.6f, -52.6f, -189.1f, -53.4f, -188.6f, -54.1f, -187.5f, -55.4f, -186.9f, -56.1f,
1378 -186.2f, -56.7f, -185.5f, -57.2f, -184.0f, -58.1f, -183.3f, -58.5f, -182.5f, -58.9f,
1379 -181.6f, -59.2f, -180.8f, -59.5f, -179.9f, -59.7f, -179.1f, -59.9f, -178.2f, -60.0f,
1380 -174.7f, -60.1f, -168.5f, -60.2f, -162.4f, -60.3f, -156.2f, -60.4f, -149.2f, -60.5f,
1381 -143.0f, -60.6f, -136.9f, -60.7f, -130.7f, -60.8f, -123.7f, -60.9f, -117.5f, -61.0f,
1382 -110.5f, -61.1f, -94.4f, -60.4f, -94.4f, -59.5f, -94.4f, -20.6f,
1383};
1384
1385constexpr std::array<float, 41 * 2> left_joycon_slider_topview = {
1386 -95.1f, -51.5f, -95.0f, -51.5f, -91.2f, -51.6f, -91.2f, -51.7f, -91.1f, -52.4f, -91.1f, -52.6f,
1387 -91.0f, -54.1f, -86.3f, -54.0f, -86.0f, -53.9f, -85.9f, -53.8f, -85.6f, -53.4f, -85.5f, -53.2f,
1388 -85.5f, -53.1f, -85.4f, -52.9f, -85.4f, -52.8f, -85.3f, -52.4f, -85.3f, -52.3f, -85.4f, -27.2f,
1389 -85.4f, -27.1f, -85.5f, -27.0f, -85.5f, -26.9f, -85.6f, -26.7f, -85.6f, -26.6f, -85.7f, -26.5f,
1390 -85.9f, -26.4f, -86.0f, -26.3f, -86.4f, -26.0f, -86.5f, -25.9f, -86.7f, -25.8f, -87.1f, -25.7f,
1391 -90.4f, -25.8f, -90.7f, -25.9f, -90.8f, -26.0f, -90.9f, -26.3f, -91.0f, -26.4f, -91.0f, -26.5f,
1392 -91.1f, -26.7f, -91.1f, -26.9f, -91.2f, -28.9f, -95.2f, -29.1f, -95.2f, -29.2f,
1393};
1394
1395constexpr std::array<float, 42 * 2> left_joycon_sideview_zl = {
1396 -148.9f, -128.2f, -148.7f, -126.6f, -148.4f, -124.9f, -148.2f, -123.3f, -147.9f, -121.7f,
1397 -147.7f, -120.1f, -147.4f, -118.5f, -147.2f, -116.9f, -146.9f, -115.3f, -146.4f, -112.1f,
1398 -146.1f, -110.5f, -145.9f, -108.9f, -145.6f, -107.3f, -144.2f, -107.3f, -142.6f, -107.5f,
1399 -141.0f, -107.8f, -137.8f, -108.3f, -136.2f, -108.6f, -131.4f, -109.4f, -129.8f, -109.7f,
1400 -125.6f, -111.4f, -124.5f, -112.7f, -123.9f, -114.1f, -123.8f, -115.8f, -123.8f, -117.4f,
1401 -123.9f, -120.6f, -124.5f, -122.1f, -125.8f, -123.1f, -127.4f, -123.4f, -129.0f, -123.6f,
1402 -130.6f, -124.0f, -132.1f, -124.4f, -133.7f, -124.8f, -135.3f, -125.3f, -136.8f, -125.9f,
1403 -138.3f, -126.4f, -139.9f, -126.9f, -141.4f, -127.5f, -142.9f, -128.0f, -144.5f, -128.5f,
1404 -146.0f, -129.0f, -147.6f, -129.4f,
1405};
1406
1407constexpr std::array<float, 72 * 2> left_joystick_sideview = {
1408 -14.7f, -3.8f, -15.2f, -5.6f, -15.2f, -7.6f, -15.5f, -17.6f, -17.4f, -18.3f, -19.4f, -18.2f,
1409 -21.3f, -17.6f, -22.8f, -16.4f, -23.4f, -14.5f, -23.4f, -12.5f, -24.1f, -8.6f, -24.8f, -6.7f,
1410 -25.3f, -4.8f, -25.7f, -2.8f, -25.9f, -0.8f, -26.0f, 1.2f, -26.0f, 3.2f, -25.8f, 5.2f,
1411 -25.5f, 7.2f, -25.0f, 9.2f, -24.4f, 11.1f, -23.7f, 13.0f, -23.4f, 14.9f, -23.4f, 16.9f,
1412 -23.3f, 18.9f, -22.0f, 20.5f, -20.2f, 21.3f, -18.3f, 21.6f, -16.3f, 21.4f, -15.3f, 19.9f,
1413 -15.3f, 17.8f, -15.2f, 7.8f, -13.5f, 6.4f, -12.4f, 7.2f, -11.4f, 8.9f, -10.2f, 10.5f,
1414 -8.7f, 11.8f, -7.1f, 13.0f, -5.3f, 14.0f, -3.5f, 14.7f, -1.5f, 15.0f, 0.5f, 15.0f,
1415 2.5f, 14.7f, 4.4f, 14.2f, 6.3f, 13.4f, 8.0f, 12.4f, 9.6f, 11.1f, 10.9f, 9.6f,
1416 12.0f, 7.9f, 12.7f, 6.0f, 13.2f, 4.1f, 13.3f, 2.1f, 13.2f, 0.1f, 12.9f, -1.9f,
1417 12.2f, -3.8f, 11.3f, -5.6f, 10.2f, -7.2f, 8.8f, -8.6f, 7.1f, -9.8f, 5.4f, -10.8f,
1418 3.5f, -11.5f, 1.5f, -11.9f, -0.5f, -12.0f, -2.5f, -11.8f, -4.4f, -11.3f, -6.2f, -10.4f,
1419 -8.0f, -9.4f, -9.6f, -8.2f, -10.9f, -6.7f, -11.9f, -4.9f, -12.8f, -3.2f, -13.5f, -3.8f,
1420};
1421
1422constexpr std::array<float, 63 * 2> left_joystick_L_topview = {
1423 -186.7f, -43.7f, -186.4f, -43.7f, -110.6f, -43.4f, -110.6f, -43.1f, -110.7f, -34.3f,
1424 -110.7f, -34.0f, -110.8f, -33.7f, -111.1f, -32.9f, -111.2f, -32.6f, -111.4f, -32.3f,
1425 -111.5f, -32.1f, -111.7f, -31.8f, -111.8f, -31.5f, -112.0f, -31.3f, -112.2f, -31.0f,
1426 -112.4f, -30.8f, -112.8f, -30.3f, -113.0f, -30.1f, -114.1f, -29.1f, -114.3f, -28.9f,
1427 -114.6f, -28.7f, -114.8f, -28.6f, -115.1f, -28.4f, -115.3f, -28.3f, -115.6f, -28.1f,
1428 -115.9f, -28.0f, -116.4f, -27.8f, -116.7f, -27.7f, -117.3f, -27.6f, -117.6f, -27.5f,
1429 -182.9f, -27.6f, -183.5f, -27.7f, -183.8f, -27.8f, -184.4f, -27.9f, -184.6f, -28.1f,
1430 -184.9f, -28.2f, -185.4f, -28.5f, -185.7f, -28.7f, -185.9f, -28.8f, -186.2f, -29.0f,
1431 -186.4f, -29.2f, -187.0f, -29.9f, -187.2f, -30.1f, -187.6f, -30.6f, -187.8f, -30.8f,
1432 -187.9f, -31.1f, -188.1f, -31.3f, -188.2f, -31.6f, -188.4f, -31.9f, -188.5f, -32.1f,
1433 -188.6f, -32.4f, -188.8f, -33.3f, -188.9f, -33.6f, -188.9f, -33.9f, -188.8f, -39.9f,
1434 -188.8f, -40.2f, -188.7f, -41.1f, -188.7f, -41.4f, -188.6f, -41.7f, -188.0f, -43.1f,
1435 -187.9f, -43.4f, -187.6f, -43.6f, -187.3f, -43.7f,
1436};
1437
1438constexpr std::array<float, 44 * 2> left_joystick_ZL_topview = {
1439 -179.4f, -53.3f, -177.4f, -53.3f, -111.2f, -53.3f, -111.3f, -53.3f, -111.5f, -58.6f,
1440 -111.8f, -60.5f, -112.2f, -62.4f, -113.1f, -66.1f, -113.8f, -68.0f, -114.5f, -69.8f,
1441 -115.3f, -71.5f, -116.3f, -73.2f, -117.3f, -74.8f, -118.5f, -76.4f, -119.8f, -77.8f,
1442 -121.2f, -79.1f, -122.8f, -80.2f, -124.4f, -81.2f, -126.2f, -82.0f, -128.1f, -82.6f,
1443 -130.0f, -82.9f, -131.9f, -83.0f, -141.5f, -82.9f, -149.3f, -82.8f, -153.1f, -82.6f,
1444 -155.0f, -82.1f, -156.8f, -81.6f, -158.7f, -80.9f, -160.4f, -80.2f, -162.2f, -79.3f,
1445 -163.8f, -78.3f, -165.4f, -77.2f, -166.9f, -76.0f, -168.4f, -74.7f, -169.7f, -73.3f,
1446 -172.1f, -70.3f, -173.2f, -68.7f, -174.2f, -67.1f, -175.2f, -65.4f, -176.1f, -63.7f,
1447 -178.7f, -58.5f, -179.6f, -56.8f, -180.4f, -55.1f, -181.3f, -53.3f,
1448};
1449
1450void PlayerControlPreview::DrawProBody(QPainter& p, const QPointF center) {
1451 std::array<QPointF, pro_left_handle.size() / 2> qleft_handle;
1452 std::array<QPointF, pro_left_handle.size() / 2> qright_handle;
1453 std::array<QPointF, pro_body.size()> qbody;
1454 constexpr int radius1 = 32;
1455
1456 for (std::size_t point = 0; point < pro_left_handle.size() / 2; ++point) {
1457 const float left_x = pro_left_handle[point * 2 + 0];
1458 const float left_y = pro_left_handle[point * 2 + 1];
1459
1460 qleft_handle[point] = center + QPointF(left_x, left_y);
1461 qright_handle[point] = center + QPointF(-left_x, left_y);
1462 }
1463 for (std::size_t point = 0; point < pro_body.size() / 2; ++point) {
1464 const float body_x = pro_body[point * 2 + 0];
1465 const float body_y = pro_body[point * 2 + 1];
1466
1467 qbody[point] = center + QPointF(body_x, body_y);
1468 qbody[pro_body.size() - 1 - point] = center + QPointF(-body_x, body_y);
1469 }
1470
1471 // Draw left handle body
1472 p.setPen(colors.outline);
1473 p.setBrush(colors.left);
1474 DrawPolygon(p, qleft_handle);
1475
1476 // Draw right handle body
1477 p.setBrush(colors.right);
1478 DrawPolygon(p, qright_handle);
1479
1480 // Draw body
1481 p.setBrush(colors.primary);
1482 DrawPolygon(p, qbody);
1483
1484 // Draw joycon circles
1485 p.setBrush(colors.transparent);
1486 p.drawEllipse(center + QPoint(-111, -55), radius1, radius1);
1487 p.drawEllipse(center + QPoint(51, 0), radius1, radius1);
1488}
1489
1490void PlayerControlPreview::DrawGCBody(QPainter& p, const QPointF center) {
1491 std::array<QPointF, gc_left_body.size() / 2> qleft_handle;
1492 std::array<QPointF, gc_left_body.size() / 2> qright_handle;
1493 std::array<QPointF, gc_body.size()> qbody;
1494 std::array<QPointF, 8> left_hex;
1495 std::array<QPointF, 8> right_hex;
1496 constexpr float angle = 2 * 3.1415f / 8;
1497
1498 for (std::size_t point = 0; point < gc_left_body.size() / 2; ++point) {
1499 const float body_x = gc_left_body[point * 2 + 0];
1500 const float body_y = gc_left_body[point * 2 + 1];
1501
1502 qleft_handle[point] = center + QPointF(body_x, body_y);
1503 qright_handle[point] = center + QPointF(-body_x, body_y);
1504 }
1505 for (std::size_t point = 0; point < gc_body.size() / 2; ++point) {
1506 const float body_x = gc_body[point * 2 + 0];
1507 const float body_y = gc_body[point * 2 + 1];
1508
1509 qbody[point] = center + QPointF(body_x, body_y);
1510 qbody[gc_body.size() - 1 - point] = center + QPointF(-body_x, body_y);
1511 }
1512 for (std::size_t point = 0; point < 8; ++point) {
1513 const float point_cos = std::cos(point * angle);
1514 const float point_sin = std::sin(point * angle);
1515
1516 left_hex[point] = center + QPointF(34 * point_cos - 111, 34 * point_sin - 44);
1517 right_hex[point] = center + QPointF(26 * point_cos + 61, 26 * point_sin + 37);
1518 }
1519
1520 // Draw body
1521 p.setPen(colors.outline);
1522 p.setBrush(colors.primary);
1523 DrawPolygon(p, qbody);
1524
1525 // Draw left handle body
1526 p.setBrush(colors.left);
1527 DrawPolygon(p, qleft_handle);
1528
1529 // Draw right handle body
1530 p.setBrush(colors.right);
1531 DrawPolygon(p, qright_handle);
1532
1533 DrawText(p, center + QPoint(0, -58), 4.7f, tr("START/PAUSE"));
1534
1535 // Draw right joystick body
1536 p.setBrush(colors.button);
1537 DrawCircle(p, center + QPointF(61, 37), 23.5f);
1538
1539 // Draw joystick details
1540 p.setBrush(colors.transparent);
1541 DrawPolygon(p, left_hex);
1542 DrawPolygon(p, right_hex);
1543}
1544
1545void PlayerControlPreview::DrawHandheldBody(QPainter& p, const QPointF center) {
1546 const std::size_t body_outline_end = handheld_body.size() / 2 - 6;
1547 const std::size_t bezel_outline_end = handheld_bezel.size() / 2 - 6;
1548 const std::size_t bezel_inline_size = 4;
1549 const std::size_t bezel_inline_start = 35;
1550 std::array<QPointF, left_joycon_body.size() / 2> left_joycon;
1551 std::array<QPointF, left_joycon_body.size() / 2> right_joycon;
1552 std::array<QPointF, handheld_body.size() / 2> qhandheld_body;
1553 std::array<QPointF, body_outline_end> qhandheld_body_outline;
1554 std::array<QPointF, handheld_bezel.size() / 2> qhandheld_bezel;
1555 std::array<QPointF, bezel_inline_size> qhandheld_bezel_inline;
1556 std::array<QPointF, bezel_outline_end> qhandheld_bezel_outline;
1557 std::array<QPointF, handheld_buttons.size() / 2> qhandheld_buttons;
1558
1559 for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) {
1560 left_joycon[point] =
1561 center + QPointF(left_joycon_body[point * 2], left_joycon_body[point * 2 + 1]);
1562 right_joycon[point] =
1563 center + QPointF(-left_joycon_body[point * 2], left_joycon_body[point * 2 + 1]);
1564 }
1565 for (std::size_t point = 0; point < body_outline_end; ++point) {
1566 qhandheld_body_outline[point] =
1567 center + QPointF(handheld_body[point * 2], handheld_body[point * 2 + 1]);
1568 }
1569 for (std::size_t point = 0; point < handheld_body.size() / 2; ++point) {
1570 qhandheld_body[point] =
1571 center + QPointF(handheld_body[point * 2], handheld_body[point * 2 + 1]);
1572 }
1573 for (std::size_t point = 0; point < handheld_bezel.size() / 2; ++point) {
1574 qhandheld_bezel[point] =
1575 center + QPointF(handheld_bezel[point * 2], handheld_bezel[point * 2 + 1]);
1576 }
1577 for (std::size_t point = 0; point < bezel_outline_end; ++point) {
1578 qhandheld_bezel_outline[point] =
1579 center + QPointF(handheld_bezel[point * 2], handheld_bezel[point * 2 + 1]);
1580 }
1581 for (std::size_t point = 0; point < bezel_inline_size; ++point) {
1582 qhandheld_bezel_inline[point] =
1583 center + QPointF(handheld_bezel[(point + bezel_inline_start) * 2],
1584 handheld_bezel[(point + bezel_inline_start) * 2 + 1]);
1585 }
1586 for (std::size_t point = 0; point < handheld_buttons.size() / 2; ++point) {
1587 qhandheld_buttons[point] =
1588 center + QPointF(handheld_buttons[point * 2], handheld_buttons[point * 2 + 1]);
1589 }
1590
1591 // Draw left joycon
1592 p.setPen(colors.outline);
1593 p.setBrush(colors.left);
1594 DrawPolygon(p, left_joycon);
1595
1596 // Draw right joycon
1597 p.setPen(colors.outline);
1598 p.setBrush(colors.right);
1599 DrawPolygon(p, right_joycon);
1600
1601 // Draw Handheld buttons
1602 p.setPen(colors.outline);
1603 p.setBrush(colors.button);
1604 DrawPolygon(p, qhandheld_buttons);
1605
1606 // Draw handheld body
1607 p.setPen(colors.transparent);
1608 p.setBrush(colors.primary);
1609 DrawPolygon(p, qhandheld_body);
1610 p.setPen(colors.outline);
1611 p.setBrush(colors.transparent);
1612 DrawPolygon(p, qhandheld_body_outline);
1613
1614 // Draw Handheld bezel
1615 p.setPen(colors.transparent);
1616 p.setBrush(colors.button);
1617 DrawPolygon(p, qhandheld_bezel);
1618 p.setPen(colors.outline);
1619 p.setBrush(colors.transparent);
1620 DrawPolygon(p, qhandheld_bezel_outline);
1621 DrawPolygon(p, qhandheld_bezel_inline);
1622}
1623
1624void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) {
1625 std::array<QPointF, left_joycon_body.size() / 2> left_joycon;
1626 std::array<QPointF, left_joycon_body.size() / 2> right_joycon;
1627 std::array<QPointF, left_joycon_slider.size() / 2> qleft_joycon_slider;
1628 std::array<QPointF, left_joycon_slider.size() / 2> qright_joycon_slider;
1629 std::array<QPointF, left_joycon_slider_topview.size() / 2> qleft_joycon_slider_topview;
1630 std::array<QPointF, left_joycon_slider_topview.size() / 2> qright_joycon_slider_topview;
1631 std::array<QPointF, left_joycon_topview.size() / 2> qleft_joycon_topview;
1632 std::array<QPointF, left_joycon_topview.size() / 2> qright_joycon_topview;
1633 constexpr float size = 1.61f;
1634 constexpr float size2 = 0.9f;
1635 constexpr float offset = 209.3f;
1636
1637 for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) {
1638 const float body_x = left_joycon_body[point * 2 + 0];
1639 const float body_y = left_joycon_body[point * 2 + 1];
1640
1641 left_joycon[point] = center + QPointF(body_x * size + offset, body_y * size - 1);
1642 right_joycon[point] = center + QPointF(-body_x * size - offset, body_y * size - 1);
1643 }
1644 for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) {
1645 const float slider_x = left_joycon_slider[point * 2 + 0];
1646 const float slider_y = left_joycon_slider[point * 2 + 1];
1647
1648 qleft_joycon_slider[point] = center + QPointF(slider_x, slider_y);
1649 qright_joycon_slider[point] = center + QPointF(-slider_x, slider_y);
1650 }
1651 for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) {
1652 const float top_view_x = left_joycon_topview[point * 2 + 0];
1653 const float top_view_y = left_joycon_topview[point * 2 + 1];
1654
1655 qleft_joycon_topview[point] =
1656 center + QPointF(top_view_x * size2 - 52, top_view_y * size2 - 52);
1657 qright_joycon_topview[point] =
1658 center + QPointF(-top_view_x * size2 + 52, top_view_y * size2 - 52);
1659 }
1660 for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) {
1661 const float top_view_x = left_joycon_slider_topview[point * 2 + 0];
1662 const float top_view_y = left_joycon_slider_topview[point * 2 + 1];
1663
1664 qleft_joycon_slider_topview[point] =
1665 center + QPointF(top_view_x * size2 - 52, top_view_y * size2 - 52);
1666 qright_joycon_slider_topview[point] =
1667 center + QPointF(-top_view_x * size2 + 52, top_view_y * size2 - 52);
1668 }
1669
1670 // right joycon body
1671 p.setPen(colors.outline);
1672 p.setBrush(colors.right);
1673 DrawPolygon(p, right_joycon);
1674
1675 // Left joycon body
1676 p.setPen(colors.outline);
1677 p.setBrush(colors.left);
1678 DrawPolygon(p, left_joycon);
1679
1680 // Slider release button top view
1681 p.setBrush(colors.button);
1682 DrawRoundRectangle(p, center + QPoint(-149, -108), 12, 11, 2);
1683 DrawRoundRectangle(p, center + QPoint(149, -108), 12, 11, 2);
1684
1685 // Joycon slider top view
1686 p.setBrush(colors.slider);
1687 DrawPolygon(p, qleft_joycon_slider_topview);
1688 p.drawLine(center + QPointF(-133.8f, -99.0f), center + QPointF(-133.8f, -78.5f));
1689 DrawPolygon(p, qright_joycon_slider_topview);
1690 p.drawLine(center + QPointF(133.8f, -99.0f), center + QPointF(133.8f, -78.5f));
1691
1692 // Joycon body top view
1693 p.setBrush(colors.left);
1694 DrawPolygon(p, qleft_joycon_topview);
1695 p.setBrush(colors.right);
1696 DrawPolygon(p, qright_joycon_topview);
1697
1698 // Right SR and SL sideview buttons
1699 p.setPen(colors.outline);
1700 p.setBrush(colors.slider_button);
1701 DrawRoundRectangle(p, center + QPoint(19, 47), 7, 22, 1);
1702 DrawRoundRectangle(p, center + QPoint(19, -62), 7, 22, 1);
1703
1704 // Left SR and SL sideview buttons
1705 DrawRoundRectangle(p, center + QPoint(-19, 47), 7, 22, 1);
1706 DrawRoundRectangle(p, center + QPoint(-19, -62), 7, 22, 1);
1707
1708 // Right Sideview body
1709 p.setBrush(colors.slider);
1710 DrawPolygon(p, qright_joycon_slider);
1711
1712 // Left Sideview body
1713 p.setBrush(colors.slider);
1714 DrawPolygon(p, qleft_joycon_slider);
1715}
1716
1717void PlayerControlPreview::DrawLeftBody(QPainter& p, const QPointF center) {
1718 std::array<QPointF, left_joycon_body.size() / 2> left_joycon;
1719 std::array<QPointF, left_joycon_sideview.size() / 2> qleft_joycon_sideview;
1720 std::array<QPointF, left_joycon_body_trigger.size() / 2> qleft_joycon_trigger;
1721 std::array<QPointF, left_joycon_slider.size() / 2> qleft_joycon_slider;
1722 std::array<QPointF, left_joycon_slider_topview.size() / 2> qleft_joycon_slider_topview;
1723 std::array<QPointF, left_joycon_topview.size() / 2> qleft_joycon_topview;
1724 constexpr float size = 1.78f;
1725 constexpr float size2 = 1.1115f;
1726 constexpr float offset = 312.39f;
1727 constexpr float offset2 = 335;
1728
1729 for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) {
1730 left_joycon[point] = center + QPointF(left_joycon_body[point * 2] * size + offset,
1731 left_joycon_body[point * 2 + 1] * size - 1);
1732 }
1733
1734 for (std::size_t point = 0; point < left_joycon_sideview.size() / 2; ++point) {
1735 qleft_joycon_sideview[point] =
1736 center + QPointF(left_joycon_sideview[point * 2] * size2 + offset2,
1737 left_joycon_sideview[point * 2 + 1] * size2 + 2);
1738 }
1739 for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) {
1740 qleft_joycon_slider[point] = center + QPointF(left_joycon_slider[point * 2] * size2 + 81,
1741 left_joycon_slider[point * 2 + 1] * size2);
1742 }
1743 for (std::size_t point = 0; point < left_joycon_body_trigger.size() / 2; ++point) {
1744 qleft_joycon_trigger[point] =
1745 center + QPointF(left_joycon_body_trigger[point * 2] * size2 + offset2,
1746 left_joycon_body_trigger[point * 2 + 1] * size2 + 2);
1747 }
1748 for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) {
1749 qleft_joycon_topview[point] =
1750 center + QPointF(left_joycon_topview[point * 2], left_joycon_topview[point * 2 + 1]);
1751 }
1752 for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) {
1753 qleft_joycon_slider_topview[point] =
1754 center + QPointF(left_joycon_slider_topview[point * 2],
1755 left_joycon_slider_topview[point * 2 + 1]);
1756 }
1757
1758 // Joycon body
1759 p.setPen(colors.outline);
1760 p.setBrush(colors.left);
1761 DrawPolygon(p, left_joycon);
1762 DrawPolygon(p, qleft_joycon_trigger);
1763
1764 // Slider release button top view
1765 p.setBrush(colors.button);
1766 DrawRoundRectangle(p, center + QPoint(-107, -62), 14, 12, 2);
1767
1768 // Joycon slider top view
1769 p.setBrush(colors.slider);
1770 DrawPolygon(p, qleft_joycon_slider_topview);
1771 p.drawLine(center + QPointF(-91.1f, -51.7f), center + QPointF(-91.1f, -26.5f));
1772
1773 // Joycon body top view
1774 p.setBrush(colors.left);
1775 DrawPolygon(p, qleft_joycon_topview);
1776
1777 // Slider release button
1778 p.setBrush(colors.button);
1779 DrawRoundRectangle(p, center + QPoint(175, -110), 12, 14, 2);
1780
1781 // Sideview body
1782 p.setBrush(colors.left);
1783 DrawPolygon(p, qleft_joycon_sideview);
1784 p.setBrush(colors.slider);
1785 DrawPolygon(p, qleft_joycon_slider);
1786
1787 const QPointF sideview_center = QPointF(155, 0) + center;
1788
1789 // Sideview slider body
1790 p.setBrush(colors.slider);
1791 DrawRoundRectangle(p, sideview_center + QPointF(0, -5), 28, 253, 3);
1792 p.setBrush(colors.button2);
1793 DrawRoundRectangle(p, sideview_center + QPointF(0, 97), 22.44f, 44.66f, 3);
1794
1795 // Slider decorations
1796 p.setPen(colors.outline);
1797 p.setBrush(colors.slider_arrow);
1798 DrawArrow(p, sideview_center + QPoint(0, 83), Direction::Down, 2.2f);
1799 DrawArrow(p, sideview_center + QPoint(0, 96), Direction::Down, 2.2f);
1800 DrawArrow(p, sideview_center + QPoint(0, 109), Direction::Down, 2.2f);
1801 DrawCircle(p, sideview_center + QPointF(0, 19), 4.44f);
1802
1803 // LED indicators
1804 const float led_size = 5.0f;
1805 const QPointF led_position = sideview_center + QPointF(0, -36);
1806 int led_count = 0;
1807 for (const auto color : led_color) {
1808 p.setBrush(color);
1809 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1810 }
1811}
1812
1813void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) {
1814 std::array<QPointF, left_joycon_body.size() / 2> right_joycon;
1815 std::array<QPointF, left_joycon_sideview.size() / 2> qright_joycon_sideview;
1816 std::array<QPointF, left_joycon_body_trigger.size() / 2> qright_joycon_trigger;
1817 std::array<QPointF, left_joycon_slider.size() / 2> qright_joycon_slider;
1818 std::array<QPointF, left_joycon_slider_topview.size() / 2> qright_joycon_slider_topview;
1819 std::array<QPointF, left_joycon_topview.size() / 2> qright_joycon_topview;
1820 constexpr float size = 1.78f;
1821 constexpr float size2 = 1.1115f;
1822 constexpr float offset = 312.39f;
1823 constexpr float offset2 = 335;
1824
1825 for (std::size_t point = 0; point < left_joycon_body.size() / 2; ++point) {
1826 right_joycon[point] = center + QPointF(-left_joycon_body[point * 2] * size - offset,
1827 left_joycon_body[point * 2 + 1] * size - 1);
1828 }
1829
1830 for (std::size_t point = 0; point < left_joycon_sideview.size() / 2; ++point) {
1831 qright_joycon_sideview[point] =
1832 center + QPointF(-left_joycon_sideview[point * 2] * size2 - offset2,
1833 left_joycon_sideview[point * 2 + 1] * size2 + 2);
1834 }
1835 for (std::size_t point = 0; point < left_joycon_body_trigger.size() / 2; ++point) {
1836 qright_joycon_trigger[point] =
1837 center + QPointF(-left_joycon_body_trigger[point * 2] * size2 - offset2,
1838 left_joycon_body_trigger[point * 2 + 1] * size2 + 2);
1839 }
1840 for (std::size_t point = 0; point < left_joycon_slider.size() / 2; ++point) {
1841 qright_joycon_slider[point] = center + QPointF(-left_joycon_slider[point * 2] * size2 - 81,
1842 left_joycon_slider[point * 2 + 1] * size2);
1843 }
1844 for (std::size_t point = 0; point < left_joycon_topview.size() / 2; ++point) {
1845 qright_joycon_topview[point] =
1846 center + QPointF(-left_joycon_topview[point * 2], left_joycon_topview[point * 2 + 1]);
1847 }
1848 for (std::size_t point = 0; point < left_joycon_slider_topview.size() / 2; ++point) {
1849 qright_joycon_slider_topview[point] =
1850 center + QPointF(-left_joycon_slider_topview[point * 2],
1851 left_joycon_slider_topview[point * 2 + 1]);
1852 }
1853
1854 // Joycon body
1855 p.setPen(colors.outline);
1856 p.setBrush(colors.left);
1857 DrawPolygon(p, right_joycon);
1858 DrawPolygon(p, qright_joycon_trigger);
1859
1860 // Slider release button top view
1861 p.setBrush(colors.button);
1862 DrawRoundRectangle(p, center + QPoint(107, -62), 14, 12, 2);
1863
1864 // Joycon slider top view
1865 p.setBrush(colors.slider);
1866 DrawPolygon(p, qright_joycon_slider_topview);
1867 p.drawLine(center + QPointF(91.1f, -51.7f), center + QPointF(91.1f, -26.5f));
1868
1869 // Joycon body top view
1870 p.setBrush(colors.left);
1871 DrawPolygon(p, qright_joycon_topview);
1872
1873 // Slider release button
1874 p.setBrush(colors.button);
1875 DrawRoundRectangle(p, center + QPoint(-175, -110), 12, 14, 2);
1876
1877 // Sideview body
1878 p.setBrush(colors.left);
1879 DrawPolygon(p, qright_joycon_sideview);
1880 p.setBrush(colors.slider);
1881 DrawPolygon(p, qright_joycon_slider);
1882
1883 const QPointF sideview_center = QPointF(-155, 0) + center;
1884
1885 // Sideview slider body
1886 p.setBrush(colors.slider);
1887 DrawRoundRectangle(p, sideview_center + QPointF(0, -5), 28, 253, 3);
1888 p.setBrush(colors.button2);
1889 DrawRoundRectangle(p, sideview_center + QPointF(0, 97), 22.44f, 44.66f, 3);
1890
1891 // Slider decorations
1892 p.setPen(colors.outline);
1893 p.setBrush(colors.slider_arrow);
1894 DrawArrow(p, sideview_center + QPoint(0, 83), Direction::Down, 2.2f);
1895 DrawArrow(p, sideview_center + QPoint(0, 96), Direction::Down, 2.2f);
1896 DrawArrow(p, sideview_center + QPoint(0, 109), Direction::Down, 2.2f);
1897 DrawCircle(p, sideview_center + QPointF(0, 19), 4.44f);
1898
1899 // LED indicators
1900 const float led_size = 5.0f;
1901 const QPointF led_position = sideview_center + QPointF(0, -36);
1902 int led_count = 0;
1903 for (const auto color : led_color) {
1904 p.setBrush(color);
1905 DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size);
1906 }
1907}
1908
1909void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bool left_pressed,
1910 bool right_pressed) {
1911 std::array<QPointF, pro_left_trigger.size() / 2> qleft_trigger;
1912 std::array<QPointF, pro_left_trigger.size() / 2> qright_trigger;
1913 std::array<QPointF, pro_body_top.size()> qbody_top;
1914
1915 for (std::size_t point = 0; point < pro_left_trigger.size() / 2; ++point) {
1916 const float trigger_x = pro_left_trigger[point * 2 + 0];
1917 const float trigger_y = pro_left_trigger[point * 2 + 1];
1918
1919 qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 2 : 0));
1920 qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 2 : 0));
1921 }
1922
1923 for (std::size_t point = 0; point < pro_body_top.size() / 2; ++point) {
1924 const float top_x = pro_body_top[point * 2 + 0];
1925 const float top_y = pro_body_top[point * 2 + 1];
1926
1927 qbody_top[pro_body_top.size() - 1 - point] = center + QPointF(-top_x, top_y);
1928 qbody_top[point] = center + QPointF(top_x, top_y);
1929 }
1930
1931 // Pro body detail
1932 p.setPen(colors.outline);
1933 p.setBrush(colors.primary);
1934 DrawPolygon(p, qbody_top);
1935
1936 // Left trigger
1937 p.setBrush(left_pressed ? colors.highlight : colors.button);
1938 DrawPolygon(p, qleft_trigger);
1939
1940 // Right trigger
1941 p.setBrush(right_pressed ? colors.highlight : colors.button);
1942 DrawPolygon(p, qright_trigger);
1943}
1944
1945void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, bool left_pressed,
1946 bool right_pressed) {
1947 std::array<QPointF, left_gc_trigger.size() / 2> qleft_trigger;
1948 std::array<QPointF, left_gc_trigger.size() / 2> qright_trigger;
1949
1950 for (std::size_t point = 0; point < left_gc_trigger.size() / 2; ++point) {
1951 const float trigger_x = left_gc_trigger[point * 2 + 0];
1952 const float trigger_y = left_gc_trigger[point * 2 + 1];
1953
1954 qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 10 : 0));
1955 qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 10 : 0));
1956 }
1957
1958 // Left trigger
1959 p.setPen(colors.outline);
1960 p.setBrush(left_pressed ? colors.highlight : colors.button);
1961 DrawPolygon(p, qleft_trigger);
1962
1963 // Right trigger
1964 p.setBrush(right_pressed ? colors.highlight : colors.button);
1965 DrawPolygon(p, qright_trigger);
1966
1967 // Draw L text
1968 p.setPen(colors.transparent);
1969 p.setBrush(colors.font);
1970 DrawSymbol(p, center + QPointF(-132, -119 + (left_pressed ? 10 : 0)), Symbol::L, 1.7f);
1971
1972 // Draw R text
1973 p.setPen(colors.transparent);
1974 p.setBrush(colors.font);
1975 DrawSymbol(p, center + QPointF(121.5f, -119 + (right_pressed ? 10 : 0)), Symbol::R, 1.7f);
1976}
1977
1978void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF center,
1979 bool left_pressed, bool right_pressed) {
1980 std::array<QPointF, left_joycon_trigger.size() / 2> qleft_trigger;
1981 std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger;
1982
1983 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
1984 const float left_trigger_x = left_joycon_trigger[point * 2 + 0];
1985 const float left_trigger_y = left_joycon_trigger[point * 2 + 1];
1986
1987 qleft_trigger[point] =
1988 center + QPointF(left_trigger_x, left_trigger_y + (left_pressed ? 0.5f : 0));
1989 qright_trigger[point] =
1990 center + QPointF(-left_trigger_x, left_trigger_y + (right_pressed ? 0.5f : 0));
1991 }
1992
1993 // Left trigger
1994 p.setPen(colors.outline);
1995 p.setBrush(left_pressed ? colors.highlight : colors.button);
1996 DrawPolygon(p, qleft_trigger);
1997
1998 // Right trigger
1999 p.setBrush(right_pressed ? colors.highlight : colors.button);
2000 DrawPolygon(p, qright_trigger);
2001}
2002
2003void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, bool left_pressed,
2004 bool right_pressed) {
2005 std::array<QPointF, left_joycon_trigger.size() / 2> qleft_trigger;
2006 std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger;
2007 constexpr float size = 1.62f;
2008 constexpr float offset = 210.6f;
2009 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
2010 const float left_trigger_x = left_joycon_trigger[point * 2 + 0];
2011 const float left_trigger_y = left_joycon_trigger[point * 2 + 1];
2012
2013 qleft_trigger[point] = center + QPointF(left_trigger_x * size + offset,
2014 left_trigger_y * size + (left_pressed ? 0.5f : 0));
2015 qright_trigger[point] =
2016 center + QPointF(-left_trigger_x * size - offset,
2017 left_trigger_y * size + (right_pressed ? 0.5f : 0));
2018 }
2019
2020 // Left trigger
2021 p.setPen(colors.outline);
2022 p.setBrush(left_pressed ? colors.highlight : colors.button);
2023 DrawPolygon(p, qleft_trigger);
2024
2025 // Right trigger
2026 p.setBrush(right_pressed ? colors.highlight : colors.button);
2027 DrawPolygon(p, qright_trigger);
2028}
2029
2030void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF center,
2031 bool left_pressed, bool right_pressed) {
2032 std::array<QPointF, left_joystick_L_topview.size() / 2> qleft_trigger;
2033 std::array<QPointF, left_joystick_L_topview.size() / 2> qright_trigger;
2034 constexpr float size = 0.9f;
2035
2036 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
2037 const float top_view_x = left_joystick_L_topview[point * 2 + 0];
2038 const float top_view_y = left_joystick_L_topview[point * 2 + 1];
2039
2040 qleft_trigger[point] = center + QPointF(top_view_x * size - 50, top_view_y * size - 52);
2041 }
2042 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
2043 const float top_view_x = left_joystick_L_topview[point * 2 + 0];
2044 const float top_view_y = left_joystick_L_topview[point * 2 + 1];
2045
2046 qright_trigger[point] = center + QPointF(-top_view_x * size + 50, top_view_y * size - 52);
2047 }
2048
2049 p.setPen(colors.outline);
2050 p.setBrush(left_pressed ? colors.highlight : colors.button);
2051 DrawPolygon(p, qleft_trigger);
2052 p.setBrush(right_pressed ? colors.highlight : colors.button);
2053 DrawPolygon(p, qright_trigger);
2054
2055 // Draw L text
2056 p.setPen(colors.transparent);
2057 p.setBrush(colors.font2);
2058 DrawSymbol(p, center + QPointF(-183, -84), Symbol::L, 1.0f);
2059
2060 // Draw R text
2061 p.setPen(colors.transparent);
2062 p.setBrush(colors.font2);
2063 DrawSymbol(p, center + QPointF(177, -84), Symbol::R, 1.0f);
2064}
2065
2066void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF center,
2067 bool left_pressed, bool right_pressed) {
2068 std::array<QPointF, left_joystick_ZL_topview.size() / 2> qleft_trigger;
2069 std::array<QPointF, left_joystick_ZL_topview.size() / 2> qright_trigger;
2070 constexpr float size = 0.9f;
2071
2072 for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) {
2073 qleft_trigger[point] =
2074 center + QPointF(left_joystick_ZL_topview[point * 2] * size - 52,
2075 left_joystick_ZL_topview[point * 2 + 1] * size - 52);
2076 }
2077 for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) {
2078 qright_trigger[point] =
2079 center + QPointF(-left_joystick_ZL_topview[point * 2] * size + 52,
2080 left_joystick_ZL_topview[point * 2 + 1] * size - 52);
2081 }
2082
2083 p.setPen(colors.outline);
2084 p.setBrush(left_pressed ? colors.highlight : colors.button);
2085 DrawPolygon(p, qleft_trigger);
2086 p.setBrush(right_pressed ? colors.highlight : colors.button);
2087 DrawPolygon(p, qright_trigger);
2088
2089 // Draw ZL text
2090 p.setPen(colors.transparent);
2091 p.setBrush(colors.font2);
2092 DrawSymbol(p, center + QPointF(-180, -113), Symbol::ZL, 1.0f);
2093
2094 // Draw ZR text
2095 p.setPen(colors.transparent);
2096 p.setBrush(colors.font2);
2097 DrawSymbol(p, center + QPointF(180, -113), Symbol::ZR, 1.0f);
2098}
2099
2100void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, bool left_pressed) {
2101 std::array<QPointF, left_joycon_trigger.size() / 2> qleft_trigger;
2102 constexpr float size = 1.78f;
2103 constexpr float offset = 311.5f;
2104
2105 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
2106 qleft_trigger[point] = center + QPointF(left_joycon_trigger[point * 2] * size + offset,
2107 left_joycon_trigger[point * 2 + 1] * size -
2108 (left_pressed ? 0.5f : 1.0f));
2109 }
2110
2111 p.setPen(colors.outline);
2112 p.setBrush(left_pressed ? colors.highlight : colors.button);
2113 DrawPolygon(p, qleft_trigger);
2114}
2115
2116void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, bool left_pressed) {
2117 std::array<QPointF, left_joycon_sideview_zl.size() / 2> qleft_trigger;
2118 constexpr float size = 1.1115f;
2119 constexpr float offset2 = 335;
2120
2121 for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) {
2122 qleft_trigger[point] = center + QPointF(left_joycon_sideview_zl[point * 2] * size + offset2,
2123 left_joycon_sideview_zl[point * 2 + 1] * size +
2124 (left_pressed ? 1.5f : 1.0f));
2125 }
2126
2127 p.setPen(colors.outline);
2128 p.setBrush(left_pressed ? colors.highlight : colors.button);
2129 DrawPolygon(p, qleft_trigger);
2130 p.drawArc(center.x() + 158, center.y() + (left_pressed ? -203.5f : -204.0f), 77, 77, 225 * 16,
2131 44 * 16);
2132}
2133
2134void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF center,
2135 bool left_pressed) {
2136 std::array<QPointF, left_joystick_L_topview.size() / 2> qleft_trigger;
2137
2138 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
2139 qleft_trigger[point] = center + QPointF(left_joystick_L_topview[point * 2],
2140 left_joystick_L_topview[point * 2 + 1]);
2141 }
2142
2143 p.setPen(colors.outline);
2144 p.setBrush(left_pressed ? colors.highlight : colors.button);
2145 DrawPolygon(p, qleft_trigger);
2146
2147 // Draw L text
2148 p.setPen(colors.transparent);
2149 p.setBrush(colors.font2);
2150 DrawSymbol(p, center + QPointF(-143, -36), Symbol::L, 1.0f);
2151}
2152
2153void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF center,
2154 bool left_pressed) {
2155 std::array<QPointF, left_joystick_ZL_topview.size() / 2> qleft_trigger;
2156
2157 for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) {
2158 qleft_trigger[point] = center + QPointF(left_joystick_ZL_topview[point * 2],
2159 left_joystick_ZL_topview[point * 2 + 1]);
2160 }
2161
2162 p.setPen(colors.outline);
2163 p.setBrush(left_pressed ? colors.highlight : colors.button);
2164 DrawPolygon(p, qleft_trigger);
2165
2166 // Draw ZL text
2167 p.setPen(colors.transparent);
2168 p.setBrush(colors.font2);
2169 DrawSymbol(p, center + QPointF(-140, -68), Symbol::ZL, 1.0f);
2170}
2171
2172void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center,
2173 bool right_pressed) {
2174 std::array<QPointF, left_joycon_trigger.size() / 2> qright_trigger;
2175 constexpr float size = 1.78f;
2176 constexpr float offset = 311.5f;
2177
2178 for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) {
2179 qright_trigger[point] = center + QPointF(-left_joycon_trigger[point * 2] * size - offset,
2180 left_joycon_trigger[point * 2 + 1] * size -
2181 (right_pressed ? 0.5f : 1.0f));
2182 }
2183
2184 p.setPen(colors.outline);
2185 p.setBrush(right_pressed ? colors.highlight : colors.button);
2186 DrawPolygon(p, qright_trigger);
2187}
2188
2189void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center,
2190 bool right_pressed) {
2191 std::array<QPointF, left_joycon_sideview_zl.size() / 2> qright_trigger;
2192 constexpr float size = 1.1115f;
2193 constexpr float offset2 = 335;
2194
2195 for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) {
2196 qright_trigger[point] =
2197 center +
2198 QPointF(-left_joycon_sideview_zl[point * 2] * size - offset2,
2199 left_joycon_sideview_zl[point * 2 + 1] * size + (right_pressed ? 0.5f : 0) + 1);
2200 }
2201
2202 p.setPen(colors.outline);
2203 p.setBrush(right_pressed ? colors.highlight : colors.button);
2204 DrawPolygon(p, qright_trigger);
2205 p.drawArc(center.x() - 236, center.y() + (right_pressed ? -203.5f : -204.0f), 77, 77, 271 * 16,
2206 44 * 16);
2207}
2208
2209void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF center,
2210 bool right_pressed) {
2211 std::array<QPointF, left_joystick_L_topview.size() / 2> qright_trigger;
2212
2213 for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) {
2214 qright_trigger[point] = center + QPointF(-left_joystick_L_topview[point * 2],
2215 left_joystick_L_topview[point * 2 + 1]);
2216 }
2217
2218 p.setPen(colors.outline);
2219 p.setBrush(right_pressed ? colors.highlight : colors.button);
2220 DrawPolygon(p, qright_trigger);
2221
2222 // Draw R text
2223 p.setPen(colors.transparent);
2224 p.setBrush(colors.font2);
2225 DrawSymbol(p, center + QPointF(137, -36), Symbol::R, 1.0f);
2226}
2227
2228void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF center,
2229 bool right_pressed) {
2230 std::array<QPointF, left_joystick_ZL_topview.size() / 2> qright_trigger;
2231
2232 for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) {
2233 qright_trigger[point] = center + QPointF(-left_joystick_ZL_topview[point * 2],
2234 left_joystick_ZL_topview[point * 2 + 1]);
2235 }
2236
2237 p.setPen(colors.outline);
2238 p.setBrush(right_pressed ? colors.highlight : colors.button);
2239 DrawPolygon(p, qright_trigger);
2240
2241 // Draw ZR text
2242 p.setPen(colors.transparent);
2243 p.setBrush(colors.font2);
2244 DrawSymbol(p, center + QPointF(140, -68), Symbol::ZR, 1.0f);
2245}
2246
2247void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float size,
2248 bool pressed) {
2249 const float radius1 = 13.0f * size;
2250 const float radius2 = 9.0f * size;
2251
2252 // Outer circle
2253 p.setPen(colors.outline);
2254 p.setBrush(pressed ? colors.highlight : colors.button);
2255 DrawCircle(p, center, radius1);
2256
2257 // Cross
2258 p.drawLine(center - QPoint(radius1, 0), center + QPoint(radius1, 0));
2259 p.drawLine(center - QPoint(0, radius1), center + QPoint(0, radius1));
2260
2261 // Inner circle
2262 p.setBrush(pressed ? colors.highlight2 : colors.button2);
2263 DrawCircle(p, center, radius2);
2264}
2265
2266void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF center, float angle,
2267 float size, bool pressed) {
2268 QVector<QPointF> joystick;
2269 joystick.reserve(static_cast<int>(left_joystick_sideview.size() / 2));
2270
2271 for (std::size_t point = 0; point < left_joystick_sideview.size() / 2; ++point) {
2272 joystick.append(QPointF(left_joystick_sideview[point * 2] * size + (pressed ? 1 : 0),
2273 left_joystick_sideview[point * 2 + 1] * size - 1));
2274 }
2275
2276 // Rotate joystick
2277 QTransform t;
2278 t.translate(center.x(), center.y());
2279 t.rotate(18 * angle);
2280 QPolygonF p2 = t.map(QPolygonF(joystick));
2281
2282 // Draw joystick
2283 p.setPen(colors.outline);
2284 p.setBrush(pressed ? colors.highlight : colors.button);
2285 p.drawPolygon(p2);
2286 p.drawLine(p2.at(1), p2.at(30));
2287 p.drawLine(p2.at(32), p2.at(71));
2288}
2289
2290void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, const QPointF offset,
2291 float offset_scalar, bool pressed) {
2292 const float radius1 = 24.0f;
2293 const float radius2 = 17.0f;
2294
2295 const QPointF offset_center = center + offset * offset_scalar;
2296
2297 const auto amplitude = static_cast<float>(
2298 1.0 - std::sqrt((offset.x() * offset.x()) + (offset.y() * offset.y())) * 0.1f);
2299
2300 const float rotation =
2301 ((offset.x() == 0) ? atan(1) * 2 : atan(offset.y() / offset.x())) * (180 / (atan(1) * 4));
2302
2303 p.save();
2304 p.translate(offset_center);
2305 p.rotate(rotation);
2306
2307 // Outer circle
2308 p.setPen(colors.outline);
2309 p.setBrush(pressed ? colors.highlight : colors.button);
2310 p.drawEllipse(QPointF(0, 0), radius1 * amplitude, radius1);
2311
2312 // Inner circle
2313 p.setBrush(pressed ? colors.highlight2 : colors.button2);
2314
2315 const float inner_offset =
2316 (radius1 - radius2) * 0.4f * ((offset.x() == 0 && offset.y() < 0) ? -1.0f : 1.0f);
2317 const float offset_factor = (1.0f - amplitude) / 0.1f;
2318
2319 p.drawEllipse(QPointF((offset.x() < 0) ? -inner_offset : inner_offset, 0) * offset_factor,
2320 radius2 * amplitude, radius2);
2321
2322 p.restore();
2323}
2324
2325void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, bool pressed) {
2326 // Outer circle
2327 p.setPen(colors.outline);
2328 p.setBrush(pressed ? colors.highlight : colors.button);
2329 DrawCircle(p, center, 26.0f);
2330
2331 // Inner circle
2332 p.setBrush(pressed ? colors.highlight2 : colors.button2);
2333 DrawCircle(p, center, 19.0f);
2334 p.setBrush(colors.transparent);
2335 DrawCircle(p, center, 13.5f);
2336 DrawCircle(p, center, 7.5f);
2337}
2338
2339void PlayerControlPreview::DrawRawJoystick(QPainter& p, const QPointF center, const QPointF value,
2340 const Input::AnalogProperties& properties) {
2341 constexpr float size = 45.0f;
2342 const float range = size * properties.range;
2343 const float deadzone = size * properties.deadzone;
2344
2345 // Max range zone circle
2346 p.setPen(colors.outline);
2347 p.setBrush(colors.transparent);
2348 QPen pen = p.pen();
2349 pen.setStyle(Qt::DotLine);
2350 p.setPen(pen);
2351 DrawCircle(p, center, range);
2352
2353 // Deadzone circle
2354 pen.setColor(colors.deadzone);
2355 p.setPen(pen);
2356 DrawCircle(p, center, deadzone);
2357
2358 // Dot pointer
2359 p.setPen(colors.indicator);
2360 p.setBrush(colors.indicator);
2361 DrawCircle(p, center + (value * range), 2);
2362}
2363
2364void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width,
2365 float height, Direction direction, float radius) {
2366 p.setBrush(button_color);
2367 if (pressed) {
2368 switch (direction) {
2369 case Direction::Left:
2370 center.setX(center.x() - 1);
2371 break;
2372 case Direction::Right:
2373 center.setX(center.x() + 1);
2374 break;
2375 case Direction::Down:
2376 center.setY(center.y() + 1);
2377 break;
2378 case Direction::Up:
2379 center.setY(center.y() - 1);
2380 break;
2381 case Direction::None:
2382 break;
2383 }
2384 p.setBrush(colors.highlight);
2385 }
2386 QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f};
2387 p.drawRoundedRect(rect, radius, radius);
2388}
2389void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, bool pressed,
2390 int button_size) {
2391 p.setPen(colors.outline);
2392 p.setBrush(pressed ? colors.highlight : colors.button);
2393 DrawRectangle(p, center, button_size, button_size / 3.0f);
2394}
2395void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, bool pressed,
2396 int button_size) {
2397 // Draw outer line
2398 p.setPen(colors.outline);
2399 p.setBrush(pressed ? colors.highlight : colors.button);
2400 DrawRectangle(p, center, button_size, button_size / 3.0f);
2401 DrawRectangle(p, center, button_size / 3.0f, button_size);
2402
2403 // Scale down size
2404 button_size *= 0.88f;
2405
2406 // Draw inner color
2407 p.setPen(colors.transparent);
2408 DrawRectangle(p, center, button_size, button_size / 3.0f);
2409 DrawRectangle(p, center, button_size / 3.0f, button_size);
2410}
2411
2412void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, bool pressed) {
2413 std::array<QPointF, gc_button_x.size() / 2> button_x;
2414
2415 for (std::size_t point = 0; point < gc_button_x.size() / 2; ++point) {
2416 button_x[point] = center + QPointF(gc_button_x[point * 2], gc_button_x[point * 2 + 1]);
2417 }
2418
2419 p.setPen(colors.outline);
2420 p.setBrush(pressed ? colors.highlight : colors.button);
2421 DrawPolygon(p, button_x);
2422}
2423
2424void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, bool pressed) {
2425 std::array<QPointF, gc_button_y.size() / 2> button_x;
2426
2427 for (std::size_t point = 0; point < gc_button_y.size() / 2; ++point) {
2428 button_x[point] = center + QPointF(gc_button_y[point * 2], gc_button_y[point * 2 + 1]);
2429 }
2430
2431 p.setPen(colors.outline);
2432 p.setBrush(pressed ? colors.highlight : colors.button);
2433 DrawPolygon(p, button_x);
2434}
2435
2436void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, bool pressed) {
2437 std::array<QPointF, gc_button_z.size() / 2> button_x;
2438
2439 for (std::size_t point = 0; point < gc_button_z.size() / 2; ++point) {
2440 button_x[point] = center + QPointF(gc_button_z[point * 2],
2441 gc_button_z[point * 2 + 1] + (pressed ? 1 : 0));
2442 }
2443
2444 p.setPen(colors.outline);
2445 p.setBrush(pressed ? colors.highlight : colors.button2);
2446 DrawPolygon(p, button_x);
2447}
2448
2449void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, bool pressed,
2450 float button_size) {
2451 p.setBrush(button_color);
2452 if (pressed) {
2453 p.setBrush(colors.highlight);
2454 }
2455 p.drawEllipse(center, button_size, button_size);
2456}
2457
2458void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF center, float size) {
2459 const std::size_t arrow_points = up_arrow_button.size() / 2;
2460 std::array<QPointF, (arrow_points - 1) * 4> arrow_button_outline;
2461
2462 for (std::size_t point = 0; point < arrow_points - 1; ++point) {
2463 const float up_arrow_x = up_arrow_button[point * 2 + 0];
2464 const float up_arrow_y = up_arrow_button[point * 2 + 1];
2465
2466 arrow_button_outline[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
2467 arrow_button_outline[(arrow_points - 1) * 2 - point - 1] =
2468 center + QPointF(up_arrow_y * size, up_arrow_x * size);
2469 arrow_button_outline[(arrow_points - 1) * 2 + point] =
2470 center + QPointF(-up_arrow_x * size, -up_arrow_y * size);
2471 arrow_button_outline[(arrow_points - 1) * 4 - point - 1] =
2472 center + QPointF(-up_arrow_y * size, -up_arrow_x * size);
2473 }
2474 // Draw arrow button outline
2475 p.setPen(colors.outline);
2476 p.setBrush(colors.transparent);
2477 DrawPolygon(p, arrow_button_outline);
2478}
2479
2480void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center,
2481 const Direction direction, bool pressed, float size) {
2482 std::array<QPointF, up_arrow_button.size() / 2> arrow_button;
2483 QPoint offset;
2484
2485 for (std::size_t point = 0; point < up_arrow_button.size() / 2; ++point) {
2486 const float up_arrow_x = up_arrow_button[point * 2 + 0];
2487 const float up_arrow_y = up_arrow_button[point * 2 + 1];
2488
2489 switch (direction) {
2490 case Direction::Up:
2491 arrow_button[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
2492 break;
2493 case Direction::Left:
2494 arrow_button[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size);
2495 break;
2496 case Direction::Right:
2497 arrow_button[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size);
2498 break;
2499 case Direction::Down:
2500 arrow_button[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size);
2501 break;
2502 case Direction::None:
2503 break;
2504 }
2505 }
2506
2507 // Draw arrow button
2508 p.setPen(pressed ? colors.highlight : colors.button);
2509 p.setBrush(pressed ? colors.highlight : colors.button);
2510 DrawPolygon(p, arrow_button);
2511
2512 switch (direction) {
2513 case Direction::Up:
2514 offset = QPoint(0, -20 * size);
2515 break;
2516 case Direction::Left:
2517 offset = QPoint(-20 * size, 0);
2518 break;
2519 case Direction::Right:
2520 offset = QPoint(20 * size, 0);
2521 break;
2522 case Direction::Down:
2523 offset = QPoint(0, 20 * size);
2524 break;
2525 case Direction::None:
2526 offset = QPoint(0, 0);
2527 break;
2528 }
2529
2530 // Draw arrow icon
2531 p.setPen(colors.font2);
2532 p.setBrush(colors.font2);
2533 DrawArrow(p, center + offset, direction, size);
2534}
2535
2536void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center,
2537 const Direction direction, bool pressed) {
2538 std::array<QPointF, trigger_button.size() / 2> qtrigger_button;
2539
2540 for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) {
2541 const float trigger_button_x = trigger_button[point * 2 + 0];
2542 const float trigger_button_y = trigger_button[point * 2 + 1];
2543
2544 switch (direction) {
2545 case Direction::Left:
2546 qtrigger_button[point] = center + QPointF(-trigger_button_x, trigger_button_y);
2547 break;
2548 case Direction::Right:
2549 qtrigger_button[point] = center + QPointF(trigger_button_x, trigger_button_y);
2550 break;
2551 case Direction::Up:
2552 case Direction::Down:
2553 case Direction::None:
2554 break;
2555 }
2556 }
2557
2558 // Draw arrow button
2559 p.setPen(colors.outline);
2560 p.setBrush(pressed ? colors.highlight : colors.button);
2561 DrawPolygon(p, qtrigger_button);
2562}
2563
2564void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol symbol,
2565 float icon_size) {
2566 std::array<QPointF, house.size() / 2> house_icon;
2567 std::array<QPointF, symbol_a.size() / 2> a_icon;
2568 std::array<QPointF, symbol_b.size() / 2> b_icon;
2569 std::array<QPointF, symbol_x.size() / 2> x_icon;
2570 std::array<QPointF, symbol_y.size() / 2> y_icon;
2571 std::array<QPointF, symbol_l.size() / 2> l_icon;
2572 std::array<QPointF, symbol_r.size() / 2> r_icon;
2573 std::array<QPointF, symbol_c.size() / 2> c_icon;
2574 std::array<QPointF, symbol_zl.size() / 2> zl_icon;
2575 std::array<QPointF, symbol_sl.size() / 2> sl_icon;
2576 std::array<QPointF, symbol_zr.size() / 2> zr_icon;
2577 std::array<QPointF, symbol_sr.size() / 2> sr_icon;
2578 switch (symbol) {
2579 case Symbol::House:
2580 for (std::size_t point = 0; point < house.size() / 2; ++point) {
2581 house_icon[point] = center + QPointF(house[point * 2] * icon_size,
2582 (house[point * 2 + 1] - 0.025f) * icon_size);
2583 }
2584 p.drawPolygon(house_icon.data(), static_cast<int>(house_icon.size()));
2585 break;
2586 case Symbol::A:
2587 for (std::size_t point = 0; point < symbol_a.size() / 2; ++point) {
2588 a_icon[point] = center + QPointF(symbol_a[point * 2] * icon_size,
2589 symbol_a[point * 2 + 1] * icon_size);
2590 }
2591 p.drawPolygon(a_icon.data(), static_cast<int>(a_icon.size()));
2592 break;
2593 case Symbol::B:
2594 for (std::size_t point = 0; point < symbol_b.size() / 2; ++point) {
2595 b_icon[point] = center + QPointF(symbol_b[point * 2] * icon_size,
2596 symbol_b[point * 2 + 1] * icon_size);
2597 }
2598 p.drawPolygon(b_icon.data(), static_cast<int>(b_icon.size()));
2599 break;
2600 case Symbol::X:
2601 for (std::size_t point = 0; point < symbol_x.size() / 2; ++point) {
2602 x_icon[point] = center + QPointF(symbol_x[point * 2] * icon_size,
2603 symbol_x[point * 2 + 1] * icon_size);
2604 }
2605 p.drawPolygon(x_icon.data(), static_cast<int>(x_icon.size()));
2606 break;
2607 case Symbol::Y:
2608 for (std::size_t point = 0; point < symbol_y.size() / 2; ++point) {
2609 y_icon[point] = center + QPointF(symbol_y[point * 2] * icon_size,
2610 (symbol_y[point * 2 + 1] - 1.0f) * icon_size);
2611 }
2612 p.drawPolygon(y_icon.data(), static_cast<int>(y_icon.size()));
2613 break;
2614 case Symbol::L:
2615 for (std::size_t point = 0; point < symbol_l.size() / 2; ++point) {
2616 l_icon[point] = center + QPointF(symbol_l[point * 2] * icon_size,
2617 (symbol_l[point * 2 + 1] - 1.0f) * icon_size);
2618 }
2619 p.drawPolygon(l_icon.data(), static_cast<int>(l_icon.size()));
2620 break;
2621 case Symbol::R:
2622 for (std::size_t point = 0; point < symbol_r.size() / 2; ++point) {
2623 r_icon[point] = center + QPointF(symbol_r[point * 2] * icon_size,
2624 (symbol_r[point * 2 + 1] - 1.0f) * icon_size);
2625 }
2626 p.drawPolygon(r_icon.data(), static_cast<int>(r_icon.size()));
2627 break;
2628 case Symbol::C:
2629 for (std::size_t point = 0; point < symbol_c.size() / 2; ++point) {
2630 c_icon[point] = center + QPointF(symbol_c[point * 2] * icon_size,
2631 (symbol_c[point * 2 + 1] - 1.0f) * icon_size);
2632 }
2633 p.drawPolygon(c_icon.data(), static_cast<int>(c_icon.size()));
2634 break;
2635 case Symbol::ZL:
2636 for (std::size_t point = 0; point < symbol_zl.size() / 2; ++point) {
2637 zl_icon[point] = center + QPointF(symbol_zl[point * 2] * icon_size,
2638 symbol_zl[point * 2 + 1] * icon_size);
2639 }
2640 p.drawPolygon(zl_icon.data(), static_cast<int>(zl_icon.size()));
2641 break;
2642 case Symbol::SL:
2643 for (std::size_t point = 0; point < symbol_sl.size() / 2; ++point) {
2644 sl_icon[point] = center + QPointF(symbol_sl[point * 2] * icon_size,
2645 symbol_sl[point * 2 + 1] * icon_size);
2646 }
2647 p.drawPolygon(sl_icon.data(), static_cast<int>(sl_icon.size()));
2648 break;
2649 case Symbol::ZR:
2650 for (std::size_t point = 0; point < symbol_zr.size() / 2; ++point) {
2651 zr_icon[point] = center + QPointF(symbol_zr[point * 2] * icon_size,
2652 symbol_zr[point * 2 + 1] * icon_size);
2653 }
2654 p.drawPolygon(zr_icon.data(), static_cast<int>(zr_icon.size()));
2655 break;
2656 case Symbol::SR:
2657 for (std::size_t point = 0; point < symbol_sr.size() / 2; ++point) {
2658 sr_icon[point] = center + QPointF(symbol_sr[point * 2] * icon_size,
2659 symbol_sr[point * 2 + 1] * icon_size);
2660 }
2661 p.drawPolygon(sr_icon.data(), static_cast<int>(sr_icon.size()));
2662 break;
2663 }
2664}
2665
2666void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Direction direction,
2667 float size) {
2668
2669 std::array<QPointF, up_arrow_symbol.size() / 2> arrow_symbol;
2670
2671 for (std::size_t point = 0; point < up_arrow_symbol.size() / 2; ++point) {
2672 const float up_arrow_x = up_arrow_symbol[point * 2 + 0];
2673 const float up_arrow_y = up_arrow_symbol[point * 2 + 1];
2674
2675 switch (direction) {
2676 case Direction::Up:
2677 arrow_symbol[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size);
2678 break;
2679 case Direction::Left:
2680 arrow_symbol[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size);
2681 break;
2682 case Direction::Right:
2683 arrow_symbol[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size);
2684 break;
2685 case Direction::Down:
2686 arrow_symbol[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size);
2687 break;
2688 case Direction::None:
2689 break;
2690 }
2691 }
2692
2693 DrawPolygon(p, arrow_symbol);
2694}
2695
2696template <size_t N>
2697void PlayerControlPreview::DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon) {
2698 p.drawPolygon(polygon.data(), static_cast<int>(polygon.size()));
2699}
2700
2701void PlayerControlPreview::DrawCircle(QPainter& p, const QPointF center, float size) {
2702 p.drawEllipse(center, size, size);
2703}
2704
2705void PlayerControlPreview::DrawRectangle(QPainter& p, const QPointF center, float width,
2706 float height) {
2707 const QRectF rect = QRectF(center.x() - (width / 2), center.y() - (height / 2), width, height);
2708 p.drawRect(rect);
2709}
2710void PlayerControlPreview::DrawRoundRectangle(QPainter& p, const QPointF center, float width,
2711 float height, float round) {
2712 const QRectF rect = QRectF(center.x() - (width / 2), center.y() - (height / 2), width, height);
2713 p.drawRoundedRect(rect, round, round);
2714}
2715
2716void PlayerControlPreview::DrawText(QPainter& p, const QPointF center, float text_size,
2717 const QString& text) {
2718 SetTextFont(p, text_size);
2719 const QFontMetrics fm(p.font());
2720 const QPointF offset = {fm.horizontalAdvance(text) / 2.0f, -text_size / 2.0f};
2721 p.drawText(center - offset, text);
2722}
2723
2724void PlayerControlPreview::SetTextFont(QPainter& p, float text_size, const QString& font_family) {
2725 QFont font = p.font();
2726 font.setPointSizeF(text_size);
2727 font.setFamily(font_family);
2728 p.setFont(font);
2729}
diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h
new file mode 100644
index 000000000..91c3343f1
--- /dev/null
+++ b/src/yuzu/configuration/configure_input_player_widget.h
@@ -0,0 +1,192 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <QFrame>
9#include <QPointer>
10#include "core/frontend/input.h"
11#include "core/settings.h"
12
13class QLabel;
14
15using AnalogParam = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
16using ButtonParam = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
17
18// Widget for representing controller animations
19class PlayerControlPreview : public QFrame {
20 Q_OBJECT
21
22public:
23 explicit PlayerControlPreview(QWidget* parent);
24 ~PlayerControlPreview() override;
25
26 void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param,
27 const AnalogParam& analogs_param);
28 void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw& buttons_,
29 Settings::AnalogsRaw analogs_);
30 void SetConnectedStatus(bool checked);
31 void SetControllerType(Settings::ControllerType type);
32 void BeginMappingButton(std::size_t button_id);
33 void BeginMappingAnalog(std::size_t button_id);
34 void EndMapping();
35 void UpdateInput();
36
37protected:
38 void paintEvent(QPaintEvent* event) override;
39
40private:
41 enum class Direction : std::size_t {
42 None,
43 Up,
44 Right,
45 Down,
46 Left,
47 };
48
49 enum class Symbol {
50 House,
51 A,
52 B,
53 X,
54 Y,
55 L,
56 R,
57 C,
58 SL,
59 ZL,
60 ZR,
61 SR,
62 };
63
64 struct AxisValue {
65 QPointF value{};
66 QPointF raw_value{};
67 Input::AnalogProperties properties{};
68 int size{};
69 QPoint offset{};
70 bool active{};
71 };
72
73 struct LedPattern {
74 bool position1;
75 bool position2;
76 bool position3;
77 bool position4;
78 };
79
80 struct ColorMapping {
81 QColor outline{};
82 QColor primary{};
83 QColor left{};
84 QColor right{};
85 QColor button{};
86 QColor button2{};
87 QColor font{};
88 QColor font2{};
89 QColor highlight{};
90 QColor highlight2{};
91 QColor transparent{};
92 QColor indicator{};
93 QColor led_on{};
94 QColor led_off{};
95 QColor slider{};
96 QColor slider_button{};
97 QColor slider_arrow{};
98 QColor deadzone{};
99 };
100
101 static LedPattern GetColorPattern(std::size_t index, bool player_on);
102 void UpdateColors();
103
104 // Draw controller functions
105 void DrawHandheldController(QPainter& p, QPointF center);
106 void DrawDualController(QPainter& p, QPointF center);
107 void DrawLeftController(QPainter& p, QPointF center);
108 void DrawRightController(QPainter& p, QPointF center);
109 void DrawProController(QPainter& p, QPointF center);
110 void DrawGCController(QPainter& p, QPointF center);
111
112 // Draw body functions
113 void DrawHandheldBody(QPainter& p, QPointF center);
114 void DrawDualBody(QPainter& p, QPointF center);
115 void DrawLeftBody(QPainter& p, QPointF center);
116 void DrawRightBody(QPainter& p, QPointF center);
117 void DrawProBody(QPainter& p, QPointF center);
118 void DrawGCBody(QPainter& p, QPointF center);
119
120 // Draw triggers functions
121 void DrawProTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
122 void DrawGCTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
123 void DrawHandheldTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
124 void DrawDualTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
125 void DrawDualTriggersTopView(QPainter& p, QPointF center, bool left_pressed,
126 bool right_pressed);
127 void DrawDualZTriggersTopView(QPainter& p, QPointF center, bool left_pressed,
128 bool right_pressed);
129 void DrawLeftTriggers(QPainter& p, QPointF center, bool left_pressed);
130 void DrawLeftZTriggers(QPainter& p, QPointF center, bool left_pressed);
131 void DrawLeftTriggersTopView(QPainter& p, QPointF center, bool left_pressed);
132 void DrawLeftZTriggersTopView(QPainter& p, QPointF center, bool left_pressed);
133 void DrawRightTriggers(QPainter& p, QPointF center, bool right_pressed);
134 void DrawRightZTriggers(QPainter& p, QPointF center, bool right_pressed);
135 void DrawRightTriggersTopView(QPainter& p, QPointF center, bool right_pressed);
136 void DrawRightZTriggersTopView(QPainter& p, QPointF center, bool right_pressed);
137
138 // Draw joystick functions
139 void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed);
140 void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed);
141 void DrawRawJoystick(QPainter& p, QPointF center, QPointF value,
142 const Input::AnalogProperties& properties);
143 void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed);
144 void DrawGCJoystick(QPainter& p, QPointF center, bool pressed);
145
146 // Draw button functions
147 void DrawCircleButton(QPainter& p, QPointF center, bool pressed, float button_size);
148 void DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height,
149 Direction direction = Direction::None, float radius = 2);
150 void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size);
151 void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size);
152 void DrawGCButtonX(QPainter& p, QPointF center, bool pressed);
153 void DrawGCButtonY(QPainter& p, QPointF center, bool pressed);
154 void DrawGCButtonZ(QPainter& p, QPointF center, bool pressed);
155 void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f);
156 void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed,
157 float size = 1.0f);
158 void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed);
159
160 // Draw icon functions
161 void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
162 void DrawArrow(QPainter& p, QPointF center, Direction direction, float size);
163
164 // Draw primitive types
165 template <size_t N>
166 void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon);
167 void DrawCircle(QPainter& p, QPointF center, float size);
168 void DrawRectangle(QPainter& p, QPointF center, float width, float height);
169 void DrawRoundRectangle(QPainter& p, QPointF center, float width, float height, float round);
170 void DrawText(QPainter& p, QPointF center, float text_size, const QString& text);
171 void SetTextFont(QPainter& p, float text_size,
172 const QString& font_family = QStringLiteral("sans-serif"));
173
174 using ButtonArray =
175 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::BUTTON_NS_END>;
176 using StickArray =
177 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>;
178
179 bool mapping_active{};
180 int blink_counter{};
181 QColor button_color{};
182 ColorMapping colors{};
183 std::array<QColor, 4> led_color{};
184 ButtonArray buttons{};
185 StickArray sticks{};
186 std::size_t player_index{};
187 std::size_t button_mapping_index{Settings::NativeButton::BUTTON_NS_END};
188 std::size_t analog_mapping_index{Settings::NativeAnalog::NUM_STICKS_HID};
189 std::array<AxisValue, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{};
190 std::array<bool, Settings::NativeButton::NumButtons> button_values{};
191 Settings::ControllerType controller_type{Settings::ControllerType::ProController};
192};
diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp
new file mode 100644
index 000000000..85724a8f3
--- /dev/null
+++ b/src/yuzu/debugger/controller.cpp
@@ -0,0 +1,66 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QAction>
6#include <QLayout>
7#include <QString>
8#include "core/settings.h"
9#include "yuzu/configuration/configure_input_player_widget.h"
10#include "yuzu/debugger/controller.h"
11
12ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) {
13 setObjectName(QStringLiteral("Controller"));
14 setWindowTitle(tr("Controller P1"));
15 resize(500, 350);
16 setMinimumSize(500, 350);
17 // Remove the "?" button from the titlebar and enable the maximize button
18 setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) |
19 Qt::WindowMaximizeButtonHint);
20
21 widget = new PlayerControlPreview(this);
22 refreshConfiguration();
23 QLayout* layout = new QVBoxLayout(this);
24 layout->setContentsMargins(0, 0, 0, 0);
25 layout->addWidget(widget);
26 setLayout(layout);
27
28 // Configure focus so that widget is focusable and the dialog automatically forwards focus to
29 // it.
30 setFocusProxy(widget);
31 widget->setFocusPolicy(Qt::StrongFocus);
32 widget->setFocus();
33}
34
35void ControllerDialog::refreshConfiguration() {
36 const auto& players = Settings::values.players.GetValue();
37 constexpr std::size_t player = 0;
38 widget->SetPlayerInputRaw(player, players[player].buttons, players[player].analogs);
39 widget->SetConnectedStatus(players[player].connected);
40 widget->SetControllerType(players[player].controller_type);
41}
42
43QAction* ControllerDialog::toggleViewAction() {
44 if (toggle_view_action == nullptr) {
45 toggle_view_action = new QAction(windowTitle(), this);
46 toggle_view_action->setCheckable(true);
47 toggle_view_action->setChecked(isVisible());
48 connect(toggle_view_action, &QAction::toggled, this, &ControllerDialog::setVisible);
49 }
50
51 return toggle_view_action;
52}
53
54void ControllerDialog::showEvent(QShowEvent* ev) {
55 if (toggle_view_action) {
56 toggle_view_action->setChecked(isVisible());
57 }
58 QWidget::showEvent(ev);
59}
60
61void ControllerDialog::hideEvent(QHideEvent* ev) {
62 if (toggle_view_action) {
63 toggle_view_action->setChecked(isVisible());
64 }
65 QWidget::hideEvent(ev);
66}
diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h
new file mode 100644
index 000000000..c54750070
--- /dev/null
+++ b/src/yuzu/debugger/controller.h
@@ -0,0 +1,31 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QWidget>
8
9class QAction;
10class QHideEvent;
11class QShowEvent;
12class PlayerControlPreview;
13
14class ControllerDialog : public QWidget {
15 Q_OBJECT
16
17public:
18 explicit ControllerDialog(QWidget* parent = nullptr);
19
20 /// Returns a QAction that can be used to toggle visibility of this dialog.
21 QAction* toggleViewAction();
22 void refreshConfiguration();
23
24protected:
25 void showEvent(QShowEvent* ev) override;
26 void hideEvent(QHideEvent* ev) override;
27
28private:
29 QAction* toggle_view_action = nullptr;
30 PlayerControlPreview* widget;
31};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 1991d0da6..52218eb70 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -109,6 +109,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
109#include "yuzu/configuration/config.h" 109#include "yuzu/configuration/config.h"
110#include "yuzu/configuration/configure_dialog.h" 110#include "yuzu/configuration/configure_dialog.h"
111#include "yuzu/debugger/console.h" 111#include "yuzu/debugger/console.h"
112#include "yuzu/debugger/controller.h"
112#include "yuzu/debugger/profiler.h" 113#include "yuzu/debugger/profiler.h"
113#include "yuzu/debugger/wait_tree.h" 114#include "yuzu/debugger/wait_tree.h"
114#include "yuzu/discord.h" 115#include "yuzu/discord.h"
@@ -688,6 +689,11 @@ void GMainWindow::InitializeDebugWidgets() {
688 addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget); 689 addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
689 waitTreeWidget->hide(); 690 waitTreeWidget->hide();
690 debug_menu->addAction(waitTreeWidget->toggleViewAction()); 691 debug_menu->addAction(waitTreeWidget->toggleViewAction());
692
693 controller_dialog = new ControllerDialog(this);
694 controller_dialog->hide();
695 debug_menu->addAction(controller_dialog->toggleViewAction());
696
691 connect(this, &GMainWindow::EmulationStarting, waitTreeWidget, 697 connect(this, &GMainWindow::EmulationStarting, waitTreeWidget,
692 &WaitTreeWidget::OnEmulationStarting); 698 &WaitTreeWidget::OnEmulationStarting);
693 connect(this, &GMainWindow::EmulationStopping, waitTreeWidget, 699 connect(this, &GMainWindow::EmulationStopping, waitTreeWidget,
@@ -2346,6 +2352,7 @@ void GMainWindow::OnConfigure() {
2346 } 2352 }
2347 2353
2348 configure_dialog.ApplyConfiguration(); 2354 configure_dialog.ApplyConfiguration();
2355 controller_dialog->refreshConfiguration();
2349 InitializeHotkeys(); 2356 InitializeHotkeys();
2350 if (UISettings::values.theme != old_theme) { 2357 if (UISettings::values.theme != old_theme) {
2351 UpdateUITheme(); 2358 UpdateUITheme();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 31788ea62..04d37d4ae 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -27,6 +27,7 @@ class GRenderWindow;
27class LoadingScreen; 27class LoadingScreen;
28class MicroProfileDialog; 28class MicroProfileDialog;
29class ProfilerWidget; 29class ProfilerWidget;
30class ControllerDialog;
30class QLabel; 31class QLabel;
31class QPushButton; 32class QPushButton;
32class QProgressDialog; 33class QProgressDialog;
@@ -313,6 +314,7 @@ private:
313 ProfilerWidget* profilerWidget; 314 ProfilerWidget* profilerWidget;
314 MicroProfileDialog* microProfileDialog; 315 MicroProfileDialog* microProfileDialog;
315 WaitTreeWidget* waitTreeWidget; 316 WaitTreeWidget* waitTreeWidget;
317 ControllerDialog* controller_dialog;
316 318
317 QAction* actions_recent_files[max_recent_files_item]; 319 QAction* actions_recent_files[max_recent_files_item];
318 320
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
index a103b04bd..deddea9ee 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp
@@ -59,29 +59,17 @@ private:
59bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { 59bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
60 std::vector<std::string_view> unsupported_ext; 60 std::vector<std::string_view> unsupported_ext;
61 61
62 if (!GLAD_GL_ARB_buffer_storage)
63 unsupported_ext.push_back("ARB_buffer_storage");
64 if (!GLAD_GL_ARB_direct_state_access)
65 unsupported_ext.push_back("ARB_direct_state_access");
66 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
67 unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev");
68 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
69 unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge");
70 if (!GLAD_GL_ARB_multi_bind)
71 unsupported_ext.push_back("ARB_multi_bind");
72 if (!GLAD_GL_ARB_clip_control)
73 unsupported_ext.push_back("ARB_clip_control");
74
75 // Extensions required to support some texture formats. 62 // Extensions required to support some texture formats.
76 if (!GLAD_GL_EXT_texture_compression_s3tc) 63 if (!GLAD_GL_EXT_texture_compression_s3tc) {
77 unsupported_ext.push_back("EXT_texture_compression_s3tc"); 64 unsupported_ext.push_back("EXT_texture_compression_s3tc");
78 if (!GLAD_GL_ARB_texture_compression_rgtc) 65 }
66 if (!GLAD_GL_ARB_texture_compression_rgtc) {
79 unsupported_ext.push_back("ARB_texture_compression_rgtc"); 67 unsupported_ext.push_back("ARB_texture_compression_rgtc");
80 if (!GLAD_GL_ARB_depth_buffer_float) 68 }
81 unsupported_ext.push_back("ARB_depth_buffer_float");
82 69
83 for (const auto& extension : unsupported_ext) 70 for (const auto& extension : unsupported_ext) {
84 LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension); 71 LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", extension);
72 }
85 73
86 return unsupported_ext.empty(); 74 return unsupported_ext.empty();
87} 75}
@@ -89,7 +77,7 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() {
89EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) 77EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen)
90 : EmuWindow_SDL2{input_subsystem} { 78 : EmuWindow_SDL2{input_subsystem} {
91 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 79 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
92 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 80 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);
93 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); 81 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
94 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 82 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
95 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 83 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);