mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-13 18:54:27 +02:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa85ef3f92 | |||
| 12136217c4 | |||
| 0e5445d2a7 | |||
| e83a343bab | |||
| d5aeb9e20a | |||
| d9128872fd | |||
| 6e129a69d2 | |||
| 6e2d17073a | |||
| f622726bb1 | |||
| a39a0fd268 | |||
| f14e061438 | |||
| 0356b8a73e | |||
| 1d9b7c0387 | |||
| 2164078b2d | |||
| aeb1d500df | |||
| e44a388455 | |||
| 74044cdbce | |||
| 3f6ec596f0 | |||
| 1831d11671 | |||
| 362e89d668 | |||
| 936836e096 | |||
| 0e9de44c72 | |||
| d3841591a5 | |||
| 7f13863bb8 | |||
| dab29f8443 | |||
| 73d11a88da | |||
| 21320c750b | |||
| 35ce3c483f | |||
| fdd360f919 | |||
| fcb1d4ff4e | |||
| 815a59b6ed | |||
| 2097ff232c | |||
| 53d98a53e8 | |||
| f81a95f3a9 | |||
| 74e190511b | |||
| a86f441ac8 | |||
| 2557c2e887 | |||
| 6accade0d5 | |||
| 9437e1ac41 | |||
| b2b87f9e87 | |||
| f2ab17ff94 | |||
| a1514e2c6c | |||
| 329c6d42be | |||
| 800da09b1d | |||
| fb8c1b901d | |||
| df817924e0 | |||
| c227686d46 | |||
| 683ced4fe2 | |||
| ad6a8a5cf3 | |||
| 20e3896714 | |||
| 084df36598 | |||
| 28abbc6bf5 | |||
| 3a125a2d7a | |||
| 8415a4b0d6 | |||
| 209e676e3a | |||
| a64431c7b5 | |||
| 665eb3d6b3 |
@@ -17,7 +17,7 @@ jobs:
|
||||
run: ./.github/workflows/scripts/common/update_base_translation.sh
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
|
||||
with:
|
||||
title: "Qt: Update Base Translation"
|
||||
commit-message: "[ci skip] Qt: Update Base Translation."
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725
|
||||
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0
|
||||
with:
|
||||
title: "PAD: Update to latest controller database"
|
||||
commit-message: "[ci skip] PAD: Update to latest controller database."
|
||||
|
||||
@@ -18,6 +18,9 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||
INSTALLDIR="$PWD/$INSTALLDIR"
|
||||
fi
|
||||
|
||||
QT=6.10.2
|
||||
QTAPNG=1.3.0
|
||||
|
||||
FFMPEG=8.0
|
||||
FREETYPE=2.14.1
|
||||
HARFBUZZ=12.2.0
|
||||
@@ -27,8 +30,6 @@ LIBPNG=1.6.53
|
||||
LIBWEBP=1.6.0
|
||||
NVENC=13.0.19.0
|
||||
SDL=SDL3-3.4.0
|
||||
QT=6.10.1
|
||||
QTAPNG=1.3.0
|
||||
LZ4=1.10.0
|
||||
VULKAN=1.4.328.1
|
||||
ZSTD=1.5.7
|
||||
@@ -47,6 +48,14 @@ cd deps-build
|
||||
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
|
||||
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
|
||||
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
|
||||
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
|
||||
391998eb432719df26a6a67d8efdc67f8bf2afdd76c1ee3381ebff4fe7527ee2 qtwayland-everywhere-src-$QT.tar.xz
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
|
||||
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
|
||||
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
|
||||
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
|
||||
@@ -60,20 +69,14 @@ e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWE
|
||||
13da39edb3a40ed9713ae390ca89faa2f1202c9dda869ef306a8d4383e242bee nv-codec-headers-$NVENC.tar.gz
|
||||
c465aa56757e7746ac707f582b6e2d51546569a4a2488c1172fb543aa5fdfc2c vulkan-sdk-$VULKAN.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
5a6226f7e23db51fdc3223121eba53f3f5447cf0cc4d6cb82a3a2df7a65d265d qtbase-everywhere-src-$QT.tar.xz
|
||||
498eabdf2381db96f808942b3e3c765f6360fe6c0e9961f0a45ff7a4c68d7a72 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
c02f355a58f3bbcf404a628bf488b6aeb2d84a94c269afdb86f6e529343ab01f qtsvg-everywhere-src-$QT.tar.xz
|
||||
8148408380ffea03101a26305c812b612ea30dbc07121e58707601522404d49b qttools-everywhere-src-$QT.tar.xz
|
||||
8e49a2df88a12c376a479ae7bd272a91cf57ebb4e7c0cf7341b3565df99d2314 qttranslations-everywhere-src-$QT.tar.xz
|
||||
49bf6db800227a6b2c971f4c5d03dd1e81297e7ffb296ce4a96437304f27cb13 qtwayland-everywhere-src-$QT.tar.xz
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
|
||||
8a89fb6612ace8954470aae004623374a8fc8b7a34a4277bee5527173b064faf shaderc-$SHADERC.tar.gz
|
||||
272d2725b140e09e85b96eecdc59c2e00c1a14cda2301767e1bf3c363a44b931 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
@@ -213,7 +216,7 @@ tar xf "harfbuzz-$HARFBUZZ.tar.gz"
|
||||
cd "harfbuzz-$HARFBUZZ"
|
||||
# Add an SOVERSION to match system harfbuzz
|
||||
sed -i 's/PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)/PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE SOVERSION 0)/g' CMakeLists.txt
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -DHB_HAVE_FREETYPE=ON -DHB_HAVE_GOBJECT=ON -B build -G Ninja
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -DHB_HAVE_FREETYPE=ON -B build -G Ninja
|
||||
cmake --build build --parallel
|
||||
ninja -C build install
|
||||
cd ..
|
||||
@@ -247,7 +250,7 @@ tar xf "qtbase-everywhere-src-$QT.tar.xz"
|
||||
cd "qtbase-everywhere-src-$QT"
|
||||
mkdir build
|
||||
cd build
|
||||
../configure -prefix "$INSTALLDIR" -release -dbus-linked -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -xcb -gtk -- --log-level=STATUS -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_dbus=ON -DFEATURE_icu=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON
|
||||
../configure -prefix "$INSTALLDIR" -release -dbus-linked -gui -widgets -fontconfig -qt-doubleconversion -ssl -openssl-runtime -opengl desktop -qpa xcb,wayland -xkbcommon -xcb -- --log-level=STATUS -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DFEATURE_dbus=ON -DFEATURE_icu=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON -DFEATURE_gtk3=OFF
|
||||
cmake --build . --parallel
|
||||
ninja install
|
||||
cd ../../
|
||||
|
||||
@@ -38,6 +38,9 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||
INSTALLDIR="$PWD/$INSTALLDIR"
|
||||
fi
|
||||
|
||||
QT=6.10.1
|
||||
QTAPNG=1.3.0
|
||||
|
||||
FREETYPE=2.14.1
|
||||
HARFBUZZ=12.2.0
|
||||
SDL=SDL3-3.4.0
|
||||
@@ -48,8 +51,6 @@ LIBJPEGTURBO=3.1.2
|
||||
LIBWEBP=1.6.0
|
||||
FFMPEG=8.0
|
||||
MOLTENVK=1.4.1
|
||||
QT=6.10.1
|
||||
QTAPNG=1.3.0
|
||||
KDDOCKWIDGETS=2.4.0
|
||||
PLUTOVG=1.3.2
|
||||
PLUTOSVG=0.0.7
|
||||
@@ -78,6 +79,13 @@ CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
|
||||
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
|
||||
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
|
||||
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
|
||||
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
|
||||
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
|
||||
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
|
||||
082cbf5f429e0d80820f68dc2b507a94d4cc1b4e70817b119bbb8ec6a69584b8 $SDL.tar.gz
|
||||
@@ -89,19 +97,14 @@ e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWE
|
||||
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
|
||||
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
|
||||
5a6226f7e23db51fdc3223121eba53f3f5447cf0cc4d6cb82a3a2df7a65d265d qtbase-everywhere-src-$QT.tar.xz
|
||||
498eabdf2381db96f808942b3e3c765f6360fe6c0e9961f0a45ff7a4c68d7a72 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
c02f355a58f3bbcf404a628bf488b6aeb2d84a94c269afdb86f6e529343ab01f qtsvg-everywhere-src-$QT.tar.xz
|
||||
8148408380ffea03101a26305c812b612ea30dbc07121e58707601522404d49b qttools-everywhere-src-$QT.tar.xz
|
||||
8e49a2df88a12c376a479ae7bd272a91cf57ebb4e7c0cf7341b3565df99d2314 qttranslations-everywhere-src-$QT.tar.xz
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
|
||||
8a89fb6612ace8954470aae004623374a8fc8b7a34a4277bee5527173b064faf shaderc-$SHADERC.tar.gz
|
||||
272d2725b140e09e85b96eecdc59c2e00c1a14cda2301767e1bf3c363a44b931 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
EOF
|
||||
|
||||
curl -C - -L \
|
||||
|
||||
@@ -20,6 +20,9 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
|
||||
INSTALLDIR="$PWD/$INSTALLDIR"
|
||||
fi
|
||||
|
||||
QT=6.10.2
|
||||
QTAPNG=1.3.0
|
||||
|
||||
FREETYPE=2.14.1
|
||||
HARFBUZZ=12.2.0
|
||||
SDL=SDL3-3.4.0
|
||||
@@ -30,8 +33,6 @@ LIBJPEGTURBO=3.1.2
|
||||
LIBWEBP=1.6.0
|
||||
FFMPEG=8.0
|
||||
MOLTENVK=1.4.1
|
||||
QT=6.10.1
|
||||
QTAPNG=1.3.0
|
||||
KDDOCKWIDGETS=2.4.0
|
||||
PLUTOVG=1.3.2
|
||||
PLUTOSVG=0.0.7
|
||||
@@ -59,6 +60,13 @@ CMAKE_COMMON=(
|
||||
)
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
|
||||
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
|
||||
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
|
||||
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
|
||||
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
|
||||
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
|
||||
082cbf5f429e0d80820f68dc2b507a94d4cc1b4e70817b119bbb8ec6a69584b8 $SDL.tar.gz
|
||||
@@ -70,19 +78,14 @@ e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWE
|
||||
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
|
||||
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
|
||||
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
|
||||
5a6226f7e23db51fdc3223121eba53f3f5447cf0cc4d6cb82a3a2df7a65d265d qtbase-everywhere-src-$QT.tar.xz
|
||||
498eabdf2381db96f808942b3e3c765f6360fe6c0e9961f0a45ff7a4c68d7a72 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
c02f355a58f3bbcf404a628bf488b6aeb2d84a94c269afdb86f6e529343ab01f qtsvg-everywhere-src-$QT.tar.xz
|
||||
8148408380ffea03101a26305c812b612ea30dbc07121e58707601522404d49b qttools-everywhere-src-$QT.tar.xz
|
||||
8e49a2df88a12c376a479ae7bd272a91cf57ebb4e7c0cf7341b3565df99d2314 qttranslations-everywhere-src-$QT.tar.xz
|
||||
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
|
||||
8a89fb6612ace8954470aae004623374a8fc8b7a34a4277bee5527173b064faf shaderc-$SHADERC.tar.gz
|
||||
272d2725b140e09e85b96eecdc59c2e00c1a14cda2301767e1bf3c363a44b931 shaderc-glslang-$SHADERC_GLSLANG.tar.gz
|
||||
c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz
|
||||
06b0a042f2e121e954badb4fd78c9e2d4bc7ed6087eceb26ab559c23cf94334f shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
|
||||
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
|
||||
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
|
||||
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
|
||||
@@ -2,10 +2,15 @@
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo Setting environment...
|
||||
if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" (
|
||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsamd64_arm64.bat"
|
||||
) else if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" (
|
||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat"
|
||||
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" (
|
||||
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[17, 18)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
|
||||
if defined VSINSTPATH (
|
||||
echo VSINSTPATH=!VSINSTPATH!
|
||||
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" || goto error
|
||||
) else (
|
||||
echo Visual Studio 2022 not found.
|
||||
goto error
|
||||
)
|
||||
) else (
|
||||
echo Visual Studio 2022 not found.
|
||||
goto error
|
||||
@@ -42,15 +47,16 @@ echo INSTALLDIR=%INSTALLDIR%
|
||||
|
||||
cd "%BUILDDIR%"
|
||||
|
||||
set QT=6.10.2
|
||||
set QTMINOR=6.10
|
||||
set QTAPNG=1.3.0
|
||||
|
||||
set FREETYPE=2.14.1
|
||||
set HARFBUZZ=12.2.0
|
||||
set LIBJPEGTURBO=3.1.2
|
||||
set LIBPNG=1653
|
||||
set LIBPNGLONG=1.6.53
|
||||
set SDL=SDL3-3.4.0
|
||||
set QT=6.10.1
|
||||
set QTMINOR=6.10
|
||||
set QTAPNG=1.3.0
|
||||
set LZ4=1.10.0
|
||||
set WEBP=1.6.0
|
||||
set ZLIB=1.3.1
|
||||
@@ -67,6 +73,13 @@ set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
|
||||
|
||||
set AGILITYSDK=1.618.5
|
||||
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 690e08ce807041150d388b5351de2e591febf0a0bc973b56e1197e2df9a2d96f || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" a407e489ca8d68639530e881aea797f58754e355ca06024a73358bd9cc5fca17 || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" fd9f4f6e983a55f6b0ba4c49ce13f8b014cd30d12e75a49a478a640462f9bf64 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" a498357aed659c66aa87ceb556eacab55e3e7d7c9b9599049066de70eb7efa59 || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" cf5e04a2048c02369f579c1251f61af965f241cde2d69de3db90e6c9f0ee2bf3 || goto error
|
||||
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
|
||||
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
|
||||
@@ -74,12 +87,6 @@ call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 9ac2debb493e0d3e13dbd2729fb91f4bfeb00a0f4dff5e04b73cc9bac276b38d || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c43f471a808b07fc541528410e94ce89c6745bdc1d744492e19911d35fbf7d33 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 2d828d8c999fdd18167937c071781c22321c643b04a106c714411c2356cdb26d || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" ddd74a417d2397eb085d047a9b6ba52b76e748055817f728fe691f8456035d23 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" db8e49ed50912c3c064a4f9ada7791c09eccec5a8d53463a19608eaab17679f0 || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 868eb651e395d48ade5932ef2c386e606e054eb5888ebe5284fbd8cb63ed935a || goto error
|
||||
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
|
||||
@@ -2,10 +2,15 @@
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo Setting environment...
|
||||
if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" (
|
||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
||||
) else if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" (
|
||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
|
||||
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" (
|
||||
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[17, 18)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
|
||||
if defined VSINSTPATH (
|
||||
echo VSINSTPATH=!VSINSTPATH!
|
||||
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvars64.bat" || goto error
|
||||
) else (
|
||||
echo Visual Studio 2022 not found.
|
||||
goto error
|
||||
)
|
||||
) else (
|
||||
echo Visual Studio 2022 not found.
|
||||
goto error
|
||||
@@ -40,15 +45,16 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
|
||||
|
||||
cd "%BUILDDIR%"
|
||||
|
||||
set QT=6.10.2
|
||||
set QTMINOR=6.10
|
||||
set QTAPNG=1.3.0
|
||||
|
||||
set FREETYPE=2.14.1
|
||||
set HARFBUZZ=12.2.0
|
||||
set LIBJPEGTURBO=3.1.2
|
||||
set LIBPNG=1653
|
||||
set LIBPNGLONG=1.6.53
|
||||
set SDL=SDL3-3.4.0
|
||||
set QT=6.10.1
|
||||
set QTMINOR=6.10
|
||||
set QTAPNG=1.3.0
|
||||
set LZ4=1.10.0
|
||||
set WEBP=1.6.0
|
||||
set ZLIB=1.3.1
|
||||
@@ -65,6 +71,13 @@ set SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
|
||||
|
||||
set AGILITYSDK=1.618.5
|
||||
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 690e08ce807041150d388b5351de2e591febf0a0bc973b56e1197e2df9a2d96f || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" a407e489ca8d68639530e881aea797f58754e355ca06024a73358bd9cc5fca17 || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" fd9f4f6e983a55f6b0ba4c49ce13f8b014cd30d12e75a49a478a640462f9bf64 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" a498357aed659c66aa87ceb556eacab55e3e7d7c9b9599049066de70eb7efa59 || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" cf5e04a2048c02369f579c1251f61af965f241cde2d69de3db90e6c9f0ee2bf3 || goto error
|
||||
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
|
||||
|
||||
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
|
||||
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip 31490c781bacd2ce56862555b11c51c964977c39f14f51b817dfaecf0be089fe || goto error
|
||||
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1653.zip 140566abc64bb2320cb35f1d154d1cb3eb7174a12234d33bfdffb446bdc0a1d2 || goto error
|
||||
@@ -72,12 +85,6 @@ call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net
|
||||
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 9ac2debb493e0d3e13dbd2729fb91f4bfeb00a0f4dff5e04b73cc9bac276b38d || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" c43f471a808b07fc541528410e94ce89c6745bdc1d744492e19911d35fbf7d33 || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 2d828d8c999fdd18167937c071781c22321c643b04a106c714411c2356cdb26d || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" ddd74a417d2397eb085d047a9b6ba52b76e748055817f728fe691f8456035d23 || goto error
|
||||
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" db8e49ed50912c3c064a4f9ada7791c09eccec5a8d53463a19608eaab17679f0 || goto error
|
||||
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 868eb651e395d48ade5932ef2c386e606e054eb5888ebe5284fbd8cb63ed935a || goto error
|
||||
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
|
||||
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
|
||||
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
|
||||
|
||||
@@ -84,14 +84,10 @@ endif()
|
||||
if(_M_ARM64)
|
||||
message(WARNING "
|
||||
*************** UNSUPPORTED CONFIGURATION ***************
|
||||
|
||||
Apple Silicon support in PCSX2 is INCOMPLETE. There are
|
||||
currently no EE/VU/IOP recompilers, and games will run
|
||||
VERY slow. There is no date for completion yet, you
|
||||
should set -DCMAKE_OSX_ARCHITECTURES=x86_64 for now,
|
||||
unless you want to work on the recompilers.
|
||||
|
||||
We also ask that you read https://dont-ship.it/.
|
||||
|
||||
*********************************************************")
|
||||
endif()
|
||||
|
||||
@@ -1980,6 +1980,8 @@ SCAJ-20116:
|
||||
SCAJ-20117:
|
||||
name: "Fu-un Bakumatsu-den"
|
||||
region: "NTSC-Unk"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SCAJ-20118:
|
||||
name: "ラジアータ ストーリーズ"
|
||||
name-sort: "らじあーた すとーりーず"
|
||||
@@ -6268,19 +6270,23 @@ SCES-53880:
|
||||
region: "PAL-E"
|
||||
SCES-53881:
|
||||
name: "Buzz! Le Grand Quiz"
|
||||
name-en: "Buzz! The Big Quiz"
|
||||
region: "PAL-F"
|
||||
SCES-53882:
|
||||
name: "Buzz! The Big Quiz"
|
||||
name: "Buzz! Il Superquiz"
|
||||
name-en: "Buzz! The Big Quiz"
|
||||
region: "PAL-I"
|
||||
gameFixes:
|
||||
- EETimingHack # Fixes freezes.
|
||||
SCES-53883:
|
||||
name: "Buzz! The Big Quiz"
|
||||
name: "Buzz! Das große Quiz"
|
||||
name-en: "Buzz! The Big Quiz"
|
||||
region: "PAL-G"
|
||||
gameFixes:
|
||||
- EETimingHack # Fixes freezes.
|
||||
SCES-53884:
|
||||
name: "Buzz! El GRAN Reto"
|
||||
name: "Buzz! El Gran Reto"
|
||||
name-en: "Buzz! The Big Quiz"
|
||||
region: "PAL-S"
|
||||
compat: 2
|
||||
gameFixes:
|
||||
@@ -6317,10 +6323,12 @@ SCES-53926:
|
||||
name: "Buzz! The Big Quiz"
|
||||
region: "PAL-SC"
|
||||
SCES-53927:
|
||||
name: "Buzz! The Big Quiz"
|
||||
name: "Buzz! Suuri Tietovisa"
|
||||
name-en: "Buzz! The Big Quiz"
|
||||
region: "PAL-FI"
|
||||
SCES-53929:
|
||||
name: "Buzz! The Big Quiz"
|
||||
name: "Buzz! O Grande Quiz"
|
||||
name-en: "Buzz! The Big Quiz"
|
||||
region: "PAL-P"
|
||||
SCES-53931:
|
||||
name: "Shinobido - Way of the Ninja"
|
||||
@@ -6436,19 +6444,23 @@ SCES-54258:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
region: "PAL-E"
|
||||
SCES-54259:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
name: "Buzz! Das Sport-Quiz"
|
||||
name-en: "Buzz! The Sports Quiz"
|
||||
region: "PAL-G"
|
||||
SCES-54260:
|
||||
name: "Buzz! Le Quiz du Sport"
|
||||
name-en: "Buzz! The Sports Quiz"
|
||||
region: "PAL-F"
|
||||
SCES-54261:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
region: "PAL-I"
|
||||
SCES-54262:
|
||||
name: "Buzz! - El Gran Concurso de Deportes"
|
||||
name: "Buzz! El Gran Concurso de Deportes"
|
||||
name-en: "Buzz! The Sports Quiz"
|
||||
region: "PAL-S"
|
||||
SCES-54263:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
name: "Buzz! O Quiz Desportivo"
|
||||
name-en: "Buzz! The Sports Quiz"
|
||||
region: "PAL-P"
|
||||
SCES-54264:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
@@ -6460,7 +6472,8 @@ SCES-54266:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
region: "PAL-SC"
|
||||
SCES-54267:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
name: "Buzz! Sporttivisa"
|
||||
name-en: "Buzz! The Sports Quiz"
|
||||
region: "PAL-FI"
|
||||
SCES-54268:
|
||||
name: "Buzz! The Sports Quiz"
|
||||
@@ -6496,24 +6509,29 @@ SCES-54496:
|
||||
region: "PAL-E"
|
||||
SCES-54497:
|
||||
name: "Buzz! Le Mega Quiz"
|
||||
name-en: "Buzz! The Mega Quiz"
|
||||
region: "PAL-F"
|
||||
SCES-54498:
|
||||
name: "Buzz! The Mega Quiz"
|
||||
region: "PAL-I"
|
||||
SCES-54499:
|
||||
name: "Buzz! Das Mega-Quiz"
|
||||
name-en: "Buzz! The Mega Quiz"
|
||||
region: "PAL-G"
|
||||
SCES-54500:
|
||||
name: "Buzz! El Mega Concurso"
|
||||
name-en: "Buzz! The Mega Quiz"
|
||||
region: "PAL-S"
|
||||
SCES-54501:
|
||||
name: "Buzz! The Mega Quiz"
|
||||
region: "PAL-A"
|
||||
SCES-54503:
|
||||
name: "Buzz! Megavisa"
|
||||
name-en: "Buzz! The Mega Quiz"
|
||||
region: "PAL-FI"
|
||||
SCES-54504:
|
||||
name: "Buzz! O Mega Quiz"
|
||||
name-en: "Buzz! The Mega Quiz"
|
||||
region: "PAL-P"
|
||||
SCES-54505:
|
||||
name: "Buzz! The Mega Quiz"
|
||||
@@ -13217,9 +13235,7 @@ SLAJ-25018:
|
||||
region: "NTSC-HK"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # Improves visual clarity whilst upscaling.
|
||||
roundSprite: 1 # Reduces graphics garbage on UI whilst upscaling.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLAJ-25019:
|
||||
name: "The Lord of the Rings - The Return of the King"
|
||||
region: "NTSC-C"
|
||||
@@ -22704,9 +22720,7 @@ SLES-53191:
|
||||
name: "Kaido Racer"
|
||||
region: "PAL-M5"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain/Storm.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLES-53192:
|
||||
name: "Tim Burton's The Nightmare Before Christmas - Oogie's Reveng"
|
||||
name-sort: "Nightmare Before Christmas, The - Tim Burton's"
|
||||
@@ -24969,9 +24983,7 @@ SLES-53900:
|
||||
name: "Kaido Racer 2"
|
||||
region: "PAL-M3"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Storm.
|
||||
alignSprite: 1 # Fixes black lines when upscaling.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLES-53901:
|
||||
name: "Torino 2006"
|
||||
region: "PAL-M5"
|
||||
@@ -31336,9 +31348,7 @@ SLKA-25063:
|
||||
name-en: "Kaido Battle"
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLKA-25064:
|
||||
name: "천주 3 천벌"
|
||||
name-en: "Tenchu - Wrath of Heaven"
|
||||
@@ -31433,9 +31443,7 @@ SLKA-25084:
|
||||
region: "NTSC-K"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # Improves visual clarity whilst upscaling.
|
||||
roundSprite: 1 # Reduces graphics garbage on UI whilst upscaling.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLKA-25085:
|
||||
name: "진・삼국무쌍 3 맹장전"
|
||||
name-en: "Jin Samguk Mussang 3 - Maengjangjeon"
|
||||
@@ -31723,9 +31731,7 @@ SLKA-25146:
|
||||
name-en: "Kaido Battle 2 - Chain Reaction"
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain/Storm.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLKA-25148:
|
||||
name: "MVP 베이스볼 2004"
|
||||
name-en: "MVP Baseball 2004"
|
||||
@@ -32312,9 +32318,11 @@ SLKA-25255:
|
||||
name-en: "Mobile Suit Gundam Seed - Never Ending Tomorrow"
|
||||
region: "NTSC-K"
|
||||
SLKA-25257:
|
||||
name: "풍운 막말전" # Undumped on ReDump as of 2025-08-28
|
||||
name-en: "Fu-un Bakumatsu Den"
|
||||
name: "풍운 막말전" # Undumped on ReDump as of 2025-08-28
|
||||
name-en: "Fu-un Bakumatsu-den"
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLKA-25258:
|
||||
name: "요시츠네 영웅전"
|
||||
name-sort: "Yoshitsune Yeongungjeon"
|
||||
@@ -35575,9 +35583,7 @@ SLPM-60195:
|
||||
name-en: "Kaidō Battle - Nikko, Haruna, Rokko, Hakone [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-60197:
|
||||
name: "エキサイティングプロレス 4 [体験版]"
|
||||
name-sort: "えきさいてぃんぐぷろれす4 [たいけんばん]"
|
||||
@@ -35621,9 +35627,7 @@ SLPM-60206:
|
||||
name-en: "Shutokou Battle 01 [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # Improves visual clarity whilst upscaling.
|
||||
roundSprite: 1 # Reduces graphics garbage on UI whilst upscaling.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-60207:
|
||||
name: "ロックマンX7 [体験版]"
|
||||
name-sort: "ろっくまんえっくす7 [たいけんばん]"
|
||||
@@ -35718,10 +35722,12 @@ SLPM-60220:
|
||||
name-en: "Hajime no Ippo II - Victorious Road [Trial]"
|
||||
region: "NTSC-J"
|
||||
SLPM-60225:
|
||||
name: "風雲新撰組 [体験版]"
|
||||
name: "風雲 新撰組 [体験版]"
|
||||
name-sort: "ふううん しんせんぐみ [たいけんばん]"
|
||||
name-en: "Fuuun Shinsengumi [Trial]"
|
||||
name-en: "Fu-un Shinsen-gumi [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-60226:
|
||||
name: "シャドウハーツⅡ [体験版]"
|
||||
name-sort: "しゃどうはーつ2 [たいけんばん]"
|
||||
@@ -35737,9 +35743,7 @@ SLPM-60228:
|
||||
name-en: "Kaidō Battle 2 - Chain Reaction [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain/Storm.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-60237:
|
||||
name: "電車でGO!FINAL [体験版]"
|
||||
name-sort: "でんしゃでごーFINAL [たいけんばん]"
|
||||
@@ -36489,10 +36493,12 @@ SLPM-61095:
|
||||
name-en: "Dengeki PS2 / DengekiPlayStation D74"
|
||||
region: "NTSC-J"
|
||||
SLPM-61096:
|
||||
name: "風雲幕末伝 [体験版]"
|
||||
name: "風雲 幕末伝 [体験版]"
|
||||
name-sort: "ふううんばくまつでん [たいけんばん]"
|
||||
name-en: "Fuuun Bakumatsu-den [Trial]"
|
||||
name-en: "Fu-un Bakumatsu-den [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-61097:
|
||||
name: "電撃PS2 / 電撃PlayStation D75"
|
||||
name-sort: "でんげき PS2 でんげきPlayStation D75"
|
||||
@@ -36601,8 +36607,7 @@ SLPM-61115:
|
||||
name-en: "Racing Battle - C1 Grand Prix [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-61116:
|
||||
name: "冒険王ビィト ダークネスセンチュリー [体験版]"
|
||||
name-sort: "ぼうけんおうびぃと だーくねすせんちゅりー [たいけんばん]"
|
||||
@@ -36649,9 +36654,7 @@ SLPM-61121:
|
||||
name-en: "Kaido Touge no Densetsu [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain/Storm.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-61122:
|
||||
name: "電撃PS2 / 電撃PlayStation D81"
|
||||
name-sort: "でんげき PS2 でんげきPlayStation D81"
|
||||
@@ -42495,9 +42498,7 @@ SLPM-65246:
|
||||
name-en: "Kaidō Battle - Nikko, Haruna, Rokko, Hakone"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-65247:
|
||||
name: "三國志戦記2"
|
||||
name-sort: "さんごくしせんき2"
|
||||
@@ -42872,9 +42873,7 @@ SLPM-65308:
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # Improves visual clarity whilst upscaling.
|
||||
roundSprite: 1 # Reduces graphics garbage on UI whilst upscaling.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-65309:
|
||||
name: "Splashdown [PlayStation2 the Best]"
|
||||
name-sort: "すぷらっしゅだうん [PlayStation2 the Best]"
|
||||
@@ -43907,10 +43906,12 @@ SLPM-65493:
|
||||
name-en: "Hurrah! Sailor [Limited Edition]"
|
||||
region: "NTSC-J"
|
||||
SLPM-65494:
|
||||
name: "風雲 新撰組"
|
||||
name: "風雲 新撰組"
|
||||
name-sort: "ふううん しんせんぐみ"
|
||||
name-en: "Fuuun Shinsengumi"
|
||||
name-en: "Fu-un Shinsen-gumi"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-65495:
|
||||
name: "モンスターハンター"
|
||||
name-sort: "もんすたーはんたー"
|
||||
@@ -44048,9 +44049,7 @@ SLPM-65514:
|
||||
name-en: "Kaidō Battle 2 - Chain Reaction"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain/Storm.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-65515:
|
||||
name: "サクラ大戦物語 ~ミステリアス巴里~"
|
||||
name-sort: "さくらたいせんものがたり ~みすてりあすぱり~"
|
||||
@@ -45779,11 +45778,13 @@ SLPM-65812:
|
||||
name-en: "Bakushou! Jinsei Kaidou - NOVA Usagi ga Miteruzo! [TAITO BEST]"
|
||||
region: "NTSC-J"
|
||||
SLPM-65813:
|
||||
name: "風雲幕末伝"
|
||||
name: "風雲 幕末伝"
|
||||
name-sort: "ふううん ばくまつでん"
|
||||
name-en: "Fu-un Bakumatsu Den"
|
||||
name-en: "Fu-un Bakumatsu-den"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-65815:
|
||||
name: "トム・クランシーシリーズ スプリンターセル パンドラトゥモロー"
|
||||
name-sort: "とむくらんしーしりーず すぷりんたーせる ぱんどらとぅもろー"
|
||||
@@ -46249,8 +46250,7 @@ SLPM-65897:
|
||||
name-en: "Racing Battle - C1 Grand Prix"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-65898:
|
||||
name: "キャッスルファンタジア エレンシア戦記 DXパック"
|
||||
name-sort: "きゃっするふぁんたじあ えれんしあせんき DXぱっく"
|
||||
@@ -47001,9 +47001,7 @@ SLPM-66022:
|
||||
name-en: "Kaido - Touge no Densetsu"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain/Storm.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-66023:
|
||||
name: "ふしぎ遊戯 玄武開伝 外伝 鏡の巫女 [限定版]"
|
||||
name-sort: "ふしぎゆうぎ げんぶかいでん がいでん かがみのみこ [げんていばん]"
|
||||
@@ -53752,10 +53750,12 @@ SLPM-74201:
|
||||
- "SLPM-65286"
|
||||
- "BWNETCNF"
|
||||
SLPM-74202:
|
||||
name: "風雲 新撰組 [PlayStation2 the Best]"
|
||||
name: "風雲 新撰組 [PlayStation2 the Best]"
|
||||
name-sort: "ふううん しんせんぐみ [PlayStation2 the Best]"
|
||||
name-en: "Fuuun Shinsengumi [PlayStation2 the Best]"
|
||||
name-en: "Fu-un Shinsen-gumi [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-74204:
|
||||
name: "首都高バトル01 [PlayStation2 the Best]"
|
||||
name-sort: "しゅとこうばとる01 [PlayStation2 the Best]"
|
||||
@@ -53763,9 +53763,7 @@ SLPM-74204:
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # Improves visual clarity whilst upscaling.
|
||||
roundSprite: 1 # Reduces graphics garbage on UI whilst upscaling.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-74205:
|
||||
name: "真・女神転生Ⅲ - NOCTURNE [PlayStation2 the Best]"
|
||||
name-sort: "しんめがみてんせい3 - NOCTURNE [PlayStation2 the Best]"
|
||||
@@ -53904,10 +53902,12 @@ SLPM-74227:
|
||||
halfPixelOffset: 4 # Fixes misaligned lighting and bloom.
|
||||
bilinearUpscale: 1 # Smooths out bloom.
|
||||
SLPM-74228:
|
||||
name: "風雲幕末伝 [PlayStation2 the Best]"
|
||||
name: "風雲 幕末伝 [PlayStation2 the Best]"
|
||||
name-sort: "ふううんばくまつでん [PlayStation2 the Best]"
|
||||
name-en: "Fuuun Bakumatsu-den [PlayStation2 the Best]"
|
||||
name-en: "Fu-un Bakumatsu-den [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPM-74229:
|
||||
name: "バイオハザード4 [PlayStation2 the Best]"
|
||||
name-sort: "ばいおはざーど4 [PlayStation2 the Best]"
|
||||
@@ -63488,10 +63488,12 @@ SLPS-73227:
|
||||
name-en: "Another Century's Episode [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
SLPS-73228:
|
||||
name: "風雲幕末伝 [PlayStation2 the Best]"
|
||||
name: "風雲 幕末伝 [PlayStation2 the Best]"
|
||||
name-sort: "ふううんばくまつでん [PlayStation2 the Best]"
|
||||
name-en: "Fuuun Bakumatsu-den [PlayStation2 the Best]"
|
||||
name-en: "Fu-un Bakumatsu-den [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLPS-73229:
|
||||
name: "ベルウィックサーガ [PlayStation2 the Best]"
|
||||
name-sort: "べるうぃっくさーが [PlayStation2 the Best]"
|
||||
@@ -68131,9 +68133,7 @@ SLUS-20831:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # Improves visual clarity whilst upscaling.
|
||||
roundSprite: 1 # Reduces graphics garbage on UI whilst upscaling.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLUS-20833:
|
||||
name: "Mega Man Anniversary Collection"
|
||||
region: "NTSC-U"
|
||||
@@ -70602,9 +70602,7 @@ SLUS-21236:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # Fixes double image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLUS-21237:
|
||||
name: "AND 1 Streetball"
|
||||
region: "NTSC-U"
|
||||
@@ -71786,9 +71784,7 @@ SLUS-21394:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting during Rain/Storm.
|
||||
alignSprite: 1 # Fixes vertical lines.
|
||||
forceEvenSpritePosition: 1 # De-blurs the 3D image.
|
||||
halfPixelOffset: 5 # Fixes vertical lines.
|
||||
SLUS-21395:
|
||||
name: "Avatar - The Last Airbender"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000373500002210000000000000,GameSir G7 Pro,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefty:a2,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Window,
|
||||
03000000373500002210000000000000,GameSir G7 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000ac0500001a06000000000000,GameSir T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000373500009410000000000000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
|
||||
@@ -246,8 +246,6 @@
|
||||
03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows,
|
||||
030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000c21100000791000000000000,Nacon GC101 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000c9110000f055000000000000,Nacon GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
@@ -367,7 +365,7 @@
|
||||
03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
|
||||
03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows,
|
||||
03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows,
|
||||
03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows,
|
||||
@@ -464,6 +462,8 @@
|
||||
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
|
||||
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
|
||||
03000000c9110000f055000000000000,Nacon GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000c21100000791000000000000,Nacon GC101 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000006b140000010c000000000000,Nacon GC400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
@@ -697,7 +697,7 @@
|
||||
03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
|
||||
03000000632500002705000000000000,ShanWan Q36,a:b0,b:b1,x:b3,y:b4,leftshoulder:b6,rightshoulder:b7,lefttrigger:b8,righttrigger:b9,back:b10,start:b11,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Windows,
|
||||
03000000632500002705000000000000,ShanWan Q36,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
@@ -888,6 +888,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000960000000000000,8BitDo Pro 3,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
@@ -1174,7 +1175,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Linux,
|
||||
03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
@@ -1352,7 +1353,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,
|
||||
030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
|
||||
0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
0500000047532067616d657061640000,GS Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000008a2e0000dd10000011010000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Linux,
|
||||
030000008a2e0000df10000011010000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Linux,
|
||||
@@ -1397,11 +1398,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux,
|
||||
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000f00300008d04000000010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
03000000d80400004bea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||
03000000d80400004aea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||
030000008a2e0000d910000011010000,icedragon.io STAC2 Dance Pad,a:b0,b:b1,x:b2,y:b3,back:b4,platform:Linux,
|
||||
030000008a2e0000e910000011010000,icedragon.io STAC2 Dance Pad,a:b8,b:b9,x:b10,y:b11,back:b12,platform:Linux,
|
||||
03000000d80400004aea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,back:b4,x:b2,y:b3,platform:Linux,
|
||||
03000000d80400004bea000011010000,icedragon.io STAC Dance Pad,a:b0,b:b1,back:b4,x:b2,y:b3,platform:Linux,
|
||||
030000008a2e0000d910000011010000,icedragon.io STAC2 Dance Pad,a:b0,b:b1,back:b4,x:b2,y:b3,platform:Linux,
|
||||
030000008a2e0000e910000011010000,icedragon.io STAC2 Dance Pad,a:b8,b:b9,back:b12,x:b10,y:b11,platform:Linux,
|
||||
030000008f0e00001330000001010000,iCode Retro Adapter,b:b3,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b1,start:b7,x:b2,y:b0,platform:Linux,
|
||||
050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
|
||||
@@ -1487,6 +1489,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000ea0200000f050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b000014050000,Microsoft Xbox One,a:b0,b:b1,x:b2,y:b3,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux
|
||||
030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
@@ -1504,7 +1507,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
03000000c82d00000960000000000000,8BitDo Pro 3,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1512,9 +1514,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux,
|
||||
030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006b140000010c000010010000,Nacon GC400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
0300000085320000030c000011010000,Nacon GC100,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000853200000706000012010000,Nacon GC100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006b140000010c000010010000,Nacon GC400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
05000000853200000503000000010000,Nacon MGX Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
@@ -1788,9 +1790,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000c0160000e105000010010000,Ultimate Atari Fight Stick,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,platform:Linux,
|
||||
03000000790000002601000011010000,SNES Controller,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Linux,
|
||||
03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000790000000600000007010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
|
||||
03000000790000001a18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000790000001b18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1800,17 +1803,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000002010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000047010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000072050000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00001503000000020000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000002010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000047010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000072050000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
0000000058626f782047616d65706100,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
|
||||
@@ -108,7 +108,7 @@ disable_compiler_warnings_for_target(speex)
|
||||
|
||||
# Find the Qt components that we need.
|
||||
if(ENABLE_QT_UI)
|
||||
find_package(Qt6 6.10.0 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
|
||||
find_package(Qt6 6.10.1 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
|
||||
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
if (Qt6_VERSION VERSION_GREATER_EQUAL 6.10.0)
|
||||
|
||||
@@ -144,7 +144,7 @@ void AboutDialog::showHTMLDialog(QWidget* parent, const QString& title, const QS
|
||||
{
|
||||
tb->setSource(QUrl::fromLocalFile(path));
|
||||
}
|
||||
|
||||
|
||||
layout->addWidget(tb, 1);
|
||||
|
||||
QDialogButtonBox* bb = new QDialogButtonBox(QDialogButtonBox::Close, &dialog);
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
template <typename Value>
|
||||
static std::function<void(std::optional<Value>)> wrapValueCallback(std::function<void(Value)> callback)
|
||||
{
|
||||
return [callback = std::move(callback)](std::optional<Value> input) {
|
||||
if (input.has_value())
|
||||
callback(std::move(*input));
|
||||
};
|
||||
}
|
||||
|
||||
void AsyncDialogs::getText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QString& text,
|
||||
std::function<void(QString)> value_callback)
|
||||
{
|
||||
getText(parent, title, label, QLineEdit::Normal, text, {}, Qt::ImhNone, wrapValueCallback(std::move(value_callback)));
|
||||
}
|
||||
|
||||
void AsyncDialogs::getText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
QLineEdit::EchoMode echo,
|
||||
const QString& text,
|
||||
Qt::WindowFlags flags,
|
||||
Qt::InputMethodHints input_method_hints,
|
||||
std::function<void(std::optional<QString>)> callback)
|
||||
{
|
||||
QInputDialog* dialog = new QInputDialog(parent, flags);
|
||||
dialog->setWindowTitle(title);
|
||||
dialog->setLabelText(label);
|
||||
dialog->setTextValue(text);
|
||||
dialog->setTextEchoMode(echo);
|
||||
dialog->setInputMethodHints(input_method_hints);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (callback)
|
||||
{
|
||||
QObject::connect(dialog, &QDialog::finished, [dialog, callback = std::move(callback)](int result) {
|
||||
callback(result ? std::make_optional<QString>(dialog->textValue()) : std::nullopt);
|
||||
});
|
||||
}
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void AsyncDialogs::getMultiLineText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QString& text,
|
||||
std::function<void(QString)> value_callback)
|
||||
{
|
||||
getMultiLineText(parent, title, label, text, {}, Qt::ImhNone, wrapValueCallback(std::move(value_callback)));
|
||||
}
|
||||
|
||||
void AsyncDialogs::getMultiLineText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QString& text,
|
||||
Qt::WindowFlags flags,
|
||||
Qt::InputMethodHints input_method_hints,
|
||||
std::function<void(std::optional<QString>)> callback)
|
||||
{
|
||||
QInputDialog* dialog = new QInputDialog(parent, flags);
|
||||
dialog->setOptions(QInputDialog::UsePlainTextEditForTextInput);
|
||||
dialog->setWindowTitle(title);
|
||||
dialog->setLabelText(label);
|
||||
dialog->setTextValue(text);
|
||||
dialog->setInputMethodHints(input_method_hints);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (callback)
|
||||
{
|
||||
QObject::connect(dialog, &QDialog::finished, [dialog, callback = std::move(callback)](int result) {
|
||||
callback(result ? std::make_optional<QString>(dialog->textValue()) : std::nullopt);
|
||||
});
|
||||
}
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void AsyncDialogs::getItem(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QStringList& items,
|
||||
int current,
|
||||
std::function<void(QString)> value_callback)
|
||||
{
|
||||
getItem(parent, title, label, items, current, true, {}, Qt::ImhNone, wrapValueCallback(std::move(value_callback)));
|
||||
}
|
||||
|
||||
void AsyncDialogs::getItem(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QStringList& items,
|
||||
int current,
|
||||
bool editable,
|
||||
Qt::WindowFlags flags,
|
||||
Qt::InputMethodHints input_method_hints,
|
||||
std::function<void(std::optional<QString>)> callback)
|
||||
{
|
||||
const QString text(items.value(current));
|
||||
|
||||
QInputDialog* dialog = new QInputDialog(parent, flags);
|
||||
dialog->setWindowTitle(title);
|
||||
dialog->setLabelText(label);
|
||||
dialog->setComboBoxItems(items);
|
||||
dialog->setTextValue(text);
|
||||
dialog->setComboBoxEditable(editable);
|
||||
dialog->setInputMethodHints(input_method_hints);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (callback)
|
||||
{
|
||||
QObject::connect(dialog, &QDialog::finished, [dialog, callback = std::move(callback)](int result) {
|
||||
callback(result ? std::make_optional<QString>(dialog->textValue()) : std::nullopt);
|
||||
});
|
||||
}
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void AsyncDialogs::getInt(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
int value,
|
||||
std::function<void(int)> value_callback)
|
||||
{
|
||||
getInt(parent, title, label, value, -2147483647, 2147483647, 1, {}, wrapValueCallback(std::move(value_callback)));
|
||||
}
|
||||
|
||||
void AsyncDialogs::getInt(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
int value,
|
||||
int min_value,
|
||||
int max_value,
|
||||
int step,
|
||||
Qt::WindowFlags flags,
|
||||
std::function<void(std::optional<int>)> callback)
|
||||
{
|
||||
QInputDialog* dialog = new QInputDialog(parent, flags);
|
||||
dialog->setWindowTitle(title);
|
||||
dialog->setLabelText(label);
|
||||
dialog->setIntRange(min_value, max_value);
|
||||
dialog->setIntValue(value);
|
||||
dialog->setIntStep(step);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (callback)
|
||||
{
|
||||
QObject::connect(dialog, &QDialog::finished, [dialog, callback = std::move(callback)](int result) {
|
||||
callback(result ? std::make_optional<int>(dialog->intValue()) : std::nullopt);
|
||||
});
|
||||
}
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void AsyncDialogs::getDouble(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
double value,
|
||||
std::function<void(double)> callback)
|
||||
{
|
||||
getDouble(parent, title, label, value, -2147483647, 2147483647, 1, {}, 1, wrapValueCallback(std::move(callback)));
|
||||
}
|
||||
|
||||
void AsyncDialogs::getDouble(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
double value,
|
||||
double min_value,
|
||||
double max_value,
|
||||
int decimals,
|
||||
Qt::WindowFlags flags,
|
||||
double step,
|
||||
std::function<void(std::optional<double>)> callback)
|
||||
{
|
||||
QInputDialog* dialog = new QInputDialog(parent, flags);
|
||||
dialog->setWindowTitle(title);
|
||||
dialog->setLabelText(label);
|
||||
dialog->setDoubleDecimals(decimals);
|
||||
dialog->setDoubleRange(min_value, max_value);
|
||||
dialog->setDoubleValue(value);
|
||||
dialog->setDoubleStep(step);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (callback)
|
||||
{
|
||||
QObject::connect(dialog, &QDialog::finished, [dialog, callback = std::move(callback)](int result) {
|
||||
callback(result ? std::make_optional<double>(dialog->doubleValue()) : std::nullopt);
|
||||
});
|
||||
}
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
// Based on the QMessageBoxPrivate::showNewMessageBox function from Qt Widgets.
|
||||
static void openAsyncMessageBox(QWidget* parent,
|
||||
QMessageBox::Icon icon,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
// Don't support the fallback for Qt 4.
|
||||
pxAssert(!(default_button && !(buttons & default_button)));
|
||||
|
||||
QMessageBox* message_box = new QMessageBox(icon, title, text, QMessageBox::NoButton, parent);
|
||||
message_box->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
const QDialogButtonBox* button_box = message_box->findChild<QDialogButtonBox*>();
|
||||
pxAssert(button_box);
|
||||
|
||||
u32 mask = QMessageBox::FirstButton;
|
||||
while (mask <= QMessageBox::LastButton)
|
||||
{
|
||||
QMessageBox::StandardButton standard_button =
|
||||
static_cast<QMessageBox::StandardButton>(static_cast<u32>(buttons) & mask);
|
||||
|
||||
mask <<= 1;
|
||||
|
||||
if (standard_button == QMessageBox::NoButton)
|
||||
continue;
|
||||
|
||||
QPushButton* button = message_box->addButton(standard_button);
|
||||
|
||||
if (message_box->defaultButton())
|
||||
continue;
|
||||
|
||||
if ((default_button == QMessageBox::NoButton &&
|
||||
button_box->buttonRole(button) == QDialogButtonBox::AcceptRole) ||
|
||||
(default_button != QMessageBox::NoButton &&
|
||||
standard_button == default_button))
|
||||
message_box->setDefaultButton(button);
|
||||
}
|
||||
|
||||
if (callback)
|
||||
{
|
||||
QObject::connect(message_box, &QMessageBox::finished, [message_box, callback = std::move(callback)](int result) {
|
||||
callback(message_box->standardButton(message_box->clickedButton()));
|
||||
});
|
||||
}
|
||||
|
||||
message_box->open();
|
||||
}
|
||||
|
||||
void AsyncDialogs::information(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
information(parent, title, text, QMessageBox::Ok, QMessageBox::NoButton, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncDialogs::information(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
openAsyncMessageBox(parent, QMessageBox::Information, title, text, buttons, default_button, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncDialogs::question(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void()> yes_callback)
|
||||
{
|
||||
std::function<void(QMessageBox::StandardButton)> callback;
|
||||
if (yes_callback)
|
||||
{
|
||||
callback = [yes_callback = std::move(yes_callback)](QMessageBox::StandardButton result) {
|
||||
if (result == QMessageBox::Yes)
|
||||
yes_callback();
|
||||
};
|
||||
}
|
||||
|
||||
const QMessageBox::StandardButtons buttons(QMessageBox::Yes | QMessageBox::No);
|
||||
question(parent, title, text, buttons, QMessageBox::NoButton, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncDialogs::question(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
openAsyncMessageBox(parent, QMessageBox::Question, title, text, buttons, default_button, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncDialogs::warning(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
warning(parent, title, text, QMessageBox::Ok, QMessageBox::NoButton, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncDialogs::warning(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
openAsyncMessageBox(parent, QMessageBox::Warning, title, text, buttons, default_button, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncDialogs::critical(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
critical(parent, title, text, QMessageBox::Ok, QMessageBox::NoButton, std::move(callback));
|
||||
}
|
||||
|
||||
void AsyncDialogs::critical(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback)
|
||||
{
|
||||
openAsyncMessageBox(parent, QMessageBox::Critical, title, text, buttons, default_button, std::move(callback));
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
#include <functional>
|
||||
|
||||
/// A collection of helper functions for opening asynchronous dialog boxes.
|
||||
/// These should be used in place of Qt's built-in blocking functions as those
|
||||
/// are prone to crashing if the parent is destroyed while the dialog is open.
|
||||
namespace AsyncDialogs
|
||||
{
|
||||
/// Replacement for QInputDialog::getText.
|
||||
void getText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QString& text,
|
||||
std::function<void(QString)> value_callback);
|
||||
|
||||
/// Replacement for QInputDialog::getText.
|
||||
void getText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
QLineEdit::EchoMode echo,
|
||||
const QString& text,
|
||||
Qt::WindowFlags flags,
|
||||
Qt::InputMethodHints input_method_hints,
|
||||
std::function<void(std::optional<QString>)> callback);
|
||||
|
||||
/// Replacement for QInputDialog::getMultiLineText.
|
||||
void getMultiLineText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QString& text,
|
||||
std::function<void(QString)> value_callback);
|
||||
|
||||
/// Replacement for QInputDialog::getMultiLineText.
|
||||
void getMultiLineText(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QString& text,
|
||||
Qt::WindowFlags flags,
|
||||
Qt::InputMethodHints input_method_hints,
|
||||
std::function<void(std::optional<QString>)> callback);
|
||||
|
||||
/// Replacement for QInputDialog::getItem.
|
||||
void getItem(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QStringList& items,
|
||||
int current,
|
||||
std::function<void(QString)> value_callback);
|
||||
|
||||
/// Replacement for QInputDialog::getItem.
|
||||
void getItem(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
const QStringList& items,
|
||||
int current,
|
||||
bool editable,
|
||||
Qt::WindowFlags flags,
|
||||
Qt::InputMethodHints input_method_hints,
|
||||
std::function<void(std::optional<QString>)> callback);
|
||||
|
||||
/// Replacement for QInputDialog::getInt.
|
||||
void getInt(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
int value,
|
||||
std::function<void(int)> value_callback);
|
||||
|
||||
/// Replacement for QInputDialog::getInt.
|
||||
void getInt(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
int value,
|
||||
int min_value,
|
||||
int max_value,
|
||||
int step,
|
||||
Qt::WindowFlags flags,
|
||||
std::function<void(std::optional<int>)> callback);
|
||||
|
||||
/// Replacement for QInputDialog::getDouble.
|
||||
void getDouble(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
double value,
|
||||
std::function<void(double)> value_callback);
|
||||
|
||||
/// Replacement for QInputDialog::getDouble.
|
||||
void getDouble(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& label,
|
||||
double value,
|
||||
double min_value,
|
||||
double max_value,
|
||||
int decimals,
|
||||
Qt::WindowFlags flags,
|
||||
double step,
|
||||
std::function<void(std::optional<double>)> callback);
|
||||
|
||||
/// Replacement for QMessageBox::information.
|
||||
void information(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void(QMessageBox::StandardButton)> callback = {});
|
||||
|
||||
/// Replacement for QMessageBox::information.
|
||||
void information(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback = {});
|
||||
|
||||
/// Replacement for QMessageBox::question.
|
||||
void question(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void()> yes_callback);
|
||||
|
||||
/// Replacement for QMessageBox::question.
|
||||
void question(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback);
|
||||
|
||||
/// Replacement for QMessageBox::warning.
|
||||
void warning(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void(QMessageBox::StandardButton)> callback = {});
|
||||
|
||||
/// Replacement for QMessageBox::warning.
|
||||
void warning(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback = {});
|
||||
|
||||
/// Replacement for QMessageBox::critical.
|
||||
void critical(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
std::function<void(QMessageBox::StandardButton)> callback = {});
|
||||
|
||||
/// Replacement for QMessageBox::critical.
|
||||
void critical(
|
||||
QWidget* parent,
|
||||
const QString& title,
|
||||
const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
QMessageBox::StandardButton default_button,
|
||||
std::function<void(QMessageBox::StandardButton)> callback = {});
|
||||
} // namespace AsyncDialogs
|
||||
@@ -10,6 +10,8 @@ target_sources(pcsx2-qt PRIVATE
|
||||
AboutDialog.cpp
|
||||
AboutDialog.h
|
||||
AboutDialog.ui
|
||||
AsyncDialogs.cpp
|
||||
AsyncDialogs.h
|
||||
AutoUpdaterDialog.cpp
|
||||
AutoUpdaterDialog.h
|
||||
AutoUpdaterDialog.ui
|
||||
|
||||
@@ -112,7 +112,8 @@ void CoverDownloadDialog::cancelThread()
|
||||
}
|
||||
|
||||
CoverDownloadDialog::CoverDownloadThread::CoverDownloadThread(QWidget* parent, const QString& urls, bool use_serials)
|
||||
: QtAsyncProgressThread(parent), m_use_serials(use_serials)
|
||||
: QtAsyncProgressThread(parent)
|
||||
, m_use_serials(use_serials)
|
||||
{
|
||||
for (const QString& str : urls.split(QChar('\n')))
|
||||
m_urls.push_back(str.toStdString());
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "BreakpointDialog.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "QtUtils.h"
|
||||
#include "QtHost.h"
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
|
||||
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakpointModel& model)
|
||||
: QDialog(parent)
|
||||
@@ -100,7 +101,7 @@ void BreakpointDialog::accept()
|
||||
u64 address;
|
||||
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), address, error))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid Address"), QString::fromStdString(error));
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Invalid Address"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,7 +117,7 @@ void BreakpointDialog::accept()
|
||||
|
||||
if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr, error))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid Condition"), QString::fromStdString(error));
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Invalid Condition"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -134,14 +135,14 @@ void BreakpointDialog::accept()
|
||||
u64 startAddress;
|
||||
if (!m_cpu->evaluateExpression(m_ui.txtAddress->text().toStdString().c_str(), startAddress, error))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid Address"), QString::fromStdString(error));
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Invalid Address"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
u64 size;
|
||||
if (!m_cpu->evaluateExpression(m_ui.txtSize->text().toStdString().c_str(), size, error) || !size)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid Size"), QString::fromStdString(error));
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Invalid Size"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,7 +158,7 @@ void BreakpointDialog::accept()
|
||||
PostfixExpression expr;
|
||||
if (!m_cpu->initExpression(m_ui.txtCondition->text().toStdString().c_str(), expr, error))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid Condition"), QString::fromStdString(error));
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Invalid Condition"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
|
||||
#include "BreakpointModel.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Debugger/DebuggerSettingsManager.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
@@ -13,7 +15,6 @@
|
||||
#include "common/Console.h"
|
||||
|
||||
#include <QtCore/QPointer>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -385,7 +386,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
std::string error;
|
||||
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error))
|
||||
{
|
||||
QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error));
|
||||
AsyncDialogs::warning(g_debugger_window, "Condition Error", QString::fromStdString(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -419,7 +420,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
std::string error;
|
||||
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr, error))
|
||||
{
|
||||
QMessageBox::warning(nullptr, "Condition Error", QString::fromStdString(error));
|
||||
AsyncDialogs::warning(g_debugger_window, "Condition Error", QString::fromStdString(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "DebuggerWindow.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "Debugger/DebuggerView.h"
|
||||
#include "Debugger/Docking/DockManager.h"
|
||||
|
||||
@@ -15,8 +16,6 @@
|
||||
#include "MainWindow.h"
|
||||
#include "AnalysisOptionsDialog.h"
|
||||
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
DebuggerWindow* g_debugger_window = nullptr;
|
||||
|
||||
DebuggerWindow::DebuggerWindow(QWidget* parent)
|
||||
@@ -70,19 +69,21 @@ DebuggerWindow::DebuggerWindow(QWidget* parent)
|
||||
});
|
||||
|
||||
connect(m_ui.actionResetAllLayouts, &QAction::triggered, this, [this]() {
|
||||
QString text = tr("Are you sure you want to reset all layouts?");
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
const QString title = tr("Confirmation");
|
||||
const QString text = tr("Are you sure you want to reset all layouts?");
|
||||
|
||||
m_dock_manager->resetAllLayouts();
|
||||
AsyncDialogs::question(this, title, text, [this]() {
|
||||
m_dock_manager->resetAllLayouts();
|
||||
});
|
||||
});
|
||||
|
||||
connect(m_ui.actionResetDefaultLayouts, &QAction::triggered, this, [this]() {
|
||||
QString text = tr("Are you sure you want to reset the default layouts?");
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
const QString title = tr("Confirmation");
|
||||
const QString text = tr("Are you sure you want to reset the default layouts?");
|
||||
|
||||
m_dock_manager->resetDefaultLayouts();
|
||||
AsyncDialogs::question(this, title, text, [this]() {
|
||||
m_dock_manager->resetDefaultLayouts();
|
||||
});
|
||||
});
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onVMPaused, this, []() {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "DisassemblyView.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/JsonValueWrapper.h"
|
||||
#include "Debugger/Breakpoints/BreakpointModel.h"
|
||||
@@ -18,8 +19,6 @@
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include "SymbolTree/NewSymbolDialogs.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
@@ -111,7 +110,7 @@ void DisassemblyView::contextPasteInstructionText()
|
||||
{
|
||||
if (!cpu().isCpuPaused())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Assemble Error"), tr("Unable to change assembly while core is running"));
|
||||
AsyncDialogs::warning(this, tr("Assemble Error"), tr("Unable to change assembly while core is running"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -130,7 +129,7 @@ void DisassemblyView::contextPasteInstructionText()
|
||||
bool valid = MipsAssembleOpcode(newInstructions[instructionIdx].c_str(), &cpu(), replaceAddress, encodedInstruction, errorText);
|
||||
if (!valid)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Assemble Error"), QString("%1 %2").arg(errorText.c_str()).arg(newInstructions[instructionIdx].c_str()));
|
||||
AsyncDialogs::warning(this, tr("Assemble Error"), QString("%1 %2").arg(errorText.c_str()).arg(newInstructions[instructionIdx].c_str()));
|
||||
return;
|
||||
}
|
||||
encodedInstructions.push_back(encodedInstruction);
|
||||
@@ -148,29 +147,28 @@ void DisassemblyView::contextAssembleInstruction()
|
||||
{
|
||||
if (!cpu().isCpuPaused())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Assemble Error"), tr("Unable to change assembly while core is running"));
|
||||
AsyncDialogs::warning(this, tr("Assemble Error"), tr("Unable to change assembly while core is running"));
|
||||
return;
|
||||
}
|
||||
|
||||
DisassemblyLineInfo line;
|
||||
bool ok;
|
||||
m_disassemblyManager.getLine(m_selectedAddressStart, false, line);
|
||||
QString instruction = QInputDialog::getText(this, tr("Assemble Instruction"), "",
|
||||
QLineEdit::Normal, QString("%1 %2").arg(line.name.c_str()).arg(line.params.c_str()), &ok);
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
const QString title = tr("Assemble Instruction");
|
||||
const QString text = QString("%1 %2").arg(line.name.c_str()).arg(line.params.c_str());
|
||||
|
||||
u32 encodedInstruction;
|
||||
std::string errorText;
|
||||
bool valid = MipsAssembleOpcode(instruction.toLocal8Bit().constData(), &cpu(), m_selectedAddressStart, encodedInstruction, errorText);
|
||||
if (!valid)
|
||||
{
|
||||
QMessageBox::warning(this, tr("Assemble Error"), QString::fromStdString(errorText));
|
||||
return;
|
||||
}
|
||||
AsyncDialogs::getText(this, title, "", text, [this](QString instruction) {
|
||||
u32 encodedInstruction;
|
||||
std::string errorText;
|
||||
bool valid = MipsAssembleOpcode(instruction.toLocal8Bit().constData(), &cpu(), m_selectedAddressStart, encodedInstruction, errorText);
|
||||
if (!valid)
|
||||
{
|
||||
AsyncDialogs::warning(this, tr("Assemble Error"), QString::fromStdString(errorText));
|
||||
return;
|
||||
}
|
||||
|
||||
setInstructions(m_selectedAddressStart, m_selectedAddressEnd, encodedInstruction);
|
||||
setInstructions(m_selectedAddressStart, m_selectedAddressEnd, encodedInstruction);
|
||||
});
|
||||
}
|
||||
|
||||
void DisassemblyView::contextNoopInstruction()
|
||||
@@ -249,34 +247,34 @@ void DisassemblyView::contextFollowBranch()
|
||||
|
||||
void DisassemblyView::contextGoToAddress()
|
||||
{
|
||||
bool ok;
|
||||
const QString targetString = QInputDialog::getText(this, tr("Go To In Disassembly"), "",
|
||||
QLineEdit::Normal, "", &ok);
|
||||
const QString title = tr("Go To In Disassembly");
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
AsyncDialogs::getText(this, title, "", "", [this](QString expression) {
|
||||
u64 address = 0;
|
||||
std::string error;
|
||||
if (!cpu().evaluateExpression(expression.toStdString().c_str(), address, error))
|
||||
{
|
||||
AsyncDialogs::warning(this, tr("Cannot Go To"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
u64 address = 0;
|
||||
std::string error;
|
||||
if (!cpu().evaluateExpression(targetString.toStdString().c_str(), address, error))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Cannot Go To"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
gotoAddressAndSetFocus(static_cast<u32>(address) & ~3);
|
||||
gotoAddressAndSetFocus(static_cast<u32>(address) & ~3);
|
||||
});
|
||||
}
|
||||
|
||||
void DisassemblyView::contextAddFunction()
|
||||
{
|
||||
NewFunctionDialog* dialog = new NewFunctionDialog(cpu(), this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->setName(QString("func_%1").arg(m_selectedAddressStart, 8, 16, QChar('0')));
|
||||
dialog->setAddress(m_selectedAddressStart);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (m_selectedAddressEnd != m_selectedAddressStart)
|
||||
dialog->setCustomSize(m_selectedAddressEnd - m_selectedAddressStart + 4);
|
||||
if (dialog->exec() == QDialog::Accepted)
|
||||
update();
|
||||
|
||||
connect(dialog, &QDialog::accepted, this, [this]() { update(); });
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void DisassemblyView::contextCopyFunctionName()
|
||||
@@ -304,28 +302,26 @@ void DisassemblyView::contextRemoveFunction()
|
||||
void DisassemblyView::contextRenameFunction()
|
||||
{
|
||||
const FunctionInfo curFunc = cpu().GetSymbolGuardian().FunctionOverlappingAddress(m_selectedAddressStart);
|
||||
|
||||
if (!curFunc.address.valid())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Rename Function Error"), tr("No function / symbol is currently selected."));
|
||||
AsyncDialogs::warning(this, tr("Rename Function Error"), tr("No function / symbol is currently selected."));
|
||||
return;
|
||||
}
|
||||
|
||||
QString oldName = QString::fromStdString(curFunc.name);
|
||||
const QString title = tr("Rename Function");
|
||||
const QString label = tr("Function name");
|
||||
const QString oldName = QString::fromStdString(curFunc.name);
|
||||
|
||||
bool ok;
|
||||
QString newName = QInputDialog::getText(this, tr("Rename Function"), tr("Function name"), QLineEdit::Normal, oldName, &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
AsyncDialogs::getText(this, title, label, oldName, [this, curFunc](QString newName) {
|
||||
if (newName.isEmpty())
|
||||
{
|
||||
AsyncDialogs::warning(this, tr("Rename Function Error"), tr("Function name cannot be nothing."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (newName.isEmpty())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Rename Function Error"), tr("Function name cannot be nothing."));
|
||||
return;
|
||||
}
|
||||
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
database.functions.rename_symbol(curFunc.handle, newName.toStdString());
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
database.functions.rename_symbol(curFunc.handle, newName.toStdString());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -375,7 +371,7 @@ void DisassemblyView::contextRestoreFunction()
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Restore Function Error"), tr("Unable to stub selected address."));
|
||||
AsyncDialogs::warning(this, tr("Restore Function Error"), tr("Unable to stub selected address."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public slots:
|
||||
void contextCopyInstructionHex();
|
||||
void contextCopyInstructionText();
|
||||
void contextCopyFunctionName();
|
||||
void contextPasteInstructionText();
|
||||
void contextPasteInstructionText();
|
||||
void contextAssembleInstruction();
|
||||
void contextNoopInstruction();
|
||||
void contextRestoreInstruction();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "DockManager.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "Debugger/DebuggerView.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/Docking/DockTables.h"
|
||||
@@ -24,7 +25,6 @@
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QtTranslation>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QProxyStyle>
|
||||
#include <QtWidgets/QStyleFactory>
|
||||
|
||||
@@ -518,17 +518,19 @@ void DockManager::newLayoutClicked()
|
||||
if (m_menu_bar)
|
||||
m_menu_bar->onCurrentLayoutChanged(m_current_layout);
|
||||
|
||||
auto name_validator = [this](const QString& name) {
|
||||
const auto name_validator = [this](const QString& name) {
|
||||
return !hasNameConflict(name, DockLayout::INVALID_INDEX);
|
||||
};
|
||||
|
||||
bool can_clone_current_layout = m_current_layout != DockLayout::INVALID_INDEX;
|
||||
const bool can_clone_current_layout = m_current_layout != DockLayout::INVALID_INDEX;
|
||||
|
||||
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
|
||||
name_validator, can_clone_current_layout, g_debugger_window);
|
||||
LayoutEditorDialog* dialog = new LayoutEditorDialog(name_validator, can_clone_current_layout, g_debugger_window);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
connect(dialog, &QDialog::accepted, this, [this, dialog, name_validator]() {
|
||||
if (!name_validator(dialog->name()))
|
||||
return;
|
||||
|
||||
if (dialog->exec() == QDialog::Accepted && name_validator(dialog->name()))
|
||||
{
|
||||
DockLayout::Index new_layout = DockLayout::INVALID_INDEX;
|
||||
|
||||
const auto [mode, index] = dialog->initialState();
|
||||
@@ -565,9 +567,9 @@ void DockManager::newLayoutClicked()
|
||||
updateLayoutSwitcher();
|
||||
switchToLayout(new_layout);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
delete dialog.get();
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void DockManager::openLayoutSwitcherContextMenu(const QPoint& pos, QTabBar* layout_switcher)
|
||||
@@ -605,26 +607,33 @@ void DockManager::editLayoutClicked(DockLayout::Index layout_index)
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
const DockLayout& layout = m_layouts[layout_index];
|
||||
|
||||
auto name_validator = [this, layout_index](const QString& name) {
|
||||
const auto name_validator = [this, layout_index](const QString& name) {
|
||||
return !hasNameConflict(name, layout_index);
|
||||
};
|
||||
|
||||
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
|
||||
layout.name(), layout.cpu(), name_validator, g_debugger_window);
|
||||
LayoutEditorDialog* dialog = new LayoutEditorDialog(layout.name(), layout.cpu(), name_validator, g_debugger_window);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
if (dialog->exec() != QDialog::Accepted || !name_validator(dialog->name()))
|
||||
return;
|
||||
connect(dialog, &QDialog::accepted, this, [this, layout_index, dialog, name_validator]() {
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
layout.setName(dialog->name());
|
||||
layout.setCpu(dialog->cpu());
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
|
||||
layout.save(layout_index);
|
||||
if (!name_validator(dialog->name()))
|
||||
return;
|
||||
|
||||
delete dialog.get();
|
||||
layout.setName(dialog->name());
|
||||
layout.setCpu(dialog->cpu());
|
||||
|
||||
updateLayoutSwitcher();
|
||||
layout.save(layout_index);
|
||||
|
||||
updateLayoutSwitcher();
|
||||
});
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
void DockManager::resetLayoutClicked(DockLayout::Index layout_index)
|
||||
@@ -636,20 +645,28 @@ void DockManager::resetLayoutClicked(DockLayout::Index layout_index)
|
||||
if (!layout.canReset())
|
||||
return;
|
||||
|
||||
QString text = tr("Are you sure you want to reset layout '%1'?").arg(layout.name());
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
const QString title = tr("Confirmation");
|
||||
const QString text = tr("Are you sure you want to reset layout '%1'?").arg(layout.name());
|
||||
|
||||
bool current_layout = layout_index == m_current_layout;
|
||||
AsyncDialogs::question(g_debugger_window, title, text, [this, layout_index]() {
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
if (current_layout)
|
||||
switchToLayout(DockLayout::INVALID_INDEX);
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
if (!layout.canReset())
|
||||
return;
|
||||
|
||||
layout.reset();
|
||||
layout.save(layout_index);
|
||||
bool current_layout = layout_index == m_current_layout;
|
||||
|
||||
if (current_layout)
|
||||
switchToLayout(layout_index);
|
||||
if (current_layout)
|
||||
switchToLayout(DockLayout::INVALID_INDEX);
|
||||
|
||||
layout.reset();
|
||||
layout.save(layout_index);
|
||||
|
||||
if (current_layout)
|
||||
switchToLayout(layout_index);
|
||||
});
|
||||
}
|
||||
|
||||
void DockManager::deleteLayoutClicked(DockLayout::Index layout_index)
|
||||
@@ -659,12 +676,16 @@ void DockManager::deleteLayoutClicked(DockLayout::Index layout_index)
|
||||
|
||||
DockLayout& layout = m_layouts[layout_index];
|
||||
|
||||
QString text = tr("Are you sure you want to delete layout '%1'?").arg(layout.name());
|
||||
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
|
||||
return;
|
||||
const QString title = tr("Confirmation");
|
||||
const QString text = tr("Are you sure you want to delete layout '%1'?").arg(layout.name());
|
||||
|
||||
deleteLayout(layout_index);
|
||||
updateLayoutSwitcher();
|
||||
AsyncDialogs::question(g_debugger_window, title, text, [this, layout_index]() {
|
||||
if (layout_index >= m_layouts.size())
|
||||
return;
|
||||
|
||||
deleteLayout(layout_index);
|
||||
updateLayoutSwitcher();
|
||||
});
|
||||
}
|
||||
|
||||
void DockManager::layoutSwitcherTabMoved(DockLayout::Index from_index, DockLayout::Index to_index)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "DockViews.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Debugger/DebuggerView.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
@@ -17,8 +18,6 @@
|
||||
|
||||
#include <QtGui/QActionGroup>
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QStyleFactory>
|
||||
|
||||
@@ -176,19 +175,22 @@ void DockTabBar::openContextMenu(QPoint pos)
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
bool ok;
|
||||
QString new_name = QInputDialog::getText(
|
||||
this, tr("Rename Window"), tr("New name:"), QLineEdit::Normal, widget->displayNameWithoutSuffix(), &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
const QString title = tr("Rename Window");
|
||||
const QString label = tr("New name:");
|
||||
const QString text = widget->displayNameWithoutSuffix();
|
||||
|
||||
if (!widget->setCustomDisplayName(new_name))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid Name"), tr("The specified name is too long."));
|
||||
return;
|
||||
}
|
||||
AsyncDialogs::getText(this, title, label, text, [this, widget = QPointer(widget)](QString name) {
|
||||
if (!widget || !g_debugger_window)
|
||||
return;
|
||||
|
||||
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||
if (!widget->setCustomDisplayName(name))
|
||||
{
|
||||
AsyncDialogs::warning(this, tr("Invalid Name"), tr("The specified name is too long."));
|
||||
return;
|
||||
}
|
||||
|
||||
g_debugger_window->dockManager().updateDockWidgetTitles();
|
||||
});
|
||||
});
|
||||
|
||||
QAction* reset_name_action = menu->addAction(tr("Reset Name"));
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
#include "MemorySearchView.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
#include <QtGui/QPainter>
|
||||
@@ -478,7 +478,7 @@ void MemorySearchView::onSearchButtonClicked()
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("Invalid start address"));
|
||||
AsyncDialogs::critical(this, tr("Debugger"), tr("Invalid start address"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -486,13 +486,13 @@ void MemorySearchView::onSearchButtonClicked()
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("Invalid end address"));
|
||||
AsyncDialogs::critical(this, tr("Debugger"), tr("Invalid end address"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (searchStart >= searchEnd)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("Start address can't be equal to or greater than the end address"));
|
||||
AsyncDialogs::critical(this, tr("Debugger"), tr("Start address can't be equal to or greater than the end address"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -527,7 +527,7 @@ void MemorySearchView::onSearchButtonClicked()
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("Invalid search value"));
|
||||
AsyncDialogs::critical(this, tr("Debugger"), tr("Invalid search value"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -551,7 +551,7 @@ void MemorySearchView::onSearchButtonClicked()
|
||||
if (value <= std::numeric_limits<unsigned char>::max())
|
||||
break;
|
||||
default:
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("Value is larger than type"));
|
||||
AsyncDialogs::critical(this, tr("Debugger"), tr("Value is larger than type"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -565,7 +565,7 @@ void MemorySearchView::onSearchButtonClicked()
|
||||
searchComparison == SearchComparison::IncreasedBy ||
|
||||
searchComparison == SearchComparison::NotChanged))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("This search comparison can only be used with filter searches."));
|
||||
AsyncDialogs::critical(this, tr("Debugger"), tr("This search comparison can only be used with filter searches."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -578,7 +578,7 @@ void MemorySearchView::onSearchButtonClicked()
|
||||
searchComparison == SearchComparison::IncreasedBy ||
|
||||
searchComparison == SearchComparison::NotChanged))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("This search comparison can only be used with filter searches."));
|
||||
AsyncDialogs::critical(this, tr("Debugger"), tr("This search comparison can only be used with filter searches."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "MemoryView.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "Debugger/JsonValueWrapper.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
@@ -12,8 +13,6 @@
|
||||
#include <QtGui/QActionGroup>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
using namespace QtUtils;
|
||||
|
||||
@@ -305,36 +304,33 @@ bool MemoryViewTable::InsertFloatIntoSelectedHexView(DebugInterface& cpu)
|
||||
std::memcpy(¤tFloatVal, ¤tIntVal, sizeof(currentFloatVal));
|
||||
const QString currentfloatStr = QString("%1").arg(QString::number(currentFloatVal, 'g'), 14).trimmed();
|
||||
|
||||
// Prompt user to enter a new float value
|
||||
bool isValidInput = false;
|
||||
QString newFloatStr = QInputDialog::getText(parent, tr("Input New Float"), "",
|
||||
QLineEdit::Normal, currentfloatStr, &isValidInput);
|
||||
if (!isValidInput)
|
||||
return false;
|
||||
const QString title = tr("Input New Float");
|
||||
|
||||
// Convert string into float value
|
||||
bool isValidFloat = false;
|
||||
const float newFloatVal = newFloatStr.toFloat(&isValidFloat);
|
||||
if (!isValidFloat)
|
||||
{
|
||||
QMessageBox::warning(parent, tr("Input Error"), tr("Invalid float value"));
|
||||
return false;
|
||||
}
|
||||
AsyncDialogs::getText(parent, title, "", currentfloatStr, [this, &cpu](QString newFloatStr) {
|
||||
// Convert string into float value
|
||||
bool isValidFloat = false;
|
||||
const float newFloatVal = newFloatStr.toFloat(&isValidFloat);
|
||||
if (!isValidFloat)
|
||||
{
|
||||
AsyncDialogs::warning(parent, tr("Input Error"), tr("Invalid float value"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Write new float value back to memory
|
||||
u32 newIntVal = 0;
|
||||
std::memcpy(&newIntVal, &newFloatVal, sizeof(newIntVal));
|
||||
newIntVal = convertEndian(newIntVal);
|
||||
// Write new float value back to memory
|
||||
u32 newIntVal = 0;
|
||||
std::memcpy(&newIntVal, &newFloatVal, sizeof(newIntVal));
|
||||
newIntVal = convertEndian(newIntVal);
|
||||
|
||||
const QPointer<MemoryViewTable> table(this);
|
||||
Host::RunOnCPUThread([table, address = selectedAddress, &cpu, val = newIntVal] {
|
||||
cpu.write32(address, val);
|
||||
const QPointer<MemoryViewTable> table(this);
|
||||
Host::RunOnCPUThread([table, address = selectedAddress, &cpu, val = newIntVal] {
|
||||
cpu.write32(address, val);
|
||||
|
||||
QtHost::RunOnUIThread([table] {
|
||||
if (!table)
|
||||
return;
|
||||
QtHost::RunOnUIThread([table] {
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
table->parent->update();
|
||||
table->parent->update();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -353,7 +349,7 @@ void MemoryViewTable::InsertAtCurrentSelection(const QString& text, DebugInterfa
|
||||
const float newFloatVal = text.toFloat(&isValidFloat);
|
||||
if (!isValidFloat)
|
||||
{
|
||||
QMessageBox::warning(parent, tr("Input Error"), tr("Invalid float value"));
|
||||
AsyncDialogs::warning(parent, tr("Input Error"), tr("Invalid float value"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -899,22 +895,19 @@ void MemoryView::contextPaste()
|
||||
|
||||
void MemoryView::contextGoToAddress()
|
||||
{
|
||||
bool ok;
|
||||
QString targetString = QInputDialog::getText(this, tr("Go To In Memory View"), "",
|
||||
QLineEdit::Normal, "", &ok);
|
||||
const QString title = tr("Go To In Memory View");
|
||||
|
||||
if (!ok)
|
||||
return;
|
||||
AsyncDialogs::getText(this, title, "", "", [this](QString expression) {
|
||||
u64 address = 0;
|
||||
std::string error;
|
||||
if (!cpu().evaluateExpression(expression.toStdString().c_str(), address, error))
|
||||
{
|
||||
AsyncDialogs::warning(this, tr("Cannot Go To"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
u64 address = 0;
|
||||
std::string error;
|
||||
if (!cpu().evaluateExpression(targetString.toStdString().c_str(), address, error))
|
||||
{
|
||||
QMessageBox::warning(this, tr("Cannot Go To"), QString::fromStdString(error));
|
||||
return;
|
||||
}
|
||||
|
||||
gotoAddress(static_cast<u32>(address));
|
||||
gotoAddress(static_cast<u32>(address));
|
||||
});
|
||||
}
|
||||
|
||||
void MemoryView::contextFollowAddress()
|
||||
|
||||
@@ -30,7 +30,8 @@ SavedAddressesView::SavedAddressesView(const DebuggerViewParameters& parameters)
|
||||
DebuggerSettingsManager::loadGameSettings(m_model);
|
||||
});
|
||||
|
||||
DebuggerSettingsManager::loadGameSettings(m_model);
|
||||
if (m_model->rowCount() == 0)
|
||||
DebuggerSettingsManager::loadGameSettings(m_model);
|
||||
|
||||
for (std::size_t i = 0; auto mode : SavedAddressesModel::HeaderResizeModes)
|
||||
{
|
||||
|
||||
@@ -101,7 +101,7 @@ QVariant ModuleModel::headerData(int section, Qt::Orientation orientation, int r
|
||||
//: Warning: short space limit. Abbreviate if needed.
|
||||
return tr("NAME");
|
||||
case ModuleColumns::VERSION:
|
||||
//: Warning: short space limit. Abbreviate if needed.
|
||||
//: Warning: short space limit. Abbreviate if needed.
|
||||
return tr("VERSION");
|
||||
case ModuleColumns::ENTRY:
|
||||
//: Warning: short space limit. Abbreviate if needed. // Entrypoint of the executable
|
||||
|
||||
@@ -3,17 +3,16 @@
|
||||
|
||||
#include "RegisterView.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Debugger/JsonValueWrapper.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtWidgets/QTabBar>
|
||||
#include <QtWidgets/QStylePainter>
|
||||
#include <QtWidgets/QStyleOptionTab>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QProxyStyle>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
#include <bit>
|
||||
|
||||
@@ -351,12 +350,11 @@ void RegisterView::contextCopySegment()
|
||||
QApplication::clipboard()->setText(FilledQStringFromValue(val._u32[3 - m_selected128Field], 16));
|
||||
}
|
||||
|
||||
bool RegisterView::contextFetchNewValue(u64& out, u64 currentValue, bool segment)
|
||||
void RegisterView::fetchNewValue(u64 currentValue, bool segment, std::function<void(u64)> callback)
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
const bool floatingPoint = CAT_SHOW_FLOAT && segment;
|
||||
const int regSize = cpu().getRegisterSize(categoryIndex);
|
||||
bool ok = false;
|
||||
|
||||
QString existingValue("%1");
|
||||
|
||||
@@ -366,79 +364,89 @@ bool RegisterView::contextFetchNewValue(u64& out, u64 currentValue, bool segment
|
||||
existingValue = existingValue.arg(std::bit_cast<float>((u32)currentValue));
|
||||
|
||||
//: Changing the value in a CPU register (e.g. "Change t0")
|
||||
QString input = QInputDialog::getText(this, tr("Change %1").arg(cpu().getRegisterName(categoryIndex, m_selectedRow)), "",
|
||||
QLineEdit::Normal, existingValue, &ok);
|
||||
const QString title = tr("Change %1").arg(cpu().getRegisterName(categoryIndex, m_selectedRow));
|
||||
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
if (!floatingPoint) // Get input as hexadecimal
|
||||
{
|
||||
out = input.toULongLong(&ok, 16);
|
||||
if (!ok)
|
||||
AsyncDialogs::getText(this, title, "", existingValue, [this, callback, floatingPoint](QString input) {
|
||||
u64 value;
|
||||
if (!floatingPoint) // Get input as hexadecimal
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid register value"), tr("Invalid hexadecimal register value."));
|
||||
return false;
|
||||
bool ok;
|
||||
value = input.toULongLong(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
AsyncDialogs::warning(this, tr("Invalid register value"), tr("Invalid hexadecimal register value."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out = std::bit_cast<u32>(input.toFloat(&ok));
|
||||
if (!ok)
|
||||
else
|
||||
{
|
||||
QMessageBox::warning(this, tr("Invalid register value"), tr("Invalid floating-point register value."));
|
||||
return false;
|
||||
bool ok;
|
||||
value = std::bit_cast<u32>(input.toFloat(&ok));
|
||||
if (!ok)
|
||||
{
|
||||
AsyncDialogs::warning(this, tr("Invalid register value"), tr("Invalid floating-point register value."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
callback(value);
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterView::contextChangeValue()
|
||||
{
|
||||
const int categoryIndex = ui.registerTabs->currentIndex();
|
||||
u64 newVal;
|
||||
if (contextFetchNewValue(newVal, cpu().getRegister(categoryIndex, m_selectedRow).lo))
|
||||
{
|
||||
cpu().setRegister(categoryIndex, m_selectedRow, u128::From64(newVal));
|
||||
const int category_index = ui.registerTabs->currentIndex();
|
||||
const s32 row = m_selectedRow;
|
||||
const u32 old_value = cpu().getRegister(category_index, row).lo;
|
||||
|
||||
fetchNewValue(old_value, false, [this, category_index, row](u64 input) {
|
||||
cpu().setRegister(category_index, row, u128::From64(input));
|
||||
DebuggerView::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterView::contextChangeTop()
|
||||
{
|
||||
u64 newVal;
|
||||
u128 oldVal = cpu().getRegister(ui.registerTabs->currentIndex(), m_selectedRow);
|
||||
if (contextFetchNewValue(newVal, oldVal.hi))
|
||||
{
|
||||
oldVal.hi = newVal;
|
||||
cpu().setRegister(ui.registerTabs->currentIndex(), m_selectedRow, oldVal);
|
||||
const int category_index = ui.registerTabs->currentIndex();
|
||||
const s32 row = m_selectedRow;
|
||||
const u128 old_value = cpu().getRegister(category_index, row);
|
||||
|
||||
fetchNewValue(old_value.hi, false, [this, category_index, row, old_value](u32 input) {
|
||||
u128 new_value = old_value;
|
||||
new_value.hi = input;
|
||||
cpu().setRegister(category_index, row, new_value);
|
||||
DebuggerView::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterView::contextChangeBottom()
|
||||
{
|
||||
u64 newVal;
|
||||
u128 oldVal = cpu().getRegister(ui.registerTabs->currentIndex(), m_selectedRow);
|
||||
if (contextFetchNewValue(newVal, oldVal.lo))
|
||||
{
|
||||
oldVal.lo = newVal;
|
||||
cpu().setRegister(ui.registerTabs->currentIndex(), m_selectedRow, oldVal);
|
||||
const int category_index = ui.registerTabs->currentIndex();
|
||||
const s32 row = m_selectedRow;
|
||||
const u128 old_value = cpu().getRegister(category_index, row);
|
||||
|
||||
fetchNewValue(old_value.lo, false, [this, category_index, row, old_value](u32 input) {
|
||||
u128 new_value = old_value;
|
||||
new_value.lo = input;
|
||||
cpu().setRegister(category_index, row, new_value);
|
||||
DebuggerView::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterView::contextChangeSegment()
|
||||
{
|
||||
u64 newVal;
|
||||
u128 oldVal = cpu().getRegister(ui.registerTabs->currentIndex(), m_selectedRow);
|
||||
if (contextFetchNewValue(newVal, oldVal._u32[3 - m_selected128Field], true))
|
||||
{
|
||||
oldVal._u32[3 - m_selected128Field] = (u32)newVal;
|
||||
cpu().setRegister(ui.registerTabs->currentIndex(), m_selectedRow, oldVal);
|
||||
const int category_index = ui.registerTabs->currentIndex();
|
||||
const s32 row = m_selectedRow;
|
||||
const s32 field = m_selected128Field;
|
||||
const u128 old_value = cpu().getRegister(category_index, row);
|
||||
const u32 segment = old_value._u32[3 - field];
|
||||
|
||||
fetchNewValue(segment, false, [this, category_index, row, field, old_value](u32 input) {
|
||||
u128 new_value = old_value;
|
||||
new_value._u32[3 - field] = input;
|
||||
cpu().setRegister(category_index, row, new_value);
|
||||
DebuggerView::broadcastEvent(DebuggerEvents::VMUpdate());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<DebuggerEvents::GoToAddress> RegisterView::contextCreateGotoEvent()
|
||||
@@ -454,7 +462,7 @@ std::optional<DebuggerEvents::GoToAddress> RegisterView::contextCreateGotoEvent(
|
||||
|
||||
if (!cpu().isValidAddress(addr))
|
||||
{
|
||||
QMessageBox::warning(
|
||||
AsyncDialogs::warning(
|
||||
this,
|
||||
tr("Invalid target address"),
|
||||
tr("This register holds an invalid address."));
|
||||
|
||||
@@ -49,8 +49,7 @@ public slots:
|
||||
private:
|
||||
Ui::RegisterView ui;
|
||||
|
||||
// Returns true on success
|
||||
bool contextFetchNewValue(u64& out, u64 currentValue, bool segment = false);
|
||||
void fetchNewValue(u64 currentValue, bool segment, std::function<void(u64)> callback);
|
||||
|
||||
// Used for the height offset the tab bar creates
|
||||
// because we share a widget
|
||||
|
||||
@@ -25,8 +25,7 @@ public:
|
||||
COLUMN_COUNT
|
||||
};
|
||||
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[StackColumns::COLUMN_COUNT] =
|
||||
{
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[StackColumns::COLUMN_COUNT] = {
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::Stretch,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
#include "NewSymbolDialogs.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
#include "Debugger/SymbolTree/TypeString.h"
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QMetaMethod>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
#include "TypeString.h"
|
||||
|
||||
NewSymbolDialog::NewSymbolDialog(u32 flags, u32 alignment, DebugInterface& cpu, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_cpu(cpu)
|
||||
@@ -359,7 +360,7 @@ void NewFunctionDialog::createSymbol()
|
||||
});
|
||||
|
||||
if (!error_message.isEmpty())
|
||||
QMessageBox::warning(this, tr("Cannot Create Function"), error_message);
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Cannot Create Function"), error_message);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
@@ -416,7 +417,7 @@ void NewGlobalVariableDialog::createSymbol()
|
||||
});
|
||||
|
||||
if (!error_message.isEmpty())
|
||||
QMessageBox::warning(this, tr("Cannot Create Global Variable"), error_message);
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Cannot Create Global Variable"), error_message);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
@@ -534,7 +535,7 @@ void NewLocalVariableDialog::createSymbol()
|
||||
});
|
||||
|
||||
if (!error_message.isEmpty())
|
||||
QMessageBox::warning(this, tr("Cannot Create Local Variable"), error_message);
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Cannot Create Local Variable"), error_message);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
@@ -648,5 +649,5 @@ void NewParameterVariableDialog::createSymbol()
|
||||
});
|
||||
|
||||
if (!error_message.isEmpty())
|
||||
QMessageBox::warning(this, tr("Cannot Create Parameter Variable"), error_message);
|
||||
AsyncDialogs::warning(g_debugger_window, tr("Cannot Create Parameter Variable"), error_message);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "SymbolTreeDelegates.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "Debugger/SymbolTree/SymbolTreeModel.h"
|
||||
#include "Debugger/SymbolTree/TypeString.h"
|
||||
|
||||
@@ -10,7 +11,6 @@
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QDoubleSpinBox>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
SymbolTreeValueDelegate::SymbolTreeValueDelegate(
|
||||
DebugInterface& cpu,
|
||||
@@ -495,7 +495,7 @@ void SymbolTreeTypeDelegate::setModelData(QWidget* editor, QAbstractItemModel* m
|
||||
symbol_tree_model->resetChildren(index);
|
||||
}
|
||||
else
|
||||
QMessageBox::warning(editor, tr("Cannot Change Type"), error_message);
|
||||
AsyncDialogs::warning(editor, tr("Cannot Change Type"), error_message);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
@@ -19,7 +19,7 @@ struct SymbolTreeLocation
|
||||
MEMORY,
|
||||
NONE // Put NONE last so nodes of this type sort to the bottom.
|
||||
};
|
||||
|
||||
|
||||
Type type = NONE;
|
||||
u32 address = 0;
|
||||
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
|
||||
#include "SymbolTreeViews.h"
|
||||
|
||||
#include "AsyncDialogs.h"
|
||||
#include "Debugger/JsonValueWrapper.h"
|
||||
#include "Debugger/SymbolTree/NewSymbolDialogs.h"
|
||||
#include "Debugger/SymbolTree/SymbolTreeDelegates.h"
|
||||
|
||||
#include <QtGui/QActionGroup>
|
||||
#include <QtGui/QClipboard>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
|
||||
static bool testName(const QString& name, const QString& filter);
|
||||
@@ -643,14 +642,16 @@ void SymbolTreeView::onDeleteButtonPressed()
|
||||
if (!node->symbol.valid())
|
||||
return;
|
||||
|
||||
if (QMessageBox::question(this, tr("Confirm Deletion"), tr("Delete '%1'?").arg(node->name)) != QMessageBox::Yes)
|
||||
return;
|
||||
const QString title = tr("Confirm Deletion");
|
||||
const QString text = tr("Delete '%1'?").arg(node->name);
|
||||
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
node->symbol.destroy_symbol(database, true);
|
||||
AsyncDialogs::question(this, title, text, [this, handle = node->symbol]() {
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
handle.destroy_symbol(database, true);
|
||||
});
|
||||
|
||||
reset();
|
||||
});
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void SymbolTreeView::onCopyName()
|
||||
@@ -701,13 +702,10 @@ void SymbolTreeView::onRenameSymbol()
|
||||
text = QString::fromStdString(symbol->name());
|
||||
});
|
||||
|
||||
bool ok;
|
||||
std::string name = QInputDialog::getText(this, title, label, QLineEdit::Normal, text, &ok).toStdString();
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
node->symbol.rename_symbol(name, database);
|
||||
AsyncDialogs::getText(this, title, label, text, [this, handle = node->symbol](QString new_name) {
|
||||
cpu().GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||
handle.rename_symbol(new_name.toStdString(), database);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -737,18 +735,15 @@ void SymbolTreeView::onChangeTypeTemporarily()
|
||||
std::optional<QString> old_type = m_model->typeFromModelIndexToString(index);
|
||||
if (!old_type.has_value())
|
||||
{
|
||||
QMessageBox::warning(this, tr("Cannot Change Type"), tr("That node cannot have a type."));
|
||||
AsyncDialogs::warning(this, tr("Cannot Change Type"), tr("That node cannot have a type."));
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QString type_string = QInputDialog::getText(this, title, label, QLineEdit::Normal, *old_type, &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
|
||||
std::optional<QString> error_message = m_model->changeTypeTemporarily(index, type_string.toStdString());
|
||||
if (error_message.has_value() && !error_message->isEmpty())
|
||||
QMessageBox::warning(this, tr("Cannot Change Type"), *error_message);
|
||||
AsyncDialogs::getText(this, title, label, *old_type, [this, index](QString type_string) {
|
||||
std::optional<QString> error_message = m_model->changeTypeTemporarily(index, type_string.toStdString());
|
||||
if (error_message.has_value() && !error_message->isEmpty())
|
||||
AsyncDialogs::warning(this, tr("Cannot Change Type"), *error_message);
|
||||
});
|
||||
}
|
||||
|
||||
void SymbolTreeView::onTreeViewClicked(const QModelIndex& index)
|
||||
@@ -862,8 +857,10 @@ void FunctionTreeView::onNewButtonPressed()
|
||||
{
|
||||
NewFunctionDialog* dialog = new NewFunctionDialog(cpu(), this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
if (dialog->exec() == QDialog::Accepted)
|
||||
reset();
|
||||
|
||||
connect(dialog, &QDialog::accepted, this, &FunctionTreeView::reset);
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
@@ -1005,8 +1002,10 @@ void GlobalVariableTreeView::onNewButtonPressed()
|
||||
{
|
||||
NewGlobalVariableDialog* dialog = new NewGlobalVariableDialog(cpu(), this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
if (dialog->exec() == QDialog::Accepted)
|
||||
reset();
|
||||
|
||||
connect(dialog, &QDialog::accepted, this, &GlobalVariableTreeView::reset);
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
@@ -1134,8 +1133,10 @@ void LocalVariableTreeView::onNewButtonPressed()
|
||||
{
|
||||
NewLocalVariableDialog* dialog = new NewLocalVariableDialog(cpu(), this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
if (dialog->exec() == QDialog::Accepted)
|
||||
reset();
|
||||
|
||||
connect(dialog, &QDialog::accepted, this, &LocalVariableTreeView::reset);
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
@@ -1261,8 +1262,10 @@ void ParameterVariableTreeView::onNewButtonPressed()
|
||||
{
|
||||
NewParameterVariableDialog* dialog = new NewParameterVariableDialog(cpu(), this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
if (dialog->exec() == QDialog::Accepted)
|
||||
reset();
|
||||
|
||||
connect(dialog, &QDialog::accepted, this, &ParameterVariableTreeView::reset);
|
||||
|
||||
dialog->open();
|
||||
}
|
||||
|
||||
static bool testName(const QString& name, const QString& filter)
|
||||
|
||||
@@ -27,8 +27,7 @@ public:
|
||||
COLUMN_COUNT
|
||||
};
|
||||
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[ThreadColumns::COLUMN_COUNT] =
|
||||
{
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[ThreadColumns::COLUMN_COUNT] = {
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
|
||||
@@ -479,8 +479,15 @@ bool DisplaySurface::eventFilter(QObject* object, QEvent* event)
|
||||
// macOS: When we (the display window) get focus from another window with a toolbar we update to the MainWindow toolbar.
|
||||
// This is because we are a different native window from our MainWindow. So, whenever we get focus, focus our MainWindow.
|
||||
// That way macOS will show the MainWindow toolbar when you click from the debugger / log window to the game.
|
||||
if (auto* w = qobject_cast<QWidget*>(object))
|
||||
|
||||
// Don't try to steal focus when we're showing a modal dialog
|
||||
// We end up ping ponging focus in a feedback loop
|
||||
if (QApplication::activeModalWidget() != nullptr)
|
||||
return false;
|
||||
|
||||
if (const auto* w = qobject_cast<QWidget*>(object))
|
||||
w->window()->activateWindow();
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@@ -160,7 +160,6 @@ void GameListModel::loadOrGenerateCover(const GameList::Entry* ge)
|
||||
|
||||
// Final check that scale is unchanged before we send out the produced image.
|
||||
return m_cover_scale_counter.load(std::memory_order_acquire) == counter ? image : QPixmap();
|
||||
|
||||
});
|
||||
|
||||
// Context must be 'this' so we run on the UI thread.
|
||||
@@ -221,7 +220,7 @@ QString GameListModel::formatTimespan(const time_t timespan)
|
||||
const u32 hours = static_cast<u32>(timespan / 3600);
|
||||
if (hours > 0)
|
||||
return qApp->translate("GameList", "%n hours", "", hours);
|
||||
|
||||
|
||||
const u32 minutes = static_cast<u32>((timespan % 3600) / 60);
|
||||
if (minutes > 0)
|
||||
return qApp->translate("GameList", "%n minutes", "", minutes);
|
||||
|
||||
@@ -282,7 +282,7 @@ void GameListWidget::initialize()
|
||||
connect(m_table_view, &QTableView::customContextMenuRequested, this,
|
||||
&GameListWidget::onTableViewContextMenuRequested);
|
||||
connect(m_table_view->horizontalHeader(), &QHeaderView::customContextMenuRequested, this,
|
||||
&GameListWidget::onTableViewHeaderContextMenuRequested);
|
||||
&GameListWidget::onTableViewHeaderContextMenuRequested);
|
||||
|
||||
// Save state when header state changes (hiding and showing handled within onTableViewHeaderContextMenuRequested).
|
||||
connect(m_table_view->horizontalHeader(), &QHeaderView::sectionMoved, this, &GameListWidget::onTableHeaderStateChanged);
|
||||
@@ -292,13 +292,27 @@ void GameListWidget::initialize()
|
||||
|
||||
// Load the last session's header state or create a new one.
|
||||
if (Host::ContainsBaseSettingValue("GameListTableView", "HeaderState"))
|
||||
{
|
||||
loadTableHeaderState();
|
||||
// Enforce at least one column is visible immediately after loading.
|
||||
// This handles cases where a config (perhaps from an older version) has 0 columns and
|
||||
// no games are visible to be changed (such as per-game config) or played as you can't click on any.
|
||||
// Will automatically repair a broken header state from config (PCSX2.ini) file.
|
||||
ensureMinimumOneColumnVisible();
|
||||
}
|
||||
else
|
||||
{
|
||||
applyTableHeaderDefaults();
|
||||
}
|
||||
|
||||
// After header state load to account for user-specified sort.
|
||||
m_table_view->setSortingEnabled(true);
|
||||
|
||||
// Safety Fallback: Ensure the header is actually visible and
|
||||
// force it to stretch correctly on the first launch. This is an edgecase in case it already broke for some people or broke on older versions
|
||||
m_table_view->horizontalHeader()->show();
|
||||
resizeTableViewColumnsToFit();
|
||||
|
||||
m_ui.stack->insertWidget(0, m_table_view);
|
||||
|
||||
m_list_view = new GameListGridListView(m_ui.stack);
|
||||
@@ -408,7 +422,7 @@ void GameListWidget::setCustomBackground()
|
||||
// Selected Custom background is valid, connect the signals and start animation in gamelist
|
||||
connect(m_background_movie, &QMovie::frameChanged, this, &GameListWidget::processBackgroundFrames, Qt::UniqueConnection);
|
||||
m_ui.stack->setAutoFillBackground(false);
|
||||
|
||||
|
||||
m_table_view->viewport()->setAutoFillBackground(false);
|
||||
m_list_view->viewport()->setAutoFillBackground(false);
|
||||
updateCustomBackgroundState(true);
|
||||
@@ -562,30 +576,35 @@ void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
|
||||
|
||||
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
|
||||
{
|
||||
QMenu menu;
|
||||
QHeaderView* header = m_table_view->horizontalHeader();
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
int column_visual = 0;
|
||||
QHeaderView* const header = m_table_view->horizontalHeader();
|
||||
QMenu menu(this);
|
||||
// Iterate through all available columns defined in the model.
|
||||
for (int column = 0; column < GameListModel::Column_Count; column++)
|
||||
{
|
||||
// The "cover" column is the game grid and cannot be hidden.
|
||||
// Skip the cover art column as it shouldn't be toggled manually.
|
||||
if (column == GameListModel::Column_Cover)
|
||||
continue;
|
||||
|
||||
column_visual = header->visualIndex(column);
|
||||
QAction* action = menu.addAction(m_model->getColumnDisplayName(column_visual));
|
||||
// Create a checkable menu item for each column title.
|
||||
const QString title = m_model->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
|
||||
QAction* const action = menu.addAction(title);
|
||||
action->setCheckable(true);
|
||||
action->setChecked(!m_table_view->isColumnHidden(column_visual));
|
||||
connect(action, &QAction::toggled, [this, column_visual](bool enabled) {
|
||||
m_table_view->setColumnHidden(column_visual, !enabled);
|
||||
action->setChecked(!header->isSectionHidden(column));
|
||||
// Update the GUI when the user toggles a column with left-click actions in the right-click menu on the column.
|
||||
connect(action, &QAction::triggered, [this, header, column, action]() {
|
||||
header->setSectionHidden(column, !action->isChecked());
|
||||
// Safety check: prevent the user from hiding every single column.
|
||||
ensureMinimumOneColumnVisible();
|
||||
// Lastly push the new header state to settings.
|
||||
onTableHeaderStateChanged();
|
||||
resizeTableViewColumnsToFit();
|
||||
});
|
||||
}
|
||||
|
||||
menu.exec(m_table_view->mapToGlobal(point));
|
||||
menu.addSeparator();
|
||||
// Add a "panic button" that fully restores the default column layout.
|
||||
// This allows users to recover without editing configuration files such as [GameListTableView] has a key with
|
||||
// and variable HeaderState which you can remove the line to also do the same effect but old method is not user-friendly.
|
||||
menu.addAction(tr("Reset All Columns"), this, &GameListWidget::resetTableHeaderToDefault);
|
||||
menu.exec(m_table_view->viewport()->mapToGlobal(point));
|
||||
}
|
||||
|
||||
void GameListWidget::onCoverScaleChanged()
|
||||
@@ -789,6 +808,34 @@ void GameListWidget::loadTableHeaderState()
|
||||
header->restoreState(QByteArray::fromBase64(QByteArray::fromStdString(state_setting)));
|
||||
}
|
||||
|
||||
void GameListWidget::ensureMinimumOneColumnVisible()
|
||||
{
|
||||
QHeaderView* header = m_table_view->horizontalHeader();
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
bool any_visible = false;
|
||||
for (int column = 0; column < GameListModel::Column_Count; column++)
|
||||
{
|
||||
if (column != GameListModel::Column_Cover && !header->isSectionHidden(column))
|
||||
{
|
||||
any_visible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If absolutely everything is hidden, force the Title column to be visible.
|
||||
// This ensures there is always a right-click menu on the column available to restore
|
||||
// other columns or access the "Reset All Columns" option or even re-order them with drag and drop.
|
||||
// By default Qt will hide everything if it sees 0 viable columns, so just enforce atleast 1 column.
|
||||
// Adding ghost columns would be hacky and ugly so let's not do that.
|
||||
if (!any_visible)
|
||||
{
|
||||
header->setSectionHidden(GameListModel::Column_Title, false);
|
||||
onTableHeaderStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void GameListWidget::onTableHeaderStateChanged()
|
||||
{
|
||||
QHeaderView* header = m_table_view->horizontalHeader();
|
||||
@@ -824,6 +871,8 @@ void GameListWidget::applyTableHeaderDefaults()
|
||||
}
|
||||
|
||||
// TODO (Tech): Create a button for this in the minibar. Currently unused.
|
||||
// TODO (Red): Not sure if I should integrate it in the minibar for now when I made sure they can't break their order and there is a reset function now when you right-click the column.
|
||||
// They could accidentaly press on it when they didn't want to, could be revised later still because people without mouses can't do it such as controller mode on the TV.
|
||||
void GameListWidget::resetTableHeaderToDefault()
|
||||
{
|
||||
QHeaderView* header = m_table_view->horizontalHeader();
|
||||
@@ -848,6 +897,8 @@ void GameListWidget::resetTableHeaderToDefault()
|
||||
}
|
||||
|
||||
Host::SetBaseStringSettingValue("GameListTableView", "HeaderState", header->saveState().toBase64());
|
||||
// This makes the columns expand to fill the window right now.
|
||||
resizeTableViewColumnsToFit();
|
||||
}
|
||||
|
||||
void GameListWidget::saveSortSettings(const int column, const Qt::SortOrder sort_order)
|
||||
|
||||
@@ -109,6 +109,7 @@ private:
|
||||
void loadTableHeaderState();
|
||||
void applyTableHeaderDefaults();
|
||||
void resetTableHeaderToDefault();
|
||||
void ensureMinimumOneColumnVisible();
|
||||
void saveSortSettings(int column, Qt::SortOrder sort_order);
|
||||
void listZoom(float delta);
|
||||
void updateToolbar();
|
||||
|
||||
+9
-12
@@ -52,7 +52,7 @@ void LogWindow::updateSettings()
|
||||
const bool curr_enabled = Log::IsHostOutputEnabled();
|
||||
const bool input_enabled = Host::GetBaseBoolSettingValue("Logging", "ShowEESIOInput");
|
||||
|
||||
if(g_log_window && g_log_window->m_line_input)
|
||||
if (g_log_window && g_log_window->m_line_input)
|
||||
{
|
||||
g_log_window->m_input_widget->setVisible(input_enabled);
|
||||
}
|
||||
@@ -199,18 +199,16 @@ void LogWindow::createUi()
|
||||
|
||||
m_line_input = new QLineEdit(this);
|
||||
connect(m_line_input, &QLineEdit::returnPressed, this, &LogWindow::onInputEntered);
|
||||
|
||||
|
||||
m_local_echo_checkbox = new QCheckBox(tr("Local Echo"), this);
|
||||
m_local_echo_checkbox->setChecked(m_local_echo);
|
||||
connect(m_local_echo_checkbox, &QCheckBox::checkStateChanged, this, [&](Qt::CheckState state)
|
||||
{
|
||||
connect(m_local_echo_checkbox, &QCheckBox::checkStateChanged, this, [&](Qt::CheckState state) {
|
||||
m_local_echo = state == Qt::CheckState::Checked;
|
||||
});
|
||||
|
||||
|
||||
m_newline_on_enter_checkbox = new QCheckBox(tr("Newline on send"), this);
|
||||
m_newline_on_enter_checkbox->setChecked(m_newline_on_enter);
|
||||
connect(m_newline_on_enter_checkbox, &QCheckBox::checkStateChanged, this, [&](Qt::CheckState state)
|
||||
{
|
||||
connect(m_newline_on_enter_checkbox, &QCheckBox::checkStateChanged, this, [&](Qt::CheckState state) {
|
||||
m_newline_on_enter = state == Qt::CheckState::Checked;
|
||||
});
|
||||
|
||||
@@ -243,7 +241,6 @@ void LogWindow::createUi()
|
||||
vlayout->addWidget(m_text);
|
||||
vlayout->addWidget(m_input_widget);
|
||||
|
||||
central_widget->setLayout(vlayout);
|
||||
setCentralWidget(central_widget);
|
||||
}
|
||||
|
||||
@@ -417,18 +414,18 @@ void LogWindow::onInputEntered()
|
||||
if (text.isEmpty() && !m_newline_on_enter)
|
||||
return;
|
||||
|
||||
if(m_newline_on_enter)
|
||||
if (m_newline_on_enter)
|
||||
text.append('\n');
|
||||
|
||||
std::string str = text.toUtf8().toStdString();
|
||||
|
||||
if(VMManager::WriteBytesToEESIORXFIFO({reinterpret_cast<const u8*>(str.data()), str.size()}))
|
||||
if (VMManager::WriteBytesToEESIORXFIFO({reinterpret_cast<const u8*>(str.data()), str.size()}))
|
||||
{
|
||||
m_line_input->clear();
|
||||
|
||||
if(m_local_echo)
|
||||
if (m_local_echo)
|
||||
// appendMessage expects a newline to be at the end of the string
|
||||
appendMessage(0, 0, m_newline_on_enter ? text : (text + '\n') );
|
||||
appendMessage(0, 0, m_newline_on_enter ? text : (text + '\n'));
|
||||
|
||||
QTextCursor cursor(m_text->textCursor());
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
|
||||
+2
-3
@@ -195,7 +195,7 @@ void EmuThread::stopFullscreenUI()
|
||||
{
|
||||
m_run_fullscreen_ui.store(false, std::memory_order_release);
|
||||
emit onFullscreenUIStateChange(false);
|
||||
|
||||
|
||||
// Resume and refresh background when FullscreenUI exits
|
||||
QMetaObject::invokeMethod(g_main_window, "updateGameListBackground", Qt::QueuedConnection);
|
||||
}
|
||||
@@ -1160,7 +1160,7 @@ void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directo
|
||||
if (!filters.empty())
|
||||
{
|
||||
filters_str.append(QStringLiteral("All File Types (%1)")
|
||||
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
|
||||
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
|
||||
for (const std::string& filter : filters)
|
||||
{
|
||||
filters_str.append(
|
||||
@@ -1369,7 +1369,6 @@ bool QtHost::InitializeConfig()
|
||||
.arg(QString::fromStdString(error.GetDescription())));
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Setup wizard was incomplete last time?
|
||||
|
||||
@@ -1357,8 +1357,18 @@ namespace SettingWidgetBinder
|
||||
widget->connect(widget, &QLineEdit::editingFinished, widget, std::move(value_changed));
|
||||
}
|
||||
|
||||
// No need to pass a section or key since this is only used once and has six keys associated with it
|
||||
static inline void BindWidgetToDateTimeSetting(SettingsInterface* sif, QDateTimeEdit* widget, std::string section)
|
||||
struct DateTimeKeys
|
||||
{
|
||||
const char* year = nullptr;
|
||||
const char* month = nullptr;
|
||||
const char* day = nullptr;
|
||||
const char* hour = nullptr;
|
||||
const char* minute = nullptr;
|
||||
const char* second = nullptr;
|
||||
};
|
||||
|
||||
static inline void BindWidgetToDateTimeSetting(
|
||||
SettingsInterface* sif, QDateTimeEdit* widget, std::string section, const DateTimeKeys& keys)
|
||||
{
|
||||
using Accessor = SettingAccessor<QDateTimeEdit>;
|
||||
|
||||
@@ -1370,58 +1380,36 @@ namespace SettingWidgetBinder
|
||||
const int DEFAULT_MINUTE = 0;
|
||||
const int DEFAULT_SECOND = 0;
|
||||
|
||||
const char* YEAR_KEY = "RtcYear";
|
||||
const char* MONTH_KEY = "RtcMonth";
|
||||
const char* DAY_KEY = "RtcDay";
|
||||
const char* HOUR_KEY = "RtcHour";
|
||||
const char* MINUTE_KEY = "RtcMinute";
|
||||
const char* SECOND_KEY = "RtcSecond";
|
||||
|
||||
// Fetch settings from .ini
|
||||
const s32 year_value =
|
||||
Host::GetBaseIntSettingValue(section.c_str(), YEAR_KEY, static_cast<s32>(DEFAULT_YEAR));
|
||||
const s32 month_value =
|
||||
Host::GetBaseIntSettingValue(section.c_str(), MONTH_KEY, static_cast<s32>(DEFAULT_MONTH));
|
||||
const s32 day_value =
|
||||
Host::GetBaseIntSettingValue(section.c_str(), DAY_KEY, static_cast<s32>(DEFAULT_DAY));
|
||||
const s32 hour_value =
|
||||
Host::GetBaseIntSettingValue(section.c_str(), HOUR_KEY, static_cast<s32>(DEFAULT_HOUR));
|
||||
const s32 minute_value =
|
||||
Host::GetBaseIntSettingValue(section.c_str(), MINUTE_KEY, static_cast<s32>(DEFAULT_MINUTE));
|
||||
const s32 second_value =
|
||||
Host::GetBaseIntSettingValue(section.c_str(), SECOND_KEY, static_cast<s32>(DEFAULT_SECOND));
|
||||
const int year_value = Host::GetBaseIntSettingValue(section.c_str(), keys.year, DEFAULT_YEAR);
|
||||
const int month_value = Host::GetBaseIntSettingValue(section.c_str(), keys.month, DEFAULT_MONTH);
|
||||
const int day_value = Host::GetBaseIntSettingValue(section.c_str(), keys.day, DEFAULT_DAY);
|
||||
const int hour_value = Host::GetBaseIntSettingValue(section.c_str(), keys.hour, DEFAULT_HOUR);
|
||||
const int minute_value = Host::GetBaseIntSettingValue(section.c_str(), keys.minute, DEFAULT_MINUTE);
|
||||
const int second_value = Host::GetBaseIntSettingValue(section.c_str(), keys.second, DEFAULT_SECOND);
|
||||
|
||||
if (sif)
|
||||
{
|
||||
int sif_year_value = DEFAULT_YEAR;
|
||||
int sif_month_value = DEFAULT_MONTH;
|
||||
int sif_day_value = DEFAULT_DAY;
|
||||
int sif_hour_value = DEFAULT_HOUR;
|
||||
int sif_minute_value = DEFAULT_MINUTE;
|
||||
int sif_second_value = DEFAULT_SECOND;
|
||||
|
||||
// Get Settings Interface values or default if that fails
|
||||
if (!sif->GetIntValue(section.c_str(), YEAR_KEY, &sif_year_value)) { sif_year_value = DEFAULT_YEAR; }
|
||||
if (!sif->GetIntValue(section.c_str(), MONTH_KEY, &sif_month_value)) { sif_month_value = DEFAULT_MONTH; }
|
||||
if (!sif->GetIntValue(section.c_str(), DAY_KEY, &sif_day_value)) { sif_day_value = DEFAULT_DAY; }
|
||||
if (!sif->GetIntValue(section.c_str(), HOUR_KEY, &sif_hour_value)) { sif_hour_value = DEFAULT_HOUR; }
|
||||
if (!sif->GetIntValue(section.c_str(), MINUTE_KEY, &sif_minute_value)) { sif_minute_value = DEFAULT_MINUTE; }
|
||||
if (!sif->GetIntValue(section.c_str(), SECOND_KEY, &sif_second_value)) { sif_second_value = DEFAULT_SECOND; }
|
||||
int sif_year_value = sif->GetIntValue(section.c_str(), keys.year, DEFAULT_YEAR);
|
||||
int sif_month_value = sif->GetIntValue(section.c_str(), keys.month, DEFAULT_MONTH);
|
||||
int sif_day_value = sif->GetIntValue(section.c_str(), keys.day, DEFAULT_DAY);
|
||||
int sif_hour_value = sif->GetIntValue(section.c_str(), keys.hour, DEFAULT_HOUR);
|
||||
int sif_minute_value = sif->GetIntValue(section.c_str(), keys.minute, DEFAULT_MINUTE);
|
||||
int sif_second_value = sif->GetIntValue(section.c_str(), keys.second, DEFAULT_SECOND);
|
||||
|
||||
// No need to check for valid date since QDateTime resets to minimum upon becoming invalid
|
||||
Accessor::setDateTime(widget, QDate(static_cast<int>(sif_year_value + YEAR_OFFSET), static_cast<int>(sif_month_value), static_cast<int>(sif_day_value)),
|
||||
QTime(static_cast<int>(sif_hour_value), static_cast<int>(sif_minute_value), static_cast<int>(sif_second_value)));
|
||||
QDate date(sif_year_value + YEAR_OFFSET, sif_month_value, sif_day_value);
|
||||
QTime time(sif_hour_value, sif_minute_value, sif_second_value);
|
||||
Accessor::setDateTime(widget, date, time);
|
||||
|
||||
// Update the settings interface and reload the game settings when changed
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), YEAR_KEY = std::move(YEAR_KEY), MONTH_KEY = std::move(MONTH_KEY),
|
||||
DAY_KEY = std::move(DAY_KEY), HOUR_KEY = std::move(HOUR_KEY), MINUTE_KEY = std::move(MINUTE_KEY), SECOND_KEY = std::move(SECOND_KEY), YEAR_OFFSET = std::move(YEAR_OFFSET)]() {
|
||||
|
||||
sif->SetIntValue(section.c_str(), YEAR_KEY, Accessor::getYear(widget) - YEAR_OFFSET);
|
||||
sif->SetIntValue(section.c_str(), MONTH_KEY, Accessor::getMonth(widget));
|
||||
sif->SetIntValue(section.c_str(), DAY_KEY, Accessor::getDay(widget));
|
||||
sif->SetIntValue(section.c_str(), HOUR_KEY, Accessor::getHour(widget));
|
||||
sif->SetIntValue(section.c_str(), MINUTE_KEY, Accessor::getMinute(widget));
|
||||
sif->SetIntValue(section.c_str(), SECOND_KEY, Accessor::getSecond(widget));
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), keys]() {
|
||||
sif->SetIntValue(section.c_str(), keys.year, Accessor::getYear(widget) - YEAR_OFFSET);
|
||||
sif->SetIntValue(section.c_str(), keys.month, Accessor::getMonth(widget));
|
||||
sif->SetIntValue(section.c_str(), keys.day, Accessor::getDay(widget));
|
||||
sif->SetIntValue(section.c_str(), keys.hour, Accessor::getHour(widget));
|
||||
sif->SetIntValue(section.c_str(), keys.minute, Accessor::getMinute(widget));
|
||||
sif->SetIntValue(section.c_str(), keys.second, Accessor::getSecond(widget));
|
||||
|
||||
QtHost::SaveGameSettings(sif, true);
|
||||
g_emu_thread->reloadGameSettings();
|
||||
@@ -1431,13 +1419,12 @@ namespace SettingWidgetBinder
|
||||
else
|
||||
{
|
||||
// No need to check for valid date since QDateTime resets to minimum upon becoming invalid
|
||||
Accessor::setDateTime(widget, QDate(static_cast<int>(year_value + YEAR_OFFSET), static_cast<int>(month_value), static_cast<int>(day_value)),
|
||||
QTime(static_cast<int>(hour_value), static_cast<int>(minute_value), static_cast<int>(second_value)));
|
||||
QDate date(year_value + YEAR_OFFSET, month_value, day_value);
|
||||
QTime time(hour_value, minute_value, second_value);
|
||||
Accessor::setDateTime(widget, date, time);
|
||||
|
||||
// Update and apply base settings with values from widget when user changes it in UI
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), YEAR_KEY = std::move(YEAR_KEY), MONTH_KEY = std::move(MONTH_KEY),
|
||||
DAY_KEY = std::move(DAY_KEY), HOUR_KEY = std::move(HOUR_KEY), MINUTE_KEY = std::move(MINUTE_KEY), SECOND_KEY = std::move(SECOND_KEY), YEAR_OFFSET = std::move(YEAR_OFFSET)]() {
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), keys]() {
|
||||
const int new_year_value = Accessor::getYear(widget);
|
||||
const int new_month_value = Accessor::getMonth(widget);
|
||||
const int new_day_value = Accessor::getDay(widget);
|
||||
@@ -1445,16 +1432,15 @@ namespace SettingWidgetBinder
|
||||
const int new_minute_value = Accessor::getMinute(widget);
|
||||
const int new_second_value = Accessor::getSecond(widget);
|
||||
|
||||
Host::SetBaseIntSettingValue(section.c_str(), YEAR_KEY, new_year_value - YEAR_OFFSET);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), MONTH_KEY, new_month_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), DAY_KEY, new_day_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), HOUR_KEY, new_hour_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), MINUTE_KEY, new_minute_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), SECOND_KEY, new_second_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), keys.year, new_year_value - YEAR_OFFSET);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), keys.month, new_month_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), keys.day, new_day_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), keys.hour, new_hour_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), keys.minute, new_minute_value);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), keys.second, new_second_value);
|
||||
Host::CommitBaseSettingChanges();
|
||||
g_emu_thread->applySettings();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace SettingWidgetBinder
|
||||
|
||||
@@ -133,19 +133,19 @@ void AchievementLoginDialog::processLoginResult(bool result, const QString& mess
|
||||
QMessageBox::information(
|
||||
this, tr("Login Successful"),
|
||||
tr("Successfully logged in to RetroAchievements as %1.").arg(QString::fromStdString(username)));
|
||||
|
||||
|
||||
m_ui.status->setText(tr("Successfully logged in as %1.").arg(QString::fromStdString(username)));
|
||||
m_ui.status->setStyleSheet("color: green; font-weight: bold;");
|
||||
|
||||
|
||||
disconnect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &AchievementLoginDialog::loginClicked);
|
||||
|
||||
|
||||
m_login->setVisible(false);
|
||||
QPushButton* dismissButton = m_ui.buttonBox->addButton(tr("&Dismiss"), QDialogButtonBox::AcceptRole);
|
||||
dismissButton->setDefault(true);
|
||||
dismissButton->setFocus();
|
||||
|
||||
|
||||
connect(dismissButton, &QPushButton::clicked, this, [this]() { done(0); });
|
||||
|
||||
|
||||
enableUI(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -214,8 +214,8 @@ void AchievementSettingsWidget::updateLoginState()
|
||||
StringUtil::FromChars<u64>(Host::GetBaseStringSettingValue("Achievements", "LoginTimestamp", "0")).value_or(0);
|
||||
const QDateTime login_timestamp(QDateTime::fromSecsSinceEpoch(static_cast<qint64>(login_unix_timestamp)));
|
||||
m_ui.loginStatus->setText(tr("Username: %1\nLogin token generated on %2.")
|
||||
.arg(QString::fromStdString(username))
|
||||
.arg(login_timestamp.toString(Qt::TextDate)));
|
||||
.arg(QString::fromStdString(username))
|
||||
.arg(login_timestamp.toString(Qt::TextDate)));
|
||||
m_ui.loginButton->setText(tr("Logout"));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -262,17 +262,17 @@ void AudioSettingsWidget::updateLatencyLabel()
|
||||
if (expand_buffer_ms > 0)
|
||||
{
|
||||
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms buffer + %3 ms expand + %4 ms output)")
|
||||
.arg(config_buffer_ms + expand_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(expand_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
.arg(config_buffer_ms + expand_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(expand_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms buffer + %3 ms output)")
|
||||
.arg(config_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
.arg(config_buffer_ms + output_latency_ms)
|
||||
.arg(config_buffer_ms)
|
||||
.arg(output_latency_ms));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -280,8 +280,8 @@ void AudioSettingsWidget::updateLatencyLabel()
|
||||
if (expand_buffer_ms > 0)
|
||||
{
|
||||
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms expand, minimum output latency unknown)")
|
||||
.arg(expand_buffer_ms + config_buffer_ms)
|
||||
.arg(expand_buffer_ms));
|
||||
.arg(expand_buffer_ms + config_buffer_ms)
|
||||
.arg(expand_buffer_ms));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -203,7 +203,7 @@ void ControllerBindingWidget::onAutomaticBindingClicked()
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
QAction* action;
|
||||
if(dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
if (dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
action = menu.addAction(dev.first);
|
||||
else
|
||||
action = menu.addAction(QStringLiteral("%1: %2").arg(dev.first).arg(dev.second));
|
||||
@@ -1157,7 +1157,7 @@ void USBDeviceWidget::onAutomaticBindingClicked()
|
||||
{
|
||||
// we set it as data, because the device list could get invalidated while the menu is up
|
||||
QAction* action;
|
||||
if(dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
if (dev.first.compare(dev.second, Qt::CaseInsensitive) == 0)
|
||||
action = menu.addAction(dev.first);
|
||||
else
|
||||
action = menu.addAction(QStringLiteral("%1: %2").arg(dev.first).arg(dev.second));
|
||||
|
||||
@@ -88,7 +88,7 @@ ControllerGlobalSettingsWidget::~ControllerGlobalSettingsWidget() = default;
|
||||
void ControllerGlobalSettingsWidget::addDeviceToList(const QString& identifier, const QString& name)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
if(identifier.compare(name,Qt::CaseInsensitive) == 0)
|
||||
if (identifier.compare(name, Qt::CaseInsensitive) == 0)
|
||||
item->setText(identifier);
|
||||
else
|
||||
item->setText(QStringLiteral("%1: %2").arg(identifier).arg(name));
|
||||
|
||||
@@ -89,10 +89,10 @@ void ControllerSettingsWindow::onCurrentProfileChanged(int index)
|
||||
|
||||
void ControllerSettingsWindow::onNewProfileClicked()
|
||||
{
|
||||
const QString profile_name(QInputDialog::getText(this, tr("Create Input Profile"),
|
||||
tr("Custom input profiles are used to override the Shared input profile for specific games.\n"
|
||||
"To apply a custom input profile to a game, go to its Game Properties, then change the 'Input Profile' on the Summary tab.\n\n"
|
||||
"Enter the name for the new input profile:")));
|
||||
const QString profile_name(QInputDialog::getText(this, tr("Create Input Profile"),
|
||||
tr("Custom input profiles are used to override the Shared input profile for specific games.\n"
|
||||
"To apply a custom input profile to a game, go to its Game Properties, then change the 'Input Profile' on the Summary tab.\n\n"
|
||||
"Enter the name for the new input profile:")));
|
||||
if (profile_name.isEmpty())
|
||||
return;
|
||||
|
||||
@@ -457,10 +457,16 @@ void ControllerSettingsWindow::createWidgets()
|
||||
const QString display_name(QString::fromUtf8(ci ? ci->GetLocalizedName() : "Unknown"));
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(mtap_enabled[port] ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name))
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
: tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
if (mtap_enabled[port])
|
||||
{
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
}
|
||||
item->setIcon(m_port_bindings[global_slot]->getIcon());
|
||||
item->setData(Qt::UserRole, QVariant(global_slot));
|
||||
m_ui.settingsCategory->addItem(item);
|
||||
@@ -513,10 +519,16 @@ void ControllerSettingsWindow::updateListDescription(u32 global_slot, Controller
|
||||
const Pad::ControllerInfo* ci = Pad::GetControllerInfo(widget->getControllerType());
|
||||
const QString display_name = QString::fromUtf8(ci ? ci->GetLocalizedName() : "Unknown");
|
||||
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(mtap_enabled ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name))
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
: tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
if (mtap_enabled)
|
||||
{
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
}
|
||||
item->setIcon(widget->getIcon());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,15 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* settings_dialog
|
||||
|
||||
if (dialog()->isPerGameSettings())
|
||||
{
|
||||
SettingWidgetBinder::BindWidgetToDateTimeSetting(sif, m_ui.rtcDateTime, "EmuCore");
|
||||
SettingWidgetBinder::DateTimeKeys rtc_keys;
|
||||
rtc_keys.year = "RtcYear";
|
||||
rtc_keys.month = "RtcMonth";
|
||||
rtc_keys.day = "RtcDay";
|
||||
rtc_keys.hour = "RtcHour";
|
||||
rtc_keys.minute = "RtcMinute";
|
||||
rtc_keys.second = "RtcSecond";
|
||||
|
||||
SettingWidgetBinder::BindWidgetToDateTimeSetting(sif, m_ui.rtcDateTime, "EmuCore", rtc_keys);
|
||||
m_ui.rtcDateTime->setDateRange(QDate(2000, 1, 1), QDate(2099, 12, 31));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.manuallySetRealTimeClock, "EmuCore", "ManuallySetRealTimeClock", false);
|
||||
connect(m_ui.manuallySetRealTimeClock, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::onManuallySetRealTimeClockChanged);
|
||||
|
||||
@@ -25,7 +25,7 @@ FolderSettingsWidget::FolderSettingsWidget(SettingsWindow* settings_dialog, QWid
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse, m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset,
|
||||
"Folders", "Videos", Path::Combine(EmuFolders::DataRoot, "videos"));
|
||||
dialog()->registerWidgetHelp(m_ui.organizeSnapshotsByGame, tr("Organize Snapshots by Game"), tr("Unchecked"),
|
||||
tr("Saves snapshots to per-game subfolders instead of a shared folder."));
|
||||
tr("Saves snapshots to per-game subfolders instead of a shared folder."));
|
||||
}
|
||||
|
||||
FolderSettingsWidget::~FolderSettingsWidget() = default;
|
||||
|
||||
@@ -118,9 +118,8 @@ void GameCheatSettingsWidget::onCheatListItemHovered(const QModelIndex& index)
|
||||
const QModelIndex source_index = m_model_proxy->mapToSource(index);
|
||||
const QModelIndex sibling_index = source_index.siblingAtColumn(0);
|
||||
QStandardItem* item = m_model->itemFromIndex(sibling_index);
|
||||
if (!item)
|
||||
if (!item || !item->isCheckable())
|
||||
{
|
||||
// No item is selected.
|
||||
m_ui.appliedLabel->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -342,15 +342,15 @@ void GameSummaryWidget::onVerifyClicked()
|
||||
if (!hentry->version.empty())
|
||||
{
|
||||
setVerifyResult(tr("Verified as %1 [%2] (Version %3).")
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial))
|
||||
.arg(QString::fromStdString(hentry->version)));
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial))
|
||||
.arg(QString::fromStdString(hentry->version)));
|
||||
}
|
||||
else
|
||||
{
|
||||
setVerifyResult(tr("Verified as %1 [%2].")
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial)));
|
||||
.arg(QString::fromStdString(hentry->name))
|
||||
.arg(QString::fromStdString(hentry->serial)));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -11,7 +11,7 @@ class HddCreateQt : public HddCreate
|
||||
{
|
||||
public:
|
||||
HddCreateQt(QWidget* parent);
|
||||
virtual ~HddCreateQt(){};
|
||||
virtual ~HddCreateQt() {}
|
||||
|
||||
private:
|
||||
QWidget* m_parent;
|
||||
|
||||
@@ -197,8 +197,8 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
|
||||
"and unpauses when you switch back."));
|
||||
dialog()->registerWidgetHelp(m_ui.pauseOnControllerDisconnection, tr("Pause On Controller Disconnection"),
|
||||
tr("Unchecked"), tr("Pauses the emulator when a controller with bindings is disconnected."));
|
||||
dialog()->registerWidgetHelp(m_ui.promptOnStateLoadSaveFailure, tr("Pause On State Load/Save Failure"),
|
||||
tr("Checked"), tr("Display a modal dialog when a save state load/save operation fails."));
|
||||
dialog()->registerWidgetHelp(m_ui.promptOnStateLoadSaveFailure, tr("Prompt On State Load/Save Failure"),
|
||||
tr("Checked"), tr("Displays a modal dialog when a save state load/save operation fails."));
|
||||
dialog()->registerWidgetHelp(m_ui.startFullscreen, tr("Start Fullscreen"), tr("Unchecked"),
|
||||
tr("Automatically switches to fullscreen mode when a game is started."));
|
||||
dialog()->registerWidgetHelp(m_ui.hideMouseCursor, tr("Hide Cursor In Fullscreen"), tr("Unchecked"),
|
||||
|
||||
@@ -37,41 +37,39 @@ MemoryCardConvertDialog::MemoryCardConvertDialog(QWidget* parent, QString select
|
||||
m_ui.progressBar->setRange(0, 100);
|
||||
m_ui.progressBar->setValue(0);
|
||||
|
||||
connect(m_ui.conversionTypeSelect, &QComboBox::currentIndexChanged, this, [this]()
|
||||
connect(m_ui.conversionTypeSelect, &QComboBox::currentIndexChanged, this, [this]() {
|
||||
switch (m_srcCardInfo.type)
|
||||
{
|
||||
switch (m_srcCardInfo.type)
|
||||
{
|
||||
case MemoryCardType::File:
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, tr("Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card."));
|
||||
break;
|
||||
case MemoryCardType::Folder:
|
||||
switch (m_ui.conversionTypeSelect->currentData().toInt())
|
||||
{
|
||||
case 8:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, tr("A standard, 8 MB Memory Card. Most compatible, but smallest capacity."));
|
||||
break;
|
||||
case 16:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, tr("2x larger than a standard Memory Card. May have some compatibility issues."));
|
||||
break;
|
||||
case 32:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, tr("4x larger than a standard Memory Card. Likely to have compatibility issues."));
|
||||
break;
|
||||
case 64:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, tr("8x larger than a standard Memory Card. Likely to have compatibility issues."));
|
||||
break;
|
||||
default:
|
||||
//: MemoryCardType should be left as-is.
|
||||
QMessageBox::critical(this, tr("Convert Memory Card Failed"), tr("Invalid MemoryCardType"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//: MemoryCardType should be left as-is.
|
||||
QMessageBox::critical(this, tr("Convert Memory Card Failed"), tr("Invalid MemoryCardType"));
|
||||
return;
|
||||
}
|
||||
case MemoryCardType::File:
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, tr("Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card."));
|
||||
break;
|
||||
case MemoryCardType::Folder:
|
||||
switch (m_ui.conversionTypeSelect->currentData().toInt())
|
||||
{
|
||||
case 8:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, tr("A standard, 8 MB Memory Card. Most compatible, but smallest capacity."));
|
||||
break;
|
||||
case 16:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, tr("2x larger than a standard Memory Card. May have some compatibility issues."));
|
||||
break;
|
||||
case 32:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, tr("4x larger than a standard Memory Card. Likely to have compatibility issues."));
|
||||
break;
|
||||
case 64:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, tr("8x larger than a standard Memory Card. Likely to have compatibility issues."));
|
||||
break;
|
||||
default:
|
||||
//: MemoryCardType should be left as-is.
|
||||
QMessageBox::critical(this, tr("Convert Memory Card Failed"), tr("Invalid MemoryCardType"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//: MemoryCardType should be left as-is.
|
||||
QMessageBox::critical(this, tr("Convert Memory Card Failed"), tr("Invalid MemoryCardType"));
|
||||
return;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
disconnect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, nullptr);
|
||||
|
||||
@@ -88,7 +86,6 @@ bool MemoryCardConvertDialog::IsSetup()
|
||||
|
||||
void MemoryCardConvertDialog::onStatusUpdated()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MemoryCardConvertDialog::onProgressUpdated(int value, int range)
|
||||
|
||||
@@ -64,4 +64,4 @@ namespace CardCapacity
|
||||
static constexpr size_t _16_MB = 0x3e80 * 512 * 2; //(0x3fa7 - 0x49) * 2 * 512;
|
||||
static constexpr size_t _32_MB = 0x7d00 * 512 * 2; //(0x7f67 - 0x89) * 2 * 512;
|
||||
static constexpr size_t _64_MB = 0xfde8 * 512 * 2; //(0xfee7 - 0x0109) * 2 * 512;
|
||||
}
|
||||
} // namespace CardCapacity
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "common/FileSystem.h"
|
||||
|
||||
MemoryCardConvertWorker::MemoryCardConvertWorker(QWidget* parent, MemoryCardType type, MemoryCardFileType fileType, const std::string& srcFileName, const std::string& destFileName)
|
||||
: QtAsyncProgressThread(parent)
|
||||
: QtAsyncProgressThread(parent)
|
||||
{
|
||||
this->type = type;
|
||||
this->fileType = fileType;
|
||||
|
||||
@@ -99,9 +99,8 @@ void MemoryCardCreateDialog::updateState()
|
||||
void MemoryCardCreateDialog::createCard()
|
||||
{
|
||||
const QString name = m_ui.name->text();
|
||||
const std::string name_str = QStringLiteral("%1.%2").arg(name)
|
||||
.arg((m_fileType == MemoryCardFileType::PS1) ? QStringLiteral("mcr") : QStringLiteral("ps2"))
|
||||
.toStdString();
|
||||
const QString type = (m_fileType == MemoryCardFileType::PS1) ? QStringLiteral("mcr") : QStringLiteral("ps2");
|
||||
const std::string name_str = QStringLiteral("%1.%2").arg(name).arg(type).toStdString();
|
||||
if (!Path::IsValidFileName(name_str, false))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create Memory Card"),
|
||||
|
||||
@@ -357,7 +357,6 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
||||
{
|
||||
executable_path = "flatpak run net.pcsx2.PCSX2";
|
||||
icon_name = "net.pcsx2.PCSX2";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -395,9 +394,12 @@ void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::s
|
||||
"Type=Application\n"
|
||||
"Terminal=false\n"
|
||||
"StartupWMClass=PCSX2\n"
|
||||
"Exec=" + final_args + "\n"
|
||||
"Name=" + clean_name + "\n"
|
||||
"Icon=" + icon_name + "\n"
|
||||
"Exec=" +
|
||||
final_args + "\n" +
|
||||
"Name=" +
|
||||
clean_name + "\n" +
|
||||
"Icon=" +
|
||||
icon_name + "\n" +
|
||||
"Categories=Game;Emulator;\n";
|
||||
std::string_view sv(file_content);
|
||||
|
||||
|
||||
@@ -341,11 +341,12 @@ bool QtHost::DownloadMissingFont(QWidget* dialog_parent, const char* font_name,
|
||||
msgbox.setWindowModality(Qt::WindowModal);
|
||||
msgbox.setIcon(QMessageBox::Critical);
|
||||
msgbox.setTextFormat(Qt::RichText);
|
||||
msgbox.setText(qApp->translate("MainWindow",
|
||||
"The font file '%1' is required for the On-Screen Display and Big Picture Mode to show messages in your language.<br><br>"
|
||||
"Do you want to download this file now? These files are usually less than 10 megabytes in size.<br><br>"
|
||||
"<strong>If you do not download this file, on-screen messages will not be readable.</strong>")
|
||||
.arg(QLatin1StringView(font_name)));
|
||||
msgbox.setText(
|
||||
qApp->translate("MainWindow",
|
||||
"The font file '%1' is required for the On-Screen Display and Big Picture Mode to show messages in your language.<br><br>"
|
||||
"Do you want to download this file now? These files are usually less than 10 megabytes in size.<br><br>"
|
||||
"<strong>If you do not download this file, on-screen messages will not be readable.</strong>")
|
||||
.arg(QLatin1StringView(font_name)));
|
||||
msgbox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
if (msgbox.exec() != QMessageBox::Yes)
|
||||
return false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -89,6 +89,7 @@
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AsyncDialogs.cpp" />
|
||||
<ClCompile Include="ColorPickerButton.cpp" />
|
||||
<ClCompile Include="Debugger\SymbolTree\NewSymbolDialogs.cpp" />
|
||||
<ClCompile Include="Debugger\SymbolTree\SymbolTreeDelegates.cpp" />
|
||||
@@ -183,6 +184,7 @@
|
||||
<ClCompile Include="VCRuntimeChecker.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AsyncDialogs.h" />
|
||||
<QtMoc Include="SetupWizardDialog.h" />
|
||||
<QtMoc Include="Settings\InterfaceSettingsWidget.h" />
|
||||
<QtMoc Include="Settings\GameListSettingsWidget.h" />
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PrecompiledHeader.cpp" />
|
||||
<ClCompile Include="AsyncDialogs.cpp" />
|
||||
<ClCompile Include="QtHost.cpp" />
|
||||
<ClCompile Include="MainWindow.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_MainWindow.cpp">
|
||||
@@ -518,6 +519,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="PrecompiledHeader.h" />
|
||||
<ClInclude Include="AsyncDialogs.h" />
|
||||
<ClInclude Include="QtUtils.h" />
|
||||
<ClInclude Include="SettingWidgetBinder.h" />
|
||||
<ClInclude Include="Settings\HddCreateQt.h">
|
||||
|
||||
+331
-56
@@ -143,6 +143,7 @@ namespace Achievements
|
||||
static void HandleResetEvent(const rc_client_event_t* event);
|
||||
static void HandleUnlockEvent(const rc_client_event_t* event);
|
||||
static void HandleGameCompleteEvent(const rc_client_event_t* event);
|
||||
static void HandleSubsetCompleteEvent(const rc_client_event_t* event);
|
||||
static void HandleLeaderboardStartedEvent(const rc_client_event_t* event);
|
||||
static void HandleLeaderboardFailedEvent(const rc_client_event_t* event);
|
||||
static void HandleLeaderboardSubmittedEvent(const rc_client_event_t* event);
|
||||
@@ -169,6 +170,7 @@ namespace Achievements
|
||||
static void UpdateNotificationPosition();
|
||||
|
||||
static std::string GetAchievementBadgePath(const rc_client_achievement_t* achievement, int state);
|
||||
static std::string GetSubsetBadgePath(const rc_client_subset_t* subset);
|
||||
static std::string GetUserBadgePath(const std::string_view username);
|
||||
static std::string GetLeaderboardUserBadgePath(const rc_client_leaderboard_entry_t* entry);
|
||||
|
||||
@@ -176,6 +178,7 @@ namespace Achievements
|
||||
static void DrawLeaderboardListEntry(const rc_client_leaderboard_t* lboard);
|
||||
static void DrawLeaderboardEntry(const rc_client_leaderboard_entry_t& entry, bool is_self, float rank_column_width,
|
||||
float name_column_width, float time_column_width, float column_spacing);
|
||||
static void OpenSubset(const rc_client_subset_t* subset);
|
||||
static void OpenLeaderboard(const rc_client_leaderboard_t* lboard);
|
||||
static void LeaderboardFetchNearbyCallback(
|
||||
int result, const char* error_message, rc_client_leaderboard_entry_list_t* list, rc_client_t* client, void* callback_userdata);
|
||||
@@ -183,6 +186,7 @@ namespace Achievements
|
||||
int result, const char* error_message, rc_client_leaderboard_entry_list_t* list, rc_client_t* client, void* callback_userdata);
|
||||
static void FetchNextLeaderboardEntries();
|
||||
static void CloseLeaderboard();
|
||||
static void CloseSubset();
|
||||
|
||||
static bool s_hardcore_mode = false;
|
||||
|
||||
@@ -213,9 +217,11 @@ namespace Achievements
|
||||
static rc_client_async_handle_t* s_load_game_request;
|
||||
|
||||
static rc_client_achievement_list_t* s_achievement_list;
|
||||
static rc_client_subset_list_t* s_subset_list;
|
||||
static rc_client_leaderboard_list_t* s_leaderboard_list;
|
||||
static std::vector<std::pair<const void*, std::string>> s_achievement_badge_paths;
|
||||
static const rc_client_leaderboard_t* s_open_leaderboard = nullptr;
|
||||
static const rc_client_subset_t* s_open_subset = nullptr;
|
||||
static rc_client_async_handle_t* s_leaderboard_fetch_handle = nullptr;
|
||||
static std::vector<rc_client_leaderboard_entry_list_t*> s_leaderboard_entry_lists;
|
||||
static rc_client_leaderboard_entry_list_t* s_leaderboard_nearby_entries;
|
||||
@@ -820,6 +826,10 @@ void Achievements::ClientEventHandler(const rc_client_event_t* event, rc_client_
|
||||
HandleGameCompleteEvent(event);
|
||||
break;
|
||||
|
||||
case RC_CLIENT_EVENT_SUBSET_COMPLETED:
|
||||
HandleSubsetCompleteEvent(event);
|
||||
break;
|
||||
|
||||
case RC_CLIENT_EVENT_LEADERBOARD_STARTED:
|
||||
HandleLeaderboardStartedEvent(event);
|
||||
break;
|
||||
@@ -1211,6 +1221,33 @@ void Achievements::HandleGameCompleteEvent(const rc_client_event_t* event)
|
||||
}
|
||||
}
|
||||
|
||||
void Achievements::HandleSubsetCompleteEvent(const rc_client_event_t* event)
|
||||
{
|
||||
const rc_client_subset_t* subset = event->subset;
|
||||
Console.WriteLn("Achievements: Subset '%s' (%u) complete", subset->title, subset->id);
|
||||
UpdateGameSummary();
|
||||
|
||||
if (EmuConfig.Achievements.Notifications)
|
||||
{
|
||||
std::string title = fmt::format(TRANSLATE_FS("Achievements", "Mastered {}"), subset->title);
|
||||
std::string message = fmt::format(
|
||||
TRANSLATE_FS("Achievements", "{0}, {1}"),
|
||||
TRANSLATE_PLURAL_STR("Achievements", "%n achievements", "Mastery popup",
|
||||
s_game_summary.num_unlocked_achievements),
|
||||
TRANSLATE_PLURAL_STR("Achievements", "%n points", "Mastery popup", s_game_summary.points_unlocked));
|
||||
|
||||
std::string badge_path = GetSubsetBadgePath(subset);
|
||||
|
||||
MTGS::RunOnGSThread([title = std::move(title), message = std::move(message), badge_path = std::move(badge_path)]() {
|
||||
if (ImGuiManager::InitializeFullscreenUI())
|
||||
{
|
||||
ImGuiFullscreen::AddNotification(
|
||||
"achievement_subset_mastery", GAME_COMPLETE_NOTIFICATION_TIME, std::move(title), std::move(message), std::move(badge_path));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Achievements::HandleLeaderboardStartedEvent(const rc_client_event_t* event)
|
||||
{
|
||||
DevCon.WriteLn("Achievements: Leaderboard %u (%s) started", event->leaderboard->id, event->leaderboard->title);
|
||||
@@ -2333,6 +2370,15 @@ bool Achievements::PrepareAchievementsWindow()
|
||||
|
||||
s_achievement_badge_paths = {};
|
||||
|
||||
if (s_subset_list)
|
||||
{
|
||||
rc_client_destroy_subset_list(s_subset_list);
|
||||
s_subset_list = nullptr;
|
||||
}
|
||||
CloseSubset();
|
||||
|
||||
s_subset_list = rc_client_create_subset_list(s_client);
|
||||
|
||||
if (s_achievement_list)
|
||||
rc_client_destroy_achievement_list(s_achievement_list);
|
||||
s_achievement_list = rc_client_create_achievement_list(s_client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL,
|
||||
@@ -2360,6 +2406,9 @@ void Achievements::DrawAchievementsWindow()
|
||||
// ensure image downloads still happen while we're paused
|
||||
Achievements::IdleUpdate();
|
||||
|
||||
const bool has_multiple_subsets = (s_subset_list && s_subset_list->num_subsets > 1);
|
||||
bool s_sidebar_has_focus = false;
|
||||
|
||||
static constexpr float alpha = 0.8f;
|
||||
static constexpr float heading_alpha = 0.95f;
|
||||
static constexpr float heading_height_unscaled = 110.0f;
|
||||
@@ -2409,7 +2458,7 @@ void Achievements::DrawAchievementsWindow()
|
||||
}
|
||||
|
||||
const ImRect title_bb(ImVec2(left, top), ImVec2(right, top + g_large_font.second));
|
||||
text.assign(s_game_title);
|
||||
text.assign(s_open_subset ? s_open_subset->title : s_game_title);
|
||||
|
||||
if (s_hardcore_mode)
|
||||
text.append(TRANSLATE_SV("Achievements", " (Hardcore Mode)"));
|
||||
@@ -2421,18 +2470,28 @@ void Achievements::DrawAchievementsWindow()
|
||||
ImGui::PopFont();
|
||||
|
||||
const ImRect summary_bb(ImVec2(left, top), ImVec2(right, top + g_medium_font.second));
|
||||
if (s_game_summary.num_core_achievements > 0)
|
||||
UpdateGameSummary();
|
||||
|
||||
rc_client_user_game_summary_t display_summary = {};
|
||||
const rc_client_user_game_summary_t* summary_ptr = &s_game_summary;
|
||||
if (s_open_subset)
|
||||
{
|
||||
if (s_game_summary.num_unlocked_achievements == s_game_summary.num_core_achievements)
|
||||
rc_client_get_user_subset_summary(s_client, s_open_subset->id, &display_summary);
|
||||
summary_ptr = &display_summary;
|
||||
}
|
||||
|
||||
if (summary_ptr->num_core_achievements > 0)
|
||||
{
|
||||
if (summary_ptr->num_unlocked_achievements == summary_ptr->num_core_achievements)
|
||||
{
|
||||
text.format(TRANSLATE_FS("Achievements", "You have unlocked all achievements and earned {} points!"),
|
||||
s_game_summary.points_unlocked);
|
||||
summary_ptr->points_unlocked);
|
||||
}
|
||||
else
|
||||
{
|
||||
text.format(TRANSLATE_FS("Achievements", "You have unlocked {0} of {1} achievements, earning {2} of {3} possible points."),
|
||||
s_game_summary.num_unlocked_achievements, s_game_summary.num_core_achievements, s_game_summary.points_unlocked,
|
||||
s_game_summary.points_core);
|
||||
summary_ptr->num_unlocked_achievements, summary_ptr->num_core_achievements, summary_ptr->points_unlocked,
|
||||
summary_ptr->points_core);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2447,12 +2506,12 @@ void Achievements::DrawAchievementsWindow()
|
||||
summary_bb.Min, summary_bb.Max, text.c_str(), text.end_ptr(), nullptr, ImVec2(0.0f, 0.0f), &summary_bb);
|
||||
ImGui::PopFont();
|
||||
|
||||
if (s_game_summary.num_core_achievements > 0)
|
||||
if (summary_ptr->num_core_achievements > 0)
|
||||
{
|
||||
const float progress_height = ImGuiFullscreen::LayoutScale(20.0f);
|
||||
const ImRect progress_bb(ImVec2(left, top), ImVec2(right, top + progress_height));
|
||||
const float fraction =
|
||||
static_cast<float>(s_game_summary.num_unlocked_achievements) / static_cast<float>(s_game_summary.num_core_achievements);
|
||||
static_cast<float>(summary_ptr->num_unlocked_achievements) / static_cast<float>(summary_ptr->num_core_achievements);
|
||||
dl->AddRectFilled(progress_bb.Min, progress_bb.Max, ImGui::GetColorU32(ImGuiFullscreen::UIPrimaryDarkColor));
|
||||
dl->AddRectFilled(progress_bb.Min, ImVec2(progress_bb.Min.x + fraction * progress_bb.GetWidth(), progress_bb.Max.y),
|
||||
ImGui::GetColorU32(ImGuiFullscreen::UISecondaryColor));
|
||||
@@ -2473,68 +2532,203 @@ void Achievements::DrawAchievementsWindow()
|
||||
|
||||
ImGui::SetNextWindowBgAlpha(alpha);
|
||||
|
||||
const float sidebar_width = has_multiple_subsets ? LayoutScale(200.0f) : 0.0f;
|
||||
|
||||
if (has_multiple_subsets && !s_open_subset)
|
||||
{
|
||||
OpenSubset(s_subset_list->subsets[0]);
|
||||
}
|
||||
|
||||
if (ImGuiFullscreen::BeginFullscreenWindow(
|
||||
ImVec2(0.0f, heading_height),
|
||||
ImVec2(display_size.x, display_size.y - heading_height - LayoutScale(ImGuiFullscreen::LAYOUT_FOOTER_HEIGHT)),
|
||||
"achievements", background, 0.0f, ImVec2(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, 0.0f), 0))
|
||||
"achievements", background, 0.0f, ImVec2(0.0f, 0.0f), 0))
|
||||
{
|
||||
static std::map<std::pair<u32, u32>, bool> buckets_collapsed;
|
||||
static const char* bucket_names[NUM_RC_CLIENT_ACHIEVEMENT_BUCKETS] = {
|
||||
TRANSLATE_NOOP("Achievements", "Unknown"),
|
||||
TRANSLATE_NOOP("Achievements", "Locked"),
|
||||
TRANSLATE_NOOP("Achievements", "Unlocked"),
|
||||
TRANSLATE_NOOP("Achievements", "Unsupported"),
|
||||
TRANSLATE_NOOP("Achievements", "Unofficial"),
|
||||
TRANSLATE_NOOP("Achievements", "Recently Unlocked"),
|
||||
TRANSLATE_NOOP("Achievements", "Active Challenges"),
|
||||
TRANSLATE_NOOP("Achievements", "Almost There"),
|
||||
};
|
||||
|
||||
ImGuiFullscreen::BeginMenuButtons();
|
||||
|
||||
for (u32 bucket_type : {RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE, RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED,
|
||||
RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED, RC_CLIENT_ACHIEVEMENT_BUCKET_ALMOST_THERE, RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED,
|
||||
RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL, RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED})
|
||||
if (has_multiple_subsets)
|
||||
{
|
||||
for (u32 bucket_idx = 0; bucket_idx < s_achievement_list->num_buckets; bucket_idx++)
|
||||
const ImVec4 sidebar_bg(0.10f, 0.10f, 0.10f, alpha);
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, sidebar_bg);
|
||||
|
||||
if (ImGui::BeginChild("subset_sidebar", ImVec2(sidebar_width, 0.0f), ImGuiChildFlags_NavFlattened, 0))
|
||||
{
|
||||
const rc_client_achievement_bucket_t& bucket = s_achievement_list->buckets[bucket_idx];
|
||||
if (bucket.bucket_type != bucket_type)
|
||||
continue;
|
||||
ImGuiFullscreen::BeginMenuButtons();
|
||||
|
||||
pxAssert(bucket.bucket_type < NUM_RC_CLIENT_ACHIEVEMENT_BUCKETS);
|
||||
|
||||
bool& bucket_collapsed = buckets_collapsed[std::make_pair(bucket.subset_id, bucket.bucket_type)];
|
||||
const char* translated_bucket_name = Host::TranslateToCString("Achievements", bucket_names[bucket.bucket_type]);
|
||||
|
||||
if (bucket.subset_id != 0)
|
||||
for (u32 i = 0; i < s_subset_list->num_subsets; i++)
|
||||
{
|
||||
const rc_client_subset_t* subset_info = rc_client_get_subset_info(s_client, bucket.subset_id);
|
||||
bucket_collapsed ^=
|
||||
ImGuiFullscreen::MenuHeadingButton(TinyString::from_format("{} - {}",
|
||||
subset_info != nullptr ? subset_info->title : TRANSLATE("Achievements", "Unknown Subset"),
|
||||
translated_bucket_name), bucket_collapsed ? ICON_FA_CHEVRON_DOWN : ICON_FA_CHEVRON_UP);
|
||||
const rc_client_subset_t* subset = s_subset_list->subsets[i];
|
||||
TinyString id_str;
|
||||
id_str.format("sidebar_subset_{}", subset->id);
|
||||
|
||||
ImRect bb;
|
||||
bool visible, hovered;
|
||||
ImGuiFullscreen::MenuButtonFrame(id_str, true, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY,
|
||||
&visible, &hovered, &bb.Min, &bb.Max, 0, 1.0f);
|
||||
|
||||
if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
|
||||
s_sidebar_has_focus = true;
|
||||
|
||||
const float padding = LayoutScale(10.0f);
|
||||
const float spacing = LayoutScale(8.0f);
|
||||
const float icon_size = LayoutScale(28.0f);
|
||||
|
||||
if (s_open_subset && s_open_subset->id == subset->id)
|
||||
{
|
||||
const float line_width = LayoutScale(4.0f);
|
||||
const ImVec2 line_min(bb.Min.x, bb.Min.y);
|
||||
const ImVec2 line_max(bb.Min.x + line_width, bb.Max.y);
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(line_min, line_max, IM_COL32(52, 152, 219, 255));
|
||||
}
|
||||
|
||||
const ImVec2 icon_min(bb.Min.x + padding, bb.Min.y + (bb.Max.y - bb.Min.y - icon_size) * 0.5f);
|
||||
const ImVec2 icon_max(icon_min.x + icon_size, icon_min.y + icon_size);
|
||||
|
||||
std::string badge_path = GetSubsetBadgePath(subset);
|
||||
if (!badge_path.empty())
|
||||
{
|
||||
GSTexture* badge = ImGuiFullscreen::GetCachedTextureAsync(badge_path);
|
||||
if (badge)
|
||||
{
|
||||
ImGui::GetWindowDrawList()->AddImage(reinterpret_cast<ImTextureID>(badge->GetNativeHandle()),
|
||||
icon_min, icon_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
|
||||
const float text_x = icon_max.x + spacing;
|
||||
const ImRect text_bb(ImVec2(text_x, bb.Min.y), ImVec2(bb.Max.x - padding, bb.Max.y));
|
||||
|
||||
ImGui::PushFont(g_medium_font.first, g_medium_font.second);
|
||||
ImGui::RenderTextClipped(text_bb.Min, text_bb.Max, subset->title, nullptr, nullptr, ImVec2(0.0f, 0.5f), &text_bb);
|
||||
ImGui::PopFont();
|
||||
|
||||
if (ImGui::IsItemClicked() || ImGui::IsItemActivated())
|
||||
OpenSubset(subset);
|
||||
}
|
||||
else
|
||||
|
||||
ImGuiFullscreen::EndMenuButtons();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
|
||||
s_sidebar_has_focus = true;
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
const float content_width = has_multiple_subsets ? (display_size.x - sidebar_width) : display_size.x;
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, 0.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, background);
|
||||
ImGui::PushStyleColor(ImGuiCol_Header, ImGui::GetColorU32(ImGuiFullscreen::UIPrimaryDarkColor));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImGui::GetColorU32(ImGuiFullscreen::UIPrimaryColor));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImGui::GetColorU32(ImGuiFullscreen::UISecondaryColor));
|
||||
|
||||
if (ImGui::BeginChild("achievements_content", ImVec2(content_width, 0.0f), ImGuiChildFlags_NavFlattened, 0))
|
||||
{
|
||||
if (ImGui::IsWindowHovered() || ImGui::IsWindowFocused())
|
||||
s_sidebar_has_focus = false;
|
||||
|
||||
static std::map<std::pair<u32, u32>, bool> buckets_collapsed;
|
||||
static const char* bucket_names[NUM_RC_CLIENT_ACHIEVEMENT_BUCKETS] = {
|
||||
TRANSLATE_NOOP("Achievements", "Unknown"),
|
||||
TRANSLATE_NOOP("Achievements", "Locked"),
|
||||
TRANSLATE_NOOP("Achievements", "Unlocked"),
|
||||
TRANSLATE_NOOP("Achievements", "Unsupported"),
|
||||
TRANSLATE_NOOP("Achievements", "Unofficial"),
|
||||
TRANSLATE_NOOP("Achievements", "Recently Unlocked"),
|
||||
TRANSLATE_NOOP("Achievements", "Active Challenges"),
|
||||
TRANSLATE_NOOP("Achievements", "Almost There"),
|
||||
};
|
||||
|
||||
ImGuiFullscreen::BeginMenuButtons();
|
||||
|
||||
for (u32 bucket_type : {RC_CLIENT_ACHIEVEMENT_BUCKET_ACTIVE_CHALLENGE, RC_CLIENT_ACHIEVEMENT_BUCKET_RECENTLY_UNLOCKED,
|
||||
RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED, RC_CLIENT_ACHIEVEMENT_BUCKET_ALMOST_THERE, RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED,
|
||||
RC_CLIENT_ACHIEVEMENT_BUCKET_UNOFFICIAL, RC_CLIENT_ACHIEVEMENT_BUCKET_UNSUPPORTED})
|
||||
{
|
||||
for (u32 bucket_idx = 0; bucket_idx < s_achievement_list->num_buckets; bucket_idx++)
|
||||
{
|
||||
// Game without subsets
|
||||
const rc_client_achievement_bucket_t& bucket = s_achievement_list->buckets[bucket_idx];
|
||||
if (bucket.bucket_type != bucket_type)
|
||||
continue;
|
||||
|
||||
if (s_open_subset && bucket.subset_id != s_open_subset->id)
|
||||
continue;
|
||||
|
||||
pxAssert(bucket.bucket_type < NUM_RC_CLIENT_ACHIEVEMENT_BUCKETS);
|
||||
|
||||
bool& bucket_collapsed = buckets_collapsed[std::make_pair(bucket.subset_id, bucket.bucket_type)];
|
||||
const char* translated_bucket_name = Host::TranslateToCString("Achievements", bucket_names[bucket.bucket_type]);
|
||||
|
||||
bucket_collapsed ^=
|
||||
ImGuiFullscreen::MenuHeadingButton(translated_bucket_name,
|
||||
bucket_collapsed ? ICON_FA_CHEVRON_DOWN : ICON_FA_CHEVRON_UP);
|
||||
}
|
||||
|
||||
if (!bucket_collapsed)
|
||||
{
|
||||
for (u32 i = 0; i < bucket.num_achievements; i++)
|
||||
DrawAchievement(bucket.achievements[i]);
|
||||
if (!bucket_collapsed)
|
||||
{
|
||||
for (u32 i = 0; i < bucket.num_achievements; i++)
|
||||
DrawAchievement(bucket.achievements[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiFullscreen::EndMenuButtons();
|
||||
ImGuiFullscreen::EndMenuButtons();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::PopStyleColor(4);
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGuiFullscreen::EndFullscreenWindow();
|
||||
FullscreenUI::SetStandardSelectionFooterText(true);
|
||||
|
||||
if (has_multiple_subsets)
|
||||
{
|
||||
if (ImGuiFullscreen::IsGamepadInputSource())
|
||||
{
|
||||
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
|
||||
if (s_sidebar_has_focus)
|
||||
{
|
||||
ImGuiFullscreen::SetFullscreenFooterText(std::array{
|
||||
std::make_pair(ICON_PF_DPAD_UP_DOWN, TRANSLATE_SV("Achievements", "Navigate Subsets")),
|
||||
std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, TRANSLATE_SV("Achievements", "Back to List")),
|
||||
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, TRANSLATE_SV("Achievements", "Select")),
|
||||
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, TRANSLATE_SV("Achievements", "Back")),
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiFullscreen::SetFullscreenFooterText(std::array{
|
||||
std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, TRANSLATE_SV("Achievements", "Navigate Subsets")),
|
||||
std::make_pair(ICON_PF_DPAD_UP_DOWN, TRANSLATE_SV("Achievements", "Change Selection")),
|
||||
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, TRANSLATE_SV("Achievements", "Back")),
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_sidebar_has_focus)
|
||||
{
|
||||
ImGuiFullscreen::SetFullscreenFooterText(std::array{
|
||||
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, TRANSLATE_SV("Achievements", "Navigate Subsets")),
|
||||
std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, TRANSLATE_SV("Achievements", "Back to List")),
|
||||
std::make_pair(ICON_PF_ENTER, TRANSLATE_SV("Achievements", "Select")),
|
||||
std::make_pair(ICON_PF_ESC, TRANSLATE_SV("Achievements", "Back")),
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiFullscreen::SetFullscreenFooterText(std::array{
|
||||
std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, TRANSLATE_SV("Achievements", "Navigate Subsets")),
|
||||
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, TRANSLATE_SV("Achievements", "Change Selection")),
|
||||
std::make_pair(ICON_PF_ESC, TRANSLATE_SV("Achievements", "Back")),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FullscreenUI::SetStandardSelectionFooterText(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo)
|
||||
@@ -2610,23 +2804,36 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo)
|
||||
const float points_start = points_template_start + ((points_template_size.x - points_size.x) * 0.5f);
|
||||
|
||||
const char* right_icon_text;
|
||||
const char* badge_text;
|
||||
const char* badge_icon;
|
||||
ImVec4 badge_color;
|
||||
switch (cheevo->type)
|
||||
{
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE:
|
||||
right_icon_text = ICON_PF_ACHIEVEMENTS_MISSABLE; // Missable
|
||||
badge_text = TRANSLATE("Achievements", "Missable");
|
||||
badge_icon = ICON_PF_ACHIEVEMENTS_MISSABLE;
|
||||
badge_color = ImVec4(0.78f, 0.55f, 0.30f, 1.0f);
|
||||
right_icon_text = is_unlocked ? ICON_FA_LOCK_OPEN : ICON_FA_LOCK;
|
||||
break;
|
||||
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION:
|
||||
right_icon_text = ICON_PF_ACHIEVEMENTS_PROGRESSION; // Progression
|
||||
badge_text = TRANSLATE("Achievements", "Progression");
|
||||
badge_icon = ICON_PF_ACHIEVEMENTS_PROGRESSION;
|
||||
badge_color = ImVec4(0.62f, 0.48f, 0.80f, 1.0f);
|
||||
right_icon_text = is_unlocked ? ICON_FA_LOCK_OPEN : ICON_FA_LOCK;
|
||||
break;
|
||||
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_WIN:
|
||||
right_icon_text = ICON_PF_ACHIEVEMENTS_WIN; // Win Condition
|
||||
badge_text = TRANSLATE("Achievements", "Win Condition");
|
||||
badge_icon = ICON_PF_ACHIEVEMENTS_WIN;
|
||||
badge_color = ImVec4(0.36f, 0.62f, 0.36f, 1.0f);
|
||||
right_icon_text = is_unlocked ? ICON_FA_LOCK_OPEN : ICON_FA_LOCK;
|
||||
break;
|
||||
|
||||
// Just use the lock for standard achievements.
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD:
|
||||
default:
|
||||
badge_text = nullptr;
|
||||
badge_icon = nullptr;
|
||||
right_icon_text = is_unlocked ? ICON_FA_LOCK_OPEN : ICON_FA_LOCK;
|
||||
break;
|
||||
}
|
||||
@@ -2634,7 +2841,34 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo)
|
||||
const ImVec2 right_icon_size(g_large_font.first->CalcTextSizeA(g_large_font.second, FLT_MAX, 0.0f, right_icon_text));
|
||||
|
||||
const float text_start_x = bb.Min.x + image_size.x + LayoutScale(15.0f);
|
||||
const ImRect title_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(points_start, midpoint));
|
||||
|
||||
const float badge_padding = LayoutScale(6.0f);
|
||||
const float icon_text_spacing = LayoutScale(4.0f);
|
||||
const float badge_title_spacing = LayoutScale(6.0f);
|
||||
ImVec2 badge_size = ImVec2(0.0f, 0.0f);
|
||||
ImVec2 badge_icon_size = ImVec2(0.0f, 0.0f);
|
||||
ImVec2 badge_text_size = ImVec2(0.0f, 0.0f);
|
||||
if (badge_text && badge_icon)
|
||||
{
|
||||
badge_icon_size = g_medium_font.first->CalcTextSizeA(g_medium_font.second, FLT_MAX, 0.0f, badge_icon);
|
||||
badge_text_size = g_medium_font.first->CalcTextSizeA(g_medium_font.second, FLT_MAX, 0.0f, badge_text);
|
||||
badge_size = ImVec2(badge_icon_size.x + icon_text_spacing + badge_text_size.x + (badge_padding * 2.0f),
|
||||
g_medium_font.second + badge_padding);
|
||||
}
|
||||
|
||||
const ImVec2 title_size(g_large_font.first->CalcTextSizeA(g_large_font.second, FLT_MAX, 0.0f, cheevo->title));
|
||||
const float title_text_end_x = text_start_x + title_size.x;
|
||||
|
||||
float title_max_x = points_start;
|
||||
float badge_x = 0.0f;
|
||||
if (badge_text && badge_icon)
|
||||
{
|
||||
const float effective_title_max_x = points_start - (badge_size.x + badge_title_spacing);
|
||||
badge_x = std::min(title_text_end_x + badge_title_spacing, effective_title_max_x);
|
||||
title_max_x = badge_x - badge_title_spacing;
|
||||
}
|
||||
|
||||
const ImRect title_bb(ImVec2(text_start_x, bb.Min.y), ImVec2(title_max_x, midpoint));
|
||||
const ImRect summary_bb(ImVec2(text_start_x, midpoint), ImVec2(points_start, midpoint + g_medium_font.second + extra_summary_height));
|
||||
const ImRect points_bb(ImVec2(points_start, midpoint), bb.Max);
|
||||
const ImRect lock_bb(
|
||||
@@ -2645,6 +2879,24 @@ void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo)
|
||||
ImGui::RenderTextClipped(lock_bb.Min, lock_bb.Max, right_icon_text, nullptr, &right_icon_size, ImVec2(0.0f, 0.0f), &lock_bb);
|
||||
ImGui::PopFont();
|
||||
|
||||
if (badge_text && badge_icon)
|
||||
{
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
const ImVec2 badge_min(badge_x, bb.Min.y + ((midpoint - bb.Min.y) / 2.0f) - (badge_size.y / 2.0f));
|
||||
const ImVec2 badge_max(badge_min.x + badge_size.x, badge_min.y + badge_size.y);
|
||||
|
||||
dl->AddRectFilled(badge_min, badge_max, ImGui::GetColorU32(badge_color), LayoutScale(3.0f));
|
||||
|
||||
const float icon_y = badge_min.y + ((badge_size.y - badge_icon_size.y) * 0.5f);
|
||||
const float text_y = badge_min.y + ((badge_size.y - badge_text_size.y) * 0.5f);
|
||||
|
||||
const ImVec2 icon_pos(badge_min.x + badge_padding, icon_y);
|
||||
dl->AddText(g_medium_font.first, g_medium_font.second, icon_pos, IM_COL32(255, 255, 255, 255), badge_icon);
|
||||
|
||||
const ImVec2 text_pos(icon_pos.x + badge_icon_size.x + icon_text_spacing, text_y);
|
||||
dl->AddText(g_medium_font.first, g_medium_font.second, text_pos, IM_COL32(255, 255, 255, 255), badge_text);
|
||||
}
|
||||
|
||||
ImGui::PushFont(g_medium_font.first, g_medium_font.second);
|
||||
if (cheevo->description && summary_length > 0)
|
||||
{
|
||||
@@ -3286,6 +3538,29 @@ void Achievements::CloseLeaderboard()
|
||||
s_open_leaderboard = nullptr;
|
||||
}
|
||||
|
||||
std::string Achievements::GetSubsetBadgePath(const rc_client_subset_t* subset)
|
||||
{
|
||||
if (!subset || !subset->badge_name[0])
|
||||
return {};
|
||||
|
||||
std::string path = Path::Combine(s_image_directory, fmt::format("subset_{}.png", subset->badge_name));
|
||||
if (!path.empty() && subset->badge_url && !FileSystem::FileExists(path.c_str()))
|
||||
DownloadImage(subset->badge_url, path);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void Achievements::OpenSubset(const rc_client_subset_t* subset)
|
||||
{
|
||||
Console.WriteLn("Achievements: Opening subset '%s' (%u)", subset->title, subset->id);
|
||||
s_open_subset = subset;
|
||||
}
|
||||
|
||||
void Achievements::CloseSubset()
|
||||
{
|
||||
s_open_subset = nullptr;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_RAINTEGRATION
|
||||
|
||||
#include "RA_Consoles.h"
|
||||
|
||||
+8
-2
@@ -102,10 +102,16 @@ static void CDVD_INT(int eCycle)
|
||||
// test (which will cause the exception to be handled).
|
||||
static void cdvdSetIrq(uint id = (1 << Irq_CommandComplete))
|
||||
{
|
||||
if (!(cdvd.IntrStat & id))
|
||||
{
|
||||
iopIntcIrq(2);
|
||||
psxSetNextBranchDelta(20);
|
||||
}
|
||||
else
|
||||
DevCon.Warning("CDVD trying to double issue IRQ %x", id);
|
||||
|
||||
cdvd.IntrStat |= id;
|
||||
cdvd.AbortRequested = false;
|
||||
iopIntcIrq(2);
|
||||
psxSetNextBranchDelta(20);
|
||||
}
|
||||
|
||||
static int mg_BIToffset(u8* buffer)
|
||||
|
||||
@@ -247,7 +247,6 @@ set(pcsx2SPU2Sources
|
||||
SPU2/ADSR.cpp
|
||||
SPU2/Debug.cpp
|
||||
SPU2/Dma.cpp
|
||||
SPU2/Mixer.cpp
|
||||
SPU2/spu2.cpp
|
||||
SPU2/ReadInput.cpp
|
||||
SPU2/RegTable.cpp
|
||||
@@ -258,6 +257,7 @@ set(pcsx2SPU2Sources
|
||||
)
|
||||
|
||||
set(pcsx2SPU2SourcesUnshared
|
||||
SPU2/Mixer.cpp
|
||||
SPU2/ReverbResample.cpp
|
||||
)
|
||||
|
||||
|
||||
+336
-85
@@ -3560,7 +3560,7 @@ __forceinline bool AreTrianglesQuad(const GSVertex* RESTRICT vin, const u16* RES
|
||||
return are_quad;
|
||||
}
|
||||
|
||||
bool GSState::AreTrianglesQuadNonAA(const GSVertex* RESTRICT vin, const u16* RESTRICT index0, const u16* RESTRICT index1)
|
||||
__forceinline bool AreTrianglesQuadNonAA(const GSVertex* RESTRICT vin, const u16* RESTRICT index0, const u16* RESTRICT index1)
|
||||
{
|
||||
u32 v0[3] = {
|
||||
vin[index0[0]].XYZ.U32[0],
|
||||
@@ -3754,12 +3754,11 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
|
||||
const u16* RESTRICT index = m_index.buff;
|
||||
const u32 count = m_index.tail;
|
||||
|
||||
// Optimize out using indices for sprites and points; probably not much difference.
|
||||
const auto GetIndex = [&](int i) {
|
||||
const auto GetPoint = [v, index](int i) -> GSVector4i {
|
||||
if constexpr (primclass == GS_SPRITE_CLASS || primclass == GS_POINT_CLASS)
|
||||
return i;
|
||||
return GSVector4i(v[i].m[1]).upl16(); // Optimize out using the indices.
|
||||
else
|
||||
return index[i];
|
||||
return GSVector4i(v[index[i]].m[1]).upl16();
|
||||
};
|
||||
|
||||
// Batch prim into groups so that within each group the cumulative bboxes are non-overlapping.
|
||||
@@ -3783,8 +3782,15 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
|
||||
|
||||
u32 i = 0;
|
||||
u32 skip = 0; // Number of indices to skip if we have the bbox from the previous iteration.
|
||||
|
||||
// To cache a tristrip for the next iteration if we cannot use it in this iteration.
|
||||
struct SavedTristrip {
|
||||
bool saved = false;
|
||||
u32 skip;
|
||||
BoundingOct bbox;
|
||||
} saved_tristrip;
|
||||
|
||||
GSVector4i all(INT_MAX, INT_MAX, -INT_MAX, -INT_MAX);
|
||||
BoundingOct all;
|
||||
|
||||
while (i < count)
|
||||
{
|
||||
@@ -3792,149 +3798,394 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlistImpl(bool save_drawlis
|
||||
|
||||
skip = 0;
|
||||
|
||||
GSVector4i bbox(INT_MAX, INT_MAX, -INT_MAX, -INT_MAX);
|
||||
BoundingOct bbox;
|
||||
|
||||
while (j < count)
|
||||
{
|
||||
bool got_bbox = false;
|
||||
|
||||
// Assuming that indices 0-5 represent two triangles:
|
||||
// Triangle strips: indices 1, 2 are identical to indices 3, 4. Indices 0, 5 are different.
|
||||
// Triangles fans: indices 0, 2 are identical to indices 3, 4. Indices 1, 5 are different.
|
||||
// Warning: this depends on how the vertices are arranged in the vertex kick.
|
||||
// if that changes this detection will break.
|
||||
constexpr std::array<std::array<std::array<int, 3>, 2>, 2> tri_order({
|
||||
// Triangle strip expected indices.
|
||||
std::array{ std::array<int, 3>{ 1, 2, 0 }, std::array<int, 3>{ 3, 4, 5 } },
|
||||
// Test overlap of two adjacent triangles give the indices of the
|
||||
// shared edge and two unshared points.
|
||||
const auto TrianglesOverlap = [v, index, GetPoint]
|
||||
(u32 s0, u32 s1, u32 u0, u32 u1, bool& sign_out) -> bool {
|
||||
|
||||
// Triangle fan expected indices.
|
||||
std::array{ std::array<int, 3>{ 0, 2, 1 }, std::array<int, 3>{ 3, 4, 5 } },
|
||||
});
|
||||
const GSVector4i shared0 = GetPoint(s0);
|
||||
const GSVector4i shared1 = GetPoint(s1) - shared0;
|
||||
const GSVector4i unshared0 = GetPoint(u0) - shared0;
|
||||
const GSVector4i unshared1 = GetPoint(u1) - shared0;
|
||||
|
||||
// Determine which side of the shared edge each triangle is on.
|
||||
const bool sign0 = unshared0.x * shared1.y - unshared0.y * shared1.x >= 0;
|
||||
const bool sign1 = unshared1.x * shared1.y - unshared1.y * shared1.x >= 0;
|
||||
|
||||
sign_out = sign0; // Output side of the first triangle with respect to the shared edge.
|
||||
|
||||
// Cross product signs comparison. If true, triangles are on same side of the shared edge.
|
||||
return sign0 == sign1;
|
||||
};
|
||||
|
||||
// Helper to detect triangles strips/fans (template 0 for strips, 1 for fans).
|
||||
const auto CheckTriangleQuads = [v, index, count, TrianglesOverlap, GetPoint]
|
||||
<int type>(u32 i, u32& skip, BoundingOct& bbox) -> bool {
|
||||
|
||||
// Assuming that indices 0-5 represent two triangles:
|
||||
// Triangle strips: indices 1, 2 are identical to indices 3, 4. Indices 0, 5 are different.
|
||||
// Triangles fans: indices 0, 2 are identical to indices 3, 4. Indices 1, 5 are different.
|
||||
// Warning: this depends on how the vertices are arranged in the vertex kick.
|
||||
// if that changes this detection will break.
|
||||
constexpr std::array<std::array<std::array<int, 3>, 2>, 2> tri_order({
|
||||
// Triangle strip expected indices.
|
||||
std::array{ std::array<int, 3>{ 1, 2, 0 }, std::array<int, 3>{ 3, 4, 5 } },
|
||||
|
||||
// Triangle fan expected indices.
|
||||
std::array{ std::array<int, 3>{ 0, 2, 1 }, std::array<int, 3>{ 3, 4, 5 } },
|
||||
});
|
||||
|
||||
const auto CheckTriangleQuads = [&]<int type>() {
|
||||
constexpr std::array<int, 3> tri0 = tri_order[type][0];
|
||||
constexpr std::array<int, 3> tri1 = tri_order[type][1];
|
||||
|
||||
if (!got_bbox && primclass == GS_TRIANGLE_CLASS && j + 3 < count &&
|
||||
index[j + tri0[0]] == index[j + tri1[0]] &&
|
||||
index[j + tri0[1]] == index[j + tri1[1]])
|
||||
// Check that the initial two triangles form a strip.
|
||||
if (!(primclass == GS_TRIANGLE_CLASS && i + 6 <= count &&
|
||||
index[i + tri0[0]] == index[i + tri1[0]] &&
|
||||
index[i + tri0[1]] == index[i + tri1[1]]))
|
||||
{
|
||||
// Get the initial triangle bbox.
|
||||
bbox = GSVector4i(v[index[j + 0]].m[1]).upl16().xyxy();
|
||||
bbox = bbox.runion(GSVector4i(v[index[j + 1]].m[1]).upl16().xyxy());
|
||||
bbox = bbox.runion(GSVector4i(v[index[j + 2]].m[1]).upl16().xyxy());
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true)
|
||||
u32 j = i;
|
||||
|
||||
// Get the initial triangle bbox.
|
||||
bbox = BoundingOct::FromPoint(GetPoint(j + 0));
|
||||
bbox = bbox.Union(GetPoint(j + 1));
|
||||
bbox = bbox.Union(GetPoint(j + 2));
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Check if the two triangles overlap.
|
||||
[[maybe_unused]] bool sign;// ignore
|
||||
if (TrianglesOverlap(j + tri1[0], j + tri1[1], j + tri0[2], j + tri1[2], sign))
|
||||
{
|
||||
// There is a shared edge between this and next triangle.
|
||||
// Check if the unshared point is on opposite sides of the shared edge.
|
||||
const GSVector4i shared0 = GSVector4i(v[index[j + skip + tri0[0]]].m[1]).upl16();
|
||||
const GSVector4i shared1 = GSVector4i(v[index[j + skip + tri0[1]]].m[1]).upl16() - shared0;
|
||||
const GSVector4i unshared0 = GSVector4i(v[index[j + skip + tri0[2]]].m[1]).upl16() - shared0;
|
||||
const GSVector4i unshared1 = GSVector4i(v[index[j + skip + tri1[2]]].m[1]).upl16() - shared0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Cross product signs comparison.
|
||||
if ((unshared0.x * shared1.y - unshared0.y * shared1.x >= 0) ==
|
||||
(unshared1.x * shared1.y - unshared1.y * shared1.x >= 0))
|
||||
// Corners are on opposite sides so we can assume a non-axis-aligned quad.
|
||||
// Take union with the single unshared point.
|
||||
bbox = bbox.Union(GetPoint(j + tri1[2]));
|
||||
j += 3;
|
||||
|
||||
if (!(j + 6 <= count &&
|
||||
index[j + tri0[0]] == index[j + tri1[0]] &&
|
||||
index[j + tri0[1]] == index[j + tri1[1]]))
|
||||
{
|
||||
// Cannot continue the strip/fan.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == i)
|
||||
{
|
||||
return false; // Only a single triangle in the strip.
|
||||
}
|
||||
|
||||
skip = j - i + 3; // Number of vertices in the loop + first triangle.
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Helper functions to find a common edge between two triangles and check if they overlap.
|
||||
// Template parameter indicates if the triangle is at the end of the strip or beginning.
|
||||
const auto MatchTriangles = [v, index, TrianglesOverlap]<bool end0, bool end1>
|
||||
(u32 tri0, u32 tri1, bool& sign) -> bool {
|
||||
|
||||
// For the end triangle only consider the last edge of the triangle.
|
||||
// For the start triangle only consider the first edge of the triangle.
|
||||
const u32 base0 = end0 ? 1 : 0;
|
||||
const u32 base1 = end1 ? 1 : 0;
|
||||
|
||||
for (int i0 = base0; i0 < base0 + 2; i0++)
|
||||
{
|
||||
for (int i1 = base1; i1 < base1 + 2; i1++)
|
||||
{
|
||||
if (v[index[tri0 + i0]].XYZ.U32[0] == v[index[tri1 + i1]].XYZ.U32[0])
|
||||
{
|
||||
break; // Triangles are on same side of the shared edge so there's overlap.
|
||||
}
|
||||
// Get the index that should be shared between the adjacent triangles.
|
||||
const int j0 = end0 ? (i0 == 2 ? 0 : i0 - 4) : (i0 == 0 ? 2 : i0 + 4);
|
||||
const int j1 = end1 ? (i1 == 2 ? 0 : i1 - 4) : (i1 == 0 ? 2 : i1 + 4);
|
||||
|
||||
// Corners are on opposite sides so we can assume a non-axis-aligned quad.
|
||||
// Take union with the single unshared point.
|
||||
bbox = bbox.runion(GSVector4i(v[index[j + skip + tri1[2]]].m[1]).upl16().xyxy());
|
||||
if (v[index[tri0 + j0]].XYZ.U32[0] != v[index[tri1 + j1]].XYZ.U32[0])
|
||||
{
|
||||
return false; // Edge is not shared.
|
||||
}
|
||||
|
||||
skip += 3;
|
||||
// Get the indices that should be unshared.
|
||||
const int k0 = end0 ? 3 - i0 : 1 - i0;
|
||||
const int k1 = end1 ? 3 - i1 : 1 - i1;
|
||||
|
||||
got_bbox = true;
|
||||
// Get the shared edge in the order of the first strip's increasing indices.
|
||||
// Consistency is important for the sign check to work correctly.
|
||||
const int s0 = std::min(i0, j0);
|
||||
const int t0 = std::max(i0, j0);
|
||||
|
||||
if (!(j + skip + 3 < count &&
|
||||
index[j + skip + tri0[0]] == index[j + skip + tri1[0]] &&
|
||||
index[j + skip + tri0[1]] == index[j + skip + tri1[1]]))
|
||||
{
|
||||
// Cannot continue the strip/fan. Consume the last triangle and exit.
|
||||
skip += 3;
|
||||
break;
|
||||
return !TrianglesOverlap(tri0 + s0, tri0 + t0, tri0 + k0, tri1 + k1, sign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// First check: see if the triangles are part of triangle strip/fan.
|
||||
if (primclass == GS_TRIANGLE_CLASS)
|
||||
{
|
||||
CheckTriangleQuads.template operator()<0>(); // Check triangle strips.
|
||||
CheckTriangleQuads.template operator()<1>(); // Check triangle fans.
|
||||
}
|
||||
// Helper function to detect triangles strips and merge them together into
|
||||
// a grid of triangles strips.
|
||||
const auto CheckTriangleStrips = [index, v, count, CheckTriangleQuads, MatchTriangles, GetPoint]
|
||||
(u32 i, u32& skip, BoundingOct& bbox_all, SavedTristrip& saved_tristrip) -> bool {
|
||||
|
||||
// Second check: see if triangles form an axis-aligned quad.
|
||||
if (!got_bbox && primclass == GS_TRIANGLE_CLASS && check_quads && j + 3 < count)
|
||||
{
|
||||
const u16* RESTRICT idx0 = &index[j + 0];
|
||||
const u16* RESTRICT idx1 = &index[j + 3];
|
||||
if (!(primclass == GS_TRIANGLE_CLASS && i + 6 <= count))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 j = i;
|
||||
|
||||
u32 prev_tri0; // First triangle of previous tristrip.
|
||||
u32 prev_tri1; // Last triangle of previous tristrip.
|
||||
|
||||
bool all_small; // Whether all strips so far have 2 triangles only.
|
||||
|
||||
u32 n_tristrips = 0; // Number of tristrips merged so far.
|
||||
|
||||
// Used to make sure the tristrips are adjacent in the same direction so there's not overlap.
|
||||
bool expected_sign;
|
||||
|
||||
// For another heuristic to determine if the tristrips are overlapping themselves.
|
||||
// Stores the maximum difference in X/Y from the starting point.
|
||||
GSVector4i start_pt;
|
||||
GSVector4i max_delta(0, 0);
|
||||
|
||||
// Whether the current tristrip is oriented in the same direction as the first.
|
||||
bool orientation = true;
|
||||
|
||||
BoundingOct bbox; // BBox of current strip.
|
||||
|
||||
// Check for the first tristrip in the chain.
|
||||
if (saved_tristrip.saved)
|
||||
{
|
||||
// Have a tristrip saved from a previous iteration.
|
||||
skip = saved_tristrip.skip;
|
||||
bbox = saved_tristrip.bbox;
|
||||
saved_tristrip.saved = false;
|
||||
}
|
||||
else if (!CheckTriangleQuads.template operator()<0>(j, skip, bbox))
|
||||
{
|
||||
return false;// Could not find a new tristrip.
|
||||
}
|
||||
|
||||
// Initialize loop variables.
|
||||
prev_tri0 = j;
|
||||
prev_tri1 = j + skip - 3;
|
||||
all_small = (skip <= 6);
|
||||
bbox_all = bbox;
|
||||
start_pt = GetPoint(prev_tri0);
|
||||
n_tristrips++;
|
||||
j += skip;
|
||||
|
||||
while (j < count)
|
||||
{
|
||||
if (!CheckTriangleQuads.template operator()<0>(j, skip, bbox))
|
||||
{
|
||||
break; // Cannot continue tristrip grid.
|
||||
}
|
||||
|
||||
// Save the tristrip in case it can be used on the next iteration.
|
||||
saved_tristrip.saved = true;
|
||||
saved_tristrip.skip = skip;
|
||||
saved_tristrip.bbox = bbox;
|
||||
|
||||
// Get first/last triangle of current tristrip.
|
||||
const u32 tri0 = j;
|
||||
const u32 tri1 = j + skip - 3;
|
||||
|
||||
all_small = all_small && (skip <= 6);
|
||||
|
||||
// First heuristic: check if the previous and this tristrip are part of a grid by
|
||||
// checking if the first/last triangles in each strip have a common edge and do not overlap.
|
||||
bool sign0, sign1; // Orientation of how the first and last triangles are adjacent.
|
||||
bool flip; // Whether to flip the expected orientation because the two strips are in opposite directions.
|
||||
|
||||
// Check the first two vertices of first triangles and last two vertices of last triangles.
|
||||
if (MatchTriangles.template operator()<false, false>(prev_tri0, tri0, sign0) &&
|
||||
MatchTriangles.template operator()<true, true>(prev_tri1, tri1, sign1))
|
||||
{
|
||||
flip = false; // Tristrips are in the same directions.
|
||||
}
|
||||
else if (MatchTriangles.template operator()<false, true>(prev_tri0, tri1, sign0) &&
|
||||
MatchTriangles.template operator()<true, false>(prev_tri1, tri0, sign1))
|
||||
{
|
||||
flip = true; // Tristrips are in opposite directions.
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // Cannot continue the tristrip chain.
|
||||
}
|
||||
|
||||
// Second heuristic: make sure the new tristrip is always on the same side as the previous one.
|
||||
if (n_tristrips >= 2)
|
||||
{
|
||||
if (!(sign0 == expected_sign && sign1 == expected_sign))
|
||||
{
|
||||
break; // New tristrip is on the wrong side.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sign0 != sign1)
|
||||
{
|
||||
break; // First/last triangles are on different sides.
|
||||
}
|
||||
expected_sign = sign0;
|
||||
}
|
||||
|
||||
if (flip)
|
||||
{
|
||||
expected_sign = !expected_sign;
|
||||
orientation = !orientation;
|
||||
}
|
||||
|
||||
// Third heuristic: for small tristrips make sure that we never move closer to
|
||||
// the first tristrip in the grid. Small tristrips appears to be more likely to
|
||||
// overlap themself.
|
||||
const GSVector4i curr_pt = GetPoint(orientation ? tri0 : tri1 + 2);
|
||||
const GSVector4i curr_delta = (curr_pt - start_pt).abs32();
|
||||
|
||||
// Check if we moved closer.
|
||||
if (n_tristrips >= 2 && all_small)
|
||||
{
|
||||
if (((curr_delta <= max_delta).mask() & 0xFF) == 0xFF)
|
||||
{
|
||||
break; // We moved closer to the start point in both X/Y so end the merging.
|
||||
}
|
||||
}
|
||||
|
||||
// Update maximum displacement from start.
|
||||
max_delta = max_delta.max_i32(curr_delta);
|
||||
|
||||
prev_tri0 = tri0;
|
||||
prev_tri1 = tri1;
|
||||
bbox_all = bbox_all.Union(bbox);
|
||||
j += skip;
|
||||
saved_tristrip.saved = false; // We consumed the new tristrip.
|
||||
n_tristrips++;
|
||||
}
|
||||
|
||||
skip = j - i;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Helper functions to detect when two triangles form an axis-aligned quad.
|
||||
const auto GetBBoxAxisAlignedTriangles = [v, index, count, GetPoint]
|
||||
(u32 i, u32& skip, BoundingOct& bbox) -> bool {
|
||||
|
||||
if (!(primclass == GS_TRIANGLE_CLASS && i + 6 <= count))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 off0 = i + 0;
|
||||
const u32 off1 = i + 3;
|
||||
TriangleOrdering tri0;
|
||||
TriangleOrdering tri1;
|
||||
|
||||
if (AreTrianglesQuad<0, 0>(v, idx0, idx1, &tri0, &tri1))
|
||||
if (!AreTrianglesQuad<0, 0>(v, index + off0, index + off1, &tri0, &tri1))
|
||||
{
|
||||
// tri.b is right angle corner
|
||||
bbox = GSVector4i(v[idx0[tri0.b]].m[1]).upl16().xyxy();
|
||||
bbox = bbox.runion(GSVector4i(v[idx1[tri1.b]].m[1]).upl16().xyxy());
|
||||
|
||||
skip = 6;
|
||||
return false;
|
||||
}
|
||||
|
||||
got_bbox = true;
|
||||
// tri.b is right angle corner
|
||||
const GSVector4i pt0 = GetPoint(off0 + tri0.b);
|
||||
const GSVector4i pt1 = GetPoint(off1 + tri1.b);
|
||||
bbox = BoundingOct::FromSprite(pt0, pt1);
|
||||
skip = 6;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// Helper functions to just get the individual prim bbox.
|
||||
const auto GetBBox = [v, count, GetPoint](u32 i, u32& skip, BoundingOct& bbox) -> bool {
|
||||
if constexpr (primclass == GS_SPRITE_CLASS)
|
||||
{
|
||||
bbox = BoundingOct::FromSprite(GetPoint(i + 0), GetPoint(i + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we fail a quad check assume the rest are not quads since the check is relatively expensive.
|
||||
check_quads = false;
|
||||
bbox = BoundingOct::FromPoint(GetPoint(i + 0));
|
||||
for (u32 j = 1; j < n; j++) // Unroll
|
||||
{
|
||||
bbox = bbox.Union(GetPoint(i + j));
|
||||
}
|
||||
}
|
||||
skip = n;
|
||||
return true;
|
||||
};
|
||||
|
||||
// First check: see if the triangles are part of a triangle strip.
|
||||
if (!got_bbox)
|
||||
{
|
||||
got_bbox = CheckTriangleStrips(j, skip, bbox, saved_tristrip);
|
||||
}
|
||||
|
||||
// Second check: see if the triangles are part of triangle fan.
|
||||
if (!got_bbox)
|
||||
{
|
||||
got_bbox = CheckTriangleQuads.template operator()<1>(j, skip, bbox);
|
||||
}
|
||||
|
||||
// Third check: see if a pair of triangles are an axis-aligned quad.
|
||||
// This doesn't require indices to match like the tristrip check.
|
||||
if (!got_bbox && check_quads)
|
||||
{
|
||||
got_bbox = GetBBoxAxisAlignedTriangles(j, skip, bbox);
|
||||
|
||||
// If we fail a quad check assume the rest are not quads since the check is relatively expensive.
|
||||
check_quads = got_bbox;
|
||||
}
|
||||
|
||||
// Default case: just take the bbox of the prim vertices.
|
||||
if (!got_bbox)
|
||||
{
|
||||
bbox = GSVector4i(v[GetIndex(j)].m[1]).upl16().xyxy();
|
||||
for (int k = 1; k < n; k++) // Unroll
|
||||
bbox = bbox.runion(GSVector4i(v[GetIndex(j + k)].m[1]).upl16().xyxy());
|
||||
|
||||
skip = n;
|
||||
|
||||
got_bbox = true;
|
||||
got_bbox = GetBBox(j, skip, bbox);
|
||||
}
|
||||
|
||||
// Avoid degenerate bbox.
|
||||
bbox = bbox.blend(bbox + GSVector4i(0, 0, 1, 1), bbox.xyxy() == bbox.zwzw());
|
||||
bbox = bbox.FixDegenerate();
|
||||
|
||||
if (all.rintersects(bbox))
|
||||
if (all.Intersects(bbox))
|
||||
{
|
||||
overlap = PRIM_OVERLAP_YES;
|
||||
break;
|
||||
}
|
||||
|
||||
all = all.runion(bbox);
|
||||
|
||||
all = all.Union(bbox);
|
||||
j += skip;
|
||||
|
||||
skip = 0;
|
||||
}
|
||||
|
||||
if (save_drawlist)
|
||||
{
|
||||
m_drawlist.push_back((j - i) / n); // Prim count
|
||||
}
|
||||
else if (j < count)
|
||||
{
|
||||
return PRIM_OVERLAP_YES; // Early exit if not saving drawlist.
|
||||
}
|
||||
|
||||
if (save_bbox)
|
||||
{
|
||||
m_drawlist_bbox.push_back(ProcessBBox(all));
|
||||
m_drawlist_bbox.push_back(ProcessBBox(all.ToBBox()));
|
||||
}
|
||||
|
||||
all = bbox;
|
||||
|
||||
i = j;
|
||||
}
|
||||
|
||||
return overlap;
|
||||
}
|
||||
|
||||
|
||||
@@ -478,7 +478,6 @@ public:
|
||||
|
||||
template<bool shuffle_check>
|
||||
bool TrianglesAreQuadsImpl();
|
||||
bool AreTrianglesQuadNonAA(const GSVertex* RESTRICT vin, const u16* RESTRICT index0, const u16* RESTRICT index1);
|
||||
bool TrianglesAreQuads(bool shuffle_check = false);
|
||||
template <u32 primclass>
|
||||
PRIM_OVERLAP GetPrimitiveOverlapDrawlistImpl(bool save_drawlist = false, bool save_bbox = false, float bbox_scale = 1.0f);
|
||||
|
||||
@@ -76,3 +76,89 @@ public:
|
||||
return GetClassVertexCount(GetPrimClass(prim));
|
||||
}
|
||||
};
|
||||
|
||||
// Class that represents an octogonal bounding area with sides at 45 degree increments.
|
||||
class BoundingOct
|
||||
{
|
||||
private:
|
||||
GSVector4i bbox0; // Standard bbox.
|
||||
GSVector4i bbox1; // Bounding diamond (rotated 45 degrees axes and scaled, so (x, y) becomes (x + y, x - y)).
|
||||
|
||||
// Assumes that v is of the form { x, y, x, y }.
|
||||
static GSVector4i Rotate45(const GSVector4i& v)
|
||||
{
|
||||
const GSVector4i swap = v.yxwz();
|
||||
return (v + swap).blend32<0xa>(swap - v);
|
||||
}
|
||||
|
||||
BoundingOct(const GSVector4i& bbox0, const GSVector4i& bbox1)
|
||||
: bbox0(bbox0)
|
||||
, bbox1(bbox1)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
// Initialize to null bounding area.
|
||||
BoundingOct()
|
||||
: bbox0(GSVector4i(INT_MAX, INT_MAX, INT_MIN, INT_MIN))
|
||||
, bbox1(GSVector4i(INT_MAX, INT_MAX, INT_MIN, INT_MIN))
|
||||
{
|
||||
}
|
||||
|
||||
static BoundingOct FromPoint(GSVector4i v)
|
||||
{
|
||||
v = v.xyxy();
|
||||
return { v, Rotate45(v) };
|
||||
}
|
||||
|
||||
// The two inputs are assumed to be diagonally opposite to each other in an axis-aligned quad (i.e. sprite).
|
||||
static BoundingOct FromSprite(GSVector4i v0, GSVector4i v1)
|
||||
{
|
||||
const GSVector4i min = v0.min_i32(v1);
|
||||
const GSVector4i max = v0.max_i32(v1);
|
||||
const GSVector4i bbox = min.upl64(max);
|
||||
// Rotate45(x, y) => (x + y, x - y), we want the (min, max) result for any pair of (x, y)
|
||||
// Min: (min.x + min.y, min.x - max.y)
|
||||
// Max: (max.x + max.y, max.x - min.y)
|
||||
const GSVector4i x = GSVector4i::cast(GSVector4::cast(min).xxxx(GSVector4::cast(max))); // Don't use bbox immediately to help the compiler optimize.
|
||||
const GSVector4i y = bbox.ywwy();
|
||||
return {
|
||||
bbox,
|
||||
(x + y).blend32<0xa>(x - y),
|
||||
};
|
||||
}
|
||||
|
||||
BoundingOct Union(GSVector4i v) const
|
||||
{
|
||||
v = v.xyxy();
|
||||
return { bbox0.runion(v), bbox1.runion(Rotate45(v)) };
|
||||
}
|
||||
|
||||
BoundingOct Union(const BoundingOct& other) const
|
||||
{
|
||||
return { bbox0.runion(other.bbox0), bbox1.runion(other.bbox1) };
|
||||
}
|
||||
|
||||
BoundingOct UnionSprite(GSVector4i pt0, GSVector4i pt1) const
|
||||
{
|
||||
return Union(FromSprite(pt0, pt1));
|
||||
}
|
||||
|
||||
bool Intersects(const BoundingOct& other) const
|
||||
{
|
||||
return bbox0.rintersects(other.bbox0) && bbox1.rintersects(other.bbox1);
|
||||
}
|
||||
|
||||
BoundingOct FixDegenerate() const
|
||||
{
|
||||
return {
|
||||
bbox0.blend(bbox0 + GSVector4i(0, 0, 1, 1), bbox0.xyxy() == bbox0.zwzw()),
|
||||
bbox1.blend(bbox1 + GSVector4i(0, 0, 1, 1), bbox1.xyxy() == bbox1.zwzw()),
|
||||
};
|
||||
}
|
||||
|
||||
const GSVector4i& ToBBox()
|
||||
{
|
||||
return bbox0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -494,6 +494,16 @@ public:
|
||||
return GSVector4i(_mm_packus_epi32(m, m));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i pkl32(const GSVector4i& a) const
|
||||
{
|
||||
return GSVector4i(_mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(m), _mm_castsi128_ps(a.m), _MM_SHUFFLE(2, 0, 2, 0))));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i pku32(const GSVector4i& a) const
|
||||
{
|
||||
return GSVector4i(_mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(m), _mm_castsi128_ps(a.m), _MM_SHUFFLE(3, 1, 3, 1))));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i upl8(const GSVector4i& a) const
|
||||
{
|
||||
return GSVector4i(_mm_unpacklo_epi8(m, a));
|
||||
@@ -840,6 +850,11 @@ public:
|
||||
return GSVector4i(_mm_srli_epi64(m, i));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i abs32() const
|
||||
{
|
||||
return GSVector4i(_mm_abs_epi32(m));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i add8(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_add_epi8(m, v.m));
|
||||
@@ -855,6 +870,11 @@ public:
|
||||
return GSVector4i(_mm_add_epi32(m, v.m));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i hadd32(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_hadd_epi32(m, v.m));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i adds8(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_adds_epi8(m, v.m));
|
||||
@@ -895,6 +915,11 @@ public:
|
||||
return GSVector4i(_mm_sub_epi32(m, v.m));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i hsub32(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_hsub_epi32(m, v.m));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i subs8(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_subs_epi8(m, v.m));
|
||||
@@ -1967,6 +1992,11 @@ public:
|
||||
return v ^ GSVector4i(i);
|
||||
}
|
||||
|
||||
__forceinline friend GSVector4i operator-(const GSVector4i& v)
|
||||
{
|
||||
return GSVector4i(_mm_sub_epi32(_mm_setzero_si128(), v));
|
||||
}
|
||||
|
||||
__forceinline friend GSVector4i operator~(const GSVector4i& v)
|
||||
{
|
||||
return v ^ (v == v);
|
||||
|
||||
@@ -506,6 +506,16 @@ public:
|
||||
return GSVector4i(vreinterpretq_s32_u16(vcombine_u16(vqmovun_s32(v4s), vqmovun_s32(v4s))));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i pkl32(const GSVector4i& a) const
|
||||
{
|
||||
return GSVector4i(vuzp1q_u32(v4s, a.v4s));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i pku32(const GSVector4i& a) const
|
||||
{
|
||||
return GSVector4i(vuzp2q_u32(v4s, a.v4s));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i upl8(const GSVector4i& a) const
|
||||
{
|
||||
return GSVector4i(vreinterpretq_s32_s8(vzip1q_s8(vreinterpretq_s8_s32(v4s), vreinterpretq_s8_s32(a.v4s))));
|
||||
@@ -807,6 +817,11 @@ public:
|
||||
vreinterpretq_s32_u64(vshlq_u64(vreinterpretq_u64_s32(v4s), vnegq_s64(vreinterpretq_s64_s32(v.v4s)))));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i abs32() const
|
||||
{
|
||||
return GSVector4i(vabsq_s32(v4s));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i add8(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(vreinterpretq_s32_s8(vaddq_s8(vreinterpretq_s8_s32(v4s), vreinterpretq_s8_s32(v.v4s))));
|
||||
@@ -822,6 +837,11 @@ public:
|
||||
return GSVector4i(vaddq_s32(v4s, v.v4s));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i hadd32(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(vpaddq_s32(v4s, v.v4s));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i adds8(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(vreinterpretq_s32_s8(vqaddq_s8(vreinterpretq_s8_s32(v4s), vreinterpretq_s8_s32(v.v4s))));
|
||||
@@ -866,6 +886,11 @@ public:
|
||||
return GSVector4i(vsubq_s32(v4s, v.v4s));
|
||||
}
|
||||
|
||||
__forceinline GSVector4i hsub32(const GSVector4i& v) const
|
||||
{
|
||||
return vsubq_u32(vuzp1q_u32(v4s, v.v4s), vuzp2q_u32(v4s, v.v4s));;
|
||||
}
|
||||
|
||||
__forceinline GSVector4i subs8(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(vreinterpretq_s32_s8(vqsubq_s8(vreinterpretq_s8_s32(v4s), vreinterpretq_s8_s32(v.v4s))));
|
||||
@@ -1920,6 +1945,11 @@ public:
|
||||
return v ^ GSVector4i(i);
|
||||
}
|
||||
|
||||
__forceinline friend GSVector4i operator-(const GSVector4i& v)
|
||||
{
|
||||
return GSVector4i(vnegq_s32(v.v4s));
|
||||
}
|
||||
|
||||
__forceinline friend GSVector4i operator~(const GSVector4i& v)
|
||||
{
|
||||
return GSVector4i(vmvnq_s32(v.v4s));
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "IconsFontAwesome.h"
|
||||
|
||||
#include <appmodel.h>
|
||||
#include <array>
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
@@ -382,29 +381,7 @@ GSRendererType D3D::GetPreferredRenderer()
|
||||
return device;
|
||||
};
|
||||
#ifdef ENABLE_VULKAN
|
||||
static constexpr auto check_for_mapping_layers = []() {
|
||||
PCWSTR familyName = L"Microsoft.D3DMappingLayers_8wekyb3d8bbwe";
|
||||
UINT32 numPackages = 0, bufferLength = 0;
|
||||
const DWORD error = GetPackagesByPackageFamily(familyName, &numPackages, nullptr, &bufferLength, nullptr);
|
||||
if (error == ERROR_INSUFFICIENT_BUFFER || numPackages > 0)
|
||||
{
|
||||
Host::AddIconOSDMessage("VKDriverUnsupported", ICON_FA_TV,
|
||||
TRANSLATE_STR("GS",
|
||||
"Your system has the \"OpenCL, OpenGL, and Vulkan Compatibility Pack\" installed.\n"
|
||||
"This Vulkan driver crashes PCSX2 on some GPUs.\n"
|
||||
"To use the Vulkan renderer, you should remove this app package."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
static constexpr auto check_vulkan_supported = []() {
|
||||
// Don't try to enumerate Vulkan devices if the DX12 Vulkan driver is present.
|
||||
// It crashes on AMD GPUs.
|
||||
if (check_for_mapping_layers())
|
||||
return false;
|
||||
|
||||
if (!GSDeviceVK::EnumerateGPUs().empty())
|
||||
return true;
|
||||
|
||||
|
||||
@@ -1413,7 +1413,7 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
cb.SetSource(sRect, sTex->GetSize());
|
||||
cb.SetTarget(dRect, ds);
|
||||
cb.SetTime(shaderTime);
|
||||
m_ctx->UpdateSubresource(m_present.ps_cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
UpdateSubresource(m_present.ps_cb.get(), &cb, &m_present.cb_uniforms, sizeof(cb));
|
||||
|
||||
// om
|
||||
|
||||
@@ -1465,7 +1465,7 @@ void GSDevice11::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u
|
||||
u32 pad2;
|
||||
};
|
||||
const Uniforms cb = {sScale, {}, offsetX, offsetY, dOffset, 0};
|
||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
UpdateSubresource(m_merge.cb.get(), &cb, &m_merge.cb_uniforms, sizeof(cb));
|
||||
|
||||
const GSVector4 dRect(0, 0, dSize, 1);
|
||||
const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8;
|
||||
@@ -1484,7 +1484,7 @@ void GSDevice11::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offs
|
||||
};
|
||||
|
||||
const Uniforms cb = {sScale, {}, SBW, DBW, SPSM, 0};
|
||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
UpdateSubresource(m_merge.cb.get(), &cb, &m_merge.cb_uniforms, sizeof(cb));
|
||||
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
@@ -1505,7 +1505,7 @@ void GSDevice11::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u32
|
||||
|
||||
const Uniforms cb = {
|
||||
static_cast<float>(downsample_factor * downsample_factor), (GSConfig.UserHacks_NativeScaling > GSNativeScaling::Aggressive) ? 2.0f : 1.0f, {}, clamp_min, static_cast<int>(downsample_factor), 0};
|
||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
UpdateSubresource(m_merge.cb.get(), &cb, &m_merge.cb_uniforms, sizeof(cb));
|
||||
|
||||
const ShaderConvert shader = ShaderConvert::DOWNSAMPLE_COPY;
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), m_merge.cb.get(), nullptr, false);
|
||||
@@ -1599,7 +1599,6 @@ void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rect
|
||||
DrawIndexedPrimitive();
|
||||
}
|
||||
|
||||
|
||||
void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
{
|
||||
const GSVector4 full_r(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
@@ -1616,7 +1615,7 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
if (feedback_write_2 || feedback_write_1 || sTex[0])
|
||||
{
|
||||
const MergeConstantBuffer cb = {GSVector4::unorm8(c), EXTBUF.EMODA, EXTBUF.EMODC};
|
||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
UpdateSubresource(m_merge.cb.get(), &cb, &m_merge.cb_uniforms, sizeof(cb));
|
||||
}
|
||||
|
||||
if (sTex[1] && (PMODE.SLBG == 0 || feedback_write_2_but_blend_bg))
|
||||
@@ -1652,7 +1651,7 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
|
||||
void GSDevice11::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb)
|
||||
{
|
||||
m_ctx->UpdateSubresource(m_interlace.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
UpdateSubresource(m_interlace.cb.get(), &cb, &m_interlace.cb_uniforms, sizeof(cb));
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_interlace.ps[static_cast<int>(shader)].get(), m_interlace.cb.get(), linear);
|
||||
}
|
||||
@@ -1690,7 +1689,7 @@ void GSDevice11::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float para
|
||||
const GSVector4 sRect(0, 0, 1, 1);
|
||||
const GSVector4 dRect(0, 0, s.x, s.y);
|
||||
|
||||
m_ctx->UpdateSubresource(m_shadeboost.cb.get(), 0, nullptr, params, 0, 0);
|
||||
UpdateSubresource(m_shadeboost.cb.get(), params, &m_shadeboost.cb_uniforms, sizeof(float) * 4);
|
||||
|
||||
DoStretchRect(sTex, sRect, dTex, dRect, m_shadeboost.ps.get(), m_shadeboost.cb.get(), false);
|
||||
}
|
||||
@@ -2113,7 +2112,7 @@ void GSDevice11::RenderImGui()
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
m_ctx->UpdateSubresource(m_imgui.vs_cb.get(), 0, nullptr, ortho_projection, 0, 0);
|
||||
UpdateSubresource(m_imgui.vs_cb.get(), ortho_projection, &m_imgui.vs_cb_uniforms, sizeof(ortho_projection));
|
||||
|
||||
const UINT vb_stride = sizeof(ImDrawVert);
|
||||
const UINT vb_offset = 0;
|
||||
@@ -2612,6 +2611,15 @@ void GSDevice11::SetScissor(const GSVector4i& scissor)
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice11::UpdateSubresource(ID3D11Buffer* buffer, const void* cb_uniforms, void* cached_cb_uniforms, size_t cb_uniforms_size)
|
||||
{
|
||||
if (memcmp(cb_uniforms, cached_cb_uniforms, cb_uniforms_size) != 0)
|
||||
{
|
||||
memcpy(cached_cb_uniforms, cb_uniforms, cb_uniforms_size);
|
||||
m_ctx->UpdateSubresource(buffer, 0, nullptr, cached_cb_uniforms, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice11::ShaderMacro::AddMacro(const char* n, int d)
|
||||
{
|
||||
AddMacro(n, std::to_string(d));
|
||||
|
||||
@@ -191,6 +191,7 @@ private:
|
||||
wil::com_ptr_nothrow<ID3D11VertexShader> vs;
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps[static_cast<int>(PresentShader::Count)];
|
||||
wil::com_ptr_nothrow<ID3D11Buffer> ps_cb;
|
||||
DisplayConstantBuffer cb_uniforms;
|
||||
} m_present;
|
||||
|
||||
struct
|
||||
@@ -198,12 +199,14 @@ private:
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps[2];
|
||||
wil::com_ptr_nothrow<ID3D11Buffer> cb;
|
||||
wil::com_ptr_nothrow<ID3D11BlendState> bs;
|
||||
MergeConstantBuffer cb_uniforms;
|
||||
} m_merge;
|
||||
|
||||
struct
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps[NUM_INTERLACE_SHADERS];
|
||||
wil::com_ptr_nothrow<ID3D11Buffer> cb;
|
||||
InterlaceConstantBuffer cb_uniforms;
|
||||
} m_interlace;
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> m_fxaa_ps;
|
||||
@@ -212,6 +215,7 @@ private:
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps;
|
||||
wil::com_ptr_nothrow<ID3D11Buffer> cb;
|
||||
float cb_uniforms[4];
|
||||
} m_shadeboost;
|
||||
|
||||
struct
|
||||
@@ -235,6 +239,7 @@ private:
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> ps;
|
||||
wil::com_ptr_nothrow<ID3D11BlendState> bs;
|
||||
wil::com_ptr_nothrow<ID3D11Buffer> vs_cb;
|
||||
GSVector4 vs_cb_uniforms[4];
|
||||
} m_imgui;
|
||||
|
||||
// Shaders...
|
||||
@@ -342,6 +347,8 @@ public:
|
||||
void SetViewport(const GSVector2i& viewport);
|
||||
void SetScissor(const GSVector4i& scissor);
|
||||
|
||||
void UpdateSubresource(ID3D11Buffer* buffer, const void* cb_uniforms, void* cached_cb_uniforms, size_t cb_uniforms_size);
|
||||
|
||||
void SetupVS(VSSelector sel, const GSHWDrawConfig::VSConstantBuffer* cb);
|
||||
void SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstantBuffer* cb, PSSamplerSelector ssel);
|
||||
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 afix);
|
||||
|
||||
@@ -4711,260 +4711,31 @@ void GSRendererHW::Draw()
|
||||
// Note: second hack corrects only the texture coordinate
|
||||
// Be careful to not correct downscaled targets, this can get messy and break post processing
|
||||
// but it still needs to adjust native stuff from memory as it's not been compensated for upscaling (Dragon Quest 8 font for example).
|
||||
if (CanUpscale() && ((m_vt.m_primclass == GS_SPRITE_CLASS) || ((m_index.tail % 6 == 0) && m_vt.m_primclass == GS_TRIANGLE_CLASS && m_vt.m_eq.z)) && rt && rt->GetScale() > 1.0f)
|
||||
if (CanUpscale() && (m_vt.m_primclass == GS_SPRITE_CLASS) && rt && rt->GetScale() > 1.0f)
|
||||
{
|
||||
bool valid_format = true;
|
||||
const u32 count = m_vertex.next;
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
|
||||
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
// Hack to avoid vertical black line in various games (ace combat/tekken)
|
||||
if (GSConfig.UserHacks_AlignSpriteX)
|
||||
{
|
||||
const GSVertex* RESTRICT v = m_vertex.buff;
|
||||
const u16* RESTRICT index = m_index.buff;
|
||||
const size_t count = m_index.tail;
|
||||
|
||||
for (int i = 0; i < count; i += 6)
|
||||
// Note for performance reason I do the check only once on the first
|
||||
// primitive
|
||||
const int win_position = v[1].XYZ.X - context->XYOFFSET.OFX;
|
||||
const bool unaligned_position = ((win_position & 0xF) == 8);
|
||||
const bool unaligned_texture = ((v[1].U & 0xF) == 0) && PRIM->FST; // I'm not sure this check is useful
|
||||
const bool hole_in_vertex = (count < 4) || (v[1].XYZ.X != v[2].XYZ.X);
|
||||
if (hole_in_vertex && unaligned_position && (unaligned_texture || !PRIM->FST))
|
||||
{
|
||||
// Non-axis aligned check when only two triangles
|
||||
if (!AreTrianglesQuadNonAA(v, &index[i], &index[i + 3]))
|
||||
// Normaly vertex are aligned on full pixels and texture in half
|
||||
// pixels. Let's extend the coverage of an half-pixel to avoid
|
||||
// hole after upscaling
|
||||
for (u32 i = 0; i < count; i += 2)
|
||||
{
|
||||
valid_format = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valid_format)
|
||||
{
|
||||
const u32 count = m_vertex.next;
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
u16* idx = &m_index.buff[0];
|
||||
const bool indexed_texture = src && src->m_scale == 1.0f && GSLocalMemory::m_psm[src->m_TEX0.PSM].pal > 0;
|
||||
|
||||
// Shortcut for when the sprites are right up against each other.
|
||||
if (GSConfig.UserHacks_AlignSpriteX && m_vt.m_primclass == GS_SPRITE_CLASS && indexed_texture && PRIM->FST && m_index.tail > 2 &&
|
||||
((v[idx[1]].U == v[idx[2]].U && (v[idx[1]].XYZ.X == v[idx[2]].XYZ.X) && v[idx[0]].V == v[idx[2]].V) ||
|
||||
(v[idx[1]].V == v[idx[2]].V && (v[idx[1]].XYZ.Y == v[idx[2]].XYZ.Y) && v[idx[0]].U == v[idx[2]].U)))
|
||||
{
|
||||
for (int i = 0; i < m_index.tail; i += 2)
|
||||
{
|
||||
if (!((v[idx[i + 1]].U == v[idx[i + 2]].U && (v[idx[i + 1]].XYZ.X == v[idx[i + 2]].XYZ.X) && v[idx[i]].V == v[idx[i + 2]].V)))
|
||||
{
|
||||
if (v[idx[i + 1]].U & 0x8)
|
||||
v[idx[i + 1]].U -= 8;
|
||||
}
|
||||
if (!((v[idx[i + 1]].V == v[idx[i + 2]].V && (v[idx[i + 1]].XYZ.Y == v[idx[i + 2]].XYZ.Y) && v[idx[i]].U == v[idx[i + 2]].U)))
|
||||
{
|
||||
if (v[idx[i + 1]].V & 0x8)
|
||||
v[idx[i + 11]].V -= 8;
|
||||
}
|
||||
}
|
||||
if (v[idx[m_index.tail - 1]].U & 0x8)
|
||||
v[idx[m_index.tail - 1]].U -= 8;
|
||||
|
||||
if (v[idx[m_index.tail - 1]].V & 0x8)
|
||||
v[idx[m_index.tail - 1]].V -= 8;
|
||||
}
|
||||
else
|
||||
// Hack to avoid vertical black line in various games (ace combat/tekken)
|
||||
if (GSConfig.UserHacks_AlignSpriteX)
|
||||
{
|
||||
// Note for performance reason I do the check only once on the first
|
||||
// primitive
|
||||
const int win_position0 = v[idx[0]].XYZ.X - context->XYOFFSET.OFX;
|
||||
const int win_position1 = v[idx[1]].XYZ.X - context->XYOFFSET.OFX;
|
||||
const bool unaligned_position = ((win_position0 & 0xf) != 0) || ((win_position1 & 0xF) != 0);
|
||||
const int first_s = (v[idx[0]].ST.S / v[idx[0]].RGBAQ.Q) * static_cast<int>(1 << m_cached_ctx.TEX0.TW);
|
||||
const bool unaligned_texture = (PRIM->FST && ((v[1].U & 0xF) == 0)) || (!PRIM->FST && (first_s & 0xF) == 0); // I'm not sure this check is useful
|
||||
const int gap = std::min(static_cast<int>(v[2].XYZ.X), static_cast<int>(v[3].XYZ.X)) - std::max(static_cast<int>(v[0].XYZ.X), static_cast<int>(v[1].XYZ.X));
|
||||
bool hole_in_vertex = (count < 4) || (v[1].XYZ.X != v[2].XYZ.X && ((v[1].XYZ.X ^ v[2].XYZ.X) & 0xF) != 0);
|
||||
const bool is_tri = m_vt.m_primclass == GS_TRIANGLE_CLASS;
|
||||
const int skip = is_tri ? 3 : 2;
|
||||
|
||||
GSVector2 gradient = GSVector2(1.0f, 1.0f);
|
||||
|
||||
if (m_lod.y == 0)
|
||||
{
|
||||
bool can_disable_linear = true;
|
||||
for (u32 i = 0; i < m_index.tail; i += skip)
|
||||
{
|
||||
const int x_offset = (is_tri && v[idx[i]].XYZ.X == v[idx[i + 1]].XYZ.X) ? 2 : 1;
|
||||
const int y_offset = (is_tri && v[idx[i]].XYZ.Y == v[idx[i + 1]].XYZ.Y) ? 2 : 1;
|
||||
|
||||
GSVector2 vert = GSVector2(std::abs(static_cast<float>(v[idx[i]].XYZ.X - v[idx[i + x_offset]].XYZ.X)), std::abs(static_cast<float>(v[idx[i]].XYZ.Y - v[idx[i + y_offset]].XYZ.Y)));
|
||||
GSVector2 tex;
|
||||
|
||||
if (!PRIM->FST)
|
||||
{
|
||||
const int s_offset = (is_tri && (v[idx[i]].ST.S / v[idx[i]].RGBAQ.Q) == (v[idx[i + 1]].ST.S / v[idx[i + 1]].RGBAQ.Q)) ? 2 : 1;
|
||||
const int t_offset = (is_tri && (v[idx[i]].ST.T / v[idx[i]].RGBAQ.Q) == (v[idx[i + 1]].ST.T / v[idx[i + 1]].RGBAQ.Q)) ? 2 : 1;
|
||||
GSVector2 v0, v1;
|
||||
float s = std::min((v[idx[i]].ST.S / v[idx[i]].RGBAQ.Q), 1.0f);
|
||||
float t = std::min((v[idx[i]].ST.T / v[idx[i]].RGBAQ.Q), 1.0f);
|
||||
v0.x = static_cast<int>((1 << m_cached_ctx.TEX0.TW) * s * 16.0f);
|
||||
v0.y = static_cast<int>((1 << m_cached_ctx.TEX0.TH) * t * 16.0f);
|
||||
|
||||
s = std::min((v[idx[i + s_offset]].ST.S / v[idx[i + s_offset]].RGBAQ.Q), 1.0f);
|
||||
t = std::min((v[idx[i + t_offset]].ST.T / v[idx[i + t_offset]].RGBAQ.Q), 1.0f);
|
||||
v1.x = static_cast<int>((1 << m_cached_ctx.TEX0.TW) * s * 16.0f);
|
||||
v1.y = static_cast<int>((1 << m_cached_ctx.TEX0.TH) * t * 16.0f);
|
||||
|
||||
tex = GSVector2(std::abs(v1.x - v0.x), std::abs(v1.y - v0.y));
|
||||
}
|
||||
else
|
||||
{
|
||||
const int u_offset = (is_tri && v[idx[i]].U == v[idx[i + 1]].U) ? 2 : 1;
|
||||
const int v_offset = (is_tri && v[idx[i]].V == v[idx[i + 1]].V) ? 2 : 1;
|
||||
tex = GSVector2(std::abs(static_cast<float>(v[idx[i]].U - v[idx[i + u_offset]].U)), std::abs(static_cast<float>(v[idx[i]].V - v[idx[i + v_offset]].V)));
|
||||
}
|
||||
|
||||
GSVector2 grad = tex / vert;
|
||||
if ((grad.x != gradient.x && grad.x != floor(grad.x)) || (grad.y != gradient.y && grad.y != floor(grad.y)))
|
||||
{
|
||||
can_disable_linear = false;
|
||||
gradient = grad;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (can_disable_linear)
|
||||
{
|
||||
m_vt.m_filter.linear = 0;
|
||||
m_vt.m_filter.opt_linear = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*if ((m_vt.m_primclass == GS_SPRITE_CLASS) && hole_in_vertex && unaligned_position && (unaligned_texture || !PRIM->FST))
|
||||
{
|
||||
// Normaly vertex are aligned on full pixels and texture in half
|
||||
// pixels. Let's extend the coverage of an half-pixel to avoid
|
||||
// hole after upscaling
|
||||
for (u32 i = 0; i < count; i += 2)
|
||||
{
|
||||
v[i + 1].XYZ.X += 8;
|
||||
// I really don't know if it is a good idea. Neither what to do for !PRIM->FST
|
||||
if (unaligned_texture)
|
||||
v[i + 1].U += 8;
|
||||
}
|
||||
}
|
||||
else */if (indexed_texture && (gradient.x > (1.0f / 16.0f) || gradient.y > (1.0f / 16.0f)))
|
||||
{
|
||||
const int comparitor = unaligned_position ? 0 : 8;
|
||||
|
||||
if (!PRIM->FST)
|
||||
{
|
||||
int s_offset = (is_tri && (v[idx[0]].ST.S / v[idx[0]].RGBAQ.Q) == (v[idx[1]].ST.S / v[idx[1]].RGBAQ.Q)) ? 2 : 1;
|
||||
int t_offset = (is_tri && (v[idx[0]].ST.T / v[idx[0]].RGBAQ.Q) == (v[idx[1]].ST.T / v[idx[1]].RGBAQ.Q)) ? 2 : 1;
|
||||
GSVector2i v0, v1;
|
||||
float q = v[idx[0]].RGBAQ.Q == 0 ? FLT_MIN : v[idx[0]].RGBAQ.Q;
|
||||
float s = v[idx[0]].ST.S / q;
|
||||
float t = v[idx[0]].ST.T / q;
|
||||
v0.x = static_cast<int>((1 << m_cached_ctx.TEX0.TW) * s * 16.0f);
|
||||
v0.y = static_cast<int>((1 << m_cached_ctx.TEX0.TH) * t * 16.0f);
|
||||
|
||||
q = v[idx[s_offset]].RGBAQ.Q == 0 ? FLT_MIN : v[idx[s_offset]].RGBAQ.Q;
|
||||
s = v[idx[s_offset]].ST.S / q;
|
||||
t = v[idx[t_offset]].ST.T / q;
|
||||
v1.x = static_cast<int>((1 << m_cached_ctx.TEX0.TW) * s * 16.0f);
|
||||
v1.y = static_cast<int>((1 << m_cached_ctx.TEX0.TH) * t * 16.0f);
|
||||
bool small_texture = std::abs(v1.x - v0.x) <= (64 * 16) || std::abs(v1.y - v0.y) <= (64 * 16);
|
||||
bool offset_texture_x = (m_vt.IsLinear() || ((v0.x & 0xF) && (v1.x & 0xF))) && small_texture; // Keep them relatively small to avoid full screen stuff.
|
||||
bool offset_texture_y = (m_vt.IsLinear() || ((v0.y & 0xF) && (v1.y & 0xF))) && small_texture;
|
||||
|
||||
//if (offset_texture_x && offset_texture_y)
|
||||
{
|
||||
for (u32 i = m_index.buff[0]; i < m_index.tail; i += skip)
|
||||
{
|
||||
GSVector2 st;
|
||||
|
||||
if (gradient.x > (1.0f / 16.0f))
|
||||
{
|
||||
float largest_s = std::max(is_tri ? (v[i + 2].ST.S / v[i + 2].RGBAQ.Q) : static_cast<float>(0), std::max((v[i].ST.S / v[i].RGBAQ.Q), (v[i + 1].ST.S / v[i + 1].RGBAQ.Q)));
|
||||
float smallest_s = std::min(is_tri ? (v[i + 2].ST.S / v[i + 2].RGBAQ.Q) : static_cast<float>(0), std::min((v[i].ST.S / v[i].RGBAQ.Q), (v[i + 1].ST.S / v[i + 1].RGBAQ.Q)));
|
||||
|
||||
for (int j = 0; j < skip; j++)
|
||||
{
|
||||
q = v[i + j].RGBAQ.Q == 0 ? FLT_MIN : v[i + j].RGBAQ.Q;
|
||||
float s = v[i + j].ST.S / q;
|
||||
st.x = static_cast<float>(1 << m_cached_ctx.TEX0.TW) * s;
|
||||
if ((v[i + j].ST.S / q) == largest_s)
|
||||
v[i + j].ST.S = ((st.x - 0.5f) / static_cast<float>(1 << m_cached_ctx.TEX0.TW)) * q;
|
||||
// Check the minimap in Persona 3.
|
||||
if ((static_cast<int>(st.x * 16) & 0x8) == comparitor && (v[i + j].ST.S / q) == smallest_s)
|
||||
v[i + j].ST.S = (std::max(0.0f, (st.x - 0.5f)) / static_cast<float>(1 << m_cached_ctx.TEX0.TW)) * q;
|
||||
}
|
||||
}
|
||||
|
||||
if (gradient.y > (1.0f / 16.0f))
|
||||
{
|
||||
float largest_t = std::max(is_tri ? (v[i + 2].ST.T / v[i + 2].RGBAQ.Q) : static_cast<float>(0), std::max((v[i].ST.T / v[i].RGBAQ.Q), (v[i + 1].ST.T / v[i + 1].RGBAQ.Q)));
|
||||
float smallest_t = std::min(is_tri ? (v[i + 2].ST.T / v[i + 2].RGBAQ.Q) : static_cast<float>(0), std::min((v[i].ST.T / v[i].RGBAQ.Q), (v[i + 1].ST.T / v[i + 1].RGBAQ.Q)));
|
||||
for (int j = 0; j < skip; j++)
|
||||
{
|
||||
q = v[i + j].RGBAQ.Q == 0 ? FLT_MIN : v[i + j].RGBAQ.Q;
|
||||
float t = v[i + j].ST.T / q;
|
||||
st.y = static_cast<float>(1 << m_cached_ctx.TEX0.TH) * t;
|
||||
if ((v[i + j].ST.T / q) == largest_t)
|
||||
v[i + j].ST.T = ((st.y - 0.5f) / static_cast<float>(1 << m_cached_ctx.TEX0.TH)) * q;
|
||||
// Check the minimap in Persona 3.
|
||||
if ((static_cast<int>(st.y * 16) & 0x8) == comparitor && (v[i + j].ST.T / q) == smallest_t)
|
||||
v[i + j].ST.T = (std::max(0.0f, (st.y - 0.5f)) / static_cast<float>(1 << m_cached_ctx.TEX0.TH)) * q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int u_offset = (is_tri && (v[0].U == v[1].U)) ? 2 : 1;
|
||||
int v_offset = (is_tri && (v[0].V == v[1].V)) ? 2 : 1;
|
||||
bool small_texture = std::abs(static_cast<int>(v[idx[u_offset]].U) - static_cast<int>(v[idx[0]].U)) <= (64 * 16) || std::abs(static_cast<int>(v[idx[v_offset]].V) - static_cast<int>(v[idx[0]].V)) <= (64 * 16);
|
||||
bool offset_texture_x = (m_vt.IsLinear() || ((v[0].U & 0xF) && (v[idx[u_offset]].U & 0xF))) && small_texture;
|
||||
bool offset_texture_y = (m_vt.IsLinear() || ((v[0].V & 0xF) && (v[idx[v_offset]].V & 0xF))) && small_texture;
|
||||
|
||||
if (offset_texture_x && offset_texture_y)
|
||||
{
|
||||
for (u32 i = m_index.buff[0]; i < m_index.tail; i += skip)
|
||||
{
|
||||
if (gradient.x > (1.0f / 16.0f))
|
||||
{
|
||||
const u16 largest_u = std::max(is_tri ? v[idx[i + 2]].U : static_cast<u16>(0), std::max(v[idx[i]].U, v[idx[i + 1]].U));
|
||||
|
||||
if ((v[idx[i]].U & 0x8) == comparitor && v[idx[i]].U == largest_u)
|
||||
v[idx[i]].U = std::max(static_cast<int>(v[idx[i]].U) - 8, 0);
|
||||
|
||||
if ((v[idx[i + 1]].U & 0x8) == comparitor && v[idx[i + 1]].U == largest_u)
|
||||
v[idx[i + 1]].U = std::max(static_cast<int>(v[idx[i + 1]].U) - 8, 0);
|
||||
|
||||
if (is_tri && (v[idx[i + 2]].U & 0x8) == comparitor && v[idx[i + 2]].U == largest_u)
|
||||
v[idx[i + 2]].U = std::max(static_cast<int>(v[idx[i + 2]].U) - 8, 0);
|
||||
}
|
||||
|
||||
if (gradient.y > (1.0f / 16.0f))
|
||||
{
|
||||
const u16 largest_v = std::max(is_tri ? v[idx[i + 2]].V : static_cast<u16>(0), std::max(v[idx[i]].V, v[idx[i + 1]].V));
|
||||
|
||||
if ((v[idx[i]].V & 0x8) == comparitor && v[idx[i]].V == largest_v)
|
||||
v[idx[i]].V = std::max(static_cast<int>(v[idx[i]].V) - 8, 0);
|
||||
|
||||
if ((v[idx[i + 1]].V & 0x8) == comparitor && v[idx[i + 1]].V == largest_v)
|
||||
v[idx[i + 1]].V = std::max(static_cast<int>(v[idx[i + 1]].V) - 8, 0);
|
||||
|
||||
if (is_tri && (v[idx[i + 2]].V & 0x8) == comparitor && v[idx[i + 2]].V == largest_v)
|
||||
v[idx[i + 2]].V = std::max(static_cast<int>(v[idx[i + 2]].V) - 8, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((m_vt.m_primclass == GS_SPRITE_CLASS) && hole_in_vertex && unaligned_position && (unaligned_texture || !PRIM->FST))
|
||||
{
|
||||
// Normaly vertex are aligned on full pixels and texture in half
|
||||
// pixels. Let's extend the coverage of an half-pixel to avoid
|
||||
// hole after upscaling
|
||||
for (u32 i = 0; i < count; i += 2)
|
||||
{
|
||||
v[i + 1].XYZ.X += 8;
|
||||
// I really don't know if it is a good idea. Neither what to do for !PRIM->FST
|
||||
if (unaligned_texture)
|
||||
v[i + 1].U += 8;
|
||||
}
|
||||
v[i + 1].XYZ.X += 8;
|
||||
// I really don't know if it is a good idea. Neither what to do for !PRIM->FST
|
||||
if (unaligned_texture)
|
||||
v[i + 1].U += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2837,7 +2837,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage();
|
||||
|
||||
// If we're changing resolution scale, just toss the texture, it's not going to get reused.
|
||||
if ((!GSConfig.UserHacks_NativePaletteDraw && !dst->m_downscaled) || (dst->m_scale != 1.0f && scale != 1.0f))
|
||||
if ((!GSConfig.UserHacks_NativePaletteDraw && !dst->m_downscaled && scale != 1.0f) || (dst->m_scale != 1.0f && scale != 1.0f))
|
||||
delete dst->m_texture;
|
||||
else
|
||||
g_gs_device->Recycle(dst->m_texture);
|
||||
|
||||
@@ -629,9 +629,8 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_ext_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_khr_feature = {
|
||||
// VK_EXT_swapchain_maintenance1 types/enums are aliases of VK_KHR_swapchain_maintenance1 types/enums.
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR};
|
||||
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
@@ -656,16 +655,8 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
|
||||
}
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1)
|
||||
{
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1_is_khr)
|
||||
{
|
||||
swapchain_maintenance1_khr_feature.swapchainMaintenance1 = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_khr_feature);
|
||||
}
|
||||
else
|
||||
{
|
||||
swapchain_maintenance1_ext_feature.swapchainMaintenance1 = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_ext_feature);
|
||||
}
|
||||
swapchain_maintenance1_feature.swapchainMaintenance1 = VK_TRUE;
|
||||
Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_feature);
|
||||
}
|
||||
|
||||
VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device);
|
||||
@@ -732,9 +723,8 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_ext_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_TRUE};
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_khr_feature = {
|
||||
// VK_EXT_swapchain_maintenance1 types/enums are aliases of VK_KHR_swapchain_maintenance1 types/enums.
|
||||
VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR, nullptr, VK_TRUE};
|
||||
VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT};
|
||||
@@ -748,10 +738,8 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout)
|
||||
Vulkan::AddPointerToChain(&features2, &attachment_feedback_loop_feature);
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1 && m_optional_extensions.vk_swapchain_maintenance1_is_khr)
|
||||
Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_khr_feature);
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1 && !m_optional_extensions.vk_swapchain_maintenance1_is_khr)
|
||||
Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_ext_feature);
|
||||
if (m_optional_extensions.vk_swapchain_maintenance1)
|
||||
Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_feature);
|
||||
|
||||
// query
|
||||
vkGetPhysicalDeviceFeatures2(m_physical_device, &features2);
|
||||
@@ -826,9 +814,8 @@ bool GSDeviceVK::ProcessDeviceExtensions()
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps = false;
|
||||
}
|
||||
|
||||
m_optional_extensions.vk_swapchain_maintenance1 &= m_optional_extensions.vk_swapchain_maintenance1_is_khr ?
|
||||
(swapchain_maintenance1_khr_feature.swapchainMaintenance1 == VK_TRUE) :
|
||||
(swapchain_maintenance1_ext_feature.swapchainMaintenance1 == VK_TRUE);
|
||||
m_optional_extensions.vk_swapchain_maintenance1 &=
|
||||
(swapchain_maintenance1_feature.swapchainMaintenance1 == VK_TRUE);
|
||||
|
||||
Console.WriteLn(
|
||||
"VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
|
||||
@@ -5817,26 +5804,11 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
Console.Warning("VK: Failed to allocate temp texture for RT copy.");
|
||||
}
|
||||
|
||||
// We don't need the very first barrier if this is the first draw after switching to feedback loop,
|
||||
// because the layout change in itself enforces the execution dependency. colclip hw needs a barrier between
|
||||
// setup and the first draw to read it. TODO: Make colclip hw use subpasses instead.
|
||||
|
||||
// However, it turns out *not* doing this causes GPU resets on RDNA3, specifically Windows drivers.
|
||||
// Despite the layout changing enforcing the execution dependency between previous draws and the first
|
||||
// input attachment read, it still wants the region/fragment-local barrier...
|
||||
|
||||
const bool skip_first_barrier =
|
||||
(draw_rt && draw_rt->GetLayout() != GSTextureVK::Layout::FeedbackLoop && !pipe.ps.colclip_hw && !IsDeviceAMD());
|
||||
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
|
||||
if (pipe.IsRTFeedbackLoop())
|
||||
{
|
||||
pxAssertMsg(m_features.texture_barrier, "Texture barriers enabled");
|
||||
PSSetShaderResource(2, draw_rt, false);
|
||||
|
||||
// If this is the first draw to the target as a feedback loop, make sure we re-generate the texture descriptor.
|
||||
// Otherwise, we might have a previous descriptor left over, that has the RT in a different state.
|
||||
m_dirty_flags |= (skip_first_barrier ? static_cast<u32>(DIRTY_FLAG_TFX_TEXTURE_RT) : 0);
|
||||
}
|
||||
|
||||
// Begin render pass if new target or out of the area.
|
||||
@@ -5911,7 +5883,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
// now we can do the actual draw
|
||||
if (BindDrawPipeline(pipe))
|
||||
SendHWDraw(config, draw_rt, config.require_one_barrier, config.require_full_barrier, skip_first_barrier);
|
||||
SendHWDraw(config, draw_rt, config.require_one_barrier, config.require_full_barrier);
|
||||
|
||||
// blend second pass
|
||||
if (config.blend_multi_pass.enable)
|
||||
@@ -5947,7 +5919,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
if (BindDrawPipeline(pipe))
|
||||
{
|
||||
SendHWDraw(config, draw_rt, config.alpha_second_pass.require_one_barrier,
|
||||
config.alpha_second_pass.require_full_barrier, false);
|
||||
config.alpha_second_pass.require_full_barrier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6070,7 +6042,7 @@ VkDependencyFlags GSDeviceVK::GetColorBufferBarrierFlags() const
|
||||
}
|
||||
|
||||
void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
bool one_barrier, bool full_barrier, bool skip_first_barrier)
|
||||
bool one_barrier, bool full_barrier)
|
||||
{
|
||||
if (!m_features.texture_barrier) [[unlikely]]
|
||||
{
|
||||
@@ -6092,21 +6064,9 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
const u32 draw_list_size = static_cast<u32>(config.drawlist->size());
|
||||
|
||||
GL_PUSH("Split the draw");
|
||||
g_perfmon.Put(
|
||||
GSPerfMon::Barriers, static_cast<u32>(draw_list_size) - static_cast<u32>(skip_first_barrier));
|
||||
g_perfmon.Put(GSPerfMon::Barriers, static_cast<u32>(draw_list_size));
|
||||
|
||||
u32 p = 0;
|
||||
u32 n = 0;
|
||||
|
||||
if (skip_first_barrier)
|
||||
{
|
||||
const u32 count = (*config.drawlist)[n] * indices_per_prim;
|
||||
DrawIndexedPrimitive(p, count);
|
||||
p += count;
|
||||
++n;
|
||||
}
|
||||
|
||||
for (; n < draw_list_size; n++)
|
||||
for (u32 n = 0, p = 0; n < draw_list_size; n++)
|
||||
{
|
||||
vkCmdPipelineBarrier(GetCurrentCommandBuffer(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier_flags, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
@@ -6119,7 +6079,7 @@ void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
return;
|
||||
}
|
||||
|
||||
if (one_barrier && !skip_first_barrier)
|
||||
if (one_barrier)
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
|
||||
|
||||
@@ -574,7 +574,7 @@ public:
|
||||
VkImageMemoryBarrier GetColorBufferBarrier(GSTextureVK* rt) const;
|
||||
VkDependencyFlags GetColorBufferBarrierFlags() const;
|
||||
void SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,
|
||||
bool one_barrier, bool full_barrier, bool skip_first_barrier);
|
||||
bool one_barrier, bool full_barrier);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Vulkan State
|
||||
|
||||
@@ -379,8 +379,12 @@ bool VKSwapChain::CreateSwapChain()
|
||||
|
||||
m_swap_chain = VK_NULL_HANDLE;
|
||||
|
||||
// VK_EXT_swapchain_maintenance1 types/enums are aliases of VK_KHR_swapchain_maintenance1 types/enums.
|
||||
const VkSwapchainPresentModesCreateInfoKHR modes_info{VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_KHR, nullptr, 1u, &m_present_mode};
|
||||
|
||||
// Now we can actually create the swap chain
|
||||
VkSwapchainCreateInfoKHR swap_chain_info = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, nullptr, 0, m_surface,
|
||||
VkSwapchainCreateInfoKHR swap_chain_info = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1 ? &modes_info : nullptr, 0, m_surface,
|
||||
image_count, surface_format->format, surface_format->colorSpace, size, 1u, image_usage,
|
||||
VK_SHARING_MODE_EXCLUSIVE, 0, nullptr, transform, alpha, m_present_mode, VK_TRUE, old_swap_chain};
|
||||
std::array<uint32_t, 2> indices = {{
|
||||
@@ -563,23 +567,17 @@ void VKSwapChain::ReleaseCurrentImage()
|
||||
{
|
||||
GSDeviceVK::GetInstance()->WaitForGPUIdle();
|
||||
|
||||
// VK_EXT_swapchain_maintenance1 types/enums are aliases of VK_KHR_swapchain_maintenance1 types/enums.
|
||||
const VkReleaseSwapchainImagesInfoKHR info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_KHR,
|
||||
.swapchain = m_swap_chain,
|
||||
.imageIndexCount = 1,
|
||||
.pImageIndices = &m_current_image};
|
||||
|
||||
VkResult res;
|
||||
if (GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1_is_khr)
|
||||
{
|
||||
const VkReleaseSwapchainImagesInfoKHR info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_KHR,
|
||||
.swapchain = m_swap_chain,
|
||||
.imageIndexCount = 1,
|
||||
.pImageIndices = &m_current_image};
|
||||
res = vkReleaseSwapchainImagesKHR(GSDeviceVK::GetInstance()->GetDevice(), &info);
|
||||
}
|
||||
else
|
||||
{
|
||||
const VkReleaseSwapchainImagesInfoEXT info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT,
|
||||
.swapchain = m_swap_chain,
|
||||
.imageIndexCount = 1,
|
||||
.pImageIndices = &m_current_image};
|
||||
res = vkReleaseSwapchainImagesEXT(GSDeviceVK::GetInstance()->GetDevice(), &info);
|
||||
}
|
||||
if (res != VK_SUCCESS)
|
||||
LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImages() failed: ");
|
||||
}
|
||||
|
||||
@@ -314,6 +314,13 @@ void ipuSoftReset()
|
||||
g_ipu_thresh[0] = 0;
|
||||
g_ipu_thresh[1] = 0;
|
||||
|
||||
if (!decoder.intra_dc_precision)
|
||||
{
|
||||
decoder.dc_dct_pred[0] =
|
||||
decoder.dc_dct_pred[1] =
|
||||
decoder.dc_dct_pred[2] = 128 << decoder.intra_dc_precision;
|
||||
}
|
||||
|
||||
ipuRegs.ctrl.reset();
|
||||
ipuRegs.top = 0;
|
||||
ipu_cmd.clear();
|
||||
|
||||
@@ -782,8 +782,8 @@ void psxRcntSetNewIntrMode(int index)
|
||||
psxCounters[index].mode.overflowFlag = false;
|
||||
psxCounters[index].mode.intrEnable = true;
|
||||
|
||||
if (psxCounters[index].mode.repeatIntr != psxCounters[index].currentIrqMode.repeatInterrupt || psxCounters[index].mode.toggleIntr != psxCounters[index].currentIrqMode.toggleInterrupt)
|
||||
DevCon.Warning("Updating psxCounter[%d] mode old repeat %d new %d old toggle %d new %d", index, psxCounters[index].mode.repeatIntr, psxCounters[index].currentIrqMode.repeatInterrupt, psxCounters[index].mode.toggleIntr, psxCounters[index].currentIrqMode.toggleInterrupt);
|
||||
//if (psxCounters[index].mode.repeatIntr != psxCounters[index].currentIrqMode.repeatInterrupt || psxCounters[index].mode.toggleIntr != psxCounters[index].currentIrqMode.toggleInterrupt)
|
||||
// DevCon.Warning("Updating psxCounter[%d] mode old repeat %d new %d old toggle %d new %d", index, psxCounters[index].mode.repeatIntr, psxCounters[index].currentIrqMode.repeatInterrupt, psxCounters[index].mode.toggleIntr, psxCounters[index].currentIrqMode.toggleInterrupt);
|
||||
|
||||
psxCounters[index].currentIrqMode.repeatInterrupt = psxCounters[index].mode.repeatIntr;
|
||||
psxCounters[index].currentIrqMode.toggleInterrupt = psxCounters[index].mode.toggleIntr;
|
||||
|
||||
+7
-7
@@ -64,14 +64,14 @@ static const u32
|
||||
|
||||
// SIO2 is a DMA interface for the SIO.
|
||||
|
||||
HW_SIO2_DATAIN = 0x1F808260,
|
||||
HW_SIO2_FIFO = 0x1f808264,
|
||||
HW_SIO2_TX = 0x1F808260,
|
||||
HW_SIO2_RX = 0x1f808264,
|
||||
HW_SIO2_CTRL = 0x1f808268,
|
||||
HW_SIO2_RECV1 = 0x1f80826c,
|
||||
HW_SIO2_RECV2 = 0x1f808270,
|
||||
HW_SIO2_RECV3 = 0x1f808274,
|
||||
HW_SIO2_8278 = 0x1F808278, // May as well add defs
|
||||
HW_SIO2_827C = 0x1F80827C, // for these 2...
|
||||
HW_SIO2_CMD_STAT = 0x1f80826c,
|
||||
HW_SIO2_PORT_STAT = 0x1f808270,
|
||||
HW_SIO2_FIFO_STAT = 0x1f808274,
|
||||
HW_SIO2_FIFO_TX = 0x1F808278, // May as well add defs
|
||||
HW_SIO2_FIFO_RX = 0x1F80827C, // for these 2...
|
||||
HW_SIO2_INTR = 0x1f808280;
|
||||
|
||||
enum DMAMadrAddresses
|
||||
|
||||
+2
-2
@@ -522,11 +522,11 @@ void Patch::ExtractPatchInfo(std::vector<PatchInfo>* dst, const std::string& pna
|
||||
}
|
||||
}
|
||||
current_patch = {};
|
||||
last_place = std::nullopt;
|
||||
unknown_place = false;
|
||||
}
|
||||
|
||||
current_patch.name = line.substr(1, line.length() - 2);
|
||||
last_place = std::nullopt;
|
||||
unknown_place = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+70
-65
@@ -29,25 +29,25 @@ bool Sio2::Initialize()
|
||||
{
|
||||
this->SoftReset();
|
||||
|
||||
for (size_t i = 0; i < send3.size(); i++)
|
||||
for (size_t i = 0; i < CmdQueue.size(); i++)
|
||||
{
|
||||
send3[i] = 0;
|
||||
CmdQueue[i] = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < send1.size(); i++)
|
||||
for (size_t i = 0; i < PortCtrl0.size(); i++)
|
||||
{
|
||||
send1[i] = 0;
|
||||
send2[i] = 0;
|
||||
PortCtrl0[i] = 0;
|
||||
PortCtrl1[i] = 0;
|
||||
}
|
||||
|
||||
dataIn = 0;
|
||||
dataOut = 0;
|
||||
SetCtrl(Sio2Ctrl::SIO2MAN_RESET);
|
||||
SetRecv1(Recv1::DISCONNECTED);
|
||||
recv2 = Recv2::DEFAULT;
|
||||
recv3 = Recv3::DEFAULT;
|
||||
unknown1 = 0;
|
||||
unknown2 = 0;
|
||||
SetCmdStat(CmdStat::DISCONNECTED);
|
||||
PortStat = PortStat::DEFAULT;
|
||||
FifoStat = FifoStat::DEFAULT;
|
||||
FifoTxPos = 0;
|
||||
FifoRxPos = 0;
|
||||
iStat = 0;
|
||||
|
||||
port = 0;
|
||||
@@ -80,13 +80,13 @@ bool Sio2::Shutdown()
|
||||
|
||||
void Sio2::SoftReset()
|
||||
{
|
||||
send3Read = false;
|
||||
send3Position = 0;
|
||||
queueRead = false;
|
||||
queuePosition = 0;
|
||||
commandLength = 0;
|
||||
processedLength = 0;
|
||||
// Clear dmaBlockSize, in case the next SIO2 command is not sent over DMA11.
|
||||
dmaBlockSize = 0;
|
||||
send3Complete = false;
|
||||
queueComplete = false;
|
||||
|
||||
// Anything in g_Sio2FifoIn which was not necessary to consume should be cleared out prior to the next SIO2 cycle.
|
||||
while (!g_Sio2FifoIn.empty())
|
||||
@@ -94,13 +94,18 @@ void Sio2::SoftReset()
|
||||
g_Sio2FifoIn.pop_front();
|
||||
}
|
||||
|
||||
// RECV1 should always be reassembled based on the devices being probed by the packet.
|
||||
recv1 = 0;
|
||||
// cmd_stat should always be reassembled based on the devices being probed by the packet.
|
||||
CmdStat = 0;
|
||||
}
|
||||
|
||||
void Sio2::Interrupt()
|
||||
{
|
||||
iopIntcIrq(17);
|
||||
if (!iStat)
|
||||
iopIntcIrq(17);
|
||||
else
|
||||
DevCon.Warning("Nearly sent double SIO2 IRQ");
|
||||
|
||||
iStat |= 1;
|
||||
}
|
||||
|
||||
void Sio2::SetCtrl(u32 value)
|
||||
@@ -113,9 +118,9 @@ void Sio2::SetCtrl(u32 value)
|
||||
}
|
||||
}
|
||||
|
||||
void Sio2::SetSend3(size_t position, u32 value)
|
||||
void Sio2::SetCmd(size_t position, u32 value)
|
||||
{
|
||||
this->send3[position] = value;
|
||||
this->CmdQueue[position] = value;
|
||||
|
||||
if (position == 0)
|
||||
{
|
||||
@@ -123,9 +128,9 @@ void Sio2::SetSend3(size_t position, u32 value)
|
||||
}
|
||||
}
|
||||
|
||||
void Sio2::SetRecv1(u32 value)
|
||||
void Sio2::SetCmdStat(u32 value)
|
||||
{
|
||||
this->recv1 = value;
|
||||
this->CmdStat = value;
|
||||
}
|
||||
|
||||
void Sio2::Pad()
|
||||
@@ -134,29 +139,29 @@ void Sio2::Pad()
|
||||
PadBase* pad = Pad::GetPad(port, mtap.GetPadSlot());
|
||||
|
||||
// Update the third nibble with which ports have been accessed
|
||||
if (this->recv1 & Recv1::ONE_PORT_OPEN)
|
||||
if (this->CmdStat & CmdStat::ONE_PORT_OPEN)
|
||||
{
|
||||
this->recv1 &= ~(Recv1::ONE_PORT_OPEN);
|
||||
this->recv1 |= Recv1::TWO_PORTS_OPEN;
|
||||
this->CmdStat &= ~(CmdStat::ONE_PORT_OPEN);
|
||||
this->CmdStat |= CmdStat::TWO_PORTS_OPEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->recv1 |= Recv1::ONE_PORT_OPEN;
|
||||
this->CmdStat |= CmdStat::ONE_PORT_OPEN;
|
||||
}
|
||||
|
||||
// This bit is always set, whether the pad is present or missing
|
||||
this->recv1 |= Recv1::NO_DEVICES_MISSING;
|
||||
this->CmdStat |= CmdStat::NO_DEVICES_MISSING;
|
||||
|
||||
// If the currently accessed pad is missing, also tick those bits
|
||||
if (pad->GetType() == Pad::ControllerType::NotConnected || pad->ejectTicks)
|
||||
{
|
||||
if (!port)
|
||||
{
|
||||
this->recv1 |= Recv1::PORT_1_MISSING;
|
||||
this->CmdStat |= CmdStat::PORT_1_MISSING;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->recv1 |= Recv1::PORT_2_MISSING;
|
||||
this->CmdStat |= CmdStat::PORT_2_MISSING;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,18 +201,18 @@ void Sio2::Multitap()
|
||||
const bool multitapEnabled = EmuConfig.Pad.IsMultitapPortEnabled(this->port);
|
||||
|
||||
// Update the third nibble with which ports have been accessed
|
||||
if (this->recv1 & Recv1::ONE_PORT_OPEN)
|
||||
if (this->CmdStat & CmdStat::ONE_PORT_OPEN)
|
||||
{
|
||||
this->recv1 &= ~(Recv1::ONE_PORT_OPEN);
|
||||
this->recv1 |= Recv1::TWO_PORTS_OPEN;
|
||||
this->CmdStat &= ~(CmdStat::ONE_PORT_OPEN);
|
||||
this->CmdStat |= CmdStat::TWO_PORTS_OPEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->recv1 |= Recv1::ONE_PORT_OPEN;
|
||||
this->CmdStat |= CmdStat::ONE_PORT_OPEN;
|
||||
}
|
||||
|
||||
// This bit is always set, whether the pad is present or missing
|
||||
this->recv1 |= Recv1::NO_DEVICES_MISSING;
|
||||
this->CmdStat |= CmdStat::NO_DEVICES_MISSING;
|
||||
|
||||
// If the currently accessed multitap is missing, also tick those bits.
|
||||
// MTAPMAN is special though.
|
||||
@@ -217,11 +222,11 @@ void Sio2::Multitap()
|
||||
// then a disconnect value would look like 0x0002D100.
|
||||
//
|
||||
// MTAPMAN however does not check the bit set by 0x00020000. It only checks the bit
|
||||
// set by 0x00010000. So even if port 2 is being addressed, RECV1 should be 0x0001D100
|
||||
// set by 0x00010000. So even if port 2 is being addressed, cmd stat should be 0x0001D100
|
||||
// (or 0x0001D200 if there are both ports being accessed in that packet).
|
||||
if (!multitapEnabled)
|
||||
{
|
||||
this->recv1 |= Recv1::PORT_1_MISSING;
|
||||
this->CmdStat |= CmdStat::PORT_1_MISSING;
|
||||
}
|
||||
|
||||
g_MultitapArr.at(this->port).SendToMultitap();
|
||||
@@ -229,7 +234,7 @@ void Sio2::Multitap()
|
||||
|
||||
void Sio2::Infrared()
|
||||
{
|
||||
SetRecv1(Recv1::DISCONNECTED);
|
||||
SetCmdStat(CmdStat::DISCONNECTED);
|
||||
|
||||
g_Sio2FifoIn.pop_front();
|
||||
const u8 responseByte = 0xff;
|
||||
@@ -246,11 +251,11 @@ void Sio2::Memcard()
|
||||
|
||||
mcd = &mcds[port][mtap.GetMemcardSlot()];
|
||||
|
||||
// Check if auto ejection is active. If so, set RECV1 to DISCONNECTED,
|
||||
// Check if auto ejection is active. If so, set cmd stat to DISCONNECTED,
|
||||
// and zero out the fifo to simulate dead air over the wire.
|
||||
if (mcd->autoEjectTicks)
|
||||
{
|
||||
SetRecv1(Recv1::DISCONNECTED);
|
||||
SetCmdStat(CmdStat::DISCONNECTED);
|
||||
g_Sio2FifoOut.push_back(0xff); // Because Sio2::Write pops the first g_Sio2FifoIn member
|
||||
|
||||
while (!g_Sio2FifoIn.empty())
|
||||
@@ -262,7 +267,7 @@ void Sio2::Memcard()
|
||||
return;
|
||||
}
|
||||
|
||||
SetRecv1(mcd->IsPresent() ? Recv1::CONNECTED : Recv1::DISCONNECTED);
|
||||
SetCmdStat(mcd->IsPresent() ? CmdStat::CONNECTED : CmdStat::DISCONNECTED);
|
||||
|
||||
const u8 commandByte = g_Sio2FifoIn.front();
|
||||
g_Sio2FifoIn.pop_front();
|
||||
@@ -376,25 +381,25 @@ void Sio2::Write(u8 data)
|
||||
{
|
||||
Sio2Log.WriteLn("%s(%02X) SIO2 DATA Write", __FUNCTION__, data);
|
||||
|
||||
if (!send3Read)
|
||||
if (!queueRead)
|
||||
{
|
||||
// No more SEND3 positions to access, but the game is still sending us SIO2 writes. Lets ignore them.
|
||||
if (send3Position > send3.size())
|
||||
// No more queue positions to access, but the game is still sending us SIO2 writes. Lets ignore them.
|
||||
if (queuePosition > CmdQueue.size())
|
||||
{
|
||||
Console.Warning("%s(%02X) Received data after exhausting all SEND3 values!", __FUNCTION__, data);
|
||||
Console.Warning("%s(%02X) Received data after exhausting all queue entries!", __FUNCTION__, data);
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 currentSend3 = send3[send3Position];
|
||||
port = currentSend3 & Send3::PORT;
|
||||
commandLength = (currentSend3 >> 8) & Send3::COMMAND_LENGTH_MASK;
|
||||
send3Read = true;
|
||||
const u32 currentCmd = CmdQueue[queuePosition];
|
||||
port = currentCmd & Sio2Cmd::PORT;
|
||||
commandLength = (currentCmd >> 8) & Sio2Cmd::COMMAND_LENGTH_MASK;
|
||||
queueRead = true;
|
||||
|
||||
// The freshly read SEND3 position had a length of 0, so we are done handling SIO2 commands until
|
||||
// the next SEND3 writes.
|
||||
// The freshly read cmd position had a length of 0, so we are done handling SIO2 commands until
|
||||
// the next cmd writes.
|
||||
if (commandLength == 0)
|
||||
{
|
||||
send3Complete = true;
|
||||
queueComplete = true;
|
||||
}
|
||||
|
||||
// If the prior command did not need to fully pop g_Sio2FifoIn, do so now,
|
||||
@@ -405,7 +410,7 @@ void Sio2::Write(u8 data)
|
||||
}
|
||||
}
|
||||
|
||||
if (send3Complete)
|
||||
if (queueComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -418,9 +423,9 @@ void Sio2::Write(u8 data)
|
||||
// ... These were from SIO2 DMA (DMA block size is non-zero when SIO2 DMA occurs)
|
||||
if ((g_Sio2FifoIn.size() == g_Sio2.commandLength && g_Sio2.dmaBlockSize == 0) || g_Sio2FifoIn.size() == g_Sio2.dmaBlockSize)
|
||||
{
|
||||
// Go ahead and prep so the next write triggers a load of the new SEND3 value.
|
||||
g_Sio2.send3Read = false;
|
||||
g_Sio2.send3Position++;
|
||||
// Go ahead and prep so the next write triggers a load of the new cmd value.
|
||||
g_Sio2.queueRead = false;
|
||||
g_Sio2.queuePosition++;
|
||||
|
||||
// Check the SIO mode
|
||||
const u8 sioMode = g_Sio2FifoIn.front();
|
||||
@@ -443,7 +448,7 @@ void Sio2::Write(u8 data)
|
||||
default:
|
||||
Console.Error("%s(%02X) Unhandled SIO mode %02X", __FUNCTION__, data, sioMode);
|
||||
g_Sio2FifoOut.push_back(0xff);
|
||||
SetRecv1(Recv1::DISCONNECTED);
|
||||
SetCmdStat(CmdStat::DISCONNECTED);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -488,25 +493,25 @@ bool Sio2::DoState(StateWrapper& sw)
|
||||
if (!sw.DoMarker("Sio2"))
|
||||
return false;
|
||||
|
||||
sw.Do(&send3);
|
||||
sw.Do(&send1);
|
||||
sw.Do(&send2);
|
||||
sw.Do(&CmdQueue);
|
||||
sw.Do(&PortCtrl0);
|
||||
sw.Do(&PortCtrl1);
|
||||
sw.Do(&dataIn);
|
||||
sw.Do(&dataOut);
|
||||
sw.Do(&ctrl);
|
||||
sw.Do(&recv1);
|
||||
sw.Do(&recv2);
|
||||
sw.Do(&recv3);
|
||||
sw.Do(&unknown1);
|
||||
sw.Do(&unknown2);
|
||||
sw.Do(&CmdStat);
|
||||
sw.Do(&PortStat);
|
||||
sw.Do(&FifoStat);
|
||||
sw.Do(&FifoTxPos);
|
||||
sw.Do(&FifoRxPos);
|
||||
sw.Do(&iStat);
|
||||
sw.Do(&port);
|
||||
sw.Do(&send3Read);
|
||||
sw.Do(&send3Position);
|
||||
sw.Do(&queueRead);
|
||||
sw.Do(&queuePosition);
|
||||
sw.Do(&commandLength);
|
||||
sw.Do(&processedLength);
|
||||
sw.Do(&dmaBlockSize);
|
||||
sw.Do(&send3Complete);
|
||||
sw.Do(&queueComplete);
|
||||
|
||||
sw.Do(&g_Sio2FifoIn);
|
||||
sw.Do(&g_Sio2FifoOut);
|
||||
|
||||
+16
-18
@@ -3,6 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Pcsx2Types.h"
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
|
||||
@@ -11,37 +13,33 @@ class StateWrapper;
|
||||
class Sio2
|
||||
{
|
||||
public:
|
||||
std::array<u32, 16> send3; // 0x1f808200 - 0x1f80823f
|
||||
// SEND1 and SEND2 are an unusual bunch. It's not entirely clear just from
|
||||
// documentation but these registers almost seem like they are the same thing;
|
||||
// when bit 2 is set, SEND2 is being read/written. When bit 2 isn't set, it is
|
||||
// SEND1. Their use is not really known, either.
|
||||
std::array<u32, 4> send1; // 0x1f808240 - 0x1f80825f
|
||||
std::array<u32, 4> send2; // 0x1f808240 - 0x1f80825f
|
||||
std::array<u32, 16> CmdQueue; // 0x1f808200 - 0x1f80823f
|
||||
std::array<u32, 4> PortCtrl0; // 0x1f808240 - 0x1f80825f
|
||||
std::array<u32, 4> PortCtrl1; // 0x1f808240 - 0x1f80825f
|
||||
u32 dataIn; // 0x1f808260
|
||||
u32 dataOut; // 0x1f808264
|
||||
u32 ctrl; // 0x1f808268
|
||||
u32 recv1; // 0x1f80826c
|
||||
u32 recv2; // 0x1f808270
|
||||
u32 recv3; // 0x1f808274
|
||||
u32 unknown1; // 0x1f808278
|
||||
u32 unknown2; // 0x1f80827c
|
||||
u32 CmdStat; // 0x1f80826c
|
||||
u32 PortStat; // 0x1f808270
|
||||
u32 FifoStat; // 0x1f808274
|
||||
u32 FifoTxPos; // 0x1f808278
|
||||
u32 FifoRxPos; // 0x1f80827c
|
||||
u32 iStat; // 0x1f808280
|
||||
|
||||
u8 port = 0;
|
||||
|
||||
// The current working index of SEND3. The SEND3 register is a 16 position
|
||||
// The current working index of the command queue. The queue is a 16 position
|
||||
// array of command descriptors. Each descriptor describes the port the command
|
||||
// is targeting, as well as the length of the command in bytes.
|
||||
bool send3Read = false;
|
||||
size_t send3Position = 0;
|
||||
bool queueRead = false;
|
||||
size_t queuePosition = 0;
|
||||
size_t commandLength = 0;
|
||||
size_t processedLength = 0;
|
||||
// Tracks the size of a single block of DMA11/DMA12 data. psxDma11 will set this prior
|
||||
// to doing writes, and Sio2::SetSend3 will clear this to ensure a non-DMA write into SIO2
|
||||
// does not accidentally use dmaBlockSize.
|
||||
size_t dmaBlockSize = 0;
|
||||
bool send3Complete = false;
|
||||
bool queueComplete = false;
|
||||
|
||||
Sio2();
|
||||
~Sio2();
|
||||
@@ -55,8 +53,8 @@ public:
|
||||
void Interrupt();
|
||||
|
||||
void SetCtrl(u32 value);
|
||||
void SetSend3(size_t position, u32 value);
|
||||
void SetRecv1(u32 value);
|
||||
void SetCmd(size_t position, u32 value);
|
||||
void SetCmdStat(u32 value);
|
||||
|
||||
void Pad();
|
||||
void Multitap();
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace SIO0_CTRL
|
||||
static constexpr u16 PORT = 0x2000;
|
||||
} // namespace SIO0_CTRL
|
||||
|
||||
namespace Send3
|
||||
namespace Sio2Cmd
|
||||
{
|
||||
static constexpr u32 PORT = 0x01;
|
||||
static constexpr u16 COMMAND_LENGTH_MASK = 0x3ff;
|
||||
@@ -119,7 +119,7 @@ namespace Sio2Ctrl
|
||||
} // namespace Sio2Ctrl
|
||||
|
||||
// TODO: Remove deprecated options once memcards are no longer using them.
|
||||
namespace Recv1
|
||||
namespace CmdStat
|
||||
{
|
||||
// Deprecated
|
||||
static constexpr u32 DISCONNECTED = 0x1d100;
|
||||
@@ -135,7 +135,7 @@ namespace Recv1
|
||||
|
||||
} // namespace Recv1
|
||||
|
||||
namespace Recv2
|
||||
namespace PortStat
|
||||
{
|
||||
static constexpr u32 DEFAULT = 0xf;
|
||||
} // namespace Recv2
|
||||
@@ -145,7 +145,7 @@ namespace Recv2
|
||||
// to use them. We're going to try and respect these where it seems like
|
||||
// it may make sense to do so, but these are still largely unknown and
|
||||
// tests suggest they are not even used at all.
|
||||
namespace Recv3
|
||||
namespace FifoStat
|
||||
{
|
||||
static constexpr u32 DEFAULT = 0x0;
|
||||
// Set when getting memcard specs
|
||||
|
||||
+56
-49
@@ -9,6 +9,28 @@
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
|
||||
// LOOP seems to only have any effect on the block with LOOP/END set, where it prevents muting the voice
|
||||
// (the documented requirement that every block in a loop has the LOOP bit set is nonsense according to tests)
|
||||
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
|
||||
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
|
||||
#define XAFLAG_LOOP_END (1ul << 0)
|
||||
#define XAFLAG_LOOP (1ul << 1)
|
||||
#define XAFLAG_LOOP_START (1ul << 2)
|
||||
|
||||
#if MULTI_ISA_COMPILE_ONCE
|
||||
// decoded pcm data, used to cache the decoded data so that it needn't be decoded
|
||||
// multiple times. Cache chunks are decoded when the mixer requests the blocks, and
|
||||
// invalided when DMA transfers and memory writes are performed.
|
||||
PcmCacheEntry pcm_cache_data[pcm_BlockCount];
|
||||
|
||||
int g_counter_cache_hits = 0;
|
||||
int g_counter_cache_misses = 0;
|
||||
int g_counter_cache_ignores = 0;
|
||||
#endif
|
||||
|
||||
MULTI_ISA_UNSHARED_START
|
||||
|
||||
static const s32 tbl_XA_Factor[16][2] =
|
||||
{
|
||||
{0, 0},
|
||||
@@ -71,24 +93,6 @@ static void __forceinline IncrementNextA(V_Core& thiscore, uint voiceidx)
|
||||
vc.NextA &= 0xFFFFF;
|
||||
}
|
||||
|
||||
// decoded pcm data, used to cache the decoded data so that it needn't be decoded
|
||||
// multiple times. Cache chunks are decoded when the mixer requests the blocks, and
|
||||
// invalided when DMA transfers and memory writes are performed.
|
||||
PcmCacheEntry pcm_cache_data[pcm_BlockCount];
|
||||
|
||||
int g_counter_cache_hits = 0;
|
||||
int g_counter_cache_misses = 0;
|
||||
int g_counter_cache_ignores = 0;
|
||||
|
||||
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
|
||||
// LOOP seems to only have any effect on the block with LOOP/END set, where it prevents muting the voice
|
||||
// (the documented requirement that every block in a loop has the LOOP bit set is nonsense according to tests)
|
||||
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
|
||||
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
|
||||
#define XAFLAG_LOOP_END (1ul << 0)
|
||||
#define XAFLAG_LOOP (1ul << 1)
|
||||
#define XAFLAG_LOOP_START (1ul << 2)
|
||||
|
||||
static __forceinline void GetNextDataBuffered(V_Core& thiscore, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
@@ -416,8 +420,6 @@ static __forceinline StereoOut32 MixVoice(uint coreidx, uint voiceidx)
|
||||
return voiceOut;
|
||||
}
|
||||
|
||||
const VoiceMixSet VoiceMixSet::Empty((StereoOut32()), (StereoOut32())); // Don't use SteroOut32::Empty because C++ doesn't make any dep/order checks on global initializers.
|
||||
|
||||
static __forceinline void MixCoreVoices(VoiceMixSet& dest, const uint coreidx)
|
||||
{
|
||||
V_Core& thiscore(Cores[coreidx]);
|
||||
@@ -435,40 +437,42 @@ static __forceinline void MixCoreVoices(VoiceMixSet& dest, const uint coreidx)
|
||||
}
|
||||
}
|
||||
|
||||
StereoOut32 V_Core::Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext)
|
||||
static __forceinline StereoOut32 MixCore(const uint coreidx, const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext)
|
||||
{
|
||||
MasterVol.Update();
|
||||
UpdateNoise(*this);
|
||||
V_Core& thiscore(Cores[coreidx]);
|
||||
|
||||
thiscore.MasterVol.Update();
|
||||
UpdateNoise(thiscore);
|
||||
|
||||
// Saturate final result to standard 16 bit range.
|
||||
const VoiceMixSet Voices(clamp_mix(inVoices.Dry), clamp_mix(inVoices.Wet));
|
||||
|
||||
// Write Mixed results To Output Area
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1000 : 0x1800) + OutPos, Voices.Dry.Left);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1200 : 0x1A00) + OutPos, Voices.Dry.Right);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1400 : 0x1C00) + OutPos, Voices.Wet.Left);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1600 : 0x1E00) + OutPos, Voices.Wet.Right);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1000 : 0x1800) + OutPos, Voices.Dry.Left);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1200 : 0x1A00) + OutPos, Voices.Dry.Right);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1400 : 0x1C00) + OutPos, Voices.Wet.Left);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1600 : 0x1E00) + OutPos, Voices.Wet.Right);
|
||||
|
||||
// Write mixed results to logfile (if enabled)
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
WaveDump::WriteCore(Index, CoreSrc_DryVoiceMix, Voices.Dry);
|
||||
WaveDump::WriteCore(Index, CoreSrc_WetVoiceMix, Voices.Wet);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_DryVoiceMix, Voices.Dry);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_WetVoiceMix, Voices.Wet);
|
||||
#endif
|
||||
|
||||
// Mix in the Input data
|
||||
|
||||
StereoOut32 TD(
|
||||
Input.Left & DryGate.InpL,
|
||||
Input.Right & DryGate.InpR);
|
||||
Input.Left & thiscore.DryGate.InpL,
|
||||
Input.Right & thiscore.DryGate.InpR);
|
||||
|
||||
// Mix in the Voice data
|
||||
TD.Left += Voices.Dry.Left & DryGate.SndL;
|
||||
TD.Right += Voices.Dry.Right & DryGate.SndR;
|
||||
TD.Left += Voices.Dry.Left & thiscore.DryGate.SndL;
|
||||
TD.Right += Voices.Dry.Right & thiscore.DryGate.SndR;
|
||||
|
||||
// Mix in the External (nothing/core0) data
|
||||
TD.Left += Ext.Left & DryGate.ExtL;
|
||||
TD.Right += Ext.Right & DryGate.ExtR;
|
||||
TD.Left += Ext.Left & thiscore.DryGate.ExtL;
|
||||
TD.Right += Ext.Right & thiscore.DryGate.ExtR;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Reverberation Effects Processing
|
||||
@@ -492,27 +496,27 @@ StereoOut32 V_Core::Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, c
|
||||
|
||||
// Mix Input, Voice, and External data:
|
||||
|
||||
TW.Left = Input.Left & WetGate.InpL;
|
||||
TW.Right = Input.Right & WetGate.InpR;
|
||||
TW.Left = Input.Left & thiscore.WetGate.InpL;
|
||||
TW.Right = Input.Right & thiscore.WetGate.InpR;
|
||||
|
||||
TW.Left += Voices.Wet.Left & WetGate.SndL;
|
||||
TW.Right += Voices.Wet.Right & WetGate.SndR;
|
||||
TW.Left += Ext.Left & WetGate.ExtL;
|
||||
TW.Right += Ext.Right & WetGate.ExtR;
|
||||
TW.Left += Voices.Wet.Left & thiscore.WetGate.SndL;
|
||||
TW.Right += Voices.Wet.Right & thiscore.WetGate.SndR;
|
||||
TW.Left += Ext.Left & thiscore.WetGate.ExtL;
|
||||
TW.Right += Ext.Right & thiscore.WetGate.ExtR;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
WaveDump::WriteCore(Index, CoreSrc_PreReverb, TW);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_PreReverb, TW);
|
||||
#endif
|
||||
|
||||
StereoOut32 RV = DoReverb(TW);
|
||||
StereoOut32 RV = thiscore.DoReverb(TW);
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
WaveDump::WriteCore(Index, CoreSrc_PostReverb, RV);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_PostReverb, RV);
|
||||
#endif
|
||||
|
||||
// Mix Dry + Wet
|
||||
// (master volume is applied later to the result of both outputs added together).
|
||||
return TD + ApplyVolume(RV, FxVol);
|
||||
return TD + ApplyVolume(RV, thiscore.FxVol);
|
||||
}
|
||||
|
||||
static StereoOut32 DCFilter(StereoOut32 input)
|
||||
@@ -529,7 +533,7 @@ static StereoOut32 DCFilter(StereoOut32 input)
|
||||
return output;
|
||||
}
|
||||
|
||||
__forceinline void spu2Mix()
|
||||
void spu2Mix()
|
||||
{
|
||||
// Note: Playmode 4 is SPDIF, which overrides other inputs.
|
||||
StereoOut32 InputData[2] =
|
||||
@@ -549,11 +553,12 @@ __forceinline void spu2Mix()
|
||||
#endif
|
||||
|
||||
// Todo: Replace me with memzero initializer!
|
||||
VoiceMixSet VoiceData[2] = {VoiceMixSet::Empty, VoiceMixSet::Empty}; // mixed voice data for each core.
|
||||
VoiceMixSet VoiceData[2] = {{StereoOut32(), StereoOut32()}, {StereoOut32(), StereoOut32()}}; // mixed voice data for each core.
|
||||
|
||||
MixCoreVoices(VoiceData[0], 0);
|
||||
MixCoreVoices(VoiceData[1], 1);
|
||||
|
||||
StereoOut32 Ext(Cores[0].Mix(VoiceData[0], InputData[0], StereoOut32::Empty));
|
||||
StereoOut32 Ext(MixCore(0, VoiceData[0], InputData[0], StereoOut32::Empty));
|
||||
|
||||
if ((PlayMode & 4) || (Cores[0].Mute != 0))
|
||||
Ext = StereoOut32::Empty;
|
||||
@@ -571,7 +576,7 @@ __forceinline void spu2Mix()
|
||||
#endif
|
||||
|
||||
Ext = ApplyVolume(Ext, Cores[1].ExtVol);
|
||||
StereoOut32 Out(Cores[1].Mix(VoiceData[1], InputData[1], Ext));
|
||||
StereoOut32 Out(MixCore(1, VoiceData[1], InputData[1], Ext));
|
||||
|
||||
if (PlayMode & 8)
|
||||
{
|
||||
@@ -628,3 +633,5 @@ __forceinline void spu2Mix()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MULTI_ISA_UNSHARED_END
|
||||
|
||||
+5
-8
@@ -63,11 +63,12 @@ struct StereoOut32
|
||||
}
|
||||
};
|
||||
|
||||
extern void (*spu2Mix)();
|
||||
extern s16* GetMemPtr(u32 addr);
|
||||
extern s16 spu2M_Read(u32 addr);
|
||||
extern void spu2M_Write(u32 addr, s16 value);
|
||||
extern void spu2M_Write(u32 addr, u16 value);
|
||||
extern void spu2Mix();
|
||||
MULTI_ISA_DEF(void spu2Mix();)
|
||||
extern void spu2Output(StereoOut32 out);
|
||||
|
||||
static __forceinline s16 SignExtend16(u16 v)
|
||||
@@ -391,7 +392,6 @@ struct V_CoreGates
|
||||
|
||||
struct VoiceMixSet
|
||||
{
|
||||
static const VoiceMixSet Empty;
|
||||
StereoOut32 Dry, Wet;
|
||||
|
||||
VoiceMixSet() {}
|
||||
@@ -478,11 +478,6 @@ struct V_Core
|
||||
u16 psxSoundDataTransferControl;
|
||||
u16 psxSPUSTAT;
|
||||
|
||||
// HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
|
||||
// corruption that originates elsewhere. >_< The actual ADMA buffer
|
||||
// is an area mapped to SPU2 main memory.
|
||||
//s16 ADMATempBuffer[0x1000];
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// V_Core Methods
|
||||
// ----------------------------------------------------------------------------------
|
||||
@@ -506,7 +501,6 @@ struct V_Core
|
||||
// Mixer Section
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
StereoOut32 Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext);
|
||||
StereoOut32 DoReverb(StereoOut32 Input);
|
||||
s32 RevbGetIndexer(s32 offset);
|
||||
|
||||
@@ -630,3 +624,6 @@ struct PcmCacheEntry
|
||||
};
|
||||
|
||||
extern PcmCacheEntry pcm_cache_data[pcm_BlockCount];
|
||||
extern int g_counter_cache_hits;
|
||||
extern int g_counter_cache_misses;
|
||||
extern int g_counter_cache_ignores;
|
||||
|
||||
@@ -219,6 +219,10 @@ bool SPU2::IsAudioCaptureActive()
|
||||
|
||||
void SPU2::InternalReset(bool psxmode)
|
||||
{
|
||||
spu2Mix = MULTI_ISA_SELECT(spu2Mix);
|
||||
ReverbDownsample = MULTI_ISA_SELECT(ReverbDownsample);
|
||||
ReverbUpsample = MULTI_ISA_SELECT(ReverbUpsample);
|
||||
|
||||
s_current_chunk_pos = 0;
|
||||
s_psxmode = psxmode;
|
||||
if (!s_psxmode)
|
||||
|
||||
+9
-22
@@ -33,19 +33,23 @@ u32 Cycles;
|
||||
|
||||
int PlayMode;
|
||||
|
||||
static bool has_to_call_irq[2] = { false, false };
|
||||
static bool has_to_call_irq_dma[2] = { false, false };
|
||||
static bool has_to_call_irq_dma[2] = {false, false};
|
||||
StereoOut32 (*ReverbUpsample)(V_Core& core);
|
||||
s32 (*ReverbDownsample)(V_Core& core, bool right);
|
||||
|
||||
// Function pointer for multi-isa mixer
|
||||
void (*spu2Mix)();
|
||||
|
||||
static bool psxmode = false;
|
||||
|
||||
void SetIrqCall(int core)
|
||||
{
|
||||
// reset by an irq disable/enable cycle, behaviour found by
|
||||
// test programs that bizarrely only fired one interrupt
|
||||
has_to_call_irq[core] = true;
|
||||
//SPU2::ConLog("* SPU2: Irq Called (%04x) at cycle %d.\n", Spdif.Info, Cycles);
|
||||
if (!(Spdif.Info & (4 << core)) && Cores[core].IRQEnable)
|
||||
{
|
||||
Spdif.Info |= (4 << core);
|
||||
spu2Irq();
|
||||
}
|
||||
}
|
||||
|
||||
void SetIrqCallDMA(int core)
|
||||
@@ -103,9 +107,6 @@ void V_Core::Init(int index)
|
||||
if (SPU2::MsgToConsole())
|
||||
SPU2::ConLog("* SPU2: Init SPU2 core %d \n", index);
|
||||
|
||||
ReverbDownsample = MULTI_ISA_SELECT(ReverbDownsample);
|
||||
ReverbUpsample = MULTI_ISA_SELECT(ReverbUpsample);
|
||||
|
||||
//memset(this, 0, sizeof(V_Core));
|
||||
// Explicitly initializing variables instead.
|
||||
Mute = false;
|
||||
@@ -342,20 +343,6 @@ __forceinline void TimeUpdate(u32 cClocks)
|
||||
//Update Mixing Progress
|
||||
while (dClocks >= TickInterval)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (has_to_call_irq[i])
|
||||
{
|
||||
//ConLog("* SPU2: Irq Called (%04x) at cycle %d.\n", Spdif.Info, Cycles);
|
||||
has_to_call_irq[i] = false;
|
||||
if (!(Spdif.Info & (4 << i)) && Cores[i].IRQEnable)
|
||||
{
|
||||
Spdif.Info |= (4 << i);
|
||||
spu2Irq();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dClocks -= TickInterval;
|
||||
lClocks += TickInterval;
|
||||
Cycles++;
|
||||
|
||||
+13
-13
@@ -119,7 +119,7 @@ mem8_t iopHwRead8_Page8( u32 addr )
|
||||
|
||||
mem8_t ret;
|
||||
|
||||
if (addr == HW_SIO2_FIFO)
|
||||
if (addr == HW_SIO2_RX)
|
||||
{
|
||||
ret = g_Sio2.Read();
|
||||
}
|
||||
@@ -415,7 +415,7 @@ mem32_t iopHwRead32_Page8( u32 addr )
|
||||
if( masked_addr < 0x240 )
|
||||
{
|
||||
const int parm = (masked_addr-0x200) / 4;
|
||||
ret = g_Sio2.send3[parm];
|
||||
ret = g_Sio2.CmdQueue[parm];
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 SEND3 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
}
|
||||
else if ( masked_addr < 0x260 )
|
||||
@@ -423,18 +423,18 @@ mem32_t iopHwRead32_Page8( u32 addr )
|
||||
// SIO2 Send commands alternate registers. First reg maps to Send1, second
|
||||
// to Send2, third to Send1, etc. And the following clever code does this:
|
||||
const int parm = (masked_addr-0x240) / 8;
|
||||
ret = (masked_addr & 4) ? g_Sio2.send2[parm] : g_Sio2.send1[parm];
|
||||
ret = (masked_addr & 4) ? g_Sio2.PortCtrl1[parm] : g_Sio2.PortCtrl0[parm];
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 SEND1/2 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
}
|
||||
else if ( masked_addr <= 0x280 )
|
||||
{
|
||||
switch( masked_addr )
|
||||
{
|
||||
case (HW_SIO2_DATAIN & 0x0fff):
|
||||
case (HW_SIO2_TX & 0x0fff):
|
||||
ret = psxHu32(addr);
|
||||
Sio2Log.Warning("%s(%08X) Unexpected 32 bit read of HW_SIO2_DATAIN (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_FIFO & 0x0fff):
|
||||
case (HW_SIO2_RX & 0x0fff):
|
||||
ret = psxHu32(addr);
|
||||
Sio2Log.Warning("%s(%08X) Unexpected 32 bit read of HW_SIO2_FIFO (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
@@ -442,24 +442,24 @@ mem32_t iopHwRead32_Page8( u32 addr )
|
||||
ret = g_Sio2.ctrl;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 CTRL Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_RECV1 & 0xfff):
|
||||
ret = g_Sio2.recv1;
|
||||
case (HW_SIO2_CMD_STAT & 0xfff):
|
||||
ret = g_Sio2.CmdStat;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 RECV1 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_RECV2 & 0x0fff):
|
||||
ret = g_Sio2.recv2;
|
||||
case (HW_SIO2_PORT_STAT & 0x0fff):
|
||||
ret = g_Sio2.PortStat;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 RECV2 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_RECV3 & 0x0fff):
|
||||
ret = g_Sio2.recv3;
|
||||
case (HW_SIO2_FIFO_STAT & 0x0fff):
|
||||
ret = g_Sio2.FifoStat;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 RECV3 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (0x1f808278 & 0x0fff):
|
||||
ret = g_Sio2.unknown1;
|
||||
ret = g_Sio2.FifoTxPos;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 UNK1 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (0x1f80827C & 0x0fff):
|
||||
ret = g_Sio2.unknown2;
|
||||
ret = g_Sio2.FifoRxPos;
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 UNK2 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
break;
|
||||
case (HW_SIO2_INTR & 0x0fff):
|
||||
|
||||
@@ -162,7 +162,7 @@ void iopHwWrite8_Page8( u32 addr, mem8_t val )
|
||||
// all addresses are assumed to be prefixed with 0x1f808xxx:
|
||||
pxAssert( (addr >> 12) == 0x1f808 );
|
||||
|
||||
if (addr == HW_SIO2_DATAIN)
|
||||
if (addr == HW_SIO2_TX)
|
||||
{
|
||||
g_Sio2.Write(val);
|
||||
}
|
||||
@@ -595,9 +595,9 @@ void iopHwWrite32_Page8( u32 addr, mem32_t val )
|
||||
{
|
||||
if( masked_addr < 0x240 )
|
||||
{
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND3 Write (len = %d / %d) (port = %d)", __FUNCTION__, addr, val, (val >> 8) & Send3::COMMAND_LENGTH_MASK, (val >> 18) & Send3::COMMAND_LENGTH_MASK, val & 0x01);
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND3 Write (len = %d / %d) (port = %d)", __FUNCTION__, addr, val, (val >> 8) & Sio2Cmd::COMMAND_LENGTH_MASK, (val >> 18) & Sio2Cmd::COMMAND_LENGTH_MASK, val & 0x01);
|
||||
const int parm = (masked_addr - 0x200) / 4;
|
||||
g_Sio2.SetSend3(parm, val);
|
||||
g_Sio2.SetCmd(parm, val);
|
||||
}
|
||||
else if ( masked_addr < 0x260 )
|
||||
{
|
||||
@@ -609,51 +609,51 @@ void iopHwWrite32_Page8( u32 addr, mem32_t val )
|
||||
if (masked_addr & 4)
|
||||
{
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND2 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.send2[parm] = val;
|
||||
g_Sio2.PortCtrl1[parm] = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND1 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.send1[parm] = val;
|
||||
g_Sio2.PortCtrl0[parm] = val;
|
||||
}
|
||||
}
|
||||
else if ( masked_addr <= 0x280 )
|
||||
{
|
||||
switch( masked_addr )
|
||||
{
|
||||
case (HW_SIO2_DATAIN & 0x0fff):
|
||||
case (HW_SIO2_TX & 0x0fff):
|
||||
Sio2Log.Warning("%s(%08X, %08X) Unexpected 32 bit write to HW_SIO2_DATAIN", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO2_FIFO & 0x0fff):
|
||||
case (HW_SIO2_RX & 0x0fff):
|
||||
Sio2Log.Warning("%s(%08X, %08X) Unexpected 32 bit write to HW_SIO2_FIFO", __FUNCTION__, addr, val);
|
||||
break;
|
||||
case (HW_SIO2_CTRL & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 CTRL Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.SetCtrl(val);
|
||||
break;
|
||||
case (HW_SIO2_RECV1 & 0x0fff):
|
||||
case (HW_SIO2_CMD_STAT & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 RECV1 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.recv1 = val;
|
||||
g_Sio2.CmdStat = val;
|
||||
break;
|
||||
case (HW_SIO2_RECV2 & 0x0fff):
|
||||
case (HW_SIO2_PORT_STAT & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 RECV2 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.recv2 = val;
|
||||
g_Sio2.PortStat = val;
|
||||
break;
|
||||
case (HW_SIO2_RECV3 & 0x0fff):
|
||||
case (HW_SIO2_FIFO_STAT & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 RECV3 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.recv3 = val;
|
||||
g_Sio2.FifoStat = val;
|
||||
break;
|
||||
case (HW_SIO2_8278 & 0x0fff):
|
||||
case (HW_SIO2_FIFO_TX & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 UNK1 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.unknown1 = val;
|
||||
g_Sio2.FifoTxPos = val;
|
||||
break;
|
||||
case (HW_SIO2_827C & 0x0fff):
|
||||
case (HW_SIO2_FIFO_RX & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 UNK2 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.unknown2 = val;
|
||||
g_Sio2.FifoRxPos = val;
|
||||
break;
|
||||
case (HW_SIO2_INTR & 0x0fff):
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 ISTAT Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.iStat = val;
|
||||
g_Sio2.iStat &= ~val;
|
||||
break;
|
||||
// Other SIO2 registers are read-only, no-ops on write.
|
||||
default:
|
||||
|
||||
@@ -136,14 +136,14 @@ static __ri const char* _ioplog_GetHwName( u32 addr, T val )
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
case HW_SIO2_FIFO: return "SIO2 FIFO";
|
||||
case HW_SIO2_CTRL: return "SIO2 CTRL";
|
||||
case HW_SIO2_RECV1: return "SIO2 RECV1";
|
||||
case HW_SIO2_RECV2: return "SIO2 RECV2";
|
||||
case HW_SIO2_RECV3: return "SIO2 RECV3";
|
||||
case HW_SIO2_INTR: return "SIO2 INTR";
|
||||
case 0x1f808278: return "SIO2 8278";
|
||||
case 0x1f80827C: return "SIO2 827C";
|
||||
case HW_SIO2_RX: return "SIO2 RX";
|
||||
case HW_SIO2_CTRL: return "SIO2 CTRL";
|
||||
case HW_SIO2_CMD_STAT: return "SIO2 CMD_STAT";
|
||||
case HW_SIO2_PORT_STAT: return "SIO2 PORT_STAT";
|
||||
case HW_SIO2_FIFO_STAT: return "SIO2 FIFO_STAT";
|
||||
case HW_SIO2_INTR: return "SIO2 INTR";
|
||||
case HW_SIO2_FIFO_TX: return "SIO2 FIFO_TX";
|
||||
case HW_SIO2_FIFO_RX: return "SIO2 FIFO_RX";
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Check for "zoned" registers in the default case.
|
||||
|
||||
Reference in New Issue
Block a user