Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b3d4615b8 | ||
|
|
a8f6336b47 | ||
|
|
0b33df3341 | ||
|
|
744cc4b705 | ||
|
|
9d3cd5784f | ||
|
|
06ea58198a | ||
|
|
3692d7d090 | ||
|
|
460a2dbbd3 | ||
|
|
228f4f1010 | ||
|
|
2703b91e41 | ||
|
|
24171787f8 | ||
|
|
49d3338d4a | ||
|
|
a9d693e1c3 | ||
|
|
4ef69248d0 | ||
|
|
247b3ed740 | ||
|
|
1edca6235c | ||
|
|
ab5c03b1d9 | ||
|
|
d4cb35469d | ||
|
|
fd1b1d0c24 | ||
|
|
bf96ceeacc | ||
|
|
2c08b385e5 | ||
|
|
051d13ec7a | ||
|
|
a2a9643123 | ||
|
|
1286bfe75b |
@@ -9583,9 +9583,9 @@ SLAJ-25049:
|
||||
region: "NTSC-Unk"
|
||||
SLAJ-25051:
|
||||
name: "Lord of the Rings, The - The Third Age"
|
||||
region: "NTSC-Unk"
|
||||
region: "NTSC-Ch"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes ghosting in cutscenes.
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLAJ-25052:
|
||||
name: "Urbz, The - Sims in the City"
|
||||
region: "NTSC-Unk"
|
||||
@@ -9603,6 +9603,7 @@ SLAJ-25053:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLAJ-25055:
|
||||
@@ -9641,6 +9642,7 @@ SLAJ-25066:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
memcardFilters:
|
||||
@@ -9775,6 +9777,7 @@ SLAJ-25094:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLAJ-25095:
|
||||
@@ -10012,6 +10015,7 @@ SLED-52597:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLED-52736:
|
||||
@@ -10113,6 +10117,7 @@ SLED-53512:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLED-53537:
|
||||
@@ -10245,6 +10250,11 @@ SLED-54401:
|
||||
mergeSprite: 1 # Fixes misaligned bloom.
|
||||
halfPixelOffset: 2 # Fixes misaligned bloom.
|
||||
autoFlush: 2 # Fixes sun occlusion and brightness.
|
||||
SLED-54509:
|
||||
name: "Guitar Hero II [Demo]"
|
||||
region: "PAL-M5"
|
||||
roundModes:
|
||||
vu1RoundMode: 0 # Massages the Z on the score meter for hardware mode, software doesn't really need this.
|
||||
SLES-50003:
|
||||
name: "Swap Magic DVD Disc v2.0"
|
||||
region: "PAL-Unk"
|
||||
@@ -14691,6 +14701,7 @@ SLES-51914:
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
roundSprite: 2 # Fixes various lines / reduces bars on right edge.
|
||||
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
|
||||
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
|
||||
SLES-51915:
|
||||
name: "Pro Evolution Soccer 3"
|
||||
region: "PAL-I"
|
||||
@@ -16114,7 +16125,7 @@ SLES-52570:
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes misaligned lighting and other effects.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects, needs Special otherwise lights flicker.
|
||||
SLES-52571:
|
||||
name: "Pacific Air Warriors 2 - Dogfight"
|
||||
region: "PAL-E"
|
||||
@@ -16154,6 +16165,7 @@ SLES-52584:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLES-52585:
|
||||
@@ -16168,6 +16180,7 @@ SLES-52585:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLES-52587:
|
||||
@@ -16703,25 +16716,27 @@ SLES-52801:
|
||||
name: "Lord of the Rings, The - The Third Age"
|
||||
region: "PAL-M5"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes ghosting in cutscenes.
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLES-52802:
|
||||
name: "Seigneur des anneaux, Le - Le Tiers Âge"
|
||||
region: "PAL-F"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes ghosting in cutscenes.
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLES-52803:
|
||||
name: "Herr der Ringe, Der - Das dritte Zeitalter"
|
||||
region: "PAL-G"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLES-52804:
|
||||
name: "Signore degli Anelli, Il - La Terza Era"
|
||||
region: "PAL-I"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes ghosting in cutscenes.
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLES-52805:
|
||||
name: "Señor de Los Anillos, El - La Tercera Edad"
|
||||
region: "PAL-S"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes ghosting in cutscenes.
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLES-52807:
|
||||
name: "Lemony Snicket's A Series of Unfortunate Events"
|
||||
region: "PAL-E"
|
||||
@@ -16925,7 +16940,8 @@ SLES-52877:
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes blurriness.
|
||||
halfPixelOffset: 2 # Reduces blurriness. Normal Vertex works better, but causes some lights to disappear.
|
||||
roundSprite: 1 # Further reduces blurriness.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
SLES-52882:
|
||||
name: "Stolen"
|
||||
@@ -17540,7 +17556,7 @@ SLES-53075:
|
||||
name: "Area 51"
|
||||
region: "PAL-M5"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes misaligned lighting and other effects.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects, needs Special otherwise lights flicker.
|
||||
SLES-53076:
|
||||
name: "Triggerman"
|
||||
region: "PAL-M5"
|
||||
@@ -18545,6 +18561,7 @@ SLES-53506:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
memcardFilters:
|
||||
@@ -18566,6 +18583,7 @@ SLES-53507:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
memcardFilters:
|
||||
@@ -18695,6 +18713,7 @@ SLES-53534:
|
||||
trilinearFiltering: 1
|
||||
wildArmsHack: 1 # Reduces post-processing misalignment.
|
||||
mergeSprite: 1 # Reduces post-processing misalignment.
|
||||
autoFlush: 1 # Improves post-processing rendering.
|
||||
SLES-53535:
|
||||
name: "Tony Hawk's American Wasteland"
|
||||
region: "PAL-M4"
|
||||
@@ -18706,6 +18725,7 @@ SLES-53535:
|
||||
trilinearFiltering: 1
|
||||
wildArmsHack: 1 # Reduces post-processing misalignment.
|
||||
mergeSprite: 1 # Reduces post-processing misalignment.
|
||||
autoFlush: 1 # Improves post-processing rendering.
|
||||
SLES-53536:
|
||||
name: "London Racer - Police Madness"
|
||||
region: "PAL-M3"
|
||||
@@ -21679,6 +21699,7 @@ SLES-54627:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLES-54628:
|
||||
@@ -21859,6 +21880,7 @@ SLES-54681:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLES-54683:
|
||||
@@ -22647,6 +22669,8 @@ SLES-54962:
|
||||
region: "PAL-E"
|
||||
roundModes:
|
||||
vu1RoundMode: 0 # Crashes without.
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Crowd textures.
|
||||
SLES-54963:
|
||||
name: "Tony Hawk's Proving Ground"
|
||||
region: "PAL-E"
|
||||
@@ -22678,6 +22702,8 @@ SLES-54974:
|
||||
region: "PAL-M4"
|
||||
roundModes:
|
||||
vu1RoundMode: 0 # Crashes without.
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Crowd textures.
|
||||
SLES-54975:
|
||||
name: "George Of The Jungle"
|
||||
region: "PAL-E"
|
||||
@@ -24174,6 +24200,7 @@ SLES-55605:
|
||||
- SoftwareRendererFMVHack # Fixes vertical lines in FMVs.
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Corrects post processing position.
|
||||
cpuCLUTRender: 1 # Reduces the bloomy blur of characters.
|
||||
clampModes:
|
||||
vu1ClampMode: 3 # Fixes SPS on characters.
|
||||
SLES-55609:
|
||||
@@ -25000,6 +25027,7 @@ SLKA-25093:
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
roundSprite: 2 # Fixes various lines / reduces bars on right edge.
|
||||
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
|
||||
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
|
||||
SLKA-25095:
|
||||
name: "Madden NFL 2004"
|
||||
region: "NTSC-K"
|
||||
@@ -25329,6 +25357,7 @@ SLKA-25206:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLKA-25207:
|
||||
@@ -25445,7 +25474,7 @@ SLKA-25237:
|
||||
name: "Lord of the Rings, The - The Third Age"
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes ghosting in cutscenes.
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLKA-25241:
|
||||
name: "Need for Speed - Underground 2"
|
||||
region: "NTSC-K"
|
||||
@@ -25654,6 +25683,7 @@ SLKA-25304:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLKA-25307:
|
||||
@@ -25933,6 +25963,13 @@ SLKA-25410:
|
||||
SLKA-25413:
|
||||
name: "SD Gundam G - Generation Spirits"
|
||||
region: "NTSC-K"
|
||||
SLKA-25414:
|
||||
name: "Guitar Hero III - Legends of Rock"
|
||||
region: "NTSC-K"
|
||||
roundModes:
|
||||
vu1RoundMode: 0 # Crashes without.
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Crowd textures.
|
||||
SLKA-25422:
|
||||
name: "Silent Hill - Origins"
|
||||
region: "NTSC-K"
|
||||
@@ -26017,6 +26054,7 @@ SLPM-55004:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLPM-55005:
|
||||
@@ -26068,6 +26106,7 @@ SLPM-55036:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLPM-55039:
|
||||
@@ -26692,6 +26731,7 @@ SLPM-60246:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLPM-60250:
|
||||
@@ -30740,6 +30780,7 @@ SLPM-65413:
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
roundSprite: 2 # Fixes various lines / reduces bars on right edge.
|
||||
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
|
||||
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
|
||||
SLPM-65414:
|
||||
name: "Simple 2000 Series Vol. 45 - The Koi to Namida to, Tsuioku to..."
|
||||
region: "NTSC-J"
|
||||
@@ -31758,6 +31799,7 @@ SLPM-65719:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLPM-65720:
|
||||
@@ -32250,6 +32292,8 @@ SLPM-65845:
|
||||
SLPM-65846:
|
||||
name: "Lord of the Rings, The - Uchitsu Kuni Daisanki"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLPM-65847:
|
||||
name: "Soriaro no Fuukin Remix [First Print - Limited Edition]"
|
||||
region: "NTSC-J"
|
||||
@@ -32636,6 +32680,7 @@ SLPM-65958:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLPM-65959:
|
||||
@@ -33199,6 +33244,7 @@ SLPM-66108:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
memcardFilters:
|
||||
@@ -34670,7 +34716,7 @@ SLPM-66468:
|
||||
name: "Area 51"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes misaligned lighting and other effects.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects, needs Special otherwise lights flicker.
|
||||
SLPM-66469:
|
||||
name: "Love-Com - Punch de Court [Limited Edition]"
|
||||
region: "NTSC-J"
|
||||
@@ -35388,6 +35434,7 @@ SLPM-66652:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
memcardFilters:
|
||||
@@ -35776,6 +35823,7 @@ SLPM-66739:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLPM-66740:
|
||||
@@ -36542,6 +36590,7 @@ SLPM-66962:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLPM-66963:
|
||||
@@ -36909,6 +36958,7 @@ SLPM-68019:
|
||||
- SoftwareRendererFMVHack # Fixes vertical lines in FMVs.
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Corrects post processing position.
|
||||
cpuCLUTRender: 1 # Reduces the bloomy blur of characters.
|
||||
clampModes:
|
||||
vu1ClampMode: 3 # Fixes SPS on characters.
|
||||
SLPM-68503:
|
||||
@@ -41914,6 +41964,7 @@ SLPS-25837:
|
||||
- SoftwareRendererFMVHack # Fixes vertical lines in FMVs.
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Corrects post processing position.
|
||||
cpuCLUTRender: 1 # Reduces the bloomy blur of characters.
|
||||
clampModes:
|
||||
vu1ClampMode: 3 # Fixes SPS on characters.
|
||||
SLPS-25838:
|
||||
@@ -41927,6 +41978,8 @@ SLPS-25840:
|
||||
region: "NTSC-J"
|
||||
roundModes:
|
||||
vu1RoundMode: 0 # Crashes without.
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Crowd textures.
|
||||
SLPS-25841:
|
||||
name: "Tales of Destiny [Director's Cut] [Premium Box]"
|
||||
region: "NTSC-J"
|
||||
@@ -42099,10 +42152,12 @@ SLPS-25889:
|
||||
roundModes:
|
||||
vu1RoundMode: 0 # Fixes VU size spam and potential graphical issues with GH3 engine.
|
||||
SLPS-25890:
|
||||
name: "Guitar Hero III - Legends of Rock [with Guitar]"
|
||||
name: "Guitar Hero III - Legends of Rock"
|
||||
region: "NTSC-J"
|
||||
roundModes:
|
||||
vu1RoundMode: 0 # Crashes without.
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Crowd textures.
|
||||
SLPS-25892:
|
||||
name: "Nogizaka Haruka no Himitsu - Cosplay Hajimemashita"
|
||||
region: "NTSC-J"
|
||||
@@ -45660,7 +45715,7 @@ SLUS-20595:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes misaligned lighting and other effects.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects, needs Special otherwise lights flicker.
|
||||
SLUS-20596:
|
||||
name: "UFC - Ultimate Fighting Championship - Sudden Impact"
|
||||
region: "NTSC-U"
|
||||
@@ -46144,6 +46199,7 @@ SLUS-20694:
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
roundSprite: 2 # Fixes various lines / reduces bars on right edge.
|
||||
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
|
||||
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
|
||||
SLUS-20695:
|
||||
name: "Chaos Legion"
|
||||
region: "NTSC-U"
|
||||
@@ -47932,7 +47988,7 @@ SLUS-21027:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes ghosting in cutscenes.
|
||||
halfPixelOffset: 2 # Fixes ghosting.
|
||||
SLUS-21028:
|
||||
name: "World Championship Poker"
|
||||
region: "NTSC-U"
|
||||
@@ -48079,6 +48135,7 @@ SLUS-21050:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLUS-21051:
|
||||
@@ -48190,7 +48247,8 @@ SLUS-21075:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 1 # Fixes blurriness.
|
||||
halfPixelOffset: 2 # Reduces blurriness. Normal Vertex works better, but causes some lights to disappear.
|
||||
roundSprite: 1 # Further reduces blurriness.
|
||||
beforeDraw: "OI_HauntingGround" # Fix bloom.
|
||||
SLUS-21076:
|
||||
name: "Atari Anthology"
|
||||
@@ -48869,6 +48927,7 @@ SLUS-21208:
|
||||
trilinearFiltering: 1
|
||||
wildArmsHack: 1 # Reduces post-processing misalignment.
|
||||
mergeSprite: 1 # Reduces post-processing misalignment.
|
||||
autoFlush: 1 # Improves post-processing rendering.
|
||||
SLUS-21209:
|
||||
name: "Urban Reign"
|
||||
region: "NTSC-U"
|
||||
@@ -49096,6 +49155,7 @@ SLUS-21242:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
memcardFilters: # Reads Burnout 3 and NFL 06 saves for unlockables.
|
||||
@@ -49445,6 +49505,7 @@ SLUS-21295:
|
||||
trilinearFiltering: 1
|
||||
wildArmsHack: 1 # Reduces post-processing misalignment.
|
||||
mergeSprite: 1 # Reduces post-processing misalignment.
|
||||
autoFlush: 1 # Improves post-processing rendering.
|
||||
memcardFilters: # Game saves use the normal edition serial.
|
||||
- "SLUS-21208"
|
||||
SLUS-21296:
|
||||
@@ -50993,6 +51054,7 @@ SLUS-21596:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLUS-21597:
|
||||
@@ -53259,6 +53321,7 @@ SLUS-29113:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLUS-29116:
|
||||
@@ -53410,6 +53473,7 @@ SLUS-29153:
|
||||
mipmap: 2 # Fixes over sharpening.
|
||||
trilinearFiltering: 1 # Smoothes out mipmapping.
|
||||
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
|
||||
bilinearUpscale: 2 # Smooths out sun glare textures like native.
|
||||
getSkipCount: "GSC_BurnoutGames"
|
||||
beforeDraw: "OI_BurnoutGames"
|
||||
SLUS-29154:
|
||||
@@ -53502,6 +53566,11 @@ SLUS-29174:
|
||||
SLUS-29175:
|
||||
name: "Namco Transmission Demo Disc Vol. 3.2"
|
||||
region: "NTSC-U"
|
||||
SLUS-29177:
|
||||
name: "Guitar Hero [Demo]"
|
||||
region: "NTSC-U"
|
||||
roundModes:
|
||||
vu1RoundMode: 1 # Fixes cut-off numbers and restores missing whitespace inside combo meter.
|
||||
SLUS-29178:
|
||||
name: "TOCA Race Driver 3 [Demo]"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -85,11 +85,13 @@ static double s_last_render_passes = 0;
|
||||
static double s_last_barriers = 0;
|
||||
static double s_last_copies = 0;
|
||||
static double s_last_uploads = 0;
|
||||
static double s_last_readbacks = 0;
|
||||
static u64 s_total_draws = 0;
|
||||
static u64 s_total_render_passes = 0;
|
||||
static u64 s_total_barriers = 0;
|
||||
static u64 s_total_copies = 0;
|
||||
static u64 s_total_uploads = 0;
|
||||
static u64 s_total_readbacks = 0;
|
||||
static u32 s_total_frames = 0;
|
||||
|
||||
bool GSRunner::InitializeConfig()
|
||||
@@ -255,7 +257,7 @@ void Host::OnInputDeviceDisconnected(const std::string_view& identifier)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::SetRelativeMouseMode(bool enabled)
|
||||
void Host::SetMouseMode(bool relative_mode, bool hide_cursor)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -293,6 +295,7 @@ void Host::BeginPresentFrame()
|
||||
update_stat(GSPerfMon::Barriers, s_total_barriers, s_last_barriers);
|
||||
update_stat(GSPerfMon::TextureCopies, s_total_copies, s_last_copies);
|
||||
update_stat(GSPerfMon::TextureUploads, s_total_uploads, s_last_uploads);
|
||||
update_stat(GSPerfMon::Readbacks, s_total_readbacks, s_last_readbacks);
|
||||
s_total_frames++;
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
}
|
||||
@@ -641,6 +644,7 @@ void GSRunner::DumpStats()
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Barriers: {} (avg {})", s_total_barriers, static_cast<u64>(std::ceil(s_total_barriers / static_cast<double>(s_total_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Copies: {} (avg {})", s_total_copies, static_cast<u64>(std::ceil(s_total_copies / static_cast<double>(s_total_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Uploads: {} (avg {})", s_total_uploads, static_cast<u64>(std::ceil(s_total_uploads / static_cast<double>(s_total_frames)))));
|
||||
Console.WriteLn(fmt::format("@HWSTAT@ Readbacks: {} (avg {})", s_total_readbacks, static_cast<u64>(std::ceil(s_total_readbacks / static_cast<double>(s_total_frames)))));
|
||||
Console.WriteLn("============================================");
|
||||
}
|
||||
|
||||
|
||||
@@ -380,6 +380,8 @@ void AutoUpdaterDialog::getChangesComplete(QNetworkReply* reply)
|
||||
changes_html.prepend(tr("<h2>Save State Warning</h2><p>Installing this update will make your save states "
|
||||
"<b>incompatible</b>. Please ensure you have saved your games to a Memory Card "
|
||||
"before installing this update or you will lose progress.</p>"));
|
||||
|
||||
m_update_will_break_save_states = true;
|
||||
}
|
||||
|
||||
if (update_increases_settings_version)
|
||||
@@ -407,6 +409,23 @@ void AutoUpdaterDialog::getChangesComplete(QNetworkReply* reply)
|
||||
|
||||
void AutoUpdaterDialog::downloadUpdateClicked()
|
||||
{
|
||||
if (m_update_will_break_save_states)
|
||||
{
|
||||
QMessageBox msgbox;
|
||||
msgbox.setIcon(QMessageBox::Critical);
|
||||
msgbox.setWindowTitle(tr("Savestate Warning"));
|
||||
msgbox.setText(tr("<h1>WARNING</h1><p style='font-size:12pt;'>Installing this update will make your <b>save states incompatible</b>, <i>be sure to save any progress to your memory cards before proceeding</i>.</p><p>Do you wish to continue?</p>"));
|
||||
msgbox.addButton(QMessageBox::Yes);
|
||||
msgbox.addButton(QMessageBox::No);
|
||||
msgbox.setDefaultButton(QMessageBox::No);
|
||||
// This makes the box wider, for some reason sizing boxes in Qt is hard - Source: The internet.
|
||||
QSpacerItem* horizontalSpacer = new QSpacerItem(500, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||
QGridLayout* layout = (QGridLayout*)msgbox.layout();
|
||||
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
|
||||
if (msgbox.exec() != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
m_display_messages = true;
|
||||
QUrl url(m_download_url);
|
||||
QNetworkRequest request(url);
|
||||
|
||||
@@ -134,6 +134,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Settings/SettingsDialog.ui
|
||||
Settings/USBBindingWidget_DrivingForce.ui
|
||||
Settings/USBBindingWidget_GTForce.ui
|
||||
Settings/USBBindingWidget_GunCon2.ui
|
||||
Debugger/CpuWidget.cpp
|
||||
Debugger/CpuWidget.h
|
||||
Debugger/CpuWidget.ui
|
||||
|
||||
@@ -414,7 +414,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
||||
connect(thread, &EmuThread::onAcquireRenderWindowRequested, this, &MainWindow::acquireRenderWindow, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onReleaseRenderWindowRequested, this, &MainWindow::releaseRenderWindow, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onResizeRenderWindowRequested, this, &MainWindow::displayResizeRequested);
|
||||
connect(thread, &EmuThread::onRelativeMouseModeRequested, this, &MainWindow::relativeMouseModeRequested);
|
||||
connect(thread, &EmuThread::onMouseModeRequested, this, &MainWindow::mouseModeRequested);
|
||||
connect(thread, &EmuThread::onVMStarting, this, &MainWindow::onVMStarting);
|
||||
connect(thread, &EmuThread::onVMStarted, this, &MainWindow::onVMStarted);
|
||||
connect(thread, &EmuThread::onVMPaused, this, &MainWindow::onVMPaused);
|
||||
@@ -887,7 +887,8 @@ bool MainWindow::isRenderingToMain() const
|
||||
|
||||
bool MainWindow::shouldHideMouseCursor() const
|
||||
{
|
||||
return (isRenderingFullscreen() && Host::GetBoolSettingValue("UI", "HideMouseCursor", false)) || m_relative_mouse_mode;
|
||||
return ((isRenderingFullscreen() && Host::GetBoolSettingValue("UI", "HideMouseCursor", false)) ||
|
||||
m_relative_mouse_mode || m_hide_mouse_cursor);
|
||||
}
|
||||
|
||||
bool MainWindow::shouldHideMainWindow() const
|
||||
@@ -2003,12 +2004,13 @@ void MainWindow::displayResizeRequested(qint32 width, qint32 height)
|
||||
QtUtils::ResizePotentiallyFixedSizeWindow(this, width, height + extra_height);
|
||||
}
|
||||
|
||||
void MainWindow::relativeMouseModeRequested(bool enabled)
|
||||
void MainWindow::mouseModeRequested(bool relative_mode, bool hide_cursor)
|
||||
{
|
||||
if (m_relative_mouse_mode == enabled)
|
||||
if (m_relative_mouse_mode == relative_mode && m_hide_mouse_cursor == hide_cursor)
|
||||
return;
|
||||
|
||||
m_relative_mouse_mode = enabled;
|
||||
m_relative_mouse_mode = relative_mode;
|
||||
m_hide_mouse_cursor = hide_cursor;
|
||||
if (m_display_widget && !s_vm_paused)
|
||||
updateDisplayWidgetCursor();
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ private Q_SLOTS:
|
||||
|
||||
std::optional<WindowInfo> acquireRenderWindow(bool recreate_window, bool fullscreen, bool render_to_main, bool surfaceless);
|
||||
void displayResizeRequested(qint32 width, qint32 height);
|
||||
void relativeMouseModeRequested(bool enabled);
|
||||
void mouseModeRequested(bool relative_mode, bool hide_cursor);
|
||||
void releaseRenderWindow();
|
||||
void focusDisplayWidget();
|
||||
|
||||
@@ -293,6 +293,7 @@ private:
|
||||
|
||||
bool m_display_created = false;
|
||||
bool m_relative_mouse_mode = false;
|
||||
bool m_hide_mouse_cursor = false;
|
||||
bool m_was_paused_on_surface_loss = false;
|
||||
bool m_was_disc_change_request = false;
|
||||
bool m_is_closing = false;
|
||||
|
||||
@@ -184,6 +184,10 @@
|
||||
<property name="title">
|
||||
<string>Input Recording</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="keyboard-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<addaction name="actionInputRecNew"/>
|
||||
<addaction name="actionInputRecPlay"/>
|
||||
<addaction name="actionInputRecStop"/>
|
||||
@@ -863,6 +867,10 @@
|
||||
<property name="text">
|
||||
<string>Toggle Software Rendering</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="brush-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDebugger">
|
||||
<property name="icon">
|
||||
@@ -877,6 +885,10 @@
|
||||
<property name="text">
|
||||
<string>Reload Cheats/Patches</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="refresh-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEnableSystemConsole">
|
||||
<property name="checkable">
|
||||
@@ -914,6 +926,10 @@
|
||||
<property name="text">
|
||||
<string>Save Single Frame GS Dump</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="save-3-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInputRecNew">
|
||||
<property name="enabled">
|
||||
|
||||
@@ -1468,9 +1468,9 @@ void Host::OnInputDeviceDisconnected(const std::string_view& identifier)
|
||||
emit g_emu_thread->onInputDeviceDisconnected(identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size()));
|
||||
}
|
||||
|
||||
void Host::SetRelativeMouseMode(bool enabled)
|
||||
void Host::SetMouseMode(bool relative_mode, bool hide_cursor)
|
||||
{
|
||||
emit g_emu_thread->onRelativeMouseModeRequested(enabled);
|
||||
emit g_emu_thread->onMouseModeRequested(relative_mode, hide_cursor);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -119,7 +119,7 @@ Q_SIGNALS:
|
||||
std::optional<WindowInfo> onAcquireRenderWindowRequested(bool recreate_window, bool fullscreen, bool render_to_main, bool surfaceless);
|
||||
void onResizeRenderWindowRequested(qint32 width, qint32 height);
|
||||
void onReleaseRenderWindowRequested();
|
||||
void onRelativeMouseModeRequested(bool enabled);
|
||||
void onMouseModeRequested(bool relative_mode, bool hide_cursor);
|
||||
|
||||
/// Called when the VM is starting initialization, but has not been completed yet.
|
||||
void onVMStarting();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/SIO/Pad/PadConfig.h"
|
||||
#include "pcsx2/SIO/Pad/Pad.h"
|
||||
|
||||
#include "Settings/ControllerBindingWidgets.h"
|
||||
#include "Settings/ControllerSettingsDialog.h"
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include "ui_USBBindingWidget_DrivingForce.h"
|
||||
#include "ui_USBBindingWidget_GTForce.h"
|
||||
#include "ui_USBBindingWidget_GunCon2.h"
|
||||
|
||||
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
|
||||
: QWidget(parent)
|
||||
@@ -52,7 +53,7 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett
|
||||
onTypeChanged();
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
m_dialog->getProfileSettingsInterface(), m_ui.controllerType, m_config_section, "Type", g_PadConfig.GetDefaultPadType(port));
|
||||
m_dialog->getProfileSettingsInterface(), m_ui.controllerType, m_config_section, "Type", Pad::GetDefaultPadType(port));
|
||||
|
||||
connect(m_ui.controllerType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ControllerBindingWidget::onTypeChanged);
|
||||
connect(m_ui.bindings, &QPushButton::clicked, this, &ControllerBindingWidget::onBindingsClicked);
|
||||
@@ -71,14 +72,14 @@ QIcon ControllerBindingWidget::getIcon() const
|
||||
|
||||
void ControllerBindingWidget::populateControllerTypes()
|
||||
{
|
||||
for (const auto& [name, display_name] : g_PadConfig.GetControllerTypeNames())
|
||||
m_ui.controllerType->addItem(qApp->translate("Pad", display_name), QString::fromStdString(name));
|
||||
for (const auto& [name, display_name] : Pad::GetControllerTypeNames())
|
||||
m_ui.controllerType->addItem(QString::fromUtf8(display_name), QString::fromUtf8(name));
|
||||
}
|
||||
|
||||
void ControllerBindingWidget::onTypeChanged()
|
||||
{
|
||||
const bool is_initializing = (m_ui.stackedWidget->count() == 0);
|
||||
m_controller_type = m_dialog->getStringValue(m_config_section.c_str(), "Type", g_PadConfig.GetDefaultPadType(m_port_number));
|
||||
m_controller_type = m_dialog->getStringValue(m_config_section.c_str(), "Type", Pad::GetDefaultPadType(m_port_number));
|
||||
|
||||
if (m_bindings_widget)
|
||||
{
|
||||
@@ -99,9 +100,9 @@ void ControllerBindingWidget::onTypeChanged()
|
||||
m_macros_widget = nullptr;
|
||||
}
|
||||
|
||||
const PadConfig::ControllerInfo* cinfo = g_PadConfig.GetControllerInfo(m_controller_type);
|
||||
const bool has_settings = (cinfo && cinfo->num_settings > 0);
|
||||
const bool has_macros = (cinfo && cinfo->num_bindings > 0);
|
||||
const Pad::ControllerInfo* cinfo = Pad::GetControllerInfo(m_controller_type);
|
||||
const bool has_settings = (cinfo && !cinfo->settings.empty());
|
||||
const bool has_macros = (cinfo && !cinfo->bindings.empty());
|
||||
m_ui.settings->setEnabled(has_settings);
|
||||
m_ui.macros->setEnabled(has_macros);
|
||||
|
||||
@@ -123,9 +124,8 @@ void ControllerBindingWidget::onTypeChanged()
|
||||
|
||||
if (has_settings)
|
||||
{
|
||||
const std::span<const SettingInfo> settings(cinfo->settings, cinfo->num_settings);
|
||||
m_settings_widget = new ControllerCustomSettingsWidget(
|
||||
settings, m_config_section, std::string(), "Pad", getDialog(), m_ui.stackedWidget);
|
||||
cinfo->settings, m_config_section, std::string(), "Pad", getDialog(), m_ui.stackedWidget);
|
||||
m_ui.stackedWidget->addWidget(m_settings_widget);
|
||||
}
|
||||
|
||||
@@ -218,13 +218,13 @@ void ControllerBindingWidget::onClearBindingsClicked()
|
||||
{
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
g_PadConfig.ClearPortBindings(*Host::Internal::GetBaseSettingsLayer(), m_port_number);
|
||||
Pad::ClearPortBindings(*Host::Internal::GetBaseSettingsLayer(), m_port_number);
|
||||
}
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_PadConfig.ClearPortBindings(*m_dialog->getProfileSettingsInterface(), m_port_number);
|
||||
Pad::ClearPortBindings(*m_dialog->getProfileSettingsInterface(), m_port_number);
|
||||
m_dialog->getProfileSettingsInterface()->Save();
|
||||
}
|
||||
|
||||
@@ -248,14 +248,14 @@ void ControllerBindingWidget::doDeviceAutomaticBinding(const QString& device)
|
||||
{
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
result = g_PadConfig.MapController(*Host::Internal::GetBaseSettingsLayer(), m_port_number, mapping);
|
||||
result = Pad::MapController(*Host::Internal::GetBaseSettingsLayer(), m_port_number, mapping);
|
||||
}
|
||||
if (result)
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = g_PadConfig.MapController(*m_dialog->getProfileSettingsInterface(), m_port_number, mapping);
|
||||
result = Pad::MapController(*m_dialog->getProfileSettingsInterface(), m_port_number, mapping);
|
||||
if (result)
|
||||
{
|
||||
m_dialog->getProfileSettingsInterface()->Save();
|
||||
@@ -320,7 +320,7 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare
|
||||
|
||||
ControllerSettingsDialog* dialog = m_bwidget->getDialog();
|
||||
const std::string& section = m_bwidget->getConfigSection();
|
||||
const PadConfig::ControllerInfo* cinfo = g_PadConfig.GetControllerInfo(m_bwidget->getControllerType());
|
||||
const Pad::ControllerInfo* cinfo = Pad::GetControllerInfo(m_bwidget->getControllerType());
|
||||
if (!cinfo)
|
||||
{
|
||||
// Shouldn't ever happen.
|
||||
@@ -333,20 +333,19 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare
|
||||
|
||||
for (const std::string_view& button : buttons_split)
|
||||
{
|
||||
for (u32 i = 0; i < cinfo->num_bindings; i++)
|
||||
for (const InputBindingInfo& bi : cinfo->bindings)
|
||||
{
|
||||
if (button == cinfo->bindings[i].name)
|
||||
if (button == bi.name)
|
||||
{
|
||||
m_binds.push_back(&cinfo->bindings[i]);
|
||||
m_binds.push_back(&bi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// populate list view
|
||||
for (u32 i = 0; i < cinfo->num_bindings; i++)
|
||||
for (const InputBindingInfo& bi : cinfo->bindings)
|
||||
{
|
||||
const InputBindingInfo& bi = cinfo->bindings[i];
|
||||
if (bi.bind_type == InputBindingInfo::Type::Motor)
|
||||
continue;
|
||||
|
||||
@@ -358,8 +357,12 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||
dialog->getProfileSettingsInterface(), m_ui.pressure, section, fmt::format("Macro{}Pressure", index + 1u), 100.0f, 1.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||
dialog->getProfileSettingsInterface(), m_ui.deadzone, section, fmt::format("Macro{}Deadzone", index + 1u), 100.0f, 0.0f);
|
||||
connect(m_ui.pressure, &QSlider::valueChanged, this, &ControllerMacroEditWidget::onPressureChanged);
|
||||
connect(m_ui.deadzone, &QSlider::valueChanged, this, &ControllerMacroEditWidget::onDeadzoneChanged);
|
||||
onPressureChanged();
|
||||
onDeadzoneChanged();
|
||||
|
||||
m_frequency = dialog->getIntValue(section.c_str(), fmt::format("Macro{}Frequency", index + 1u).c_str(), 0);
|
||||
updateFrequencyText();
|
||||
@@ -392,6 +395,11 @@ void ControllerMacroEditWidget::onPressureChanged()
|
||||
m_ui.pressureValue->setText(tr("%1%").arg(m_ui.pressure->value()));
|
||||
}
|
||||
|
||||
void ControllerMacroEditWidget::onDeadzoneChanged()
|
||||
{
|
||||
m_ui.deadzoneValue->setText(tr("%1%").arg(m_ui.deadzone->value()));
|
||||
}
|
||||
|
||||
void ControllerMacroEditWidget::onSetFrequencyClicked()
|
||||
{
|
||||
bool okay;
|
||||
@@ -431,12 +439,12 @@ void ControllerMacroEditWidget::updateFrequencyText()
|
||||
void ControllerMacroEditWidget::updateBinds()
|
||||
{
|
||||
ControllerSettingsDialog* dialog = m_bwidget->getDialog();
|
||||
const PadConfig::ControllerInfo* cinfo = g_PadConfig.GetControllerInfo(m_bwidget->getControllerType());
|
||||
const Pad::ControllerInfo* cinfo = Pad::GetControllerInfo(m_bwidget->getControllerType());
|
||||
if (!cinfo)
|
||||
return;
|
||||
|
||||
std::vector<const InputBindingInfo*> new_binds;
|
||||
for (u32 i = 0, bind_index = 0; i < cinfo->num_bindings; i++)
|
||||
for (u32 i = 0, bind_index = 0; i < static_cast<u32>(cinfo->bindings.size()); i++)
|
||||
{
|
||||
const InputBindingInfo& bi = cinfo->bindings[i];
|
||||
if (bi.bind_type == InputBindingInfo::Type::Motor)
|
||||
@@ -801,16 +809,15 @@ QIcon ControllerBindingWidget_Base::getIcon() const
|
||||
|
||||
void ControllerBindingWidget_Base::initBindingWidgets()
|
||||
{
|
||||
const PadConfig::ControllerInfo* cinfo = g_PadConfig.GetControllerInfo(getControllerType());
|
||||
const Pad::ControllerInfo* cinfo = Pad::GetControllerInfo(getControllerType());
|
||||
if (!cinfo)
|
||||
return;
|
||||
|
||||
const std::string& config_section = getConfigSection();
|
||||
SettingsInterface* sif = getDialog()->getProfileSettingsInterface();
|
||||
|
||||
for (u32 i = 0; i < cinfo->num_bindings; i++)
|
||||
for (const InputBindingInfo& bi : cinfo->bindings)
|
||||
{
|
||||
const InputBindingInfo& bi = cinfo->bindings[i];
|
||||
if (bi.bind_type == InputBindingInfo::Type::Axis || bi.bind_type == InputBindingInfo::Type::HalfAxis ||
|
||||
bi.bind_type == InputBindingInfo::Type::Button || bi.bind_type == InputBindingInfo::Type::Pointer ||
|
||||
bi.bind_type == InputBindingInfo::Type::Device)
|
||||
@@ -1269,6 +1276,11 @@ USBBindingWidget* USBBindingWidget::createInstance(
|
||||
has_template = true;
|
||||
}
|
||||
}
|
||||
else if (type == "guncon2")
|
||||
{
|
||||
Ui::USBBindingWidget_GunCon2().setupUi(widget);
|
||||
has_template = true;
|
||||
}
|
||||
|
||||
if (has_template)
|
||||
widget->bindWidgets(bindings);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pcsx2/SIO/Pad/PadMacros.h"
|
||||
#include "pcsx2/SIO/Pad/PadTypes.h"
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
void updateListItem(u32 index);
|
||||
|
||||
private:
|
||||
static constexpr u32 NUM_MACROS = PadMacros::NUM_MACRO_BUTTONS_PER_CONTROLLER;
|
||||
static constexpr u32 NUM_MACROS = Pad::NUM_MACRO_BUTTONS_PER_CONTROLLER;
|
||||
|
||||
void createWidgets(ControllerBindingWidget* parent);
|
||||
|
||||
@@ -115,6 +115,7 @@ public:
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPressureChanged();
|
||||
void onDeadzoneChanged();
|
||||
void onSetFrequencyClicked();
|
||||
void updateBinds();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>691</width>
|
||||
<height>547</height>
|
||||
<height>433</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -83,6 +83,9 @@
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -123,6 +126,46 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="deadzoneLayout" stretch="0,1,0">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Deadzone:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="deadzone">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="deadzoneValue">
|
||||
<property name="text">
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "Settings/HotkeySettingsWidget.h"
|
||||
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "pcsx2/SIO/Pad/PadConfig.h"
|
||||
#include "pcsx2/SIO/Pad/Pad.h"
|
||||
#include "pcsx2/SIO/Sio.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
|
||||
@@ -130,7 +130,7 @@ void ControllerSettingsDialog::onNewProfileClicked()
|
||||
{
|
||||
// from global
|
||||
auto lock = Host::GetSettingsLock();
|
||||
g_PadConfig.CopyConfiguration(&temp_si, *Host::Internal::GetBaseSettingsLayer(), true, true, false);
|
||||
Pad::CopyConfiguration(&temp_si, *Host::Internal::GetBaseSettingsLayer(), true, true, false);
|
||||
USB::CopyConfiguration(&temp_si, *Host::Internal::GetBaseSettingsLayer(), true, true);
|
||||
}
|
||||
else
|
||||
@@ -138,7 +138,7 @@ void ControllerSettingsDialog::onNewProfileClicked()
|
||||
// from profile
|
||||
const bool copy_hotkey_bindings = m_profile_interface->GetBoolValue("Pad", "UseProfileHotkeyBindings", false);
|
||||
temp_si.SetBoolValue("Pad", "UseProfileHotkeyBindings", copy_hotkey_bindings);
|
||||
g_PadConfig.CopyConfiguration(&temp_si, *m_profile_interface, true, true, copy_hotkey_bindings);
|
||||
Pad::CopyConfiguration(&temp_si, *m_profile_interface, true, true, copy_hotkey_bindings);
|
||||
USB::CopyConfiguration(&temp_si, *m_profile_interface, true, true);
|
||||
}
|
||||
}
|
||||
@@ -167,7 +167,7 @@ void ControllerSettingsDialog::onLoadProfileClicked()
|
||||
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
g_PadConfig.CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true, false);
|
||||
Pad::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true, false);
|
||||
USB::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true);
|
||||
}
|
||||
Host::CommitBaseSettingChanges();
|
||||
@@ -403,8 +403,8 @@ void ControllerSettingsDialog::createWidgets()
|
||||
m_port_bindings[global_slot] = new ControllerBindingWidget(m_ui.settingsContainer, this, global_slot);
|
||||
m_ui.settingsContainer->addWidget(m_port_bindings[global_slot]);
|
||||
|
||||
const PadConfig::ControllerInfo* ci = g_PadConfig.GetControllerInfo(m_port_bindings[global_slot]->getControllerType());
|
||||
const QString display_name(ci ? qApp->translate("Pad", ci->display_name) : QStringLiteral("Unknown"));
|
||||
const Pad::ControllerInfo* ci = Pad::GetControllerInfo(m_port_bindings[global_slot]->getControllerType());
|
||||
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.
|
||||
@@ -459,8 +459,8 @@ void ControllerSettingsDialog::updateListDescription(u32 global_slot, Controller
|
||||
const auto [port, slot] = sioConvertPadToPortAndSlot(global_slot);
|
||||
const bool mtap_enabled = getBoolValue("Pad", (port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
|
||||
const PadConfig::ControllerInfo* ci = g_PadConfig.GetControllerInfo(widget->getControllerType());
|
||||
const QString display_name(ci ? qApp->translate("Pad", ci->display_name) : QStringLiteral("Unknown"));
|
||||
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)) :
|
||||
@@ -492,7 +492,7 @@ void ControllerSettingsDialog::updateListDescription(u32 port, USBDeviceWidget*
|
||||
|
||||
void ControllerSettingsDialog::refreshProfileList()
|
||||
{
|
||||
const std::vector<std::string> names(g_PadConfig.GetInputProfileNames());
|
||||
const std::vector<std::string> names = Pad::GetInputProfileNames();
|
||||
|
||||
QSignalBlocker sb(m_ui.currentProfile);
|
||||
m_ui.currentProfile->clear();
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "pcsx2/SIO/Pad/PadConfig.h"
|
||||
#include "pcsx2/SIO/Pad/Pad.h"
|
||||
#include "GameSummaryWidget.h"
|
||||
#include "SettingsDialog.h"
|
||||
#include "MainWindow.h"
|
||||
@@ -69,7 +69,7 @@ GameSummaryWidget::~GameSummaryWidget() = default;
|
||||
|
||||
void GameSummaryWidget::populateInputProfiles()
|
||||
{
|
||||
for (const std::string& name : g_PadConfig.GetInputProfileNames())
|
||||
for (const std::string& name : Pad::GetInputProfileNames())
|
||||
m_ui.inputProfile->addItem(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
|
||||
@@ -218,12 +218,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfPixelOffset, "EmuCore/GS", "UserHacks_HalfPixelOffset", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.roundSprite, "EmuCore/GS", "UserHacks_round_sprite_offset", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.bilinearHack, "EmuCore/GS", "UserHacks_BilinearHack", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureOffsetX, "EmuCore/GS", "UserHacks_TCOffsetX", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureOffsetY, "EmuCore/GS", "UserHacks_TCOffsetY", 0);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.alignSprite, "EmuCore/GS", "UserHacks_align_sprite_X", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.mergeSprite, "EmuCore/GS", "UserHacks_merge_pp_sprite", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.wildHack, "EmuCore/GS", "UserHacks_WildHack", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.bilinearHack, "EmuCore/GS", "UserHacks_BilinearHack", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.nativePaletteDraw, "EmuCore/GS", "UserHacks_NativePaletteDraw", false);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Texture Replacements
|
||||
|
||||
@@ -1168,14 +1168,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="textureOffsetLabel">
|
||||
<property name="text">
|
||||
<string>Texture Offsets:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="textureOffsetLayout" stretch="0,1,0,1">
|
||||
<item>
|
||||
<widget class="QLabel" name="textureOffsetXLabel">
|
||||
@@ -1207,7 +1207,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="alignSprite">
|
||||
@@ -1216,20 +1216,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="bilinearHack">
|
||||
<property name="text">
|
||||
<string>Bilinear Dirty Upscale</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="mergeSprite">
|
||||
<property name="text">
|
||||
<string>Merge Sprite</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="nativePaletteDraw">
|
||||
<property name="text">
|
||||
@@ -1244,8 +1230,41 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="mergeSprite">
|
||||
<property name="text">
|
||||
<string>Merge Sprite</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Bilinear Dirty Upscale:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="bilinearHack">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Automatic (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Bilinear</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Nearest</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
|
||||
779
pcsx2-qt/Settings/USBBindingWidget_GunCon2.ui
Normal file
@@ -0,0 +1,779 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>USBBindingWidget_GunCon2</class>
|
||||
<widget class="QWidget" name="USBBindingWidget_GunCon2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1000</width>
|
||||
<height>400</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1000</width>
|
||||
<height>400</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_16">
|
||||
<item row="2" column="2" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_16">
|
||||
<property name="title">
|
||||
<string>Buttons</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_10">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_19">
|
||||
<property name="title">
|
||||
<string>A</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_19">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="A">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QGroupBox" name="groupBox_20">
|
||||
<property name="title">
|
||||
<string>C</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_20">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="C">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_23">
|
||||
<property name="title">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_23">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Start">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_35">
|
||||
<property name="title">
|
||||
<string>Select</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_35">
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Select">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_18">
|
||||
<property name="title">
|
||||
<string>B</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_18">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="B">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>D-Pad</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Down</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Down">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Left">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Up">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Right">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QGroupBox" name="groupBox_15">
|
||||
<property name="title">
|
||||
<string>Pointer Setup</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><p>By default, GunCon2 will use the mouse pointer. To use the mouse, you <strong>do not</strong> need to configure any bindings apart from the trigger and buttons.</p>
|
||||
|
||||
<p>If you want to use a controller, or lightgun which simulates a controller instead of a mouse, then you should bind it to Relative Aiming. Otherwise, Relative Aiming should be <strong>left unbound</strong>.</p></string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" rowspan="3">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="3">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_10">
|
||||
<property name="title">
|
||||
<string extracomment="Try to use Sony's official terminology for this. A good place to start would be in the console or the DualShock 2's manual. If this element was officially translated to your language by Sony in later DualShocks, you may use that term.">Relative Aiming</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_11">
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_11">
|
||||
<property name="title">
|
||||
<string>Down</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_12">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeDown">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_12">
|
||||
<property name="title">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_13">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeLeft">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_13">
|
||||
<property name="title">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_14">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeUp">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_14">
|
||||
<property name="title">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_15">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="RelativeRight">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Trigger</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_9">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_7">
|
||||
<property name="title">
|
||||
<string>Trigger</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="Trigger">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QGroupBox" name="groupBox_8">
|
||||
<property name="title">
|
||||
<string>Shoot Offscreen</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="InputBindingWidget" name="ShootOffscreen">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_9">
|
||||
<property name="title">
|
||||
<string>Calibration Shot</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="0" column="1">
|
||||
<widget class="InputBindingWidget" name="Recalibrate">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>125</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Calibration shot is required to pass the setup screen in some games.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="5">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>InputBindingWidget</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>Settings/InputBindingWidget.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "pcsx2/SIO/Pad/PadConfig.h"
|
||||
#include "pcsx2/SIO/Pad/Pad.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
@@ -414,10 +414,10 @@ void SetupWizardDialog::setupControllerPage()
|
||||
const std::string section = fmt::format("Pad{}", port + 1);
|
||||
const PadWidgets& w = pad_widgets[port];
|
||||
|
||||
for (const auto& [name, display_name] : g_PadConfig.GetControllerTypeNames())
|
||||
w.type_combo->addItem(qApp->translate("Pad", display_name), QString::fromStdString(name));
|
||||
for (const auto& [name, display_name] : Pad::GetControllerTypeNames())
|
||||
w.type_combo->addItem(QString::fromUtf8(display_name), QString::fromUtf8(name));
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
nullptr, w.type_combo, section, "Type", g_PadConfig.GetDefaultPadType(port));
|
||||
nullptr, w.type_combo, section, "Type", Pad::GetDefaultPadType(port));
|
||||
|
||||
w.mapping_result->setText((port == 0) ? tr("Default (Keyboard)") : tr("Default (None)"));
|
||||
|
||||
@@ -473,7 +473,7 @@ void SetupWizardDialog::doDeviceAutomaticBinding(u32 port, QLabel* update_label,
|
||||
bool result;
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
result = g_PadConfig.MapController(*Host::Internal::GetBaseSettingsLayer(), port, mapping);
|
||||
result = Pad::MapController(*Host::Internal::GetBaseSettingsLayer(), port, mapping);
|
||||
}
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
@@ -374,6 +374,9 @@
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtUi Include="Settings\USBBindingWidget_GunCon2.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="SetupWizardDialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
@@ -395,8 +398,12 @@
|
||||
<QtUi Include="Settings\GamePatchSettingsWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<None Include="Settings\USBBindingWidget_DrivingForce.ui" />
|
||||
<None Include="Settings\USBBindingWidget_GTForce.ui" />
|
||||
<QtUi Include="Settings\USBBindingWidget_DrivingForce.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\USBBindingWidget_GTForce.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\USBDeviceWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
|
||||
@@ -624,17 +624,20 @@
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="SetupWizardDialog.ui" />
|
||||
<QtUi Include="Settings\USBBindingWidget_DrivingForce.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\USBBindingWidget_GTForce.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\USBBindingWidget_GunCon2.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Settings\FolderSettingsWidget.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</None>
|
||||
<None Include="Settings\USBBindingWidget_GTForce.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</None>
|
||||
<None Include="Settings\USBBindingWidget_DrivingForce.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtTs Include="Translations\pcsx2-qt_en.ts">
|
||||
|
||||
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="cheats" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:none;}.cls-2{fill-rule:evenodd;}</style></defs><g id="tela"><g><path class="cls-1" d="M0,0H24V24H0V0Z"/><path d="M2,4c0-.5,.5-1,1-1H21c.5,0,1,.4,1,1v14c0,.5-.5,1-1,1H3c-.5,0-1-.5-1-1h0V4Zm2,1v12H20V5H4Zm1,15h14v2H5v-2Z"/></g></g><g id="by_maxihplay"><path class="cls-2" d="M13.4,6.7c-1.1-1.2-2.6-.9-4,0-1.4-.9-2.9-1.1-4,0-.3,.4-.4,.9-.5,1.4-.2,1.1,.3,2.3,1.1,3.1l3.4,3.5,3.4-3.5c.8-.8,1.3-1.9,1.1-3.1,0-.5-.1-1-.5-1.4Z"/><path d="M17.1,12.2c.6,0,1,.2,1.5,.6,.4,.4,.6,.9,.6,1.5s-.2,1.1-.6,1.5c-.4,.4-.9,.6-1.5,.6s-1.3-.4-1.8-1c-.6,.7-1.2,1-1.8,1s-1.1-.2-1.4-.6c-.4-.4-.6-.9-.6-1.5s.2-1.1,.6-1.5c.4-.4,.9-.6,1.4-.6,.6,0,1.3,.4,1.8,1.1,.6-.8,1.2-1.1,1.8-1.1Zm-3.7,3c.4,0,.8-.3,1.2-.9-.4-.6-.8-.9-1.2-.9-.2,0-.3,0-.5,.1s-.3,.2-.3,.3-.1,.3-.1,.4c0,.2,.1,.5,.3,.6,.1,.3,.3,.4,.6,.4h0Zm3.9,0h.3c.1,0,.2-.1,.3-.1s.1-.1,.1-.2,.1-.2,.1-.3v-.3c0-.2-.1-.5-.3-.6-.2-.2-.4-.3-.7-.3-.4,0-.8,.3-1.2,.9,.6,.6,1,.9,1.4,.9h0Z"/></g></svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="cheats" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:none;}</style></defs><path class="cls-1" d="M0,0H24V24H0V0Z"/><g id="by_maxihplay"><path d="M14.38,5.18c.73,0,1.32,.26,1.87,.82,2.15,3.05-.83,6.31-5.25,10.57-.43,.41-.85,.82-1.25,1.22l-1.88-1.93-2.39-2.46c-.39-.4-.78-.8-1.18-1.13l.04-.04c-1.85-1.78-1.93-3.85-1.39-5.18,.22-.55,.92-1.83,2.53-1.83,.9,0,1.94,.41,3,1.17l1.22,.88,1.26-.81c1.29-.83,2.48-1.27,3.43-1.27m0-2.2c-1.49,0-3.08,.63-4.62,1.62-1.55-1.12-3.01-1.59-4.29-1.59-4.76,0-7.07,6.54-2.67,10.8,0,0,6.96,7.16,6.96,7.16,3.41-4.03,12.75-10.19,8.18-16.37-1.05-1.14-2.27-1.62-3.57-1.62h0Z"/><path d="M20.93,16.35c.72,0,1.34,.27,1.85,.8,.51,.53,.77,1.17,.77,1.92s-.26,1.39-.77,1.92-1.13,.8-1.85,.8c-.84,0-1.61-.45-2.34-1.34-.72,.9-1.5,1.34-2.34,1.34-.72,0-1.34-.27-1.85-.8s-.77-1.17-.77-1.92,.26-1.39,.77-1.92c.51-.53,1.13-.8,1.85-.8,.84,0,1.61,.45,2.34,1.34,.72-.9,1.5-1.34,2.34-1.34Zm-4.67,3.81c.48,0,.97-.36,1.45-1.09-.48-.73-.97-1.09-1.45-1.09-.21,0-.39,.05-.56,.14s-.31,.23-.41,.4-.15,.35-.15,.54c0,.3,.11,.55,.33,.77,.22,.22,.49,.32,.8,.32Zm4.67,0c.12,0,.24-.02,.36-.05s.22-.09,.31-.15,.18-.15,.25-.24,.13-.19,.16-.31,.05-.23,.05-.34c0-.3-.11-.55-.33-.77-.22-.22-.49-.32-.8-.32-.48,0-.97,.36-1.45,1.09,.48,.73,.97,1.09,1.45,1.09Z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -1,81 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Agrupar_1_copiar"
|
||||
data-name="Agrupar 1 copiar"
|
||||
width="384"
|
||||
height="384"
|
||||
viewBox="0 0 384 384"
|
||||
version="1.1"
|
||||
sodipodi:docname="floppy-in-line-black.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.5733333"
|
||||
inkscape:cx="118.53814"
|
||||
inkscape:cy="137.92373"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="956"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="42"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Agrupar_1_copiar" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">
|
||||
.cls-1, .cls-2, .cls-3 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
.cls-1 {
|
||||
stroke-width: 23px;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
stroke-width: 25px;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
stroke-width: 33px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
id="Forma_1"
|
||||
data-name="Forma 1"
|
||||
class="cls-1"
|
||||
d="m 325.91068,295.77571 c 0,0 0.24169,10.49815 0.73613,22.57934 0.49445,12.08118 -9.96947,12.17987 -9.96947,12.17987 0,0 -243.07578,-1.34336 -251.339361,-1.10772 -8.263582,0.23564 -8.86175,-9.96443 -8.86175,-9.96443 V 74.766689 c 0,0 1.492399,-7.461996 8.86175,-8.86175 7.36935,-1.399754 214.801761,0 214.801761,0 l 46.50304,46.503041 0.27492,86.6941"
|
||||
style="stroke:#000000;stroke-width:23;stroke-dasharray:none" />
|
||||
<path
|
||||
id="Forma_2"
|
||||
data-name="Forma 2"
|
||||
class="cls-1"
|
||||
d="m 127.34606,65.908967 1.10771,88.578223 c 0,0 -1.75825,2.69881 5.5386,3.32316 7.29684,0.62435 121.79468,1.10772 121.79468,1.10772 a 5.4681025,5.4681025 0 0 0 3.32316,-5.53859 c -0.0866,-4.38556 0,-88.578232 0,-88.578232"
|
||||
style="stroke:#000000;stroke-width:23;stroke-dasharray:none" />
|
||||
<path
|
||||
id="Forma_5"
|
||||
data-name="Forma 5"
|
||||
class="cls-2"
|
||||
d="m 224.20196,202.12313 c -0.44409,0.33533 -53.03656,46.50304 -53.03656,46.50304 l 51.02253,47.14954"
|
||||
style="stroke:#000000;stroke-width:25;stroke-dasharray:none" />
|
||||
<path
|
||||
id="Forma_6"
|
||||
data-name="Forma 6"
|
||||
class="cls-3"
|
||||
d="M 175.86514,248.44591 339.0019,247.43889"
|
||||
style="stroke:#000000;stroke-width:33;stroke-dasharray:none" />
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="PCSX2_-_load" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 384"><defs><style>.cls-1{stroke-width:28px;}.cls-1,.cls-2{fill:none;stroke:#000;}.cls-2{stroke-width:29px;}</style></defs><g id="By_maxihplay"><path id="Forma_5" class="cls-1" d="M217.39,192.85c-.45,.33-52.68,43.98-52.68,43.98l52.04,47.7"/><path id="Forma_6" class="cls-1" d="M173.41,238.01l161.32-.73"/><path id="Forma_2" class="cls-1" d="M114.53,59.5l1.11,89.07s-1.77,2.71,5.57,3.34c7.33,.63,122.47,1.11,122.47,1.11,2.21-.93,3.56-3.18,3.34-5.57-.09-4.41,0-89.07,0-89.07"/><path id="Forma_1" class="cls-2" d="M322.31,290.47s-.12,21.8-.1,22.87c.31,13.33-11.31,12.25-11.31,12.25,0,0-244.42-1.35-252.73-1.11s-8.91-10.02-8.91-10.02V68.41s1.5-7.5,8.91-8.91,215.99,0,215.99,0l48.05,46.76,.27,72.95"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 818 B |
@@ -1,81 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Agrupar_1"
|
||||
data-name="Agrupar 1"
|
||||
width="384"
|
||||
height="384"
|
||||
viewBox="0 0 384 384"
|
||||
version="1.1"
|
||||
sodipodi:docname="floppy-out-line-black.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.2683333"
|
||||
inkscape:cx="158.08148"
|
||||
inkscape:cy="207.35874"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="956"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="42"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Agrupar_1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">
|
||||
.cls-1, .cls-2, .cls-3 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
.cls-1 {
|
||||
stroke-width: 23px;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
stroke-width: 25px;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
stroke-width: 33px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
id="Forma_1"
|
||||
data-name="Forma 1"
|
||||
class="cls-1"
|
||||
d="m 325.86348,300.4432 c 0,0 0.24183,10.50408 0.73655,22.59208 0.49472,12.08801 -9.9751,12.18675 -9.9751,12.18675 0,0 -243.213007,-1.34412 -251.481254,-1.10834 -8.268247,0.23577 -8.866752,-9.97006 -8.866752,-9.97006 V 79.309414 c 0,0 1.493241,-7.466209 8.866752,-8.866753 7.373511,-1.400544 214.923034,0 214.923034,0 l 46.52929,46.529289 0.27507,86.74304"
|
||||
style="stroke:#000000;stroke-width:23;stroke-dasharray:none" />
|
||||
<path
|
||||
id="Forma_2"
|
||||
data-name="Forma 2"
|
||||
class="cls-1"
|
||||
d="m 127.18676,70.446691 1.10835,88.628229 c 0,0 -1.75925,2.70033 5.54172,3.32503 7.30096,0.62471 121.86344,1.10835 121.86344,1.10835 a 5.4711894,5.4711894 0 0 0 3.32503,-5.54172 c -0.0867,-4.38804 0,-88.628233 0,-88.628233"
|
||||
style="stroke:#000000;stroke-width:23;stroke-dasharray:none" />
|
||||
<path
|
||||
id="Forma_5"
|
||||
data-name="Forma 5"
|
||||
class="cls-2"
|
||||
d="m 267.20286,207.74533 c 1.47007,1.13656 53.06651,44.51412 53.06651,44.51412 l -51.05134,47.17617"
|
||||
style="stroke:#000000;stroke-width:25;stroke-dasharray:none" />
|
||||
<path
|
||||
id="Forma_6"
|
||||
data-name="Forma 6"
|
||||
class="cls-3"
|
||||
d="M 315.56697,253.08668 152.33811,252.0791"
|
||||
style="stroke:#000000;stroke-width:33;stroke-dasharray:none" />
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="PCSX2_-_load" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 384"><defs><style>.cls-1{stroke-width:28px;}.cls-1,.cls-2{fill:none;stroke:#000;}.cls-2{stroke-width:29px;}</style></defs><g id="By_maxihplay"><path id="Forma_6" class="cls-1" d="M309.03,236.01l-132.24-.6"/><path id="Forma_5" class="cls-1" d="M261.32,188.75c.45,.33,52.68,43.98,52.68,43.98l-52.04,47.7"/><path id="Forma_2" class="cls-1" d="M114.53,59.5l1.11,89.07s-1.77,2.71,5.57,3.34c7.33,.63,122.47,1.11,122.47,1.11,2.21-.93,3.56-3.18,3.34-5.57-.09-4.41,0-89.07,0-89.07"/><path id="Forma_1" class="cls-2" d="M322.31,290.47s-.12,21.8-.1,22.87c.31,13.33-11.31,12.25-11.31,12.25,0,0-244.42-1.35-252.73-1.11s-8.91-10.02-8.91-10.02V68.41s1.5-7.5,8.91-8.91,215.99,0,215.99,0l48.05,46.76,.27,72.95"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 818 B |
@@ -1 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="cheats" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1,.cls-2{fill:#fff;}.cls-2{fill-rule:evenodd;}.cls-3{fill:none;}</style></defs><g id="tela"><g><path class="cls-3" d="M0,0H24V24H0V0Z"/><path class="cls-1" d="M2,4c0-.5,.5-1,1-1H21c.5,0,1,.4,1,1v14c0,.5-.5,1-1,1H3c-.5,0-1-.5-1-1h0V4Zm2,1v12H20V5H4Zm1,15h14v2H5v-2Z"/></g></g><g id="by_maxihplay"><path class="cls-2" d="M13.4,6.7c-1.1-1.2-2.6-.71-4,.19-1.4-.9-2.9-1.29-4-.19-.3,.4-.4,.9-.5,1.4-.2,1.1,.3,2.3,1.1,3.1l3.4,3.5,3.4-3.5c.8-.8,1.3-1.9,1.1-3.1,0-.5-.1-1-.5-1.4Z"/><path class="cls-1" d="M17.1,12.2c.6,0,1,.2,1.5,.6,.4,.4,.6,.9,.6,1.5s-.2,1.1-.6,1.5c-.4,.4-.9,.6-1.5,.6s-1.3-.4-1.8-1c-.6,.7-1.2,1-1.8,1s-1.1-.2-1.4-.6c-.4-.4-.6-.9-.6-1.5s.2-1.1,.6-1.5c.4-.4,.9-.6,1.4-.6,.6,0,1.3,.4,1.8,1.1,.6-.8,1.2-1.1,1.8-1.1Zm-3.7,3c.4,0,.8-.3,1.2-.9-.4-.6-.8-.9-1.2-.9-.2,0-.3,0-.5,.1s-.3,.2-.3,.3-.1,.3-.1,.4c0,.2,.1,.5,.3,.6,.1,.3,.3,.4,.6,.4h0Zm3.9,0h.3c.1,0,.2-.1,.3-.1s.1-.1,.1-.2,.1-.2,.1-.3v-.3c0-.2-.1-.5-.3-.6-.2-.2-.4-.3-.7-.3-.4,0-.8,.3-1.2,.9,.6,.6,1,.9,1.4,.9h0Z"/></g></svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="cheats" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:none;}</style></defs><path class="cls-2" d="M0,0H24V24H0V0Z"/><g id="by_maxihplay"><path class="cls-1" d="M14.38,5.18c.73,0,1.32,.26,1.87,.82,2.15,3.05-.83,6.31-5.25,10.57-.43,.41-.85,.82-1.25,1.22l-1.88-1.93-2.39-2.46c-.39-.4-.78-.8-1.18-1.13l.04-.04c-1.85-1.78-1.93-3.85-1.39-5.18,.22-.55,.92-1.83,2.53-1.83,.9,0,1.94,.41,3,1.17l1.22,.88,1.26-.81c1.29-.83,2.48-1.27,3.43-1.27m0-2.2c-1.49,0-3.08,.63-4.62,1.62-1.55-1.12-3.01-1.59-4.29-1.59-4.76,0-7.07,6.54-2.67,10.8,0,0,6.96,7.16,6.96,7.16,3.41-4.03,12.75-10.19,8.18-16.37-1.05-1.14-2.27-1.62-3.57-1.62h0Z"/><path class="cls-1" d="M20.93,16.35c.72,0,1.34,.27,1.85,.8,.51,.53,.77,1.17,.77,1.92s-.26,1.39-.77,1.92-1.13,.8-1.85,.8c-.84,0-1.61-.45-2.34-1.34-.72,.9-1.5,1.34-2.34,1.34-.72,0-1.34-.27-1.85-.8s-.77-1.17-.77-1.92,.26-1.39,.77-1.92c.51-.53,1.13-.8,1.85-.8,.84,0,1.61,.45,2.34,1.34,.72-.9,1.5-1.34,2.34-1.34Zm-4.67,3.81c.48,0,.97-.36,1.45-1.09-.48-.73-.97-1.09-1.45-1.09-.21,0-.39,.05-.56,.14s-.31,.23-.41,.4-.15,.35-.15,.54c0,.3,.11,.55,.33,.77,.22,.22,.49,.32,.8,.32Zm4.67,0c.12,0,.24-.02,.36-.05s.22-.09,.31-.15,.18-.15,.25-.24,.13-.19,.16-.31,.05-.23,.05-.34c0-.3-.11-.55-.33-.77-.22-.22-.49-.32-.8-.32-.48,0-.97,.36-1.45,1.09,.48,.73,.97,1.09,1.45,1.09Z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -1,77 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Agrupar_1_copiar"
|
||||
data-name="Agrupar 1 copiar"
|
||||
width="384"
|
||||
height="384"
|
||||
viewBox="0 0 384 384"
|
||||
version="1.1"
|
||||
sodipodi:docname="floppy-in-line.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.5733333"
|
||||
inkscape:cx="135.06356"
|
||||
inkscape:cy="136.65255"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="956"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="42"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Agrupar_1_copiar" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">
|
||||
.cls-1, .cls-2, .cls-3 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
.cls-1 {
|
||||
stroke-width: 23px;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
stroke-width: 25px;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
stroke-width: 33px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
id="Forma_1"
|
||||
data-name="Forma 1"
|
||||
class="cls-1"
|
||||
d="m 325.91068,295.77571 c 0,0 0.24169,10.49815 0.73613,22.57934 0.49445,12.08118 -9.96947,12.17987 -9.96947,12.17987 0,0 -243.07578,-1.34336 -251.339361,-1.10772 -8.263582,0.23564 -8.86175,-9.96443 -8.86175,-9.96443 V 74.766689 c 0,0 1.492399,-7.461996 8.86175,-8.86175 7.36935,-1.399754 214.801761,0 214.801761,0 l 46.50304,46.503041 0.27492,86.6941" />
|
||||
<path
|
||||
id="Forma_2"
|
||||
data-name="Forma 2"
|
||||
class="cls-1"
|
||||
d="m 127.34606,65.908967 1.10771,88.578223 c 0,0 -1.75825,2.69881 5.5386,3.32316 7.29684,0.62435 121.79468,1.10772 121.79468,1.10772 a 5.4681025,5.4681025 0 0 0 3.32316,-5.53859 c -0.0866,-4.38556 0,-88.578232 0,-88.578232" />
|
||||
<path
|
||||
id="Forma_5"
|
||||
data-name="Forma 5"
|
||||
class="cls-2"
|
||||
d="m 224.20196,202.12313 c -0.44409,0.33533 -53.03656,46.50304 -53.03656,46.50304 l 51.02253,47.14954" />
|
||||
<path
|
||||
id="Forma_6"
|
||||
data-name="Forma 6"
|
||||
class="cls-3"
|
||||
d="M 175.86514,248.44591 339.0019,247.43889" />
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="PCSX2_-_Save" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 384"><defs><style>.cls-1{stroke-width:29px;}.cls-1,.cls-2{fill:none;stroke:#fff;}.cls-2{stroke-width:28px;}</style></defs><g id="By_maxihplay"><path id="Forma_5" class="cls-2" d="M217.39,192.85c-.45,.33-52.68,43.98-52.68,43.98l52.04,47.7"/><path id="Forma_6" class="cls-2" d="M173.41,238.01l161.32-.73"/><path id="Forma_2" class="cls-2" d="M114.53,59.5l1.11,89.07s-1.77,2.71,5.57,3.34c7.33,.63,122.47,1.11,122.47,1.11,2.21-.93,3.56-3.18,3.34-5.57-.09-4.41,0-89.07,0-89.07"/><path id="Forma_1" class="cls-1" d="M322.31,290.47s-.12,21.8-.1,22.87c.31,13.33-11.31,12.25-11.31,12.25,0,0-244.42-1.35-252.73-1.11s-8.91-10.02-8.91-10.02V68.41s1.5-7.5,8.91-8.91,215.99,0,215.99,0l48.05,46.76,.27,72.95"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 818 B |
@@ -1,77 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Agrupar_1"
|
||||
data-name="Agrupar 1"
|
||||
width="384"
|
||||
height="384"
|
||||
viewBox="0 0 384 384"
|
||||
version="1.1"
|
||||
sodipodi:docname="floppy-out-line.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview11"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.2683333"
|
||||
inkscape:cx="179.36926"
|
||||
inkscape:cy="207.35874"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="956"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="42"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Agrupar_1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<style
|
||||
id="style2">
|
||||
.cls-1, .cls-2, .cls-3 {
|
||||
fill: none;
|
||||
stroke: #fff;
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
|
||||
.cls-1 {
|
||||
stroke-width: 23px;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
stroke-width: 25px;
|
||||
}
|
||||
|
||||
.cls-3 {
|
||||
stroke-width: 33px;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<path
|
||||
id="Forma_1"
|
||||
data-name="Forma 1"
|
||||
class="cls-1"
|
||||
d="m 325.86348,300.4432 c 0,0 0.24183,10.50408 0.73655,22.59208 0.49472,12.08801 -9.9751,12.18675 -9.9751,12.18675 0,0 -243.213007,-1.34412 -251.481254,-1.10834 -8.268247,0.23577 -8.866752,-9.97006 -8.866752,-9.97006 V 79.309414 c 0,0 1.493241,-7.466209 8.866752,-8.866753 7.373511,-1.400544 214.923034,0 214.923034,0 l 46.52929,46.529289 0.27507,86.74304" />
|
||||
<path
|
||||
id="Forma_2"
|
||||
data-name="Forma 2"
|
||||
class="cls-1"
|
||||
d="m 127.18676,70.446691 1.10835,88.628229 c 0,0 -1.75925,2.70033 5.54172,3.32503 7.30096,0.62471 121.86344,1.10835 121.86344,1.10835 a 5.4711894,5.4711894 0 0 0 3.32503,-5.54172 c -0.0867,-4.38804 0,-88.628233 0,-88.628233" />
|
||||
<path
|
||||
id="Forma_5"
|
||||
data-name="Forma 5"
|
||||
class="cls-2"
|
||||
d="m 267.20286,207.74533 c 1.47007,1.13656 53.06651,44.51412 53.06651,44.51412 l -51.05134,47.17617" />
|
||||
<path
|
||||
id="Forma_6"
|
||||
data-name="Forma 6"
|
||||
class="cls-3"
|
||||
d="M 315.56697,253.08668 152.33811,252.0791" />
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="PCSX2_-_load" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 384"><defs><style>.cls-1{stroke-width:29px;}.cls-1,.cls-2{fill:none;stroke:#fff;}.cls-2{stroke-width:28px;}</style></defs><g id="By_maxihplay"><path id="Forma_5" class="cls-2" d="M265.05,192.85c.45,.33,52.68,43.98,52.68,43.98l-52.04,47.7"/><path id="Forma_6" class="cls-2" d="M309.03,238.01l-132.24-.6"/><path id="Forma_2" class="cls-2" d="M114.53,59.5l1.11,89.07s-1.77,2.71,5.57,3.34c7.33,.63,122.47,1.11,122.47,1.11,2.21-.93,3.56-3.18,3.34-5.57-.09-4.41,0-89.07,0-89.07"/><path id="Forma_1" class="cls-1" d="M322.31,290.47s-.12,21.8-.1,22.87c.31,13.33-11.31,12.25-11.31,12.25,0,0-244.42-1.35-252.73-1.11s-8.91-10.02-8.91-10.02V68.41s1.5-7.5,8.91-8.91,215.99,0,215.99,0l48.05,46.76,.27,72.95"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 818 B |
@@ -24,9 +24,9 @@
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.921875"
|
||||
inkscape:cx="47.728814"
|
||||
inkscape:cy="215.32203"
|
||||
inkscape:zoom="1.3037281"
|
||||
inkscape:cx="-8.0538264"
|
||||
inkscape:cy="358.20352"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="956"
|
||||
inkscape:window-x="0"
|
||||
@@ -46,13 +46,13 @@
|
||||
cy="256.1091"
|
||||
r="231.50449" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:38.6591;stroke-linecap:round;stroke-dasharray:none"
|
||||
d="M 256,93.780771 V 418.43743"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:50;stroke-linecap:round;stroke-dasharray:none"
|
||||
d="m 256,132.18075 v 247.8567"
|
||||
id="path1039"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:37.7963;stroke-linecap:round;stroke-dasharray:none"
|
||||
d="M 87.841479,256.1091 H 423.27606"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:50;stroke-linecap:round;stroke-dasharray:none"
|
||||
d="M 137.09627,256.1091 H 374.90373"
|
||||
id="path1041"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -24,9 +24,9 @@
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.921875"
|
||||
inkscape:cx="47.728814"
|
||||
inkscape:cy="215.32203"
|
||||
inkscape:zoom="1.3037281"
|
||||
inkscape:cx="-7.2867955"
|
||||
inkscape:cy="358.20352"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="956"
|
||||
inkscape:window-x="0"
|
||||
@@ -46,8 +46,8 @@
|
||||
cy="256.1091"
|
||||
r="231.50449" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:37.7963;stroke-linecap:round;stroke-dasharray:none"
|
||||
d="M 87.841479,256.1091 H 423.27606"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:50;stroke-linecap:round;stroke-dasharray:none"
|
||||
d="M 137.09627,256.1091 H 374.90373"
|
||||
id="path1041"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</g>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -482,23 +482,17 @@ endif()
|
||||
|
||||
# Host PAD
|
||||
set(pcsx2PADSources
|
||||
SIO/Pad/Pad.cpp
|
||||
SIO/Pad/PadBase.cpp
|
||||
SIO/Pad/PadConfig.cpp
|
||||
SIO/Pad/PadDualshock2.cpp
|
||||
SIO/Pad/PadGuitar.cpp
|
||||
SIO/Pad/PadMacros.cpp
|
||||
SIO/Pad/PadManager.cpp
|
||||
SIO/Pad/PadNotConnected.cpp
|
||||
)
|
||||
set(pcsx2PADHeaders
|
||||
SIO/Pad/Pad.h
|
||||
SIO/Pad/PadBase.h
|
||||
SIO/Pad/PadConfig.h
|
||||
SIO/Pad/PadDualshock2.h
|
||||
SIO/Pad/PadDualshock2Types.h
|
||||
SIO/Pad/PadGuitar.h
|
||||
SIO/Pad/PadGuitarTypes.h
|
||||
SIO/Pad/PadMacros.h
|
||||
SIO/Pad/PadManager.h
|
||||
SIO/Pad/PadNotConnected.h
|
||||
SIO/Pad/PadTypes.h
|
||||
)
|
||||
|
||||
@@ -364,6 +364,14 @@ enum class GSTextureInRtMode : u8
|
||||
MergeTargets,
|
||||
};
|
||||
|
||||
enum class GSBilinearDirtyMode : u8
|
||||
{
|
||||
Automatic,
|
||||
ForceBilinear,
|
||||
ForceNearest,
|
||||
MaxCount
|
||||
};
|
||||
|
||||
// Template function for casting enumerations to their underlying type
|
||||
template <typename Enumeration>
|
||||
typename std::underlying_type<Enumeration>::type enum_cast(Enumeration E)
|
||||
@@ -683,7 +691,6 @@ struct Pcsx2Config
|
||||
UserHacks_DisableRenderFixes : 1,
|
||||
UserHacks_MergePPSprite : 1,
|
||||
UserHacks_WildHack : 1,
|
||||
UserHacks_BilinearHack : 1,
|
||||
UserHacks_NativePaletteDraw : 1,
|
||||
UserHacks_TargetPartialInvalidation : 1,
|
||||
UserHacks_EstimateTextureRegion : 1,
|
||||
@@ -763,6 +770,7 @@ struct Pcsx2Config
|
||||
u8 UserHacks_CPUCLUTRender = 0;
|
||||
GSGPUTargetCLUTMode UserHacks_GPUTargetCLUTMode = GSGPUTargetCLUTMode::Disabled;
|
||||
GSTextureInRtMode UserHacks_TextureInsideRt = GSTextureInRtMode::Disabled;
|
||||
GSBilinearDirtyMode UserHacks_BilinearHack = GSBilinearDirtyMode::Automatic;
|
||||
TriFiltering TriFilter = TriFiltering::Automatic;
|
||||
s8 OverrideTextureBarriers = -1;
|
||||
|
||||
|
||||
@@ -547,20 +547,6 @@ static __fi void DoFMVSwitch()
|
||||
RendererSwitched = false;
|
||||
}
|
||||
|
||||
// Convenience function to update UI thread and set patches.
|
||||
static __fi void VSyncUpdateCore()
|
||||
{
|
||||
DoFMVSwitch();
|
||||
|
||||
VMManager::Internal::VSyncOnCPUThread();
|
||||
}
|
||||
|
||||
static __fi void VSyncCheckExit()
|
||||
{
|
||||
if (VMManager::Internal::IsExecutionInterrupted())
|
||||
Cpu->ExitExecution();
|
||||
}
|
||||
|
||||
// Framelimiter - Measures the delta time between calls and stalls until a
|
||||
// certain amount of time passes if such time hasn't passed yet.
|
||||
static __fi void frameLimit()
|
||||
@@ -605,13 +591,13 @@ static __fi void frameLimit()
|
||||
|
||||
static __fi void VSyncStart(u32 sCycle)
|
||||
{
|
||||
// Update vibration at the end of a frame.
|
||||
VSyncUpdateCore();
|
||||
// End-of-frame tasks.
|
||||
DoFMVSwitch();
|
||||
VMManager::Internal::VSyncOnCPUThread();
|
||||
|
||||
frameLimit(); // limit FPS
|
||||
gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times!
|
||||
VSyncCheckExit();
|
||||
|
||||
|
||||
if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll)
|
||||
SysTrace.EE.Counters.Write( " ================ EE COUNTER VSYNC START (frame: %d) ================", g_FrameCount );
|
||||
|
||||
@@ -642,6 +628,10 @@ static __fi void VSyncStart(u32 sCycle)
|
||||
// Therefore, there needs to be some delay in order for it to see the interrupt flag before the interrupt is acknowledged, likely helped on real hardware by the pipelines.
|
||||
// Without the patch and fixing this, the games have other issues, so I'm not going to rush to fix it.
|
||||
// Refraction
|
||||
|
||||
// Bail out before the next frame starts if we're paused, or the CPU has changed
|
||||
if (VMManager::Internal::IsExecutionInterrupted())
|
||||
Cpu->ExitExecution();
|
||||
}
|
||||
|
||||
static __fi void GSVSync()
|
||||
|
||||
@@ -187,7 +187,9 @@ bool AdapterUtils::GetAdapter(const std::string& name, Adapter* adapter, Adapter
|
||||
|
||||
do
|
||||
{
|
||||
if (pAdapter->ifa_addr->sa_family == AF_INET && strcmp(pAdapter->ifa_name, name.c_str()) == 0)
|
||||
if (pAdapter->ifa_addr != nullptr &&
|
||||
pAdapter->ifa_addr->sa_family == AF_INET &&
|
||||
strcmp(pAdapter->ifa_name, name.c_str()) == 0)
|
||||
break;
|
||||
|
||||
pAdapter = pAdapter->ifa_next;
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
"bilinearUpscale": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
"maximum": 2
|
||||
},
|
||||
"nativePaletteDraw": {
|
||||
"type": "integer",
|
||||
|
||||
@@ -2720,6 +2720,55 @@ void GSState::GrowVertexBuffer()
|
||||
m_index.buff = index;
|
||||
}
|
||||
|
||||
bool GSState::TrianglesAreQuads() const
|
||||
{
|
||||
// If this is a quad, there should only be two distinct values for both X and Y, which
|
||||
// also happen to be the minimum/maximum bounds of the primitive.
|
||||
const GSVertex* const v = m_vertex.buff;
|
||||
for (u32 idx = 0; idx < m_index.tail; idx += 6)
|
||||
{
|
||||
const u16* const i = m_index.buff + idx;
|
||||
|
||||
// Degenerate triangles should've been culled already, so we can check indices.
|
||||
u32 extra_verts = 0;
|
||||
for (u32 j = 3; j < 6; j++)
|
||||
{
|
||||
const u16 idx = i[j];
|
||||
if (idx != i[0] && idx != i[1] && idx != i[2])
|
||||
extra_verts++;
|
||||
}
|
||||
if (extra_verts == 1)
|
||||
return true;
|
||||
|
||||
// As a fallback, they might've used different vertices with a tri list, not strip.
|
||||
// Note that this won't work unless the quad is axis-aligned.
|
||||
u16 distinct_x_values[2] = {v[i[0]].XYZ.X};
|
||||
u16 distinct_y_values[2] = {v[i[0]].XYZ.Y};
|
||||
u32 num_distinct_x_values = 1, num_distinct_y_values = 1;
|
||||
for (u32 j = 1; j < 6; j++)
|
||||
{
|
||||
const GSVertex& jv = v[i[j]];
|
||||
if (jv.XYZ.X != distinct_x_values[0] && jv.XYZ.X != distinct_x_values[1])
|
||||
{
|
||||
if (num_distinct_x_values > 1)
|
||||
return false;
|
||||
|
||||
distinct_x_values[num_distinct_x_values++] = jv.XYZ.X;
|
||||
}
|
||||
|
||||
if (jv.XYZ.Y != distinct_y_values[0] && jv.XYZ.Y != distinct_y_values[1])
|
||||
{
|
||||
if (num_distinct_y_values > 1)
|
||||
return false;
|
||||
|
||||
distinct_y_values[num_distinct_y_values++] = jv.XYZ.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GSState::PRIM_OVERLAP GSState::PrimitiveOverlap()
|
||||
{
|
||||
// Either 1 triangle or 1 line or 3 POINTs
|
||||
@@ -2727,7 +2776,9 @@ GSState::PRIM_OVERLAP GSState::PrimitiveOverlap()
|
||||
if (m_vertex.next < 4)
|
||||
return PRIM_OVERLAP_NO;
|
||||
|
||||
if (m_vt.m_primclass != GS_SPRITE_CLASS)
|
||||
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
return (m_index.tail == 6 && TrianglesAreQuads()) ? PRIM_OVERLAP_NO : PRIM_OVERLAP_UNKNOW;
|
||||
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
|
||||
return PRIM_OVERLAP_UNKNOW; // maybe, maybe not
|
||||
|
||||
// Check intersection of sprite primitive only
|
||||
|
||||
@@ -418,6 +418,7 @@ public:
|
||||
|
||||
void DumpVertices(const std::string& filename);
|
||||
|
||||
bool TrianglesAreQuads() const;
|
||||
PRIM_OVERLAP PrimitiveOverlap();
|
||||
GIFRegTEX0 GetTex0Layer(u32 lod);
|
||||
};
|
||||
|
||||
@@ -216,20 +216,103 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
|
||||
|
||||
bool GSHwHack::GSC_BurnoutGames(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (RFBW == 2 && std::abs(static_cast<int>(RFBP) - static_cast<int>(RZBP)) <= static_cast<int>(BLOCKS_PER_PAGE) && (!RTME || RTPSM != PSMT8))
|
||||
{
|
||||
skip = 2;
|
||||
return true;
|
||||
}
|
||||
// Burnout has a... creative way of achieving its bloom effect, to avoid horizontal page breaks.
|
||||
// First they double strip clear a single page column to (191, 191, 191), then blend the main
|
||||
// framebuffer into this column, with (Cs - Cd) * 2. So anything lower than 191 clamps to zero,
|
||||
// and anything larger boosts up a bit. Then that column gets downsampled to half size, makes
|
||||
// sense right? The fun bit is when they move to the next page, instead of being sensible and
|
||||
// using another double strip clear, they write Z to the next page as part of the blended draw,
|
||||
// setting it to 191 (in Z24 terms). Then the buffers are swapped for the next column, 0x1a40
|
||||
// and 0x1a60 in US.
|
||||
//
|
||||
// We _could_ handle that, except for the fact that instead of pointing the texture at 0x1a60
|
||||
// for the downsample of the second column, they point it at 0x1a40, and offset the coordinates
|
||||
// by a page. This would need "tex outside RT", and no way that's happening.
|
||||
//
|
||||
// So, I present to you, dear reader, the first state machine within a CRC hack, in all its
|
||||
// disgusting glory. This effectively reduces the multi-pass effect to a single pass, by replacing
|
||||
// the column-wide draws with a fullscreen sprite, and skipping the extra passes.
|
||||
//
|
||||
// After this, they do a blur on the buffer, which is fine, because all the buffer swap BS has
|
||||
// finished, so we can return to normal.
|
||||
|
||||
// We don't check if we already have a skip here, because it gets confused when auto flush is on.
|
||||
if (RTME && (RFBP == 0x01dc0 || RFBP == 0x01c00 || RFBP == 0x01f00 || RFBP == 0x01d40 || RFBP == 0x02200 || RFBP == 0x02000) && RFPSM == RTPSM && (RTBP0 == 0x01dc0 || RTBP0 == 0x01c00 || RTBP0 == 0x01f00 || RTBP0 == 0x01d40 || RTBP0 == 0x02200 || RTBP0 == 0x02000) && RTPSM == PSMCT32)
|
||||
static u32 state = 0;
|
||||
static GIFRegTEX0 main_fb;
|
||||
static GSVector2i main_fb_size;
|
||||
static GIFRegTEX0 downsample_fb;
|
||||
static GIFRegTEX0 bloom_fb;
|
||||
switch (state)
|
||||
{
|
||||
// 0x01dc0 01c00(MP) ntsc, 0x01f00 0x01d40(MP) ntsc progressive, 0x02200(MP) pal.
|
||||
// Yellow stripes.
|
||||
// Multiplayer tested only on Takedown.
|
||||
skip = 3;
|
||||
return true;
|
||||
case 0: // waiting for double striped clear
|
||||
{
|
||||
if (RFBW != 2 || RFBP != RZBP || RTME)
|
||||
break;
|
||||
|
||||
// Need a backed up context to grab the framebuffer.
|
||||
if (r.m_backed_up_ctx < 0)
|
||||
break;
|
||||
|
||||
// Next draw should contain our source.
|
||||
GSTextureCache::Target* tgt = g_texture_cache->LookupTarget(r.m_env.CTXT[r.m_backed_up_ctx].TEX0,
|
||||
GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget);
|
||||
if (!tgt)
|
||||
break;
|
||||
|
||||
// Clear temp render target.
|
||||
main_fb = tgt->m_TEX0;
|
||||
main_fb_size = tgt->GetUnscaledSize();
|
||||
r.m_cached_ctx.FRAME.FBW = tgt->m_TEX0.TBW;
|
||||
r.m_cached_ctx.ZBUF.ZMSK = true;
|
||||
r.ReplaceVerticesWithSprite(GSVector4i::loadh(main_fb_size), main_fb_size);
|
||||
bloom_fb = GIFRegTEX0::Create(RFBP, RFBW, RFPSM);
|
||||
state = 1;
|
||||
GL_INS("GSC_BurnoutGames(): Initial double-striped clear.");
|
||||
return true;
|
||||
}
|
||||
|
||||
case 1: // reverse blend to extract bright pixels
|
||||
{
|
||||
r.ReplaceVerticesWithSprite(GSVector4i::loadh(main_fb_size), main_fb_size);
|
||||
r.m_cached_ctx.ZBUF.ZMSK = true;
|
||||
state = 2;
|
||||
GL_INS("GSC_BurnoutGames(): Extract Bright Pixels.");
|
||||
return true;
|
||||
}
|
||||
|
||||
case 2: // downsample
|
||||
{
|
||||
const GSVector4i downsample_rect = GSVector4i(0, 0, main_fb_size.x / 2, main_fb_size.y / 2);
|
||||
r.ReplaceVerticesWithSprite(downsample_rect, GSVector4i::loadh(main_fb_size), main_fb_size, downsample_rect);
|
||||
downsample_fb = GIFRegTEX0::Create(RFBP, RFBW, RFPSM);
|
||||
state = 3;
|
||||
GL_INS("GSC_BurnoutGames(): Downsampling.");
|
||||
return true;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
// Kill the downsample source, because we made it way larger than it was supposed to be.
|
||||
// That way we don't risk confusing any other targets.
|
||||
g_texture_cache->InvalidateVideoMemType(GSTextureCache::RenderTarget, bloom_fb.TBP0);
|
||||
state = 4;
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case 4: // Skip until it's downsampled again.
|
||||
{
|
||||
if (!RTME || RTBP0 != downsample_fb.TBP0)
|
||||
{
|
||||
GL_INS("GSC_BurnoutGames(): Skipping extra pass.");
|
||||
skip = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finally, we're done, let the game take over.
|
||||
GL_INS("GSC_BurnoutGames(): Bloom effect done.");
|
||||
skip = 0;
|
||||
state = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return GSC_BlackAndBurnoutSky(r, skip);
|
||||
|
||||
@@ -3345,7 +3345,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass)
|
||||
void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass)
|
||||
{
|
||||
// AA1: Don't enable blending on AA1, not yet implemented on hardware mode,
|
||||
// it requires coverage sample so it's safer to turn it off instead.
|
||||
@@ -3377,6 +3377,13 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
||||
m_conf.ps.blend_c = ALPHA.C;
|
||||
m_conf.ps.blend_d = ALPHA.D;
|
||||
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
static constexpr const char* col[3] = {"Cs", "Cd", "0"};
|
||||
static constexpr const char* alpha[3] = {"As", "Ad", "Af"};
|
||||
GL_INS("EmulateBlending(): (%s - %s) * %s + %s", col[ALPHA.A], col[ALPHA.B], alpha[ALPHA.C], col[ALPHA.D]);
|
||||
GL_INS("Draw AlphaMinMax: %d-%d, RT AlphaMinMax: %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max, rt_alpha_min, rt_alpha_max);
|
||||
#endif
|
||||
|
||||
// When AA1 is enabled and Alpha Blending is disabled, alpha blending done with coverage instead of alpha.
|
||||
// We use a COV value of 128 (full coverage) in triangles (except the edge geometry, which we can't do easily).
|
||||
if (IsCoverageAlpha())
|
||||
@@ -3396,10 +3403,12 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
||||
const bool alpha_c0_one = (m_conf.ps.blend_c == 0 && (GetAlphaMinMax().min == 128) && (GetAlphaMinMax().max == 128));
|
||||
const bool alpha_c0_high_min_one = (m_conf.ps.blend_c == 0 && GetAlphaMinMax().min > 128);
|
||||
const bool alpha_c0_high_max_one = (m_conf.ps.blend_c == 0 && GetAlphaMinMax().max > 128);
|
||||
const bool alpha_c1_zero = (m_conf.ps.blend_c == 1 && rt_alpha_min == 0 && rt_alpha_max == 0);
|
||||
const bool alpha_c1_one = (m_conf.ps.blend_c == 1 && rt_alpha_min == 128 && rt_alpha_max == 128);
|
||||
const bool alpha_c2_zero = (m_conf.ps.blend_c == 2 && AFIX == 0u);
|
||||
const bool alpha_c2_one = (m_conf.ps.blend_c == 2 && AFIX == 128u);
|
||||
const bool alpha_c2_high_one = (m_conf.ps.blend_c == 2 && AFIX > 128u);
|
||||
const bool alpha_one = alpha_c0_one || alpha_c2_one;
|
||||
const bool alpha_one = alpha_c0_one || alpha_c1_one || alpha_c2_one;
|
||||
|
||||
// Optimize blending equations, must be done before index calculation
|
||||
if ((m_conf.ps.blend_a == m_conf.ps.blend_b) || ((m_conf.ps.blend_b == m_conf.ps.blend_d) && alpha_one))
|
||||
@@ -3418,7 +3427,7 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
||||
m_conf.ps.blend_b = 0;
|
||||
m_conf.ps.blend_c = 0;
|
||||
}
|
||||
else if (alpha_c0_zero || alpha_c2_zero)
|
||||
else if (alpha_c0_zero || alpha_c1_zero || alpha_c2_zero)
|
||||
{
|
||||
// C == 0.0f
|
||||
// (A - B) * C, result will be 0.0f so set A B to Cs
|
||||
@@ -3444,7 +3453,8 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
||||
// Ad cases, alpha write is masked, one barrier is enough, for d3d11 read the fb
|
||||
// Replace Ad with As, blend flags will be used from As since we are chaging the blend_index value.
|
||||
// Must be done before index calculation, after blending equation optimizations
|
||||
bool blend_ad_alpha_masked = (m_conf.ps.blend_c == 1) && (m_cached_ctx.FRAME.FBMSK & 0xFF000000) == 0xFF000000;
|
||||
const bool blend_ad = m_conf.ps.blend_c == 1;
|
||||
bool blend_ad_alpha_masked = blend_ad && (m_cached_ctx.FRAME.FBMSK & 0xFF000000) == 0xFF000000;
|
||||
if (((GSConfig.AccurateBlendingUnit >= AccBlendLevel::Basic) || (COLCLAMP.CLAMP == 0))
|
||||
&& g_gs_device->Features().texture_barrier && blend_ad_alpha_masked)
|
||||
m_conf.ps.blend_c = 0;
|
||||
@@ -3506,13 +3516,15 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
||||
const bool prefer_sw_blend = m_conf.require_full_barrier || (one_barrier && m_prim_overlap == PRIM_OVERLAP_NO);
|
||||
|
||||
// SW Blend is (nearly) free. Let's use it.
|
||||
const bool no_prim_overlap = features.framebuffer_fetch ? (m_vt.m_primclass == GS_SPRITE_CLASS) : (m_prim_overlap == PRIM_OVERLAP_NO);
|
||||
const bool no_prim_overlap = (m_prim_overlap == PRIM_OVERLAP_NO);
|
||||
const bool impossible_or_free_blend = (blend_flag & BLEND_A_MAX) // Impossible blending
|
||||
|| blend_non_recursive // Free sw blending, doesn't require barriers or reading fb
|
||||
|| accumulation_blend // Mix of hw/sw blending
|
||||
|| no_prim_overlap // Blend can be done in a single draw
|
||||
|| (m_conf.require_full_barrier) // Another effect (for example fbmask) already requires a full barrier
|
||||
|| (one_barrier && features.framebuffer_fetch); // On fbfetch, one barrier is like full barrier
|
||||
|| (m_conf.require_full_barrier) // Another effect (for example fbmask) already requires a full barrier
|
||||
// Blend can be done in a single draw, and we already need a barrier
|
||||
// On fbfetch, one barrier is like full barrier
|
||||
|| (one_barrier && (no_prim_overlap || features.framebuffer_fetch))
|
||||
|| ((alpha_c2_high_one || alpha_c0_high_max_one) && no_prim_overlap);
|
||||
|
||||
switch (GSConfig.AccurateBlendingUnit)
|
||||
{
|
||||
@@ -3540,6 +3552,8 @@ void GSRendererHW::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
|
||||
// If prims don't overlap prefer full sw blend on blend_ad_alpha_masked cases.
|
||||
accumulation_blend &= !(prefer_sw_blend || (blend_ad_alpha_masked && m_prim_overlap == PRIM_OVERLAP_NO));
|
||||
sw_blending |= impossible_or_free_blend;
|
||||
// Ad blends are completely wrong without sw blend (Ad is 0.5 not 1 for 128). We can spare a barrier for it.
|
||||
sw_blending |= blend_ad && no_prim_overlap;
|
||||
// Try to do hw blend for clr2 case.
|
||||
sw_blending &= !clr_blend1_2;
|
||||
// Do not run BLEND MIX if sw blending is already present, it's less accurate
|
||||
@@ -4412,7 +4426,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
|
||||
}
|
||||
|
||||
bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex,
|
||||
const TextureMinMaxResult& tmm) const
|
||||
const TextureMinMaxResult& tmm)
|
||||
{
|
||||
// Minimum blending or no barriers -> we can't use tex-is-fb.
|
||||
if (GSConfig.AccurateBlendingUnit == AccBlendLevel::Minimum || !g_gs_device->Features().texture_barrier)
|
||||
@@ -4460,21 +4474,8 @@ bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextu
|
||||
|
||||
// Texture is actually the frame buffer. Stencil emulation to compute shadow (Jak series/tri-ace game)
|
||||
// Will hit the "m_ps_sel.tex_is_fb = 1" path in the draw
|
||||
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
{
|
||||
// This pattern is used by several games to emulate a stencil (shadow)
|
||||
// Ratchet & Clank, Jak do alpha integer multiplication (tfx) which is mostly equivalent to +1/-1
|
||||
// Tri-Ace (Star Ocean 3/RadiataStories/VP2) uses a palette to handle the +1/-1
|
||||
if (m_cached_ctx.FRAME.FBMSK == 0x00FFFFFF)
|
||||
{
|
||||
GL_CACHE("Tex-is-fb hack for Jak");
|
||||
return true;
|
||||
}
|
||||
|
||||
GL_CACHE("Triangle draw, not using tex-is-fb");
|
||||
return false;
|
||||
}
|
||||
else if (m_vt.m_primclass == GS_SPRITE_CLASS)
|
||||
const bool is_quads = (m_vt.m_primclass == GS_SPRITE_CLASS || m_prim_overlap == PRIM_OVERLAP_NO);
|
||||
if (is_quads)
|
||||
{
|
||||
// No bilinear for tex-is-fb.
|
||||
if (m_vt.IsLinear())
|
||||
@@ -4507,6 +4508,21 @@ bool GSRendererHW::CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextu
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
{
|
||||
// This pattern is used by several games to emulate a stencil (shadow)
|
||||
// Ratchet & Clank, Jak do alpha integer multiplication (tfx) which is mostly equivalent to +1/-1
|
||||
// Tri-Ace (Star Ocean 3/RadiataStories/VP2) uses a palette to handle the +1/-1
|
||||
if (m_cached_ctx.FRAME.FBMSK == 0x00FFFFFF)
|
||||
{
|
||||
GL_CACHE("Tex-is-fb hack for Jak");
|
||||
return true;
|
||||
}
|
||||
|
||||
GL_CACHE("Triangle draw, not using tex-is-fb");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4605,14 +4621,12 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
// Upscaling hack to avoid various line/grid issues
|
||||
MergeSprite(tex);
|
||||
|
||||
const GSDevice::FeatureSupport features(g_gs_device->Features());
|
||||
if (!features.framebuffer_fetch)
|
||||
m_prim_overlap = PrimitiveOverlap();
|
||||
else
|
||||
m_prim_overlap = PRIM_OVERLAP_UNKNOW;
|
||||
m_prim_overlap = PrimitiveOverlap();
|
||||
|
||||
EmulateTextureShuffleAndFbmask(rt);
|
||||
|
||||
const GSDevice::FeatureSupport features = g_gs_device->Features();
|
||||
|
||||
// DATE: selection of the algorithm. Must be done before blending because GL42 is not compatible with blending
|
||||
if (DATE)
|
||||
{
|
||||
@@ -4709,8 +4723,20 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
}
|
||||
|
||||
// Blend
|
||||
int blend_alpha_min = 0, blend_alpha_max = 255;
|
||||
if (rt)
|
||||
{
|
||||
blend_alpha_min = rt->m_alpha_min;
|
||||
blend_alpha_max = rt->m_alpha_max;
|
||||
|
||||
const bool is_24_bit = (GSLocalMemory::m_psm[rt->m_TEX0.PSM].trbpp == 24);
|
||||
if (is_24_bit)
|
||||
{
|
||||
// C24/Z24 - alpha is 1.
|
||||
blend_alpha_min = 128;
|
||||
blend_alpha_max = 128;
|
||||
}
|
||||
|
||||
if (!m_channel_shuffle && !m_texture_shuffle)
|
||||
{
|
||||
const int fba_value = m_prev_env.CTXT[m_prev_env.PRIM.CTXT].FBA.FBA * 128;
|
||||
@@ -4732,7 +4758,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
rt->m_alpha_max |= std::max(GetAlphaMinMax().max | fba_value, rt->m_alpha_max);
|
||||
rt->m_alpha_min = std::min(GetAlphaMinMax().min | fba_value, rt->m_alpha_min);
|
||||
}
|
||||
else
|
||||
else if (!is_24_bit)
|
||||
{
|
||||
// If both are zero then we probably don't know what the alpha is.
|
||||
if (rt->m_alpha_max == 0 && rt->m_alpha_min == 0)
|
||||
@@ -4747,6 +4773,16 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
rt->m_alpha_max = 255;
|
||||
rt->m_alpha_min = 0;
|
||||
}
|
||||
|
||||
GL_INS("RT Alpha Range: %d-%d => %d-%d", blend_alpha_min, blend_alpha_max, rt->m_alpha_min, rt->m_alpha_max);
|
||||
|
||||
// If there's no overlap, the values in the RT before FB write will be the old values.
|
||||
if (m_prim_overlap != PRIM_OVERLAP_NO)
|
||||
{
|
||||
// Otherwise, it may be a mix of the old/new values.
|
||||
blend_alpha_min = std::min(blend_alpha_min, rt->m_alpha_min);
|
||||
blend_alpha_max = std::max(blend_alpha_max, rt->m_alpha_max);
|
||||
}
|
||||
}
|
||||
|
||||
// Not gonna spend too much time with this, it's not likely to be used much, can't be less accurate than it was.
|
||||
@@ -4754,12 +4790,13 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
{
|
||||
ds->m_alpha_max = std::max(ds->m_alpha_max, static_cast<int>(m_vt.m_max.p.z) >> 24);
|
||||
ds->m_alpha_min = std::min(ds->m_alpha_min, static_cast<int>(m_vt.m_min.p.z) >> 24);
|
||||
GL_INS("New DS Alpha Range: %d-%d", ds->m_alpha_min, ds->m_alpha_max);
|
||||
}
|
||||
|
||||
bool blending_alpha_pass = false;
|
||||
if ((!IsOpaque() || m_context->ALPHA.IsBlack()) && rt && (m_conf.colormask.wrgba & 0x7))
|
||||
{
|
||||
EmulateBlending(DATE_PRIMID, DATE_BARRIER, blending_alpha_pass);
|
||||
EmulateBlending(blend_alpha_min, blend_alpha_max, DATE_PRIMID, DATE_BARRIER, blending_alpha_pass);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5204,12 +5241,12 @@ GSRendererHW::CLUTDrawTestResult GSRendererHW::PossibleCLUTDraw()
|
||||
if (HasEEUpload(r))
|
||||
return CLUTDrawTestResult::CLUTDrawOnCPU;
|
||||
|
||||
GSTextureCache::Target* tgt = g_texture_cache->GetExactTarget(
|
||||
m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.TBW, GSTextureCache::RenderTarget, m_cached_ctx.TEX0.TBP0);
|
||||
const GSTextureCache::Target* tgt = g_texture_cache->FindOverlappingTarget(
|
||||
m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.TBW, m_cached_ctx.TEX0.PSM, r);
|
||||
if (tgt)
|
||||
{
|
||||
bool is_dirty = false;
|
||||
for (GSDirtyRect& rc : tgt->m_dirty)
|
||||
for (const GSDirtyRect& rc : tgt->m_dirty)
|
||||
{
|
||||
if (!rc.GetDirtyRect(m_cached_ctx.TEX0).rintersect(r).rempty())
|
||||
{
|
||||
@@ -5798,52 +5835,13 @@ bool GSRendererHW::PrimitiveCoversWithoutGaps()
|
||||
|
||||
if (m_vt.m_primclass == GS_POINT_CLASS)
|
||||
{
|
||||
m_primitive_covers_without_gaps = true;
|
||||
return true;
|
||||
m_primitive_covers_without_gaps = (m_vertex.next < 2);
|
||||
return m_primitive_covers_without_gaps.value();
|
||||
}
|
||||
else if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
{
|
||||
if (m_index.tail != 6)
|
||||
{
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If this is a quad, there should only be two distinct values for both X and Y, which
|
||||
// also happen to be the minimum/maximum bounds of the primitive.
|
||||
const GSVertex* const v = m_vertex.buff;
|
||||
const u16* const i = m_index.buff;
|
||||
u16 distinct_x_values[2] = {v[i[0]].XYZ.X};
|
||||
u16 distinct_y_values[2] = {v[i[0]].XYZ.Y};
|
||||
u32 num_distinct_x_values = 1, num_distinct_y_values = 1;
|
||||
for (u32 j = 1; j < 6; j++)
|
||||
{
|
||||
const GSVertex& jv = v[i[j]];
|
||||
if (jv.XYZ.X != distinct_x_values[0] && jv.XYZ.X != distinct_x_values[1])
|
||||
{
|
||||
if (num_distinct_x_values > 1)
|
||||
{
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
distinct_x_values[num_distinct_x_values++] = jv.XYZ.X;
|
||||
}
|
||||
|
||||
if (jv.XYZ.Y != distinct_y_values[0] && jv.XYZ.Y != distinct_y_values[1])
|
||||
{
|
||||
if (num_distinct_y_values > 1)
|
||||
{
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
distinct_y_values[num_distinct_y_values++] = jv.XYZ.Y;
|
||||
}
|
||||
}
|
||||
|
||||
m_primitive_covers_without_gaps = true;
|
||||
return true;
|
||||
m_primitive_covers_without_gaps = (m_index.tail == 6 && TrianglesAreQuads());
|
||||
return m_primitive_covers_without_gaps.value();
|
||||
}
|
||||
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
|
||||
{
|
||||
|
||||
@@ -86,7 +86,7 @@ private:
|
||||
void SetupIA(float target_scale, float sx, float sy);
|
||||
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt);
|
||||
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only);
|
||||
void EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass);
|
||||
void EmulateBlending(int rt_alpha_min, int rt_alpha_max, bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blending_alpha_pass);
|
||||
|
||||
void EmulateTextureSampler(const GSTextureCache::Target* rt, const GSTextureCache::Target* ds,
|
||||
GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTexture*& src_copy);
|
||||
@@ -94,7 +94,7 @@ private:
|
||||
const GSTextureCache::Source* tex, const TextureMinMaxResult& tmm, GSTextureCache::SourceRegion& source_region,
|
||||
bool& target_region, GSVector2i& unscaled_size, float& scale, GSTexture*& src_copy);
|
||||
bool CanUseTexIsFB(const GSTextureCache::Target* rt, const GSTextureCache::Source* tex,
|
||||
const TextureMinMaxResult& tmm) const;
|
||||
const TextureMinMaxResult& tmm);
|
||||
|
||||
void EmulateZbuffer(const GSTextureCache::Target* ds);
|
||||
void EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2);
|
||||
|
||||
@@ -3339,6 +3339,26 @@ GSTextureCache::Target* GSTextureCache::GetTargetWithSharedBits(u32 BP, u32 PSM)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GSTextureCache::Target* GSTextureCache::FindOverlappingTarget(u32 BP, u32 end_bp) const
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
for (Target* tgt : m_dst[i])
|
||||
{
|
||||
if (CheckOverlap(tgt->m_TEX0.TBP0, tgt->m_end_block, BP, end_bp))
|
||||
return tgt;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GSTextureCache::Target* GSTextureCache::FindOverlappingTarget(u32 BP, u32 BW, u32 PSM, GSVector4i rc) const
|
||||
{
|
||||
const u32 end_bp = GSLocalMemory::GetUnwrappedEndBlockAddress(BP, BW, PSM, rc);
|
||||
return FindOverlappingTarget(BP, end_bp);
|
||||
}
|
||||
|
||||
GSVector2i GSTextureCache::GetTargetSize(u32 bp, u32 fbw, u32 psm, s32 min_width, s32 min_height)
|
||||
{
|
||||
TargetHeightElem search = {};
|
||||
@@ -5111,8 +5131,8 @@ void GSTextureCache::Target::Update()
|
||||
// Bilinear filtering this is probably not a good thing, at least in native, but upscaling Nearest can be gross and messy.
|
||||
// It's needed for depth, though.. filtering depth doesn't make much sense, but SMT3 needs it..
|
||||
const bool upscaled = (m_scale != 1.0f);
|
||||
const bool override_linear = upscaled && GSConfig.UserHacks_BilinearHack;
|
||||
const bool linear = (m_type == RenderTarget && upscaled);
|
||||
const bool override_linear = (upscaled && GSConfig.UserHacks_BilinearHack == GSBilinearDirtyMode::ForceBilinear);
|
||||
const bool linear = (m_type == RenderTarget && upscaled && GSConfig.UserHacks_BilinearHack != GSBilinearDirtyMode::ForceNearest);
|
||||
|
||||
GSDevice::MultiStretchRect* drects = static_cast<GSDevice::MultiStretchRect*>(
|
||||
alloca(sizeof(GSDevice::MultiStretchRect) * static_cast<u32>(m_dirty.size())));
|
||||
@@ -5823,8 +5843,8 @@ bool GSTextureCache::SurfaceOffsetKeyEqual::operator()(const GSTextureCache::Sur
|
||||
{
|
||||
for (size_t i = 0; i < lhs.elems.size(); ++i)
|
||||
{
|
||||
const SurfaceOffsetKeyElem& lhs_elem = lhs.elems.at(i);
|
||||
const SurfaceOffsetKeyElem& rhs_elem = rhs.elems.at(i);
|
||||
const SurfaceOffsetKeyElem& lhs_elem = lhs.elems[i];
|
||||
const SurfaceOffsetKeyElem& rhs_elem = rhs.elems[i];
|
||||
if (lhs_elem.bp != rhs_elem.bp
|
||||
|| lhs_elem.bw != rhs_elem.bw
|
||||
|| lhs_elem.psm != rhs_elem.psm
|
||||
|
||||
@@ -488,6 +488,8 @@ public:
|
||||
/// Looks up a target in the cache, and only returns it if the BP/BW match exactly.
|
||||
Target* GetExactTarget(u32 BP, u32 BW, int type, u32 end_bp);
|
||||
Target* GetTargetWithSharedBits(u32 BP, u32 PSM) const;
|
||||
Target* FindOverlappingTarget(u32 BP, u32 end_bp) const;
|
||||
Target* FindOverlappingTarget(u32 BP, u32 BW, u32 PSM, GSVector4i rc) const;
|
||||
|
||||
GSVector2i GetTargetSize(u32 bp, u32 fbw, u32 psm, s32 min_width, s32 min_height);
|
||||
bool Has32BitTarget(u32 bp);
|
||||
|
||||
@@ -728,8 +728,11 @@ void GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
||||
break;
|
||||
|
||||
case GSHWFixId::BilinearUpscale:
|
||||
config.UserHacks_BilinearHack = (value > 0);
|
||||
break;
|
||||
{
|
||||
if (value >= 0 && value < static_cast<int>(GSBilinearDirtyMode::MaxCount))
|
||||
config.UserHacks_BilinearHack = static_cast<GSBilinearDirtyMode>(value);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSHWFixId::NativePaletteDraw:
|
||||
config.UserHacks_NativePaletteDraw = (value > 0);
|
||||
|
||||
@@ -48,8 +48,7 @@
|
||||
#include "common/Timer.h"
|
||||
|
||||
#include "SIO/Memcard/MemoryCardFile.h"
|
||||
#include "SIO/Pad/PadConfig.h"
|
||||
#include "SIO/Pad/PadMacros.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Sio.h"
|
||||
|
||||
#include "imgui.h"
|
||||
@@ -2273,7 +2272,7 @@ void FullscreenUI::StartAutomaticBinding(u32 port)
|
||||
Host::RunOnCPUThread([port, name = std::move(names[index])]() {
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface* bsi = GetEditingSettingsInterface();
|
||||
const bool result = g_PadConfig.MapController(*bsi, port, InputManager::GetGenericBindingMapping(name));
|
||||
const bool result = Pad::MapController(*bsi, port, InputManager::GetGenericBindingMapping(name));
|
||||
SetSettingsChanged(bsi);
|
||||
|
||||
|
||||
@@ -3229,6 +3228,7 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
static constexpr const char* s_half_pixel_offset_options[] = {
|
||||
"Off (Default)", "Normal (Vertex)", "Special (Texture)", "Special (Texture - Aggressive)"};
|
||||
static constexpr const char* s_round_sprite_options[] = {"Off (Default)", "Half", "Full"};
|
||||
static constexpr const char* s_bilinear_dirty_options[] = {"Automatic (Default)", "Force Bilinear", "Force Nearest"};
|
||||
static constexpr const char* s_auto_flush_options[] = {
|
||||
"Disabled (Default)", "Enabled (Sprites Only)", "Enabled (All Primitives)"};
|
||||
|
||||
@@ -3281,6 +3281,10 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
"UserHacks_HalfPixelOffset", 0, s_half_pixel_offset_options, std::size(s_half_pixel_offset_options));
|
||||
DrawIntListSetting(bsi, "Round Sprite", "Adjusts sprite coordinates.", "EmuCore/GS", "UserHacks_round_sprite_offset", 0,
|
||||
s_round_sprite_options, std::size(s_round_sprite_options));
|
||||
DrawIntListSetting(bsi, "Bilinear Upscale",
|
||||
"Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare.", "EmuCore/GS",
|
||||
"UserHacks_BilinearHack", static_cast<int>(GSBilinearDirtyMode::Automatic),
|
||||
s_bilinear_dirty_options, std::size(s_bilinear_dirty_options));
|
||||
DrawIntSpinBoxSetting(
|
||||
bsi, "TC Offset X", "Adjusts target texture offsets.", "EmuCore/GS", "UserHacks_TCOffsetX", 0, -4096, 4096, 1);
|
||||
DrawIntSpinBoxSetting(
|
||||
@@ -3291,10 +3295,7 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
"UserHacks_merge_pp_sprite", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, "Wild Arms Hack",
|
||||
"Lowers the GS precision to avoid gaps between pixels when upscaling. Fixes the text on Wild Arms games.", "EmuCore/GS",
|
||||
"UserHacks_WildHack", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, "Bilinear Upscale",
|
||||
"Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare.", "EmuCore/GS",
|
||||
"UserHacks_BilinearHack", false, manual_hw_fixes);
|
||||
"UserHacks_WildHack", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, "Unscaled Palette Texture Draws", "Can fix some broken effects which rely on pixel perfect precision.",
|
||||
"EmuCore/GS", "UserHacks_NativePaletteDraw", false, manual_hw_fixes);
|
||||
}
|
||||
@@ -3650,7 +3651,7 @@ void FullscreenUI::CopyGlobalControllerSettingsToGame()
|
||||
SettingsInterface* dsi = GetEditingSettingsInterface(true);
|
||||
SettingsInterface* ssi = GetEditingSettingsInterface(false);
|
||||
|
||||
g_PadConfig.CopyConfiguration(dsi, *ssi, true, true, false);
|
||||
Pad::CopyConfiguration(dsi, *ssi, true, true, false);
|
||||
USB::CopyConfiguration(dsi, *ssi, true, true);
|
||||
SetSettingsChanged(dsi);
|
||||
|
||||
@@ -3661,15 +3662,15 @@ void FullscreenUI::ResetControllerSettings()
|
||||
{
|
||||
SettingsInterface* dsi = GetEditingSettingsInterface();
|
||||
|
||||
g_PadConfig.SetDefaultControllerConfig(*dsi);
|
||||
g_PadConfig.SetDefaultHotkeyConfig(*dsi);
|
||||
Pad::SetDefaultControllerConfig(*dsi);
|
||||
Pad::SetDefaultHotkeyConfig(*dsi);
|
||||
USB::SetDefaultConfiguration(dsi);
|
||||
ShowToast(std::string(), "Controller settings reset to default.");
|
||||
}
|
||||
|
||||
void FullscreenUI::DoLoadInputProfile()
|
||||
{
|
||||
std::vector<std::string> profiles(g_PadConfig.GetInputProfileNames());
|
||||
std::vector<std::string> profiles = Pad::GetInputProfileNames();
|
||||
if (profiles.empty())
|
||||
{
|
||||
ShowToast(std::string(), "No input profiles available.");
|
||||
@@ -3695,7 +3696,7 @@ void FullscreenUI::DoLoadInputProfile()
|
||||
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface* dsi = GetEditingSettingsInterface();
|
||||
g_PadConfig.CopyConfiguration(dsi, ssi, true, true, IsEditingGameSettings(dsi));
|
||||
Pad::CopyConfiguration(dsi, ssi, true, true, IsEditingGameSettings(dsi));
|
||||
USB::CopyConfiguration(dsi, ssi, true, true);
|
||||
SetSettingsChanged(dsi);
|
||||
ShowToast(std::string(), fmt::format("Input profile '{}' loaded.", title));
|
||||
@@ -3709,7 +3710,7 @@ void FullscreenUI::DoSaveInputProfile(const std::string& name)
|
||||
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface* ssi = GetEditingSettingsInterface();
|
||||
g_PadConfig.CopyConfiguration(&dsi, *ssi, true, true, IsEditingGameSettings(ssi));
|
||||
Pad::CopyConfiguration(&dsi, *ssi, true, true, IsEditingGameSettings(ssi));
|
||||
USB::CopyConfiguration(&dsi, *ssi, true, true);
|
||||
if (dsi.Save())
|
||||
ShowToast(std::string(), fmt::format("Input profile '{}' saved.", name));
|
||||
@@ -3719,7 +3720,7 @@ void FullscreenUI::DoSaveInputProfile(const std::string& name)
|
||||
|
||||
void FullscreenUI::DoSaveInputProfile()
|
||||
{
|
||||
std::vector<std::string> profiles(g_PadConfig.GetInputProfileNames());
|
||||
std::vector<std::string> profiles = Pad::GetInputProfileNames();
|
||||
|
||||
ImGuiFullscreen::ChoiceDialogOptions coptions;
|
||||
coptions.reserve(profiles.size() + 1);
|
||||
@@ -3853,11 +3854,11 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
.c_str());
|
||||
|
||||
const char* section = sections[global_slot];
|
||||
const std::string type(bsi->GetStringValue(section, "Type", g_PadConfig.GetDefaultPadType(global_slot)));
|
||||
const PadConfig::ControllerInfo* ci = g_PadConfig.GetControllerInfo(type);
|
||||
const std::string type(bsi->GetStringValue(section, "Type", Pad::GetDefaultPadType(global_slot)));
|
||||
const Pad::ControllerInfo* ci = Pad::GetControllerInfo(type);
|
||||
if (MenuButton(ICON_FA_GAMEPAD " Controller Type", ci ? ci->display_name : "Unknown"))
|
||||
{
|
||||
const std::vector<std::pair<const char*, const char*>> raw_options = g_PadConfig.GetControllerTypeNames();
|
||||
const std::vector<std::pair<const char*, const char*>> raw_options = Pad::GetControllerTypeNames();
|
||||
ImGuiFullscreen::ChoiceDialogOptions options;
|
||||
options.reserve(raw_options.size());
|
||||
for (auto& it : raw_options)
|
||||
@@ -3878,7 +3879,7 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
});
|
||||
}
|
||||
|
||||
if (!ci || ci->num_bindings == 0)
|
||||
if (!ci || ci->bindings.empty())
|
||||
{
|
||||
ImGui::PopID();
|
||||
continue;
|
||||
@@ -3887,20 +3888,17 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
if (MenuButton(ICON_FA_MAGIC " Automatic Mapping", "Attempts to map the selected port to a chosen controller."))
|
||||
StartAutomaticBinding(global_slot);
|
||||
|
||||
for (u32 i = 0; i < ci->num_bindings; i++)
|
||||
{
|
||||
const InputBindingInfo& bi = ci->bindings[i];
|
||||
DrawInputBindingButton(bsi, bi.bind_type, section, bi.name, bi.display_name, true);
|
||||
}
|
||||
for (const InputBindingInfo& bi : ci->bindings)
|
||||
DrawInputBindingButton(bsi, bi.bind_type, section, bi.name, Host::TranslateToCString("Pad", bi.display_name), true);
|
||||
|
||||
MenuHeading((mtap_enabled[mtap_port] ?
|
||||
fmt::format(ICON_FA_MICROCHIP " Controller Port {}{} Macros", mtap_port + 1, mtap_slot_names[mtap_slot]) :
|
||||
fmt::format(ICON_FA_MICROCHIP " Controller Port {} Macros", mtap_port + 1))
|
||||
.c_str());
|
||||
|
||||
static bool macro_button_expanded[Pad::NUM_CONTROLLER_PORTS][PadMacros::NUM_MACRO_BUTTONS_PER_CONTROLLER] = {};
|
||||
static bool macro_button_expanded[Pad::NUM_CONTROLLER_PORTS][Pad::NUM_MACRO_BUTTONS_PER_CONTROLLER] = {};
|
||||
|
||||
for (u32 macro_index = 0; macro_index < PadMacros::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_index++)
|
||||
for (u32 macro_index = 0; macro_index < Pad::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_index++)
|
||||
{
|
||||
bool& expanded = macro_button_expanded[global_slot][macro_index];
|
||||
expanded ^= MenuHeadingButton(fmt::format(ICON_FA_MICROCHIP " Macro Button {}", macro_index + 1).c_str(),
|
||||
@@ -3916,25 +3914,23 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
{
|
||||
std::vector<std::string_view> buttons_split(StringUtil::SplitString(binds_string, '&', true));
|
||||
ImGuiFullscreen::ChoiceDialogOptions options;
|
||||
for (u32 i = 0; i < ci->num_bindings; i++)
|
||||
for (const InputBindingInfo& bi : ci->bindings)
|
||||
{
|
||||
const InputBindingInfo& bi = ci->bindings[i];
|
||||
if (bi.bind_type != InputBindingInfo::Type::Button && bi.bind_type != InputBindingInfo::Type::Axis &&
|
||||
bi.bind_type != InputBindingInfo::Type::HalfAxis)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
options.emplace_back(bi.display_name, std::any_of(buttons_split.begin(), buttons_split.end(),
|
||||
[bi](const std::string_view& it) { return (it == bi.name); }));
|
||||
options.emplace_back(Host::TranslateToCString("Pad", bi.display_name), std::any_of(buttons_split.begin(), buttons_split.end(),
|
||||
[bi](const std::string_view& it) { return (it == bi.name); }));
|
||||
}
|
||||
|
||||
OpenChoiceDialog(fmt::format("Select Macro {} Binds", macro_index + 1).c_str(), true, std::move(options),
|
||||
[section, macro_index, ci](s32 index, const std::string& title, bool checked) {
|
||||
// convert display name back to bind name
|
||||
std::string_view to_modify;
|
||||
for (u32 j = 0; j < ci->num_bindings; j++)
|
||||
for (const InputBindingInfo& bi : ci->bindings)
|
||||
{
|
||||
const InputBindingInfo& bi = ci->bindings[j];
|
||||
if (bi.display_name == title)
|
||||
{
|
||||
to_modify = bi.name;
|
||||
@@ -3984,6 +3980,10 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
DrawFloatSpinBoxSetting(bsi, ICON_FA_ARROW_DOWN " Pressure", "Determines how much pressure is simulated when macro is active.",
|
||||
section, pressure_key.c_str(), 1.0f, 0.01f, 1.0f, 0.01f, 100.0f, "%.0f%%");
|
||||
|
||||
const std::string deadzone_key(fmt::format("Macro{}Deadzone", macro_index + 1));
|
||||
DrawFloatSpinBoxSetting(bsi, ICON_FA_ARROW_DOWN " Pressure", "Determines the pressure required to activate the macro.",
|
||||
section, deadzone_key.c_str(), 0.0f, 0.00f, 1.0f, 0.01f, 100.0f, "%.0f%%");
|
||||
|
||||
ImGui::SetNextWindowSize(LayoutScale(500.0f, 180.0f));
|
||||
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
|
||||
@@ -4018,18 +4018,15 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
if (ci->num_settings > 0)
|
||||
if (!ci->settings.empty())
|
||||
{
|
||||
MenuHeading((mtap_enabled[mtap_port] ?
|
||||
fmt::format(ICON_FA_SLIDERS_H " Controller Port {}{} Settings", mtap_port + 1, mtap_slot_names[mtap_slot]) :
|
||||
fmt::format(ICON_FA_SLIDERS_H " Controller Port {} Settings", mtap_port + 1))
|
||||
.c_str());
|
||||
|
||||
for (u32 i = 0; i < ci->num_settings; i++)
|
||||
{
|
||||
const SettingInfo& si = ci->settings[i];
|
||||
for (const SettingInfo& si : ci->settings)
|
||||
DrawSettingInfoSetting(bsi, section, si.name, si);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
@@ -4109,7 +4106,10 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
|
||||
const std::string section(USB::GetConfigSection(port));
|
||||
for (const InputBindingInfo& bi : bindings)
|
||||
DrawInputBindingButton(bsi, bi.bind_type, section.c_str(), USB::GetConfigSubKey(type, bi.name).c_str(), bi.display_name);
|
||||
{
|
||||
DrawInputBindingButton(bsi, bi.bind_type, section.c_str(), USB::GetConfigSubKey(type, bi.name).c_str(),
|
||||
Host::TranslateToCString("USB", bi.display_name));
|
||||
}
|
||||
}
|
||||
|
||||
const std::span<const SettingInfo> settings(USB::GetDeviceSettings(type, subtype));
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "fmt/core.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "common/Image.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
@@ -47,6 +48,17 @@
|
||||
|
||||
namespace ImGuiManager
|
||||
{
|
||||
struct SoftwareCursor
|
||||
{
|
||||
std::string image_path;
|
||||
std::unique_ptr<GSTexture> texture;
|
||||
u32 color;
|
||||
float scale;
|
||||
float extent_x;
|
||||
float extent_y;
|
||||
std::pair<float, float> pos;
|
||||
};
|
||||
|
||||
static void SetStyle();
|
||||
static void SetKeyMap();
|
||||
static bool LoadFontData();
|
||||
@@ -57,6 +69,11 @@ namespace ImGuiManager
|
||||
static bool AddIconFonts(float size);
|
||||
static void AcquirePendingOSDMessages();
|
||||
static void DrawOSDMessages();
|
||||
static void CreateSoftwareCursorTextures();
|
||||
static void UpdateSoftwareCursorTexture(u32 index);
|
||||
static void DestroySoftwareCursorTextures();
|
||||
static void DrawSoftwareCursor(const SoftwareCursor& sc, const std::pair<float, float>& pos);
|
||||
static void DrawSoftwareCursors();
|
||||
} // namespace ImGuiManager
|
||||
|
||||
static float s_global_scale = 1.0f;
|
||||
@@ -73,6 +90,8 @@ static std::vector<u8> s_standard_font_data;
|
||||
static std::vector<u8> s_fixed_font_data;
|
||||
static std::vector<u8> s_icon_font_data;
|
||||
|
||||
static float s_window_width;
|
||||
static float s_window_height;
|
||||
static Common::Timer s_last_render_time;
|
||||
|
||||
// cached copies of WantCaptureKeyboard/Mouse, used to know when to dispatch events
|
||||
@@ -86,6 +105,8 @@ static std::unordered_map<u32, ImGuiKey> s_imgui_key_map;
|
||||
// need to keep track of this, so we can reinitialize on renderer switch
|
||||
static bool s_fullscreen_ui_was_initialized = false;
|
||||
|
||||
static std::array<ImGuiManager::SoftwareCursor, InputManager::MAX_SOFTWARE_CURSORS> s_software_cursors = {};
|
||||
|
||||
void ImGuiManager::SetFontPath(std::string path)
|
||||
{
|
||||
s_font_path = std::move(path);
|
||||
@@ -146,6 +167,7 @@ bool ImGuiManager::Initialize()
|
||||
if (add_fullscreen_fonts)
|
||||
InitializeFullscreenUI();
|
||||
|
||||
CreateSoftwareCursorTextures();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -157,6 +179,8 @@ bool ImGuiManager::InitializeFullscreenUI()
|
||||
|
||||
void ImGuiManager::Shutdown(bool clear_state)
|
||||
{
|
||||
DestroySoftwareCursorTextures();
|
||||
|
||||
FullscreenUI::Shutdown(clear_state);
|
||||
ImGuiFullscreen::SetFonts(nullptr, nullptr, nullptr);
|
||||
if (clear_state)
|
||||
@@ -174,12 +198,24 @@ void ImGuiManager::Shutdown(bool clear_state)
|
||||
UnloadFontData();
|
||||
}
|
||||
|
||||
float ImGuiManager::GetWindowWidth()
|
||||
{
|
||||
return s_window_width;
|
||||
}
|
||||
|
||||
float ImGuiManager::GetWindowHeight()
|
||||
{
|
||||
return s_window_height;
|
||||
}
|
||||
|
||||
void ImGuiManager::WindowResized()
|
||||
{
|
||||
const u32 new_width = g_gs_device ? g_gs_device->GetWindowWidth() : 0;
|
||||
const u32 new_height = g_gs_device ? g_gs_device->GetWindowHeight() : 0;
|
||||
|
||||
ImGui::GetIO().DisplaySize = ImVec2(static_cast<float>(new_width), static_cast<float>(new_height));
|
||||
s_window_width = static_cast<float>(new_width);
|
||||
s_window_height = static_cast<float>(new_height);
|
||||
ImGui::GetIO().DisplaySize = ImVec2(s_window_width, s_window_height);
|
||||
|
||||
UpdateScale();
|
||||
|
||||
@@ -672,6 +708,7 @@ void ImGuiManager::RenderOSD()
|
||||
|
||||
AcquirePendingOSDMessages();
|
||||
DrawOSDMessages();
|
||||
DrawSoftwareCursors();
|
||||
}
|
||||
|
||||
float ImGuiManager::GetGlobalScale()
|
||||
@@ -810,3 +847,112 @@ bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGuiManager::CreateSoftwareCursorTextures()
|
||||
{
|
||||
for (u32 i = 0; i < InputManager::MAX_POINTER_DEVICES; i++)
|
||||
{
|
||||
if (!s_software_cursors[i].image_path.empty())
|
||||
UpdateSoftwareCursorTexture(i);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiManager::DestroySoftwareCursorTextures()
|
||||
{
|
||||
for (u32 i = 0; i < InputManager::MAX_POINTER_DEVICES; i++)
|
||||
{
|
||||
s_software_cursors[i].texture.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiManager::UpdateSoftwareCursorTexture(u32 index)
|
||||
{
|
||||
SoftwareCursor& sc = s_software_cursors[index];
|
||||
if (sc.image_path.empty())
|
||||
{
|
||||
sc.texture.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
Common::RGBA8Image image;
|
||||
if (!image.LoadFromFile(sc.image_path.c_str()))
|
||||
{
|
||||
Console.Error("Failed to load software cursor %u image '%s'", index, sc.image_path.c_str());
|
||||
return;
|
||||
}
|
||||
sc.texture = std::unique_ptr<GSTexture>(g_gs_device->CreateTexture(image.GetWidth(), image.GetHeight(), 1, GSTexture::Format::Color));
|
||||
if (!sc.texture)
|
||||
{
|
||||
Console.Error(
|
||||
"Failed to upload %ux%u software cursor %u image '%s'", image.GetWidth(), image.GetHeight(), index, sc.image_path.c_str());
|
||||
return;
|
||||
}
|
||||
sc.texture->Update(GSVector4i(0, 0, image.GetWidth(), image.GetHeight()), image.GetPixels(), image.GetByteStride(), 0);
|
||||
|
||||
sc.extent_x = std::ceil(static_cast<float>(image.GetWidth()) * sc.scale * s_global_scale) / 2.0f;
|
||||
sc.extent_y = std::ceil(static_cast<float>(image.GetHeight()) * sc.scale * s_global_scale) / 2.0f;
|
||||
}
|
||||
|
||||
void ImGuiManager::DrawSoftwareCursor(const SoftwareCursor& sc, const std::pair<float, float>& pos)
|
||||
{
|
||||
if (!sc.texture)
|
||||
return;
|
||||
|
||||
const ImVec2 min(pos.first - sc.extent_x, pos.second - sc.extent_y);
|
||||
const ImVec2 max(pos.first + sc.extent_x, pos.second + sc.extent_y);
|
||||
|
||||
ImDrawList* dl = ImGui::GetForegroundDrawList();
|
||||
|
||||
dl->AddImage(
|
||||
reinterpret_cast<ImTextureID>(sc.texture.get()->GetNativeHandle()), min, max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), sc.color);
|
||||
}
|
||||
|
||||
void ImGuiManager::DrawSoftwareCursors()
|
||||
{
|
||||
// This one's okay to race, worst that happens is we render the wrong number of cursors for a frame.
|
||||
const u32 pointer_count = InputManager::MAX_POINTER_DEVICES;
|
||||
for (u32 i = 0; i < pointer_count; i++)
|
||||
DrawSoftwareCursor(s_software_cursors[i], InputManager::GetPointerAbsolutePosition(i));
|
||||
|
||||
for (u32 i = InputManager::MAX_POINTER_DEVICES; i < InputManager::MAX_SOFTWARE_CURSORS; i++)
|
||||
DrawSoftwareCursor(s_software_cursors[i], s_software_cursors[i].pos);
|
||||
}
|
||||
|
||||
void ImGuiManager::SetSoftwareCursor(u32 index, std::string image_path, float image_scale, u32 multiply_color)
|
||||
{
|
||||
MTGS::RunOnGSThread([index, image_path = std::move(image_path), image_scale, multiply_color]() {
|
||||
pxAssert(index < std::size(s_software_cursors));
|
||||
SoftwareCursor& sc = s_software_cursors[index];
|
||||
sc.color = multiply_color | 0xFF000000;
|
||||
if (sc.image_path == image_path && sc.scale == image_scale)
|
||||
return;
|
||||
|
||||
const bool is_hiding_or_showing = (image_path.empty() != sc.image_path.empty());
|
||||
sc.image_path = std::move(image_path);
|
||||
sc.scale = image_scale;
|
||||
if (MTGS::IsOpen())
|
||||
UpdateSoftwareCursorTexture(index);
|
||||
|
||||
// Hide the system cursor when we activate a software cursor.
|
||||
if (is_hiding_or_showing && index == 0)
|
||||
Host::RunOnCPUThread(&InputManager::UpdateHostMouseMode);
|
||||
});
|
||||
}
|
||||
|
||||
bool ImGuiManager::HasSoftwareCursor(u32 index)
|
||||
{
|
||||
return (index < s_software_cursors.size() && !s_software_cursors[index].image_path.empty());
|
||||
}
|
||||
|
||||
void ImGuiManager::ClearSoftwareCursor(u32 index)
|
||||
{
|
||||
SetSoftwareCursor(index, std::string(), 0.0f, 0);
|
||||
}
|
||||
|
||||
void ImGuiManager::SetSoftwareCursorPosition(u32 index, float pos_x, float pos_y)
|
||||
{
|
||||
pxAssert(index >= InputManager::MAX_POINTER_DEVICES);
|
||||
SoftwareCursor& sc = s_software_cursors[index];
|
||||
sc.pos.first = pos_x;
|
||||
sc.pos.second = pos_y;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,10 @@ namespace ImGuiManager
|
||||
/// Frees all ImGui resources.
|
||||
void Shutdown(bool clear_state);
|
||||
|
||||
/// Returns the size of the display window. Can be safely called from any thread.
|
||||
float GetWindowWidth();
|
||||
float GetWindowHeight();
|
||||
|
||||
/// Updates internal state when the window is size.
|
||||
void WindowResized();
|
||||
|
||||
@@ -102,6 +106,14 @@ namespace ImGuiManager
|
||||
|
||||
/// Called on the CPU thread when any input event fires. Allows imgui to take over controller navigation.
|
||||
bool ProcessGenericInputEvent(GenericInputBinding key, float value);
|
||||
|
||||
/// Sets an image and scale for a software cursor. Software cursors can be used for things like crosshairs.
|
||||
void SetSoftwareCursor(u32 index, std::string image_path, float image_scale, u32 multiply_color = 0xFFFFFF);
|
||||
bool HasSoftwareCursor(u32 index);
|
||||
void ClearSoftwareCursor(u32 index);
|
||||
|
||||
/// Sets the position of a software cursor, used when we have relative coordinates such as controllers.
|
||||
void SetSoftwareCursorPosition(u32 index, float pos_x, float pos_y);
|
||||
} // namespace ImGuiManager
|
||||
|
||||
namespace Host
|
||||
|
||||
@@ -29,11 +29,11 @@
|
||||
#include "ImGui/ImGuiOverlays.h"
|
||||
#include "Input/InputManager.h"
|
||||
#include "PerformanceMetrics.h"
|
||||
#include "Recording/InputRecording.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
#include "USB/USB.h"
|
||||
#include "VMManager.h"
|
||||
#include "pcsx2/Recording/InputRecording.h"
|
||||
#include "SIO/Pad/PadConfig.h"
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
|
||||
#include "common/BitUtils.h"
|
||||
#include "common/StringUtil.h"
|
||||
@@ -408,10 +408,10 @@ void ImGuiManager::DrawSettingsOverlay()
|
||||
APPEND("SD={}/{} ", GSConfig.SkipDrawStart, GSConfig.SkipDrawEnd);
|
||||
if (GSConfig.UserHacks_TextureInsideRt != GSTextureInRtMode::Disabled)
|
||||
APPEND("TexRT={} ", static_cast<unsigned>(GSConfig.UserHacks_TextureInsideRt));
|
||||
if (GSConfig.UserHacks_BilinearHack != GSBilinearDirtyMode::Automatic)
|
||||
APPEND("BLU={} ", static_cast<unsigned>(GSConfig.UserHacks_BilinearHack));
|
||||
if (GSConfig.UserHacks_WildHack)
|
||||
APPEND("WA ");
|
||||
if (GSConfig.UserHacks_BilinearHack)
|
||||
APPEND("BLU ");
|
||||
if (GSConfig.UserHacks_NativePaletteDraw)
|
||||
APPEND("NPD ");
|
||||
if (GSConfig.UserHacks_MergePPSprite)
|
||||
@@ -485,18 +485,8 @@ void ImGuiManager::DrawInputsOverlay()
|
||||
|
||||
for (u32 slot = 0; slot < Pad::NUM_CONTROLLER_PORTS; slot++)
|
||||
{
|
||||
const std::optional<PadBase*> padOpt = g_PadManager.GetPad(slot);
|
||||
|
||||
if (padOpt.has_value())
|
||||
{
|
||||
PadBase* pad = padOpt.value();
|
||||
const Pad::ControllerType ctype = pad->GetType();
|
||||
|
||||
if (ctype != Pad::ControllerType::NotConnected)
|
||||
{
|
||||
num_ports++;
|
||||
}
|
||||
}
|
||||
if (Pad::HasConnectedPad(slot))
|
||||
num_ports++;
|
||||
}
|
||||
|
||||
for (u32 port = 0; port < USB::NUM_PORTS; port++)
|
||||
@@ -515,65 +505,55 @@ void ImGuiManager::DrawInputsOverlay()
|
||||
|
||||
for (u32 slot = 0; slot < Pad::NUM_CONTROLLER_PORTS; slot++)
|
||||
{
|
||||
const std::optional<PadBase*> padOpt = g_PadManager.GetPad(slot);
|
||||
const PadBase* const pad = Pad::GetPad(slot);
|
||||
const Pad::ControllerType ctype = pad->GetType();
|
||||
if (ctype == Pad::ControllerType::NotConnected)
|
||||
continue;
|
||||
|
||||
text.clear();
|
||||
fmt::format_to(std::back_inserter(text), "P{} |", slot + 1u);
|
||||
|
||||
if (padOpt.has_value())
|
||||
const Pad::ControllerInfo& cinfo = pad->GetInfo();
|
||||
for (u32 bind = 0; bind < static_cast<u32>(cinfo.bindings.size()); bind++)
|
||||
{
|
||||
PadBase* pad = padOpt.value();
|
||||
const Pad::ControllerType ctype = pad->GetType();
|
||||
|
||||
if (ctype == Pad::ControllerType::NotConnected)
|
||||
continue;
|
||||
|
||||
const PadConfig::ControllerInfo* cinfo = g_PadConfig.GetControllerInfo(ctype);
|
||||
|
||||
if (!cinfo)
|
||||
continue;
|
||||
|
||||
text.clear();
|
||||
fmt::format_to(std::back_inserter(text), "P{} |", slot + 1u);
|
||||
|
||||
for (u32 bind = 0; bind < cinfo->num_bindings; bind++)
|
||||
const InputBindingInfo& bi = cinfo.bindings[bind];
|
||||
switch (bi.bind_type)
|
||||
{
|
||||
const InputBindingInfo& bi = cinfo->bindings[bind];
|
||||
switch (bi.bind_type)
|
||||
case InputBindingInfo::Type::Axis:
|
||||
case InputBindingInfo::Type::HalfAxis:
|
||||
{
|
||||
case InputBindingInfo::Type::Axis:
|
||||
case InputBindingInfo::Type::HalfAxis:
|
||||
{
|
||||
// axes are always shown
|
||||
const float value = static_cast<float>(pad->GetRawInput(bind)) * (1.0f / 255.0f);
|
||||
if (value >= (254.0f / 255.0f))
|
||||
fmt::format_to(std::back_inserter(text), " {}", bi.name);
|
||||
else if (value > (1.0f / 255.0f))
|
||||
fmt::format_to(std::back_inserter(text), " {}: {:.2f}", bi.name, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case InputBindingInfo::Type::Button:
|
||||
{
|
||||
// buttons only shown when active
|
||||
const float value = static_cast<float>(pad->GetRawInput(bind)) * (1.0f / 255.0f);
|
||||
if (value >= 0.5f)
|
||||
fmt::format_to(std::back_inserter(text), " {}", bi.name);
|
||||
}
|
||||
break;
|
||||
|
||||
case InputBindingInfo::Type::Motor:
|
||||
case InputBindingInfo::Type::Macro:
|
||||
case InputBindingInfo::Type::Unknown:
|
||||
default:
|
||||
break;
|
||||
// axes are always shown
|
||||
const float value = static_cast<float>(pad->GetRawInput(bind)) * (1.0f / 255.0f);
|
||||
if (value >= (254.0f / 255.0f))
|
||||
fmt::format_to(std::back_inserter(text), " {}", bi.name);
|
||||
else if (value > (1.0f / 255.0f))
|
||||
fmt::format_to(std::back_inserter(text), " {}: {:.2f}", bi.name, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case InputBindingInfo::Type::Button:
|
||||
{
|
||||
// buttons only shown when active
|
||||
const float value = static_cast<float>(pad->GetRawInput(bind)) * (1.0f / 255.0f);
|
||||
if (value >= 0.5f)
|
||||
fmt::format_to(std::back_inserter(text), " {}", bi.name);
|
||||
}
|
||||
break;
|
||||
|
||||
case InputBindingInfo::Type::Motor:
|
||||
case InputBindingInfo::Type::Macro:
|
||||
case InputBindingInfo::Type::Unknown:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dl->AddText(font, font->FontSize, ImVec2(current_x + shadow_offset, current_y + shadow_offset), shadow_color, text.c_str(),
|
||||
text.c_str() + text.length(), 0.0f, &clip_rect);
|
||||
dl->AddText(
|
||||
font, font->FontSize, ImVec2(current_x, current_y), text_color, text.c_str(), text.c_str() + text.length(), 0.0f, &clip_rect);
|
||||
|
||||
current_y += font->FontSize + spacing;
|
||||
}
|
||||
|
||||
dl->AddText(font, font->FontSize, ImVec2(current_x + shadow_offset, current_y + shadow_offset), shadow_color, text.c_str(),
|
||||
text.c_str() + text.length(), 0.0f, &clip_rect);
|
||||
dl->AddText(
|
||||
font, font->FontSize, ImVec2(current_x, current_y), text_color, text.c_str(), text.c_str() + text.length(), 0.0f, &clip_rect);
|
||||
|
||||
current_y += font->FontSize + spacing;
|
||||
}
|
||||
|
||||
for (u32 port = 0; port < USB::NUM_PORTS; port++)
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#include "ImGui/ImGuiManager.h"
|
||||
#include "Input/InputManager.h"
|
||||
#include "Input/InputSource.h"
|
||||
#include "SIO/Pad/PadConfig.h"
|
||||
#include "SIO/Pad/PadMacros.h"
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "USB/USB.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
@@ -634,14 +632,12 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
|
||||
if (type.empty() || type == "None")
|
||||
return;
|
||||
|
||||
const PadConfig::ControllerInfo* cinfo = g_PadConfig.GetControllerInfo(type);
|
||||
const Pad::ControllerInfo* cinfo = Pad::GetControllerInfo(type);
|
||||
if (!cinfo)
|
||||
return;
|
||||
|
||||
for (u32 i = 0; i < cinfo->num_bindings; i++)
|
||||
for (const InputBindingInfo& bi : cinfo->bindings)
|
||||
{
|
||||
const InputBindingInfo& bi = cinfo->bindings[i];
|
||||
|
||||
switch (bi.bind_type)
|
||||
{
|
||||
case InputBindingInfo::Type::Button:
|
||||
@@ -656,7 +652,7 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
|
||||
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f);
|
||||
AddBindings(
|
||||
bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity, deadzone](float value) {
|
||||
g_PadManager.SetControllerState(pad_index, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||
Pad::SetControllerState(pad_index, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||
}});
|
||||
}
|
||||
}
|
||||
@@ -669,13 +665,15 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 macro_button_index = 0; macro_button_index < PadMacros::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_button_index++)
|
||||
for (u32 macro_button_index = 0; macro_button_index < Pad::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_button_index++)
|
||||
{
|
||||
const std::vector<std::string> bindings(si.GetStringList(section.c_str(), fmt::format("Macro{}", macro_button_index + 1).c_str()));
|
||||
if (!bindings.empty())
|
||||
{
|
||||
AddBindings(bindings, InputButtonEventHandler{[pad_index, macro_button_index](bool state) {
|
||||
g_PadMacros.SetMacroButtonState(pad_index, macro_button_index, state);
|
||||
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("Macro{}Deadzone", macro_button_index + 1).c_str(), 0.0f);
|
||||
AddBindings(bindings, InputAxisEventHandler{[pad_index, macro_button_index, deadzone](float value) {
|
||||
const bool state = (value > deadzone);
|
||||
Pad::SetMacroButtonState(pad_index, macro_button_index, state);
|
||||
}});
|
||||
}
|
||||
}
|
||||
@@ -1293,7 +1291,7 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
|
||||
// If there's an input profile, we load pad bindings from it alone, rather than
|
||||
// falling back to the base configuration.
|
||||
for (u32 pad = 0; pad < Pad::NUM_CONTROLLER_PORTS; pad++)
|
||||
AddPadBindings(binding_si, pad, g_PadConfig.GetDefaultPadType(pad));
|
||||
AddPadBindings(binding_si, pad, Pad::GetDefaultPadType(pad));
|
||||
|
||||
constexpr float ui_ctrl_range = 100.0f;
|
||||
constexpr float pointer_sensitivity = 0.05f;
|
||||
@@ -1311,6 +1309,11 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
|
||||
for (u32 port = 0; port < USB::NUM_PORTS; port++)
|
||||
AddUSBBindings(binding_si, port);
|
||||
|
||||
UpdateHostMouseMode();
|
||||
}
|
||||
|
||||
void InputManager::UpdateHostMouseMode()
|
||||
{
|
||||
// Check for relative mode bindings, and enable if there's anything using it.
|
||||
bool has_relative_mode_bindings = !s_pointer_move_callbacks.empty();
|
||||
if (!has_relative_mode_bindings)
|
||||
@@ -1326,7 +1329,9 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
|
||||
}
|
||||
}
|
||||
}
|
||||
Host::SetRelativeMouseMode(has_relative_mode_bindings);
|
||||
|
||||
const bool has_software_cursor = ImGuiManager::HasSoftwareCursor(0);
|
||||
Host::SetMouseMode(has_relative_mode_bindings, has_relative_mode_bindings || has_software_cursor);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -170,6 +170,10 @@ namespace InputManager
|
||||
static constexpr u32 MAX_POINTER_DEVICES = 1;
|
||||
static constexpr u32 MAX_POINTER_BUTTONS = 3;
|
||||
|
||||
/// Maximum number of software cursors. We allocate an extra two for USB devices with
|
||||
/// positioning data from the controller instead of a mouse.
|
||||
static constexpr u32 MAX_SOFTWARE_CURSORS = MAX_POINTER_BUTTONS + 2;
|
||||
|
||||
/// Returns a pointer to the external input source class, if present.
|
||||
InputSource* GetInputSourceInterface(InputSourceType type);
|
||||
|
||||
@@ -287,6 +291,9 @@ namespace InputManager
|
||||
/// Updates relative pointer position. Can call from the UI thread, use when host supports relative coordinate reporting.
|
||||
void UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input = false);
|
||||
|
||||
/// Updates host mouse mode (relative/cursor hiding).
|
||||
void UpdateHostMouseMode();
|
||||
|
||||
/// Called when a new input device is connected.
|
||||
void OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name);
|
||||
|
||||
@@ -305,6 +312,6 @@ namespace Host
|
||||
/// Called when an input device is disconnected.
|
||||
void OnInputDeviceDisconnected(const std::string_view& identifier);
|
||||
|
||||
/// Enables relative mouse mode in the host.
|
||||
void SetRelativeMouseMode(bool enabled);
|
||||
/// Enables relative mouse mode in the host, and/or hides the cursor.
|
||||
void SetMouseMode(bool relative_mode, bool hide_cursor);
|
||||
} // namespace Host
|
||||
|
||||
@@ -155,7 +155,7 @@ bool LayeredSettingsInterface::ContainsValue(const char* section, const char* ke
|
||||
{
|
||||
if (SettingsInterface* sif = m_layers[layer])
|
||||
{
|
||||
if (sif->ContainsValue(key, section))
|
||||
if (sif->ContainsValue(section, key))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,7 +538,7 @@ Pcsx2Config::GSOptions::GSOptions()
|
||||
UserHacks_DisableRenderFixes = false;
|
||||
UserHacks_MergePPSprite = false;
|
||||
UserHacks_WildHack = false;
|
||||
UserHacks_BilinearHack = false;
|
||||
UserHacks_BilinearHack = GSBilinearDirtyMode::Automatic;
|
||||
UserHacks_NativePaletteDraw = false;
|
||||
|
||||
DumpReplaceableTextures = false;
|
||||
@@ -625,6 +625,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
|
||||
OpEqu(UserHacks_CPUCLUTRender) &&
|
||||
OpEqu(UserHacks_GPUTargetCLUTMode) &&
|
||||
OpEqu(UserHacks_TextureInsideRt) &&
|
||||
OpEqu(UserHacks_BilinearHack) &&
|
||||
OpEqu(OverrideTextureBarriers) &&
|
||||
|
||||
OpEqu(CAS_Sharpness) &&
|
||||
@@ -758,7 +759,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
|
||||
GSSettingBoolEx(UserHacks_DisableRenderFixes, "UserHacks_DisableRenderFixes");
|
||||
GSSettingBoolEx(UserHacks_MergePPSprite, "UserHacks_merge_pp_sprite");
|
||||
GSSettingBoolEx(UserHacks_WildHack, "UserHacks_WildHack");
|
||||
GSSettingBoolEx(UserHacks_BilinearHack, "UserHacks_BilinearHack");
|
||||
GSSettingIntEnumEx(UserHacks_BilinearHack, "UserHacks_BilinearHack");
|
||||
GSSettingBoolEx(UserHacks_NativePaletteDraw, "UserHacks_NativePaletteDraw");
|
||||
GSSettingIntEnumEx(UserHacks_TextureInsideRt, "UserHacks_TextureInsideRt");
|
||||
GSSettingBoolEx(UserHacks_TargetPartialInvalidation, "UserHacks_TargetPartialInvalidation");
|
||||
@@ -877,7 +878,6 @@ void Pcsx2Config::GSOptions::MaskUserHacks()
|
||||
UserHacks_AlignSpriteX = false;
|
||||
UserHacks_MergePPSprite = false;
|
||||
UserHacks_WildHack = false;
|
||||
UserHacks_BilinearHack = false;
|
||||
UserHacks_NativePaletteDraw = false;
|
||||
UserHacks_DisableSafeFeatures = false;
|
||||
UserHacks_DisableRenderFixes = false;
|
||||
@@ -899,6 +899,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks()
|
||||
UserHacks_CPUSpriteRenderLevel = 0;
|
||||
UserHacks_CPUCLUTRender = 0;
|
||||
UserHacks_GPUTargetCLUTMode = GSGPUTargetCLUTMode::Disabled;
|
||||
UserHacks_BilinearHack = GSBilinearDirtyMode::Automatic;
|
||||
SkipDrawStart = 0;
|
||||
SkipDrawEnd = 0;
|
||||
}
|
||||
@@ -911,7 +912,7 @@ void Pcsx2Config::GSOptions::MaskUpscalingHacks()
|
||||
UserHacks_AlignSpriteX = false;
|
||||
UserHacks_MergePPSprite = false;
|
||||
UserHacks_WildHack = false;
|
||||
UserHacks_BilinearHack = false;
|
||||
UserHacks_BilinearHack = GSBilinearDirtyMode::Automatic;
|
||||
UserHacks_NativePaletteDraw = false;
|
||||
UserHacks_HalfPixelOffset = 0;
|
||||
UserHacks_RoundSprite = 0;
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "Recording/PadData.h"
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/PadDualshock2Types.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Pad/PadDualshock2.h"
|
||||
#include "SIO/Sio.h"
|
||||
|
||||
#include <fmt/core.h>
|
||||
@@ -28,7 +28,7 @@ PadData::PadData(const int port, const int slot)
|
||||
m_port = port;
|
||||
m_slot = slot;
|
||||
m_ext_port = sioConvertPortAndSlotToPad(m_port, m_slot);
|
||||
PadBase* pad = g_PadManager.GetPad(m_ext_port);
|
||||
PadBase* pad = Pad::GetPad(m_ext_port);
|
||||
// Get the state of the buttons
|
||||
// TODO - for the new recording file format, allow informing max number of buttons per frame per controller as well (ie. the analog button)
|
||||
const u32 buttons = pad->GetButtons();
|
||||
@@ -56,23 +56,23 @@ PadData::PadData(const int port, const int slot)
|
||||
m_rightAnalog = pad->GetRawRightAnalog();
|
||||
m_leftAnalog = pad->GetRawLeftAnalog();
|
||||
// Get pressure bytes (12 of them)
|
||||
m_left = {(0b10000000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_LEFT)};
|
||||
m_down = {(0b01000000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_DOWN)};
|
||||
m_right = {(0b00100000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_RIGHT)};
|
||||
m_up = {(0b00010000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_UP)};
|
||||
m_left = {(0b10000000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_LEFT)};
|
||||
m_down = {(0b01000000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_DOWN)};
|
||||
m_right = {(0b00100000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_RIGHT)};
|
||||
m_up = {(0b00010000 & m_compactPressFlagsGroupOne) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_UP)};
|
||||
m_start = (0b00001000 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_r3 = (0b00000100 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_l3 = (0b00000010 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_select = (0b00000001 & m_compactPressFlagsGroupOne) == 0;
|
||||
|
||||
m_square = {(0b10000000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_SQUARE)};
|
||||
m_cross = {(0b01000000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_CROSS)};
|
||||
m_circle = {(0b00100000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_CIRCLE)};
|
||||
m_triangle = {(0b00010000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_TRIANGLE)};
|
||||
m_r1 = {(0b00001000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_R1)};
|
||||
m_l1 = {(0b00000100 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_L1)};
|
||||
m_r2 = {(0b00000010 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_R2)};
|
||||
m_l2 = {(0b00000001 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(Dualshock2::Inputs::PAD_L2)};
|
||||
m_square = {(0b10000000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_SQUARE)};
|
||||
m_cross = {(0b01000000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_CROSS)};
|
||||
m_circle = {(0b00100000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_CIRCLE)};
|
||||
m_triangle = {(0b00010000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_TRIANGLE)};
|
||||
m_r1 = {(0b00001000 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_R1)};
|
||||
m_l1 = {(0b00000100 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_L1)};
|
||||
m_r2 = {(0b00000010 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_R2)};
|
||||
m_l2 = {(0b00000001 & m_compactPressFlagsGroupTwo) == 0, pad->GetRawInput(PadDualshock2::Inputs::PAD_L2)};
|
||||
}
|
||||
|
||||
PadData::PadData(const int port, const int slot, const std::array<u8, 18> data)
|
||||
@@ -81,54 +81,54 @@ PadData::PadData(const int port, const int slot, const std::array<u8, 18> data)
|
||||
m_slot = slot;
|
||||
m_ext_port = sioConvertPortAndSlotToPad(m_port, m_slot);
|
||||
|
||||
m_compactPressFlagsGroupOne = data.at(0);
|
||||
m_compactPressFlagsGroupTwo = data.at(1);
|
||||
m_compactPressFlagsGroupOne = data[0];
|
||||
m_compactPressFlagsGroupTwo = data[1];
|
||||
|
||||
m_rightAnalog = {data.at(2), data.at(3)};
|
||||
m_leftAnalog = {data.at(4), data.at(5)};
|
||||
m_rightAnalog = {data[2], data[3]};
|
||||
m_leftAnalog = {data[4], data[5]};
|
||||
|
||||
m_left = {(0b10000000 & m_compactPressFlagsGroupOne) == 0, data.at(7)};
|
||||
m_down = {(0b01000000 & m_compactPressFlagsGroupOne) == 0, data.at(9)};
|
||||
m_right = {(0b00100000 & m_compactPressFlagsGroupOne) == 0, data.at(6)};
|
||||
m_up = {(0b00010000 & m_compactPressFlagsGroupOne) == 0, data.at(8)};
|
||||
m_left = {(0b10000000 & m_compactPressFlagsGroupOne) == 0, data[7]};
|
||||
m_down = {(0b01000000 & m_compactPressFlagsGroupOne) == 0, data[9]};
|
||||
m_right = {(0b00100000 & m_compactPressFlagsGroupOne) == 0, data[6]};
|
||||
m_up = {(0b00010000 & m_compactPressFlagsGroupOne) == 0, data[8]};
|
||||
m_start = (0b00001000 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_r3 = (0b00000100 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_l3 = (0b00000010 & m_compactPressFlagsGroupOne) == 0;
|
||||
m_select = (0b00000001 & m_compactPressFlagsGroupOne) == 0;
|
||||
|
||||
m_square = {(0b10000000 & m_compactPressFlagsGroupTwo) == 0, data.at(13)};
|
||||
m_cross = {(0b01000000 & m_compactPressFlagsGroupTwo) == 0, data.at(12)};
|
||||
m_circle = {(0b00100000 & m_compactPressFlagsGroupTwo) == 0, data.at(11)};
|
||||
m_triangle = {(0b00010000 & m_compactPressFlagsGroupTwo) == 0, data.at(10)};
|
||||
m_r1 = {(0b00001000 & m_compactPressFlagsGroupTwo) == 0, data.at(15)};
|
||||
m_l1 = {(0b00000100 & m_compactPressFlagsGroupTwo) == 0, data.at(14)};
|
||||
m_r2 = {(0b00000010 & m_compactPressFlagsGroupTwo) == 0, data.at(17)};
|
||||
m_l2 = {(0b00000001 & m_compactPressFlagsGroupTwo) == 0, data.at(16)};
|
||||
m_square = {(0b10000000 & m_compactPressFlagsGroupTwo) == 0, data[13]};
|
||||
m_cross = {(0b01000000 & m_compactPressFlagsGroupTwo) == 0, data[12]};
|
||||
m_circle = {(0b00100000 & m_compactPressFlagsGroupTwo) == 0, data[11]};
|
||||
m_triangle = {(0b00010000 & m_compactPressFlagsGroupTwo) == 0, data[10]};
|
||||
m_r1 = {(0b00001000 & m_compactPressFlagsGroupTwo) == 0, data[15]};
|
||||
m_l1 = {(0b00000100 & m_compactPressFlagsGroupTwo) == 0, data[14]};
|
||||
m_r2 = {(0b00000010 & m_compactPressFlagsGroupTwo) == 0, data[17]};
|
||||
m_l2 = {(0b00000001 & m_compactPressFlagsGroupTwo) == 0, data[16]};
|
||||
}
|
||||
|
||||
void PadData::OverrideActualController() const
|
||||
{
|
||||
PadBase* pad = g_PadManager.GetPad(m_ext_port);
|
||||
PadBase* pad = Pad::GetPad(m_ext_port);
|
||||
pad->SetRawAnalogs(m_leftAnalog, m_rightAnalog);
|
||||
|
||||
pad->Set(Dualshock2::Inputs::PAD_RIGHT, std::get<1>(m_right));
|
||||
pad->Set(Dualshock2::Inputs::PAD_LEFT, std::get<1>(m_left));
|
||||
pad->Set(Dualshock2::Inputs::PAD_UP, std::get<1>(m_up));
|
||||
pad->Set(Dualshock2::Inputs::PAD_DOWN, std::get<1>(m_down));
|
||||
pad->Set(Dualshock2::Inputs::PAD_START, m_start);
|
||||
pad->Set(Dualshock2::Inputs::PAD_SELECT, m_select);
|
||||
pad->Set(Dualshock2::Inputs::PAD_R3, m_r3);
|
||||
pad->Set(Dualshock2::Inputs::PAD_L3, m_l3);
|
||||
pad->Set(PadDualshock2::Inputs::PAD_RIGHT, std::get<1>(m_right));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_LEFT, std::get<1>(m_left));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_UP, std::get<1>(m_up));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_DOWN, std::get<1>(m_down));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_START, m_start);
|
||||
pad->Set(PadDualshock2::Inputs::PAD_SELECT, m_select);
|
||||
pad->Set(PadDualshock2::Inputs::PAD_R3, m_r3);
|
||||
pad->Set(PadDualshock2::Inputs::PAD_L3, m_l3);
|
||||
|
||||
pad->Set(Dualshock2::Inputs::PAD_SQUARE, std::get<1>(m_square));
|
||||
pad->Set(Dualshock2::Inputs::PAD_CROSS, std::get<1>(m_cross));
|
||||
pad->Set(Dualshock2::Inputs::PAD_CIRCLE, std::get<1>(m_circle));
|
||||
pad->Set(Dualshock2::Inputs::PAD_TRIANGLE, std::get<1>(m_triangle));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_SQUARE, std::get<1>(m_square));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_CROSS, std::get<1>(m_cross));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_CIRCLE, std::get<1>(m_circle));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_TRIANGLE, std::get<1>(m_triangle));
|
||||
|
||||
pad->Set(Dualshock2::Inputs::PAD_R1, std::get<1>(m_r1));
|
||||
pad->Set(Dualshock2::Inputs::PAD_L1, std::get<1>(m_l1));
|
||||
pad->Set(Dualshock2::Inputs::PAD_R2, std::get<1>(m_r2));
|
||||
pad->Set(Dualshock2::Inputs::PAD_L2, std::get<1>(m_l2));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_R1, std::get<1>(m_r1));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_L1, std::get<1>(m_l1));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_R2, std::get<1>(m_r2));
|
||||
pad->Set(PadDualshock2::Inputs::PAD_L2, std::get<1>(m_l2));
|
||||
}
|
||||
|
||||
void addButtonInfoToString(std::string label, std::string& str, std::tuple<bool, u8> buttonInfo)
|
||||
|
||||
@@ -297,7 +297,7 @@ u8 MemoryCardProtocol::PS1Read(u8 data)
|
||||
mcd->Read(ps1McState.buf.data(), ps1McState.buf.size());
|
||||
[[fallthrough]];
|
||||
default:
|
||||
ret = ps1McState.buf.at(ps1McState.currentByte - 10);
|
||||
ret = ps1McState.buf[ps1McState.currentByte - 10];
|
||||
ps1McState.checksum ^= ret;
|
||||
break;
|
||||
}
|
||||
@@ -372,7 +372,7 @@ u8 MemoryCardProtocol::PS1Write(u8 data)
|
||||
ps1McState.checksum = ps1McState.sectorAddrMSB ^ ps1McState.sectorAddrLSB;
|
||||
[[fallthrough]];
|
||||
default:
|
||||
ps1McState.buf.at(ps1McState.currentByte - 6) = data;
|
||||
ps1McState.buf[ps1McState.currentByte - 6] = data;
|
||||
ps1McState.checksum ^= data;
|
||||
ret = 0x00;
|
||||
break;
|
||||
|
||||
@@ -15,28 +15,67 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "SIO/Pad/PadConfig.h"
|
||||
#include "Host.h"
|
||||
#include "Input/InputManager.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Pad/PadDualshock2.h"
|
||||
#include "SIO/Pad/PadGuitar.h"
|
||||
#include "SIO/Pad/PadNotConnected.h"
|
||||
#include "SIO/Sio.h"
|
||||
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/PadMacros.h"
|
||||
#include "SIO/Pad/PadDualshock2Types.h"
|
||||
#include "SIO/Pad/PadGuitarTypes.h"
|
||||
#include "IconsFontAwesome5.h"
|
||||
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/SettingsInterface.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "Input/InputManager.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
PadConfig g_PadConfig;
|
||||
#include <vector>
|
||||
|
||||
PadConfig::PadConfig() = default;
|
||||
PadConfig::~PadConfig() = default;
|
||||
|
||||
void PadConfig::LoadConfig(const SettingsInterface& si)
|
||||
namespace Pad
|
||||
{
|
||||
g_PadMacros.ClearMacros();
|
||||
struct MacroButton
|
||||
{
|
||||
std::vector<u32> buttons; ///< Buttons to activate.
|
||||
float pressure; ///< Pressure to apply when macro is active.
|
||||
u32 toggle_frequency; ///< Interval at which the buttons will be toggled, if not 0.
|
||||
u32 toggle_counter; ///< When this counter reaches zero, buttons will be toggled.
|
||||
bool toggle_state; ///< Current state for turbo.
|
||||
bool trigger_state; ///< Whether the macro button is active.
|
||||
};
|
||||
|
||||
static std::unique_ptr<PadBase> CreatePad(u8 unifiedSlot, Pad::ControllerType controllerType);
|
||||
static PadBase* ChangePadType(u8 unifiedSlot, Pad::ControllerType controllerType);
|
||||
|
||||
void LoadMacroButtonConfig(
|
||||
const SettingsInterface& si, u32 pad, const std::string_view& type, const std::string& section);
|
||||
static void ApplyMacroButton(u32 controller, const MacroButton& mb);
|
||||
|
||||
static std::array<std::array<MacroButton, NUM_MACRO_BUTTONS_PER_CONTROLLER>, NUM_CONTROLLER_PORTS> s_macro_buttons;
|
||||
static std::array<std::unique_ptr<PadBase>, NUM_CONTROLLER_PORTS> s_controllers;
|
||||
}
|
||||
|
||||
bool Pad::Initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Pad::Shutdown()
|
||||
{
|
||||
for (auto& port : s_controllers)
|
||||
port.reset();
|
||||
}
|
||||
|
||||
const char* Pad::ControllerInfo::GetLocalizedName() const
|
||||
{
|
||||
return Host::TranslateToCString("Pad", display_name);
|
||||
}
|
||||
|
||||
void Pad::LoadConfig(const SettingsInterface& si)
|
||||
{
|
||||
s_macro_buttons = {};
|
||||
|
||||
EmuConfig.MultitapPort0_Enabled = si.GetBoolValue("Pad", "MultitapPort1", false);
|
||||
EmuConfig.MultitapPort1_Enabled = si.GetBoolValue("Pad", "MultitapPort2", false);
|
||||
@@ -47,18 +86,18 @@ void PadConfig::LoadConfig(const SettingsInterface& si)
|
||||
const std::string section(GetConfigSection(i));
|
||||
const std::string type(si.GetStringValue(section.c_str(), "Type", GetDefaultPadType(i)));
|
||||
const ControllerInfo* ci = GetControllerInfo(type);
|
||||
PadBase* pad = g_PadManager.GetPad(i);
|
||||
PadBase* pad = Pad::GetPad(i);
|
||||
|
||||
// If a pad is not yet constructed, at minimum place a NotConnected pad in the slot.
|
||||
// Do not abort the for loop - If there pad settings, we want those to be applied to the slot.
|
||||
if (!pad)
|
||||
{
|
||||
pad = g_PadManager.ChangePadType(i, Pad::ControllerType::NotConnected);
|
||||
pad = Pad::ChangePadType(i, Pad::ControllerType::NotConnected);
|
||||
}
|
||||
|
||||
if (!ci)
|
||||
{
|
||||
pad = g_PadManager.ChangePadType(i, Pad::ControllerType::NotConnected);
|
||||
pad = Pad::ChangePadType(i, Pad::ControllerType::NotConnected);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -67,7 +106,7 @@ void PadConfig::LoadConfig(const SettingsInterface& si)
|
||||
|
||||
if (ci->type != oldType)
|
||||
{
|
||||
pad = g_PadManager.ChangePadType(i, ci->type);
|
||||
pad = Pad::ChangePadType(i, ci->type);
|
||||
}
|
||||
|
||||
const float axis_deadzone = si.GetFloatValue(section.c_str(), "Deadzone", Pad::DEFAULT_STICK_DEADZONE);
|
||||
@@ -94,17 +133,16 @@ void PadConfig::LoadConfig(const SettingsInterface& si)
|
||||
const int invert_r = si.GetIntValue(section.c_str(), "InvertR", 0);
|
||||
pad->SetAnalogInvertL((invert_l & 1) != 0, (invert_l & 2) != 0);
|
||||
pad->SetAnalogInvertR((invert_r & 1) != 0, (invert_r & 2) != 0);
|
||||
|
||||
LoadMacroButtonConfig(si, i, type, section);
|
||||
}
|
||||
}
|
||||
|
||||
const char* PadConfig::GetDefaultPadType(u32 pad)
|
||||
const char* Pad::GetDefaultPadType(u32 pad)
|
||||
{
|
||||
return (pad == 0) ? "DualShock2" : "None";
|
||||
}
|
||||
|
||||
void PadConfig::SetDefaultControllerConfig(SettingsInterface& si)
|
||||
void Pad::SetDefaultControllerConfig(SettingsInterface& si)
|
||||
{
|
||||
si.ClearSection("InputSources");
|
||||
si.ClearSection("Hotkeys");
|
||||
@@ -136,9 +174,8 @@ void PadConfig::SetDefaultControllerConfig(SettingsInterface& si)
|
||||
const ControllerInfo* ci = GetControllerInfo(type);
|
||||
if (ci)
|
||||
{
|
||||
for (u32 i = 0; i < ci->num_settings; i++)
|
||||
for (const SettingInfo& csi : ci->settings)
|
||||
{
|
||||
const SettingInfo& csi = ci->settings[i];
|
||||
switch (csi.type)
|
||||
{
|
||||
case SettingInfo::Type::Boolean:
|
||||
@@ -168,7 +205,7 @@ void PadConfig::SetDefaultControllerConfig(SettingsInterface& si)
|
||||
MapController(si, 0, InputManager::GetGenericBindingMapping("Keyboard"));
|
||||
}
|
||||
|
||||
void PadConfig::SetDefaultHotkeyConfig(SettingsInterface& si)
|
||||
void Pad::SetDefaultHotkeyConfig(SettingsInterface& si)
|
||||
{
|
||||
// PCSX2 Controller Settings - Hotkeys
|
||||
|
||||
@@ -215,74 +252,70 @@ void PadConfig::SetDefaultHotkeyConfig(SettingsInterface& si)
|
||||
si.SetStringValue("Hotkeys", "HoldTurbo", "Keyboard/Period");
|
||||
}
|
||||
|
||||
|
||||
static const PadConfig::ControllerInfo s_controller_info[] = {
|
||||
{Pad::ControllerType::NotConnected, "None", "Not Connected",
|
||||
nullptr, 0,
|
||||
nullptr, 0,
|
||||
Pad::VibrationCapabilities::NoVibration},
|
||||
{Pad::ControllerType::DualShock2, "DualShock2", "DualShock 2",
|
||||
Dualshock2::defaultBindings, std::size(Dualshock2::defaultBindings),
|
||||
Dualshock2::defaultSettings, std::size(Dualshock2::defaultSettings),
|
||||
Pad::VibrationCapabilities::LargeSmallMotors},
|
||||
{Pad::ControllerType::Guitar, "Guitar", "Guitar",
|
||||
Guitar::defaultBindings, std::size(Guitar::defaultBindings),
|
||||
Guitar::defaultSettings, std::size(Guitar::defaultSettings),
|
||||
Pad::VibrationCapabilities::NoVibration},
|
||||
static const Pad::ControllerInfo* s_controller_info[] = {
|
||||
&PadNotConnected::ControllerInfo,
|
||||
&PadDualshock2::ControllerInfo,
|
||||
&PadGuitar::ControllerInfo,
|
||||
};
|
||||
|
||||
const PadConfig::ControllerInfo* PadConfig::GetControllerInfo(Pad::ControllerType type)
|
||||
const Pad::ControllerInfo* Pad::GetControllerInfo(Pad::ControllerType type)
|
||||
{
|
||||
for (const ControllerInfo& info : s_controller_info)
|
||||
for (const ControllerInfo* info : s_controller_info)
|
||||
{
|
||||
if (type == info.type)
|
||||
return &info;
|
||||
if (type == info->type)
|
||||
return info;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PadConfig::ControllerInfo* PadConfig::GetControllerInfo(const std::string_view& name)
|
||||
const Pad::ControllerInfo* Pad::GetControllerInfo(const std::string_view& name)
|
||||
{
|
||||
for (const ControllerInfo& info : s_controller_info)
|
||||
for (const ControllerInfo* info : s_controller_info)
|
||||
{
|
||||
if (name == info.name)
|
||||
return &info;
|
||||
if (name == info->name)
|
||||
return info;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<const char*, const char*>> PadConfig::GetControllerTypeNames()
|
||||
const char* Pad::GetControllerTypeName(Pad::ControllerType type)
|
||||
{
|
||||
// Not localized, because it should never happen.
|
||||
const ControllerInfo* ci = GetControllerInfo(type);
|
||||
return ci ? ci->GetLocalizedName() : "UNKNOWN";
|
||||
}
|
||||
|
||||
const std::vector<std::pair<const char*, const char*>> Pad::GetControllerTypeNames()
|
||||
{
|
||||
std::vector<std::pair<const char*, const char*>> ret;
|
||||
for (const ControllerInfo& info : s_controller_info)
|
||||
ret.emplace_back(info.name, info.display_name);
|
||||
for (const ControllerInfo* info : s_controller_info)
|
||||
ret.emplace_back(info->name, info->GetLocalizedName());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> PadConfig::GetControllerBinds(const std::string_view& type)
|
||||
std::vector<std::string> Pad::GetControllerBinds(const std::string_view& type)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
|
||||
const ControllerInfo* info = GetControllerInfo(type);
|
||||
if (info)
|
||||
{
|
||||
for (u32 i = 0; i < info->num_bindings; i++)
|
||||
for (const InputBindingInfo& bi : info->bindings)
|
||||
{
|
||||
const InputBindingInfo& bi = info->bindings[i];
|
||||
if (bi.bind_type == InputBindingInfo::Type::Unknown || bi.bind_type == InputBindingInfo::Type::Motor)
|
||||
continue;
|
||||
|
||||
ret.emplace_back(info->bindings[i].name);
|
||||
ret.emplace_back(bi.name);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PadConfig::ClearPortBindings(SettingsInterface& si, u32 port)
|
||||
void Pad::ClearPortBindings(SettingsInterface& si, u32 port)
|
||||
{
|
||||
const std::string section(StringUtil::StdStringFromFormat("Pad%u", port + 1));
|
||||
const std::string type(si.GetStringValue(section.c_str(), "Type", GetDefaultPadType(port)));
|
||||
@@ -291,11 +324,11 @@ void PadConfig::ClearPortBindings(SettingsInterface& si, u32 port)
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
for (u32 i = 0; i < info->num_bindings; i++)
|
||||
si.DeleteValue(section.c_str(), info->bindings[i].name);
|
||||
for (const InputBindingInfo& bi : info->bindings)
|
||||
si.DeleteValue(section.c_str(), bi.name);
|
||||
}
|
||||
|
||||
void PadConfig::CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& src_si,
|
||||
void Pad::CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& src_si,
|
||||
bool copy_pad_config, bool copy_pad_bindings, bool copy_hotkey_bindings)
|
||||
{
|
||||
if (copy_pad_config)
|
||||
@@ -329,15 +362,14 @@ void PadConfig::CopyConfiguration(SettingsInterface* dest_si, const SettingsInte
|
||||
|
||||
if (copy_pad_bindings)
|
||||
{
|
||||
for (u32 i = 0; i < info->num_bindings; i++)
|
||||
{
|
||||
const InputBindingInfo& bi = info->bindings[i];
|
||||
for (const InputBindingInfo& bi : info->bindings)
|
||||
dest_si->CopyStringListValue(src_si, section.c_str(), bi.name);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < PadMacros::NUM_MACRO_BUTTONS_PER_CONTROLLER; i++)
|
||||
for (u32 i = 0; i < NUM_MACRO_BUTTONS_PER_CONTROLLER; i++)
|
||||
{
|
||||
dest_si->CopyStringListValue(src_si, section.c_str(), fmt::format("Macro{}", i + 1).c_str());
|
||||
dest_si->CopyFloatValue(src_si, section.c_str(), fmt::format("Macro{}Pressure", i + 1).c_str());
|
||||
dest_si->CopyFloatValue(src_si, section.c_str(), fmt::format("Macro{}Deadzone", i + 1).c_str());
|
||||
dest_si->CopyStringValue(src_si, section.c_str(), fmt::format("Macro{}Binds", i + 1).c_str());
|
||||
dest_si->CopyUIntValue(src_si, section.c_str(), fmt::format("Macro{}Frequency", i + 1).c_str());
|
||||
}
|
||||
@@ -353,9 +385,8 @@ void PadConfig::CopyConfiguration(SettingsInterface* dest_si, const SettingsInte
|
||||
dest_si->CopyFloatValue(src_si, section.c_str(), "SmallMotorScale");
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < info->num_settings; i++)
|
||||
for (const SettingInfo& csi : info->settings)
|
||||
{
|
||||
const SettingInfo& csi = info->settings[i];
|
||||
switch (csi.type)
|
||||
{
|
||||
case SettingInfo::Type::Boolean:
|
||||
@@ -417,7 +448,7 @@ static u32 TryMapGenericMapping(SettingsInterface& si, const std::string& sectio
|
||||
}
|
||||
|
||||
|
||||
bool PadConfig::MapController(SettingsInterface& si, u32 controller,
|
||||
bool Pad::MapController(SettingsInterface& si, u32 controller,
|
||||
const std::vector<std::pair<GenericInputBinding, std::string>>& mapping)
|
||||
{
|
||||
const std::string section(StringUtil::StdStringFromFormat("Pad%u", controller + 1));
|
||||
@@ -427,9 +458,8 @@ bool PadConfig::MapController(SettingsInterface& si, u32 controller,
|
||||
return false;
|
||||
|
||||
u32 num_mappings = 0;
|
||||
for (u32 i = 0; i < info->num_bindings; i++)
|
||||
for (const InputBindingInfo& bi : info->bindings)
|
||||
{
|
||||
const InputBindingInfo& bi = info->bindings[i];
|
||||
if (bi.generic_mapping == GenericInputBinding::Unknown)
|
||||
continue;
|
||||
|
||||
@@ -451,7 +481,7 @@ bool PadConfig::MapController(SettingsInterface& si, u32 controller,
|
||||
return (num_mappings > 0);
|
||||
}
|
||||
|
||||
std::vector<std::string> PadConfig::GetInputProfileNames()
|
||||
std::vector<std::string> Pad::GetInputProfileNames()
|
||||
{
|
||||
FileSystem::FindResultsArray results;
|
||||
FileSystem::FindFiles(EmuFolders::InputProfiles.c_str(), "*.ini",
|
||||
@@ -465,17 +495,123 @@ std::vector<std::string> PadConfig::GetInputProfileNames()
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string PadConfig::GetConfigSection(u32 pad_index)
|
||||
std::string Pad::GetConfigSection(u32 pad_index)
|
||||
{
|
||||
return fmt::format("Pad{}", pad_index + 1);
|
||||
}
|
||||
|
||||
void PadConfig::LoadMacroButtonConfig(const SettingsInterface& si, u32 pad, const std::string_view& type, const std::string& section)
|
||||
std::unique_ptr<PadBase> Pad::CreatePad(u8 unifiedSlot, ControllerType controllerType)
|
||||
{
|
||||
switch (controllerType)
|
||||
{
|
||||
case ControllerType::DualShock2:
|
||||
return std::make_unique<PadDualshock2>(unifiedSlot);
|
||||
case ControllerType::Guitar:
|
||||
return std::make_unique<PadGuitar>(unifiedSlot);
|
||||
default:
|
||||
return std::make_unique<PadNotConnected>(unifiedSlot);
|
||||
}
|
||||
}
|
||||
|
||||
PadBase* Pad::ChangePadType(u8 unifiedSlot, ControllerType controllerType)
|
||||
{
|
||||
s_controllers[unifiedSlot] = CreatePad(unifiedSlot, controllerType);
|
||||
return s_controllers[unifiedSlot].get();
|
||||
}
|
||||
|
||||
bool Pad::HasConnectedPad(u8 unifiedSlot)
|
||||
{
|
||||
return (
|
||||
unifiedSlot < NUM_CONTROLLER_PORTS && s_controllers[unifiedSlot]->GetType() != ControllerType::NotConnected);
|
||||
}
|
||||
|
||||
PadBase* Pad::GetPad(u8 port, u8 slot)
|
||||
{
|
||||
const u8 unifiedSlot = sioConvertPortAndSlotToPad(port, slot);
|
||||
return s_controllers[unifiedSlot].get();
|
||||
}
|
||||
|
||||
PadBase* Pad::GetPad(const u8 unifiedSlot)
|
||||
{
|
||||
return s_controllers[unifiedSlot].get();
|
||||
}
|
||||
|
||||
void Pad::SetControllerState(u32 controller, u32 bind, float value)
|
||||
{
|
||||
if (controller >= NUM_CONTROLLER_PORTS)
|
||||
return;
|
||||
|
||||
s_controllers[controller]->Set(bind, value);
|
||||
}
|
||||
|
||||
bool Pad::Freeze(StateWrapper& sw)
|
||||
{
|
||||
if (sw.IsReading())
|
||||
{
|
||||
if (!sw.DoMarker("PAD"))
|
||||
{
|
||||
Console.Error("PAD state is invalid! Leaving the current state in place.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u32 unifiedSlot = 0; unifiedSlot < NUM_CONTROLLER_PORTS; unifiedSlot++)
|
||||
{
|
||||
ControllerType type;
|
||||
sw.Do(&type);
|
||||
if (sw.HasError())
|
||||
return false;
|
||||
|
||||
std::unique_ptr<PadBase> tempPad;
|
||||
PadBase* pad = GetPad(unifiedSlot);
|
||||
if (!pad || pad->GetType() != type)
|
||||
{
|
||||
const auto& [port, slot] = sioConvertPadToPortAndSlot(unifiedSlot);
|
||||
Host::AddIconOSDMessage(fmt::format("UnfreezePad{}Changed", unifiedSlot), ICON_FA_GAMEPAD,
|
||||
fmt::format(TRANSLATE_FS("Pad",
|
||||
"Controller port {}, slot {} has a {} connected, but the save state has a "
|
||||
"{}.\nLeaving the original controller type connected, but this may cause issues."),
|
||||
port, slot,
|
||||
Pad::GetControllerTypeName(pad ? pad->GetType() : Pad::ControllerType::NotConnected),
|
||||
Pad::GetControllerTypeName(type)));
|
||||
|
||||
// Reset the transfer etc state of the pad, at least it has a better chance of surviving.
|
||||
if (pad)
|
||||
pad->SoftReset();
|
||||
|
||||
// But we still need to pull the data from the state..
|
||||
tempPad = CreatePad(unifiedSlot, type);
|
||||
pad = tempPad.get();
|
||||
}
|
||||
|
||||
if (!pad->Freeze(sw))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sw.DoMarker("PAD"))
|
||||
return false;
|
||||
|
||||
for (u32 unifiedSlot = 0; unifiedSlot < NUM_CONTROLLER_PORTS; unifiedSlot++)
|
||||
{
|
||||
PadBase* pad = GetPad(unifiedSlot);
|
||||
ControllerType type = pad->GetType();
|
||||
sw.Do(&type);
|
||||
if (sw.HasError() || !pad->Freeze(sw))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
|
||||
void Pad::LoadMacroButtonConfig(const SettingsInterface& si, u32 pad, const std::string_view& type, const std::string& section)
|
||||
{
|
||||
// lazily initialized
|
||||
std::vector<std::string> binds;
|
||||
|
||||
for (u32 i = 0; i < PadMacros::NUM_MACRO_BUTTONS_PER_CONTROLLER; i++)
|
||||
for (u32 i = 0; i < NUM_MACRO_BUTTONS_PER_CONTROLLER; i++)
|
||||
{
|
||||
std::string binds_string;
|
||||
if (!si.GetStringValue(section.c_str(), StringUtil::StdStringFromFormat("Macro%uBinds", i + 1).c_str(), &binds_string))
|
||||
@@ -485,6 +621,8 @@ void PadConfig::LoadMacroButtonConfig(const SettingsInterface& si, u32 pad, cons
|
||||
if (binds.empty())
|
||||
binds = GetControllerBinds(type);
|
||||
|
||||
const float pressure = si.GetFloatValue(section.c_str(), fmt::format("Macro{}Pressure", i + 1).c_str(), 1.0f);
|
||||
|
||||
// convert binds
|
||||
std::vector<u32> bind_indices;
|
||||
std::vector<std::string_view> buttons_split(StringUtil::SplitString(binds_string, '&', true));
|
||||
@@ -504,8 +642,63 @@ void PadConfig::LoadMacroButtonConfig(const SettingsInterface& si, u32 pad, cons
|
||||
if (bind_indices.empty())
|
||||
continue;
|
||||
|
||||
PadMacros::MacroButton& macro = g_PadMacros.GetMacroButton(pad, i);
|
||||
MacroButton& macro = s_macro_buttons[pad][i];
|
||||
macro.buttons = std::move(bind_indices);
|
||||
macro.toggle_frequency = frequency;
|
||||
macro.pressure = pressure;
|
||||
}
|
||||
}
|
||||
|
||||
void Pad::SetMacroButtonState(u32 pad, u32 index, bool state)
|
||||
{
|
||||
if (pad >= Pad::NUM_CONTROLLER_PORTS || index >= NUM_MACRO_BUTTONS_PER_CONTROLLER)
|
||||
return;
|
||||
|
||||
MacroButton& mb = s_macro_buttons[pad][index];
|
||||
if (mb.buttons.empty() || mb.trigger_state == state)
|
||||
return;
|
||||
|
||||
mb.toggle_counter = mb.toggle_frequency;
|
||||
mb.trigger_state = state;
|
||||
if (mb.toggle_state != state)
|
||||
{
|
||||
mb.toggle_state = state;
|
||||
ApplyMacroButton(pad, mb);
|
||||
}
|
||||
}
|
||||
|
||||
void Pad::ApplyMacroButton(u32 controller, const Pad::MacroButton& mb)
|
||||
{
|
||||
const float value = mb.toggle_state ? mb.pressure : 0.0f;
|
||||
PadBase* const pad = Pad::GetPad(controller);
|
||||
|
||||
for (const u32 btn : mb.buttons)
|
||||
pad->Set(btn, value);
|
||||
}
|
||||
|
||||
void Pad::UpdateMacroButtons()
|
||||
{
|
||||
for (u32 pad = 0; pad < Pad::NUM_CONTROLLER_PORTS; pad++)
|
||||
{
|
||||
for (u32 index = 0; index < NUM_MACRO_BUTTONS_PER_CONTROLLER; index++)
|
||||
{
|
||||
Pad::MacroButton& mb = s_macro_buttons[pad][index];
|
||||
|
||||
if (!mb.trigger_state || mb.toggle_frequency == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mb.toggle_counter--;
|
||||
|
||||
if (mb.toggle_counter > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mb.toggle_counter = mb.toggle_frequency;
|
||||
mb.toggle_state = !mb.toggle_state;
|
||||
ApplyMacroButton(pad, mb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,58 +15,69 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "SIO/Pad/PadTypes.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include <memory>
|
||||
|
||||
class PadBase;
|
||||
|
||||
class SettingsInterface;
|
||||
enum class GenericInputBinding : u8;
|
||||
class SettingsInterface;
|
||||
class StateWrapper;
|
||||
|
||||
class PadConfig
|
||||
namespace Pad
|
||||
{
|
||||
public: // Constants
|
||||
struct ControllerInfo
|
||||
{
|
||||
Pad::ControllerType type;
|
||||
const char* name;
|
||||
const char* display_name;
|
||||
const InputBindingInfo* bindings;
|
||||
u32 num_bindings;
|
||||
const SettingInfo* settings;
|
||||
u32 num_settings;
|
||||
Pad::VibrationCapabilities vibration_caps;
|
||||
};
|
||||
|
||||
public: // Public members
|
||||
PadConfig();
|
||||
~PadConfig();
|
||||
bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
// Returns the default type for the specified port.
|
||||
const char* GetDefaultPadType(u32 pad);
|
||||
|
||||
// Reloads configuration.
|
||||
void LoadConfig(const SettingsInterface& si);
|
||||
|
||||
// Restores default configuration.
|
||||
void SetDefaultControllerConfig(SettingsInterface& si);
|
||||
void SetDefaultHotkeyConfig(SettingsInterface& si);
|
||||
|
||||
// Clears all bindings for a given port.
|
||||
void ClearPortBindings(SettingsInterface& si, u32 port);
|
||||
|
||||
// Copies pad configuration from one interface (ini) to another.
|
||||
void CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& src_si,
|
||||
bool copy_pad_config = true, bool copy_pad_bindings = true, bool copy_hotkey_bindings = true);
|
||||
void CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& src_si, bool copy_pad_config = true,
|
||||
bool copy_pad_bindings = true, bool copy_hotkey_bindings = true);
|
||||
|
||||
// Returns a list of controller type names. Pair of [name, display name].
|
||||
const std::vector<std::pair<const char*, const char*>> GetControllerTypeNames();
|
||||
|
||||
// Returns the list of binds for the specified controller type.
|
||||
std::vector<std::string> GetControllerBinds(const std::string_view& type);
|
||||
|
||||
// Returns general information for the specified controller type.
|
||||
const ControllerInfo* GetControllerInfo(Pad::ControllerType type);
|
||||
const ControllerInfo* GetControllerInfo(const std::string_view& name);
|
||||
const char* GetControllerTypeName(Pad::ControllerType type);
|
||||
|
||||
// Performs automatic controller mapping with the provided list of generic mappings.
|
||||
bool MapController(SettingsInterface& si, u32 controller,
|
||||
const std::vector<std::pair<GenericInputBinding, std::string>>& mapping);
|
||||
bool MapController(
|
||||
SettingsInterface& si, u32 controller, const std::vector<std::pair<GenericInputBinding, std::string>>& mapping);
|
||||
|
||||
// Returns a list of input profiles available.
|
||||
std::vector<std::string> GetInputProfileNames();
|
||||
std::string GetConfigSection(u32 pad_index);
|
||||
void LoadMacroButtonConfig(const SettingsInterface& si, u32 pad, const std::string_view& type, const std::string& section);
|
||||
};
|
||||
|
||||
extern PadConfig g_PadConfig;
|
||||
bool HasConnectedPad(u8 unifiedSlot);
|
||||
|
||||
PadBase* GetPad(u8 port, u8 slot);
|
||||
PadBase* GetPad(const u8 unifiedSlot);
|
||||
|
||||
// Sets the specified bind on a controller to the specified pressure (normalized to 0..1).
|
||||
void SetControllerState(u32 controller, u32 bind, float value);
|
||||
|
||||
bool Freeze(StateWrapper& sw);
|
||||
|
||||
// Sets the state of the specified macro button.
|
||||
void SetMacroButtonState(u32 pad, u32 index, bool state);
|
||||
void UpdateMacroButtons();
|
||||
}; // namespace Pad
|
||||
@@ -34,3 +34,18 @@ void PadBase::FullReset()
|
||||
this->isInConfig = false;
|
||||
this->currentMode = Pad::Mode::DIGITAL;
|
||||
}
|
||||
|
||||
bool PadBase::Freeze(StateWrapper& sw)
|
||||
{
|
||||
if (!sw.DoMarker("PadBase"))
|
||||
return false;
|
||||
|
||||
// Protected PadBase members
|
||||
sw.Do(&rawInputs);
|
||||
sw.Do(&unifiedSlot);
|
||||
sw.Do(&isInConfig);
|
||||
sw.Do(¤tMode);
|
||||
sw.Do(¤tCommand);
|
||||
sw.Do(&commandBytesReceived);
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
@@ -39,25 +39,27 @@ public: // Public members
|
||||
void FullReset();
|
||||
|
||||
virtual void Init() = 0;
|
||||
virtual Pad::ControllerType GetType() = 0;
|
||||
virtual Pad::ControllerType GetType() const = 0;
|
||||
virtual const Pad::ControllerInfo& GetInfo() const = 0;
|
||||
|
||||
virtual void Set(u32 index, float value) = 0;
|
||||
virtual void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) = 0;
|
||||
virtual void SetAxisScale(float deadzone, float scale) = 0;
|
||||
virtual void SetTriggerScale(float deadzone, float scale) = 0;
|
||||
virtual float GetVibrationScale(u32 motor) = 0;
|
||||
virtual float GetVibrationScale(u32 motor) const = 0;
|
||||
virtual void SetVibrationScale(u32 motor, float scale) = 0;
|
||||
virtual float GetPressureModifier() = 0;
|
||||
virtual float GetPressureModifier() const = 0;
|
||||
virtual void SetPressureModifier(float mod) = 0;
|
||||
virtual void SetButtonDeadzone(float deadzone) = 0;
|
||||
virtual void SetAnalogInvertL(bool x, bool y) = 0;
|
||||
virtual void SetAnalogInvertR(bool x, bool y) = 0;
|
||||
virtual u8 GetRawInput(u32 index) = 0;
|
||||
virtual std::tuple<u8, u8> GetRawLeftAnalog() = 0;
|
||||
virtual std::tuple<u8, u8> GetRawRightAnalog() = 0;
|
||||
virtual u32 GetButtons() = 0;
|
||||
virtual u8 GetPressure(u32 index) = 0;
|
||||
virtual u8 GetRawInput(u32 index) const = 0;
|
||||
virtual std::tuple<u8, u8> GetRawLeftAnalog() const = 0;
|
||||
virtual std::tuple<u8, u8> GetRawRightAnalog() const = 0;
|
||||
virtual u32 GetButtons() const = 0;
|
||||
virtual u8 GetPressure(u32 index) const = 0;
|
||||
|
||||
virtual void Freeze(StateWrapper& sw) = 0;
|
||||
virtual bool Freeze(StateWrapper& sw);
|
||||
|
||||
virtual u8 SendCommandByte(u8 commandByte) = 0;
|
||||
};
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "SIO/Pad/PadDualshock2.h"
|
||||
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Sio.h"
|
||||
#include "SIO/Sio0.h"
|
||||
|
||||
@@ -25,6 +24,77 @@
|
||||
#include "Input/InputManager.h"
|
||||
#include "Host.h"
|
||||
|
||||
static const InputBindingInfo s_bindings[] = {
|
||||
// clang-format off
|
||||
{"Up", TRANSLATE_NOOP("Pad", "D-Pad Up"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_UP, GenericInputBinding::DPadUp},
|
||||
{"Right", TRANSLATE_NOOP("Pad", "D-Pad Right"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_RIGHT, GenericInputBinding::DPadRight},
|
||||
{"Down", TRANSLATE_NOOP("Pad", "D-Pad Down"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_DOWN, GenericInputBinding::DPadDown},
|
||||
{"Left", TRANSLATE_NOOP("Pad", "D-Pad Left"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_LEFT, GenericInputBinding::DPadLeft},
|
||||
{"Triangle", TRANSLATE_NOOP("Pad", "Triangle"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_TRIANGLE, GenericInputBinding::Triangle},
|
||||
{"Circle", TRANSLATE_NOOP("Pad", "Circle"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_CIRCLE, GenericInputBinding::Circle},
|
||||
{"Cross", TRANSLATE_NOOP("Pad", "Cross"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_CROSS, GenericInputBinding::Cross},
|
||||
{"Square", TRANSLATE_NOOP("Pad", "Square"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_SQUARE, GenericInputBinding::Square},
|
||||
{"Select", TRANSLATE_NOOP("Pad", "Select"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_SELECT, GenericInputBinding::Select},
|
||||
{"Start", TRANSLATE_NOOP("Pad", "Start"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_START, GenericInputBinding::Start},
|
||||
{"L1", TRANSLATE_NOOP("Pad", "L1 (Left Bumper)"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_L1, GenericInputBinding::L1},
|
||||
{"L2", TRANSLATE_NOOP("Pad", "L2 (Left Trigger)"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_L2, GenericInputBinding::L2},
|
||||
{"R1", TRANSLATE_NOOP("Pad", "R1 (Right Bumper)"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_R1, GenericInputBinding::R1},
|
||||
{"R2", TRANSLATE_NOOP("Pad", "R2 (Right Trigger)"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_R2, GenericInputBinding::R2},
|
||||
{"L3", TRANSLATE_NOOP("Pad", "L3 (Left Stick Button)"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_L3, GenericInputBinding::L3},
|
||||
{"R3", TRANSLATE_NOOP("Pad", "R3 (Right Stick Button)"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_R3, GenericInputBinding::R3},
|
||||
{"Analog", TRANSLATE_NOOP("Pad", "Analog Toggle"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_ANALOG, GenericInputBinding::System},
|
||||
{"Pressure", TRANSLATE_NOOP("Pad", "Apply Pressure"), InputBindingInfo::Type::Button, PadDualshock2::Inputs::PAD_PRESSURE, GenericInputBinding::Unknown},
|
||||
{"LUp", TRANSLATE_NOOP("Pad", "Left Stick Up"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_L_UP, GenericInputBinding::LeftStickUp},
|
||||
{"LRight", TRANSLATE_NOOP("Pad", "Left Stick Right"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_L_RIGHT, GenericInputBinding::LeftStickRight},
|
||||
{"LDown", TRANSLATE_NOOP("Pad", "Left Stick Down"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_L_DOWN, GenericInputBinding::LeftStickDown},
|
||||
{"LLeft", TRANSLATE_NOOP("Pad", "Left Stick Left"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_L_LEFT, GenericInputBinding::LeftStickLeft},
|
||||
{"RUp", TRANSLATE_NOOP("Pad", "Right Stick Up"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_R_UP, GenericInputBinding::RightStickUp},
|
||||
{"RRight", TRANSLATE_NOOP("Pad", "Right Stick Right"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_R_RIGHT, GenericInputBinding::RightStickRight},
|
||||
{"RDown", TRANSLATE_NOOP("Pad", "Right Stick Down"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_R_DOWN, GenericInputBinding::RightStickDown},
|
||||
{"RLeft", TRANSLATE_NOOP("Pad", "Right Stick Left"), InputBindingInfo::Type::HalfAxis, PadDualshock2::Inputs::PAD_R_LEFT, GenericInputBinding::RightStickLeft},
|
||||
{"LargeMotor", TRANSLATE_NOOP("Pad", "Large (Low Frequency) Motor"), InputBindingInfo::Type::Motor, 0, GenericInputBinding::LargeMotor},
|
||||
{"SmallMotor", TRANSLATE_NOOP("Pad", "Small (High Frequency) Motor"), InputBindingInfo::Type::Motor, 0, GenericInputBinding::SmallMotor},
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static const char* s_invert_options[] = {TRANSLATE_NOOP("Pad", "Not Inverted"),
|
||||
TRANSLATE_NOOP("Pad", "Invert Left/Right"), TRANSLATE_NOOP("Pad", "Invert Up/Down"),
|
||||
TRANSLATE_NOOP("Pad", "Invert Left/Right + Up/Down"), nullptr};
|
||||
|
||||
static const SettingInfo s_settings[] = {
|
||||
{SettingInfo::Type::IntegerList, "InvertL", TRANSLATE_NOOP("Pad", "Invert Left Stick"),
|
||||
TRANSLATE_NOOP("Pad", "Inverts the direction of the left analog stick."), "0", "0", "3", nullptr, nullptr,
|
||||
s_invert_options, nullptr, 0.0f},
|
||||
{SettingInfo::Type::IntegerList, "InvertR", TRANSLATE_NOOP("Pad", "Invert Right Stick"),
|
||||
TRANSLATE_NOOP("Pad", "Inverts the direction of the right analog stick."), "0", "0", "3", nullptr, nullptr,
|
||||
s_invert_options, nullptr, 0.0f},
|
||||
{SettingInfo::Type::Float, "Deadzone", TRANSLATE_NOOP("Pad", "Analog Deadzone"),
|
||||
TRANSLATE_NOOP(
|
||||
"Pad", "Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
|
||||
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "AxisScale", TRANSLATE_NOOP("Pad", "Analog Sensitivity"),
|
||||
TRANSLATE_NOOP("Pad",
|
||||
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
|
||||
"controllers, e.g. DualShock 4, Xbox One Controller."),
|
||||
"1.33", "0.01", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "LargeMotorScale", TRANSLATE_NOOP("Pad", "Large Motor Vibration Scale"),
|
||||
TRANSLATE_NOOP("Pad", "Increases or decreases the intensity of low frequency vibration sent by the game."),
|
||||
"1.00", "0.00", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "SmallMotorScale", TRANSLATE_NOOP("Pad", "Small Motor Vibration Scale"),
|
||||
TRANSLATE_NOOP("Pad", "Increases or decreases the intensity of high frequency vibration sent by the game."),
|
||||
"1.00", "0.00", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "ButtonDeadzone", TRANSLATE_NOOP("Pad", "Button/Trigger Deadzone"),
|
||||
TRANSLATE_NOOP("Pad", "Sets the deadzone for activating buttons/triggers, i.e. the fraction of the trigger "
|
||||
"which will be ignored."),
|
||||
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "PressureModifier", TRANSLATE_NOOP("Pad", "Modifier Pressure"),
|
||||
TRANSLATE_NOOP("Pad", "Sets the pressure when the modifier button is held."), "0.50", "0.01", "1.00", "0.01",
|
||||
"%.0f%%", nullptr, nullptr, 100.0f},
|
||||
};
|
||||
|
||||
const Pad::ControllerInfo PadDualshock2::ControllerInfo = {Pad::ControllerType::DualShock2, "DualShock2",
|
||||
TRANSLATE_NOOP("Pad", "DualShock 2"), s_bindings, s_settings, Pad::VibrationCapabilities::LargeSmallMotors};
|
||||
|
||||
u8 PadDualshock2::Mystery(u8 commandByte)
|
||||
{
|
||||
switch (commandBytesReceived)
|
||||
@@ -40,36 +110,49 @@ u8 PadDualshock2::Mystery(u8 commandByte)
|
||||
|
||||
u8 PadDualshock2::ButtonQuery(u8 commandByte)
|
||||
{
|
||||
switch (commandBytesReceived)
|
||||
switch (this->currentMode)
|
||||
{
|
||||
case 3:
|
||||
case 4:
|
||||
return 0xff;
|
||||
case 5:
|
||||
return 0x03;
|
||||
case 8:
|
||||
g_Sio0.SetAcknowledge(false);
|
||||
return 0x5a;
|
||||
case Pad::Mode::DUALSHOCK2:
|
||||
case Pad::Mode::ANALOG:
|
||||
switch (commandBytesReceived)
|
||||
{
|
||||
case 3:
|
||||
case 4:
|
||||
return 0xff;
|
||||
case 5:
|
||||
return 0x03;
|
||||
case 8:
|
||||
g_Sio0.SetAcknowledge(false);
|
||||
return 0x5a;
|
||||
default:
|
||||
return 0x00;
|
||||
}
|
||||
default:
|
||||
return 0x00;
|
||||
switch (commandBytesReceived)
|
||||
{
|
||||
case 8:
|
||||
g_Sio0.SetAcknowledge(false);
|
||||
return 0x5a;
|
||||
default:
|
||||
return 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8 PadDualshock2::Poll(u8 commandByte)
|
||||
{
|
||||
PadBase* pad = g_PadManager.GetPad(this->unifiedSlot);
|
||||
const u32 buttons = pad->GetButtons();
|
||||
const u32 buttons = GetButtons();
|
||||
|
||||
switch (commandBytesReceived)
|
||||
{
|
||||
case 3:
|
||||
this->vibrationMotors.at(0) = commandByte;
|
||||
this->vibrationMotors[0] = commandByte;
|
||||
return (buttons >> 8) & 0xff;
|
||||
case 4:
|
||||
this->vibrationMotors.at(1) = commandByte;
|
||||
this->vibrationMotors[1] = commandByte;
|
||||
InputManager::SetPadVibrationIntensity(this->unifiedSlot,
|
||||
std::min(static_cast<float>(this->vibrationMotors.at(0)) * GetVibrationScale(0) * (1.0f / 255.0f), 1.0f),
|
||||
std::min(static_cast<float>(this->vibrationMotors.at(1)) * GetVibrationScale(1) * (1.0f / 255.0f), 1.0f)
|
||||
std::min(static_cast<float>(this->vibrationMotors[0]) * GetVibrationScale(0) * (1.0f / 255.0f), 1.0f),
|
||||
std::min(static_cast<float>(this->vibrationMotors[1]) * GetVibrationScale(1) * (1.0f / 255.0f), 1.0f)
|
||||
);
|
||||
|
||||
// PS1 mode: If the controller is still in digital mode, it is time to stop acknowledging.
|
||||
@@ -80,40 +163,40 @@ u8 PadDualshock2::Poll(u8 commandByte)
|
||||
|
||||
return buttons & 0xff;
|
||||
case 5:
|
||||
return pad->GetPressure(Dualshock2::Inputs::PAD_R_RIGHT);
|
||||
return GetPressure(Inputs::PAD_R_RIGHT);
|
||||
case 6:
|
||||
return pad->GetPressure(Dualshock2::Inputs::PAD_R_UP);
|
||||
return GetPressure(Inputs::PAD_R_UP);
|
||||
case 7:
|
||||
return pad->GetPressure(Dualshock2::Inputs::PAD_L_RIGHT);
|
||||
return GetPressure(Inputs::PAD_L_RIGHT);
|
||||
case 8:
|
||||
// PS1 mode: If the controller reaches this byte, it is in analog mode and has irrefutably reached the last byte.
|
||||
// There's simply nothing to check, we know it's done and time to stop acknowledgements.
|
||||
g_Sio0.SetAcknowledge(false);
|
||||
return pad->GetPressure(Dualshock2::Inputs::PAD_L_UP);
|
||||
return GetPressure(Inputs::PAD_L_UP);
|
||||
case 9:
|
||||
return IsButtonBitSet(buttons, 13) ? pad->GetPressure(Dualshock2::Inputs::PAD_RIGHT) : 0;
|
||||
return IsButtonBitSet(buttons, 13) ? GetPressure(Inputs::PAD_RIGHT) : 0;
|
||||
case 10:
|
||||
return IsButtonBitSet(buttons, 15) ? pad->GetPressure(Dualshock2::Inputs::PAD_LEFT) : 0;
|
||||
return IsButtonBitSet(buttons, 15) ? GetPressure(Inputs::PAD_LEFT) : 0;
|
||||
case 11:
|
||||
return IsButtonBitSet(buttons, 12) ? pad->GetPressure(Dualshock2::Inputs::PAD_UP) : 0;
|
||||
return IsButtonBitSet(buttons, 12) ? GetPressure(Inputs::PAD_UP) : 0;
|
||||
case 12:
|
||||
return IsButtonBitSet(buttons, 14) ? pad->GetPressure(Dualshock2::Inputs::PAD_DOWN) : 0;
|
||||
return IsButtonBitSet(buttons, 14) ? GetPressure(Inputs::PAD_DOWN) : 0;
|
||||
case 13:
|
||||
return IsButtonBitSet(buttons, 4) ? pad->GetPressure(Dualshock2::Inputs::PAD_TRIANGLE) : 0;
|
||||
return IsButtonBitSet(buttons, 4) ? GetPressure(Inputs::PAD_TRIANGLE) : 0;
|
||||
case 14:
|
||||
return IsButtonBitSet(buttons, 5) ? pad->GetPressure(Dualshock2::Inputs::PAD_CIRCLE) : 0;
|
||||
return IsButtonBitSet(buttons, 5) ? GetPressure(Inputs::PAD_CIRCLE) : 0;
|
||||
case 15:
|
||||
return IsButtonBitSet(buttons, 6) ? pad->GetPressure(Dualshock2::Inputs::PAD_CROSS) : 0;
|
||||
return IsButtonBitSet(buttons, 6) ? GetPressure(Inputs::PAD_CROSS) : 0;
|
||||
case 16:
|
||||
return IsButtonBitSet(buttons, 7) ? pad->GetPressure(Dualshock2::Inputs::PAD_SQUARE) : 0;
|
||||
return IsButtonBitSet(buttons, 7) ? GetPressure(Inputs::PAD_SQUARE) : 0;
|
||||
case 17:
|
||||
return IsButtonBitSet(buttons, 2) ? pad->GetPressure(Dualshock2::Inputs::PAD_L1) : 0;
|
||||
return IsButtonBitSet(buttons, 2) ? GetPressure(Inputs::PAD_L1) : 0;
|
||||
case 18:
|
||||
return IsButtonBitSet(buttons, 3) ? pad->GetPressure(Dualshock2::Inputs::PAD_R1) : 0;
|
||||
return IsButtonBitSet(buttons, 3) ? GetPressure(Inputs::PAD_R1) : 0;
|
||||
case 19:
|
||||
return IsButtonBitSet(buttons, 0) ? pad->GetPressure(Dualshock2::Inputs::PAD_L2) : 0;
|
||||
return IsButtonBitSet(buttons, 0) ? GetPressure(Inputs::PAD_L2) : 0;
|
||||
case 20:
|
||||
return IsButtonBitSet(buttons, 1) ? pad->GetPressure(Dualshock2::Inputs::PAD_R2) : 0;
|
||||
return IsButtonBitSet(buttons, 1) ? GetPressure(Inputs::PAD_R2) : 0;
|
||||
}
|
||||
|
||||
Console.Warning("%s(%02X) Did not reach a valid return path! Returning zero as a failsafe!", __FUNCTION__, commandByte);
|
||||
@@ -224,25 +307,34 @@ u8 PadDualshock2::StatusInfo(u8 commandByte)
|
||||
|
||||
u8 PadDualshock2::Constant1(u8 commandByte)
|
||||
{
|
||||
static bool stage;
|
||||
|
||||
switch (commandBytesReceived)
|
||||
{
|
||||
case 3:
|
||||
stage = commandByte;
|
||||
commandStage = commandByte != 0;
|
||||
return 0x00;
|
||||
case 5:
|
||||
return 0x01;
|
||||
case 6:
|
||||
if (stage)
|
||||
if (commandStage)
|
||||
{
|
||||
return 0x00;
|
||||
return 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0x02;
|
||||
}
|
||||
case 7:
|
||||
if (commandStage)
|
||||
{
|
||||
return 0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0x00;
|
||||
}
|
||||
case 8:
|
||||
g_Sio0.SetAcknowledge(false);
|
||||
return (stage ? 0x14 : 0x0a);
|
||||
return (commandStage ? 0x14 : 0x0a);
|
||||
default:
|
||||
return 0x00;
|
||||
}
|
||||
@@ -264,15 +356,13 @@ u8 PadDualshock2::Constant2(u8 commandByte)
|
||||
|
||||
u8 PadDualshock2::Constant3(u8 commandByte)
|
||||
{
|
||||
static bool stage;
|
||||
|
||||
switch (commandBytesReceived)
|
||||
{
|
||||
case 3:
|
||||
stage = commandByte;
|
||||
commandStage = (commandByte != 0);
|
||||
return 0x00;
|
||||
case 6:
|
||||
if (stage)
|
||||
if (commandStage)
|
||||
{
|
||||
return 0x07;
|
||||
}
|
||||
@@ -368,38 +458,43 @@ void PadDualshock2::Init()
|
||||
|
||||
for (u8 i = 0; i < this->rawInputs.size(); i++)
|
||||
{
|
||||
this->rawInputs.at(i) = 0;
|
||||
this->rawInputs[i] = 0;
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < this->pressures.size(); i++)
|
||||
{
|
||||
this->pressures.at(i) = 0;
|
||||
this->pressures[i] = 0;
|
||||
}
|
||||
|
||||
this->axisScale = 1.0f;
|
||||
this->axisDeadzone = 0.0f;
|
||||
|
||||
this->vibrationScale.at(0) = 0.0f;
|
||||
this->vibrationScale.at(1) = 1.0f;
|
||||
this->vibrationScale[0] = 0.0f;
|
||||
this->vibrationScale[1] = 1.0f;
|
||||
|
||||
this->pressureModifier = 0.5f;
|
||||
this->buttonDeadzone = 0.0f;
|
||||
}
|
||||
|
||||
Pad::ControllerType PadDualshock2::GetType()
|
||||
Pad::ControllerType PadDualshock2::GetType() const
|
||||
{
|
||||
return Pad::ControllerType::DualShock2;
|
||||
}
|
||||
|
||||
const Pad::ControllerInfo& PadDualshock2::GetInfo() const
|
||||
{
|
||||
return ControllerInfo;
|
||||
}
|
||||
|
||||
void PadDualshock2::Set(u32 index, float value)
|
||||
{
|
||||
if (index > Dualshock2::Inputs::LENGTH)
|
||||
if (index > Inputs::LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Since we reordered the buttons for better UI, we need to remap them here.
|
||||
static constexpr std::array<u8, Dualshock2::Inputs::LENGTH> bitmaskMapping = {{
|
||||
static constexpr std::array<u8, Inputs::LENGTH> bitmaskMapping = {{
|
||||
12, // PAD_UP
|
||||
13, // PAD_RIGHT
|
||||
14, // PAD_DOWN
|
||||
@@ -434,17 +529,17 @@ void PadDualshock2::Set(u32 index, float value)
|
||||
// merge left/right or up/down into rx or ry
|
||||
|
||||
#define MERGE(pos, neg) ((this->rawInputs[pos] != 0) ? (127u + ((this->rawInputs[pos] + 1u) / 2u)) : (127u - (this->rawInputs[neg] / 2u)))
|
||||
if (index <= Dualshock2::Inputs::PAD_L_LEFT)
|
||||
if (index <= Inputs::PAD_L_LEFT)
|
||||
{
|
||||
// Left Stick
|
||||
this->analogs.lx = this->analogs.lxInvert ? MERGE(Dualshock2::Inputs::PAD_L_LEFT, Dualshock2::Inputs::PAD_L_RIGHT) : MERGE(Dualshock2::Inputs::PAD_L_RIGHT, Dualshock2::Inputs::PAD_L_LEFT);
|
||||
this->analogs.ly = this->analogs.lyInvert ? MERGE(Dualshock2::Inputs::PAD_L_UP, Dualshock2::Inputs::PAD_L_DOWN) : MERGE(Dualshock2::Inputs::PAD_L_DOWN, Dualshock2::Inputs::PAD_L_UP);
|
||||
this->analogs.lx = this->analogs.lxInvert ? MERGE(Inputs::PAD_L_LEFT, Inputs::PAD_L_RIGHT) : MERGE(Inputs::PAD_L_RIGHT, Inputs::PAD_L_LEFT);
|
||||
this->analogs.ly = this->analogs.lyInvert ? MERGE(Inputs::PAD_L_UP, Inputs::PAD_L_DOWN) : MERGE(Inputs::PAD_L_DOWN, Inputs::PAD_L_UP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Right Stick
|
||||
this->analogs.rx = this->analogs.rxInvert ? MERGE(Dualshock2::Inputs::PAD_R_LEFT, Dualshock2::Inputs::PAD_R_RIGHT) : MERGE(Dualshock2::Inputs::PAD_R_RIGHT, Dualshock2::Inputs::PAD_R_LEFT);
|
||||
this->analogs.ry = this->analogs.ryInvert ? MERGE(Dualshock2::Inputs::PAD_R_UP, Dualshock2::Inputs::PAD_R_DOWN) : MERGE(Dualshock2::Inputs::PAD_R_DOWN, Dualshock2::Inputs::PAD_R_UP);
|
||||
this->analogs.rx = this->analogs.rxInvert ? MERGE(Inputs::PAD_R_LEFT, Inputs::PAD_R_RIGHT) : MERGE(Inputs::PAD_R_RIGHT, Inputs::PAD_R_LEFT);
|
||||
this->analogs.ry = this->analogs.ryInvert ? MERGE(Inputs::PAD_R_UP, Inputs::PAD_R_DOWN) : MERGE(Inputs::PAD_R_DOWN, Inputs::PAD_R_UP);
|
||||
}
|
||||
#undef MERGE
|
||||
|
||||
@@ -455,15 +550,15 @@ void PadDualshock2::Set(u32 index, float value)
|
||||
{
|
||||
#define MERGE_F(pos, neg) ((this->rawInputs[pos] != 0) ? (static_cast<float>(this->rawInputs[pos]) / 255.0f) : (static_cast<float>(this->rawInputs[neg]) / -255.0f))
|
||||
float posX, posY;
|
||||
if (index <= Dualshock2::Inputs::PAD_L_LEFT)
|
||||
if (index <= Inputs::PAD_L_LEFT)
|
||||
{
|
||||
posX = this->analogs.lxInvert ? MERGE_F(Dualshock2::Inputs::PAD_L_LEFT, Dualshock2::Inputs::PAD_L_RIGHT) : MERGE_F(Dualshock2::Inputs::PAD_L_RIGHT, Dualshock2::Inputs::PAD_L_LEFT);
|
||||
posY = this->analogs.lyInvert ? MERGE_F(Dualshock2::Inputs::PAD_L_UP, Dualshock2::Inputs::PAD_L_DOWN) : MERGE_F(Dualshock2::Inputs::PAD_L_DOWN, Dualshock2::Inputs::PAD_L_UP);
|
||||
posX = this->analogs.lxInvert ? MERGE_F(Inputs::PAD_L_LEFT, Inputs::PAD_L_RIGHT) : MERGE_F(Inputs::PAD_L_RIGHT, Inputs::PAD_L_LEFT);
|
||||
posY = this->analogs.lyInvert ? MERGE_F(Inputs::PAD_L_UP, Inputs::PAD_L_DOWN) : MERGE_F(Inputs::PAD_L_DOWN, Inputs::PAD_L_UP);
|
||||
}
|
||||
else
|
||||
{
|
||||
posX = this->analogs.rxInvert ? MERGE_F(Dualshock2::Inputs::PAD_R_LEFT, Dualshock2::Inputs::PAD_R_RIGHT) : MERGE_F(Dualshock2::Inputs::PAD_R_RIGHT, Dualshock2::Inputs::PAD_R_LEFT);
|
||||
posY = this->analogs.ryInvert ? MERGE_F(Dualshock2::Inputs::PAD_R_UP, Dualshock2::Inputs::PAD_R_DOWN) : MERGE_F(Dualshock2::Inputs::PAD_R_DOWN, Dualshock2::Inputs::PAD_R_UP);
|
||||
posX = this->analogs.rxInvert ? MERGE_F(Inputs::PAD_R_LEFT, Inputs::PAD_R_RIGHT) : MERGE_F(Inputs::PAD_R_RIGHT, Inputs::PAD_R_LEFT);
|
||||
posY = this->analogs.ryInvert ? MERGE_F(Inputs::PAD_R_UP, Inputs::PAD_R_DOWN) : MERGE_F(Inputs::PAD_R_DOWN, Inputs::PAD_R_UP);
|
||||
}
|
||||
|
||||
// No point checking if we're at dead center (usually keyboard with no buttons pressed).
|
||||
@@ -483,7 +578,7 @@ void PadDualshock2::Set(u32 index, float value)
|
||||
if (inX && inY)
|
||||
{
|
||||
// In deadzone. Set to 127 (center).
|
||||
if (index <= Dualshock2::Inputs::PAD_L_LEFT)
|
||||
if (index <= Inputs::PAD_L_LEFT)
|
||||
{
|
||||
this->analogs.lx = this->analogs.ly = 127;
|
||||
}
|
||||
@@ -509,7 +604,7 @@ void PadDualshock2::Set(u32 index, float value)
|
||||
else
|
||||
{
|
||||
// Don't affect L2/R2, since they are analog on most pads.
|
||||
const float pMod = ((this->buttons & (1u << Dualshock2::Inputs::PAD_PRESSURE)) == 0 && !IsTriggerKey(index)) ? this->pressureModifier : 1.0f;
|
||||
const float pMod = ((this->buttons & (1u << Inputs::PAD_PRESSURE)) == 0 && !IsTriggerKey(index)) ? this->pressureModifier : 1.0f;
|
||||
const float dzValue = (value < this->buttonDeadzone) ? 0.0f : value;
|
||||
this->rawInputs[index] = static_cast<u8>(std::clamp(dzValue * pMod * 255.0f, 0.0f, 255.0f));
|
||||
|
||||
@@ -523,11 +618,11 @@ void PadDualshock2::Set(u32 index, float value)
|
||||
}
|
||||
|
||||
// Adjust pressure of all other face buttons which are active when pressure modifier is pressed..
|
||||
if (index == Dualshock2::Inputs::PAD_PRESSURE)
|
||||
if (index == Inputs::PAD_PRESSURE)
|
||||
{
|
||||
const float adjustPMod = ((this->buttons & (1u << Dualshock2::Inputs::PAD_PRESSURE)) == 0) ? this->pressureModifier : (1.0f / this->pressureModifier);
|
||||
const float adjustPMod = ((this->buttons & (1u << Inputs::PAD_PRESSURE)) == 0) ? this->pressureModifier : (1.0f / this->pressureModifier);
|
||||
|
||||
for (u32 i = 0; i < Dualshock2::Inputs::LENGTH; i++)
|
||||
for (u32 i = 0; i < Inputs::LENGTH; i++)
|
||||
{
|
||||
if (i == index || IsAnalogKey(i) || IsTriggerKey(i))
|
||||
{
|
||||
@@ -540,7 +635,7 @@ void PadDualshock2::Set(u32 index, float value)
|
||||
}
|
||||
}
|
||||
|
||||
if (index == Dualshock2::Inputs::PAD_ANALOG && !this->analogPressed && value > 0)
|
||||
if (index == Inputs::PAD_ANALOG && !this->analogPressed && value > 0)
|
||||
{
|
||||
this->analogPressed = true;
|
||||
|
||||
@@ -594,7 +689,7 @@ void PadDualshock2::SetTriggerScale(float deadzone, float scale)
|
||||
this->triggerScale = scale;
|
||||
}
|
||||
|
||||
float PadDualshock2::GetVibrationScale(u32 motor)
|
||||
float PadDualshock2::GetVibrationScale(u32 motor) const
|
||||
{
|
||||
return this->vibrationScale[motor];
|
||||
}
|
||||
@@ -604,7 +699,7 @@ void PadDualshock2::SetVibrationScale(u32 motor, float scale)
|
||||
this->vibrationScale[motor] = scale;
|
||||
}
|
||||
|
||||
float PadDualshock2::GetPressureModifier()
|
||||
float PadDualshock2::GetPressureModifier() const
|
||||
{
|
||||
return this->pressureModifier;
|
||||
}
|
||||
@@ -631,63 +726,59 @@ void PadDualshock2::SetAnalogInvertR(bool x, bool y)
|
||||
this->analogs.ryInvert = y;
|
||||
}
|
||||
|
||||
u8 PadDualshock2::GetRawInput(u32 index)
|
||||
u8 PadDualshock2::GetRawInput(u32 index) const
|
||||
{
|
||||
return this->rawInputs[index];
|
||||
return rawInputs[index];
|
||||
}
|
||||
|
||||
std::tuple<u8, u8> PadDualshock2::GetRawLeftAnalog()
|
||||
std::tuple<u8, u8> PadDualshock2::GetRawLeftAnalog() const
|
||||
{
|
||||
return {this->analogs.lx, this->analogs.ly};
|
||||
return {analogs.lx, analogs.ly};
|
||||
}
|
||||
|
||||
std::tuple<u8, u8> PadDualshock2::GetRawRightAnalog()
|
||||
std::tuple<u8, u8> PadDualshock2::GetRawRightAnalog() const
|
||||
{
|
||||
return {this->analogs.rx, this->analogs.ry};
|
||||
return {analogs.rx, analogs.ry};
|
||||
}
|
||||
|
||||
u32 PadDualshock2::GetButtons()
|
||||
u32 PadDualshock2::GetButtons() const
|
||||
{
|
||||
return this->buttons;
|
||||
return buttons;
|
||||
}
|
||||
|
||||
u8 PadDualshock2::GetPressure(u32 index)
|
||||
u8 PadDualshock2::GetPressure(u32 index) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case Dualshock2::Inputs::PAD_R_LEFT:
|
||||
case Dualshock2::Inputs::PAD_R_RIGHT:
|
||||
case Inputs::PAD_R_LEFT:
|
||||
case Inputs::PAD_R_RIGHT:
|
||||
return this->analogs.rx;
|
||||
case Dualshock2::Inputs::PAD_R_DOWN:
|
||||
case Dualshock2::Inputs::PAD_R_UP:
|
||||
case Inputs::PAD_R_DOWN:
|
||||
case Inputs::PAD_R_UP:
|
||||
return this->analogs.ry;
|
||||
case Dualshock2::Inputs::PAD_L_LEFT:
|
||||
case Dualshock2::Inputs::PAD_L_RIGHT:
|
||||
case Inputs::PAD_L_LEFT:
|
||||
case Inputs::PAD_L_RIGHT:
|
||||
return this->analogs.lx;
|
||||
case Dualshock2::Inputs::PAD_L_DOWN:
|
||||
case Dualshock2::Inputs::PAD_L_UP:
|
||||
case Inputs::PAD_L_DOWN:
|
||||
case Inputs::PAD_L_UP:
|
||||
return this->analogs.ly;
|
||||
default:
|
||||
return this->rawInputs.at(index);
|
||||
return this->rawInputs[index];
|
||||
}
|
||||
}
|
||||
|
||||
void PadDualshock2::Freeze(StateWrapper& sw)
|
||||
bool PadDualshock2::Freeze(StateWrapper& sw)
|
||||
{
|
||||
// Protected PadBase members
|
||||
sw.Do(&rawInputs);
|
||||
sw.Do(&unifiedSlot);
|
||||
sw.Do(&isInConfig);
|
||||
sw.Do(¤tMode);
|
||||
sw.Do(¤tCommand);
|
||||
sw.Do(&commandBytesReceived);
|
||||
if (!PadBase::Freeze(sw) || !sw.DoMarker("PadDualshock2"))
|
||||
return false;
|
||||
|
||||
// Private PadDualshock2 members
|
||||
sw.Do(&buttons);
|
||||
sw.DoBytes(&analogs, sizeof(Dualshock2::Analogs));
|
||||
sw.DoBytes(&analogs, sizeof(Analogs));
|
||||
sw.Do(&analogLight);
|
||||
sw.Do(&analogLocked);
|
||||
sw.Do(&analogPressed);
|
||||
sw.Do(&commandStage);
|
||||
sw.Do(&responseBytes);
|
||||
sw.Do(&pressures);
|
||||
sw.Do(&vibrationMotors);
|
||||
@@ -698,6 +789,7 @@ void PadDualshock2::Freeze(StateWrapper& sw)
|
||||
sw.Do(&vibrationScale);
|
||||
sw.Do(&pressureModifier);
|
||||
sw.Do(&buttonDeadzone);
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
u8 PadDualshock2::SendCommandByte(u8 commandByte)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
#include "SIO/Pad/PadDualshock2Types.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
@@ -25,30 +24,68 @@ static inline bool IsButtonBitSet(u32 value, size_t bit)
|
||||
return !(value & (1 << bit));
|
||||
}
|
||||
|
||||
static inline bool IsAnalogKey(int index)
|
||||
class PadDualshock2 final : public PadBase
|
||||
{
|
||||
return ((index >= Dualshock2::Inputs::PAD_L_UP) && (index <= Dualshock2::Inputs::PAD_R_LEFT));
|
||||
}
|
||||
public:
|
||||
enum Inputs
|
||||
{
|
||||
PAD_UP, // Directional pad up
|
||||
PAD_RIGHT, // Directional pad right
|
||||
PAD_DOWN, // Directional pad down
|
||||
PAD_LEFT, // Directional pad left
|
||||
PAD_TRIANGLE, // Triangle button
|
||||
PAD_CIRCLE, // Circle button
|
||||
PAD_CROSS, // Cross button
|
||||
PAD_SQUARE, // Square button
|
||||
PAD_SELECT, // Select button
|
||||
PAD_START, // Start button
|
||||
PAD_L1, // L1 button
|
||||
PAD_L2, // L2 button
|
||||
PAD_R1, // R1 button
|
||||
PAD_R2, // R2 button
|
||||
PAD_L3, // Left joystick button (L3)
|
||||
PAD_R3, // Right joystick button (R3)
|
||||
PAD_ANALOG, // Analog mode toggle
|
||||
PAD_PRESSURE, // Pressure modifier
|
||||
PAD_L_UP, // Left joystick (Up)
|
||||
PAD_L_RIGHT, // Left joystick (Right)
|
||||
PAD_L_DOWN, // Left joystick (Down)
|
||||
PAD_L_LEFT, // Left joystick (Left)
|
||||
PAD_R_UP, // Right joystick (Up)
|
||||
PAD_R_RIGHT, // Right joystick (Right)
|
||||
PAD_R_DOWN, // Right joystick (Down)
|
||||
PAD_R_LEFT, // Right joystick (Left)
|
||||
LENGTH,
|
||||
};
|
||||
|
||||
static inline bool IsTriggerKey(int index)
|
||||
{
|
||||
return (index == Dualshock2::Inputs::PAD_L2 || index == Dualshock2::Inputs::PAD_R2);
|
||||
}
|
||||
static constexpr u32 PRESSURE_BUTTONS = 12;
|
||||
static constexpr u8 VIBRATION_MOTORS = 2;
|
||||
|
||||
class PadDualshock2 : public PadBase
|
||||
{
|
||||
private:
|
||||
struct Analogs
|
||||
{
|
||||
u8 lx = 0x7f;
|
||||
u8 ly = 0x7f;
|
||||
u8 rx = 0x7f;
|
||||
u8 ry = 0x7f;
|
||||
u8 lxInvert = 0x7f;
|
||||
u8 lyInvert = 0x7f;
|
||||
u8 rxInvert = 0x7f;
|
||||
u8 ryInvert = 0x7f;
|
||||
};
|
||||
|
||||
u32 buttons;
|
||||
Dualshock2::Analogs analogs;
|
||||
Analogs analogs;
|
||||
bool analogLight = false;
|
||||
bool analogLocked = false;
|
||||
// Analog button can be held without changing its state.
|
||||
// We track here if it is currently held down, to avoid flipping in
|
||||
// and out of analog mode every frame.
|
||||
bool analogPressed = false;
|
||||
bool commandStage = false;
|
||||
u32 responseBytes;
|
||||
std::array<u8, Dualshock2::PRESSURE_BUTTONS> pressures;
|
||||
std::array<u8, Dualshock2::VIBRATION_MOTORS> vibrationMotors;
|
||||
std::array<u8, PRESSURE_BUTTONS> pressures;
|
||||
std::array<u8, VIBRATION_MOTORS> vibrationMotors;
|
||||
float axisScale;
|
||||
float axisDeadzone;
|
||||
float triggerScale;
|
||||
@@ -74,28 +111,41 @@ private:
|
||||
|
||||
public:
|
||||
PadDualshock2(u8 unifiedSlot);
|
||||
virtual ~PadDualshock2();
|
||||
~PadDualshock2() override;
|
||||
|
||||
static inline bool IsAnalogKey(int index)
|
||||
{
|
||||
return ((index >= Inputs::PAD_L_UP) && (index <= Inputs::PAD_R_LEFT));
|
||||
}
|
||||
|
||||
static inline bool IsTriggerKey(int index)
|
||||
{
|
||||
return (index == Inputs::PAD_L2 || index == Inputs::PAD_R2);
|
||||
}
|
||||
|
||||
void Init() override;
|
||||
Pad::ControllerType GetType() override;
|
||||
Pad::ControllerType GetType() const override;
|
||||
const Pad::ControllerInfo& GetInfo() const override;
|
||||
void Set(u32 index, float value) override;
|
||||
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
|
||||
void SetAxisScale(float deadzone, float scale) override;
|
||||
void SetTriggerScale(float deadzone, float scale) override;
|
||||
float GetVibrationScale(u32 motor) override;
|
||||
float GetVibrationScale(u32 motor) const override;
|
||||
void SetVibrationScale(u32 motor, float scale) override;
|
||||
float GetPressureModifier() override;
|
||||
float GetPressureModifier() const override;
|
||||
void SetPressureModifier(float mod) override;
|
||||
void SetButtonDeadzone(float deadzone) override;
|
||||
void SetAnalogInvertL(bool x, bool y) override;
|
||||
void SetAnalogInvertR(bool x, bool y) override;
|
||||
u8 GetRawInput(u32 index) override;
|
||||
std::tuple<u8, u8> GetRawLeftAnalog() override;
|
||||
std::tuple<u8, u8> GetRawRightAnalog() override;
|
||||
u32 GetButtons() override;
|
||||
u8 GetPressure(u32 index) override;
|
||||
u8 GetRawInput(u32 index) const override;
|
||||
std::tuple<u8, u8> GetRawLeftAnalog() const override;
|
||||
std::tuple<u8, u8> GetRawRightAnalog() const override;
|
||||
u32 GetButtons() const override;
|
||||
u8 GetPressure(u32 index) const override;
|
||||
|
||||
void Freeze(StateWrapper& sw) override;
|
||||
bool Freeze(StateWrapper& sw) override;
|
||||
|
||||
u8 SendCommandByte(u8 commandByte) override;
|
||||
|
||||
static const Pad::ControllerInfo ControllerInfo;
|
||||
};
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
namespace Dualshock2
|
||||
{
|
||||
enum Inputs
|
||||
{
|
||||
PAD_UP, // Directional pad up
|
||||
PAD_RIGHT, // Directional pad right
|
||||
PAD_DOWN, // Directional pad down
|
||||
PAD_LEFT, // Directional pad left
|
||||
PAD_TRIANGLE, // Triangle button
|
||||
PAD_CIRCLE, // Circle button
|
||||
PAD_CROSS, // Cross button
|
||||
PAD_SQUARE, // Square button
|
||||
PAD_SELECT, // Select button
|
||||
PAD_START, // Start button
|
||||
PAD_L1, // L1 button
|
||||
PAD_L2, // L2 button
|
||||
PAD_R1, // R1 button
|
||||
PAD_R2, // R2 button
|
||||
PAD_L3, // Left joystick button (L3)
|
||||
PAD_R3, // Right joystick button (R3)
|
||||
PAD_ANALOG, // Analog mode toggle
|
||||
PAD_PRESSURE, // Pressure modifier
|
||||
PAD_L_UP, // Left joystick (Up)
|
||||
PAD_L_RIGHT, // Left joystick (Right)
|
||||
PAD_L_DOWN, // Left joystick (Down)
|
||||
PAD_L_LEFT, // Left joystick (Left)
|
||||
PAD_R_UP, // Right joystick (Up)
|
||||
PAD_R_RIGHT, // Right joystick (Right)
|
||||
PAD_R_DOWN, // Right joystick (Down)
|
||||
PAD_R_LEFT, // Right joystick (Left)
|
||||
LENGTH,
|
||||
};
|
||||
|
||||
static constexpr u32 PRESSURE_BUTTONS = 12;
|
||||
static constexpr u8 VIBRATION_MOTORS = 2;
|
||||
|
||||
struct Analogs
|
||||
{
|
||||
u8 lx = 0x7f;
|
||||
u8 ly = 0x7f;
|
||||
u8 rx = 0x7f;
|
||||
u8 ry = 0x7f;
|
||||
u8 lxInvert = 0x7f;
|
||||
u8 lyInvert = 0x7f;
|
||||
u8 rxInvert = 0x7f;
|
||||
u8 ryInvert = 0x7f;
|
||||
};
|
||||
|
||||
static const InputBindingInfo defaultBindings[] = {
|
||||
{"Up", "D-Pad Up", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_UP, GenericInputBinding::DPadUp},
|
||||
{"Right", "D-Pad Right", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_RIGHT, GenericInputBinding::DPadRight},
|
||||
{"Down", "D-Pad Down", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_DOWN, GenericInputBinding::DPadDown},
|
||||
{"Left", "D-Pad Left", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_LEFT, GenericInputBinding::DPadLeft},
|
||||
{"Triangle", "Triangle", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_TRIANGLE, GenericInputBinding::Triangle},
|
||||
{"Circle", "Circle", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_CIRCLE, GenericInputBinding::Circle},
|
||||
{"Cross", "Cross", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_CROSS, GenericInputBinding::Cross},
|
||||
{"Square", "Square", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_SQUARE, GenericInputBinding::Square},
|
||||
{"Select", "Select", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_SELECT, GenericInputBinding::Select},
|
||||
{"Start", "Start", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_START, GenericInputBinding::Start},
|
||||
{"L1", "L1 (Left Bumper)", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_L1, GenericInputBinding::L1},
|
||||
{"L2", "L2 (Left Trigger)", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_L2, GenericInputBinding::L2},
|
||||
{"R1", "R1 (Right Bumper)", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_R1, GenericInputBinding::R1},
|
||||
{"R2", "R2 (Right Trigger)", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_R2, GenericInputBinding::R2},
|
||||
{"L3", "L3 (Left Stick Button)", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_L3, GenericInputBinding::L3},
|
||||
{"R3", "R3 (Right Stick Button)", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_R3, GenericInputBinding::R3},
|
||||
{"Analog", "Analog Toggle", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_ANALOG, GenericInputBinding::System},
|
||||
{"Pressure", "Apply Pressure", InputBindingInfo::Type::Button, Dualshock2::Inputs::PAD_PRESSURE, GenericInputBinding::Unknown},
|
||||
{"LUp", "Left Stick Up", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_L_UP, GenericInputBinding::LeftStickUp},
|
||||
{"LRight", "Left Stick Right", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_L_RIGHT, GenericInputBinding::LeftStickRight},
|
||||
{"LDown", "Left Stick Down", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_L_DOWN, GenericInputBinding::LeftStickDown},
|
||||
{"LLeft", "Left Stick Left", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_L_LEFT, GenericInputBinding::LeftStickLeft},
|
||||
{"RUp", "Right Stick Up", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_R_UP, GenericInputBinding::RightStickUp},
|
||||
{"RRight", "Right Stick Right", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_R_RIGHT, GenericInputBinding::RightStickRight},
|
||||
{"RDown", "Right Stick Down", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_R_DOWN, GenericInputBinding::RightStickDown},
|
||||
{"RLeft", "Right Stick Left", InputBindingInfo::Type::HalfAxis, Dualshock2::Inputs::PAD_R_LEFT, GenericInputBinding::RightStickLeft},
|
||||
{"LargeMotor", "Large (Low Frequency) Motor", InputBindingInfo::Type::Motor, 0, GenericInputBinding::LargeMotor},
|
||||
{"SmallMotor", "Small (High Frequency) Motor", InputBindingInfo::Type::Motor, 0, GenericInputBinding::SmallMotor},
|
||||
};
|
||||
|
||||
static const char* invertOptions[] = {
|
||||
"Not Inverted",
|
||||
"Invert Left/Right",
|
||||
"Invert Up/Down",
|
||||
"Invert Left/Right + Up/Down",
|
||||
nullptr};
|
||||
|
||||
static const SettingInfo defaultSettings[] = {
|
||||
{SettingInfo::Type::IntegerList, "InvertL", "Invert Left Stick",
|
||||
"Inverts the direction of the left analog stick.",
|
||||
"0", "0", "3", nullptr, nullptr, invertOptions, nullptr, 0.0f},
|
||||
{SettingInfo::Type::IntegerList, "InvertR", "Invert Right Stick",
|
||||
"Inverts the direction of the right analog stick.",
|
||||
"0", "0", "3", nullptr, nullptr, invertOptions, nullptr, 0.0f},
|
||||
{SettingInfo::Type::Float, "Deadzone", "Analog Deadzone",
|
||||
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored.",
|
||||
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "AxisScale", "Analog Sensitivity",
|
||||
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent "
|
||||
"controllers, e.g. DualShock 4, Xbox One Controller.",
|
||||
"1.33", "0.01", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "LargeMotorScale", "Large Motor Vibration Scale",
|
||||
"Increases or decreases the intensity of low frequency vibration sent by the game.",
|
||||
"1.00", "0.00", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "SmallMotorScale", "Small Motor Vibration Scale",
|
||||
"Increases or decreases the intensity of high frequency vibration sent by the game.",
|
||||
"1.00", "0.00", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "ButtonDeadzone", "Button/Trigger Deadzone",
|
||||
"Sets the deadzone for activating buttons/triggers, i.e. the fraction of the trigger which will be ignored.",
|
||||
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "PressureModifier", "Modifier Pressure",
|
||||
"Sets the pressure when the modifier button is held.",
|
||||
"0.50", "0.01", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
};
|
||||
} // namespace Dualshock2
|
||||
@@ -16,12 +16,40 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "SIO/Pad/PadGuitar.h"
|
||||
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/PadGuitarTypes.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Sio.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "Host.h"
|
||||
|
||||
// The generic input bindings on this might seem bizarre, but they are intended to match what DS2 buttons
|
||||
// would do what actions, if you played Guitar Hero on a PS2 with a DS2 instead of a controller.
|
||||
static const InputBindingInfo s_bindings[] = {
|
||||
// clang-format off
|
||||
{"Up", TRANSLATE_NOOP("Pad", "Strum Up"), InputBindingInfo::Type::Button, PadGuitar::Inputs::STRUM_UP, GenericInputBinding::DPadUp},
|
||||
{"Down", TRANSLATE_NOOP("Pad", "Strum Down"), InputBindingInfo::Type::Button, PadGuitar::Inputs::STRUM_DOWN, GenericInputBinding::DPadDown},
|
||||
{"Select", TRANSLATE_NOOP("Pad", "Select"), InputBindingInfo::Type::Button, PadGuitar::Inputs::SELECT, GenericInputBinding::Select},
|
||||
{"Start", TRANSLATE_NOOP("Pad", "Start"), InputBindingInfo::Type::Button, PadGuitar::Inputs::START, GenericInputBinding::Start},
|
||||
{"Green", TRANSLATE_NOOP("Pad", "Green Fret"), InputBindingInfo::Type::Button, PadGuitar::Inputs::GREEN, GenericInputBinding::R2},
|
||||
{"Red", TRANSLATE_NOOP("Pad", "Red Fret"), InputBindingInfo::Type::Button, PadGuitar::Inputs::RED, GenericInputBinding::Circle},
|
||||
{"Yellow", TRANSLATE_NOOP("Pad", "Yellow Fret"), InputBindingInfo::Type::Button, PadGuitar::Inputs::YELLOW, GenericInputBinding::Triangle},
|
||||
{"Blue", TRANSLATE_NOOP("Pad", "Blue Fret"), InputBindingInfo::Type::Button, PadGuitar::Inputs::BLUE, GenericInputBinding::Cross},
|
||||
{"Orange", TRANSLATE_NOOP("Pad", "Orange Fret"), InputBindingInfo::Type::Button, PadGuitar::Inputs::ORANGE, GenericInputBinding::Square},
|
||||
{"Whammy", TRANSLATE_NOOP("Pad", "Whammy Bar"), InputBindingInfo::Type::HalfAxis, PadGuitar::Inputs::WHAMMY, GenericInputBinding::LeftStickUp},
|
||||
{"Tilt", TRANSLATE_NOOP("Pad", "Tilt Up"), InputBindingInfo::Type::Button, PadGuitar::Inputs::TILT, GenericInputBinding::L2},
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
static const SettingInfo s_settings[] = {
|
||||
{SettingInfo::Type::Float, "Deadzone", TRANSLATE_NOOP("Pad", "Whammy Bar Deadzone"),
|
||||
TRANSLATE_NOOP("Pad", "Sets the whammy bar deadzone. Inputs below this value will not be sent to the PS2."),
|
||||
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "AxisScale", TRANSLATE_NOOP("Pad", "Whammy Bar Sensitivity"),
|
||||
TRANSLATE_NOOP("Pad", "Sets the whammy bar axis scaling factor."), "1.0", "0.01", "2.00", "0.01", "%.0f%%",
|
||||
nullptr, nullptr, 100.0f},
|
||||
};
|
||||
|
||||
const Pad::ControllerInfo PadGuitar::ControllerInfo = {Pad::ControllerType::Guitar, "Guitar",
|
||||
TRANSLATE_NOOP("Pad", "Guitar"), s_bindings, s_settings, Pad::VibrationCapabilities::NoVibration};
|
||||
|
||||
u8 PadGuitar::Mystery(u8 commandByte)
|
||||
{
|
||||
@@ -54,8 +82,7 @@ u8 PadGuitar::ButtonQuery(u8 commandByte)
|
||||
|
||||
u8 PadGuitar::Poll(u8 commandByte)
|
||||
{
|
||||
PadBase* pad = g_PadManager.GetPad(this->unifiedSlot);
|
||||
const u32 buttons = pad->GetButtons();
|
||||
const u32 buttons = GetButtons();
|
||||
|
||||
switch (this->commandBytesReceived)
|
||||
{
|
||||
@@ -70,7 +97,7 @@ u8 PadGuitar::Poll(u8 commandByte)
|
||||
case 7:
|
||||
return 0x7f;
|
||||
case 8:
|
||||
return pad->GetPressure(Guitar::Inputs::WHAMMY);
|
||||
return GetPressure(Inputs::WHAMMY);
|
||||
}
|
||||
|
||||
Console.Warning("%s(%02X) Did not reach a valid return path! Returning zero as a failsafe!", __FUNCTION__, commandByte);
|
||||
@@ -98,11 +125,11 @@ u8 PadGuitar::Config(u8 commandByte)
|
||||
{
|
||||
this->isInConfig = false;
|
||||
const auto [port, slot] = sioConvertPadToPortAndSlot(unifiedSlot);
|
||||
Console.WriteLn(StringUtil::StdStringFromFormat("[Pad] Game finished pad setup for port %d / slot %d - Analogs: %s - Analog Button: %s - Pressure: Not available on guitars",
|
||||
Console.WriteLn("[Pad] Game finished pad setup for port %d / slot %d - Analogs: %s - Analog Button: %s - Pressure: Not available on guitars",
|
||||
port + 1,
|
||||
slot + 1,
|
||||
(this->analogLight ? "On" : "Off"),
|
||||
(this->analogLocked ? "Locked" : "Usable")));
|
||||
(this->analogLocked ? "Locked" : "Usable"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -163,21 +190,19 @@ u8 PadGuitar::StatusInfo(u8 commandByte)
|
||||
|
||||
u8 PadGuitar::Constant1(u8 commandByte)
|
||||
{
|
||||
static bool stage;
|
||||
|
||||
switch (this->commandBytesReceived)
|
||||
{
|
||||
case 3:
|
||||
stage = commandByte;
|
||||
commandStage = (commandByte != 0);
|
||||
return 0x00;
|
||||
case 5:
|
||||
return 0x01;
|
||||
case 6:
|
||||
return (!stage ? 0x02 : 0x01);
|
||||
return (!commandStage ? 0x02 : 0x01);
|
||||
case 7:
|
||||
return (!stage ? 0x00 : 0x01);
|
||||
return (!commandStage ? 0x00 : 0x01);
|
||||
case 8:
|
||||
return (stage ? 0x0a : 0x14);
|
||||
return (commandStage ? 0x0a : 0x14);
|
||||
default:
|
||||
return 0x00;
|
||||
}
|
||||
@@ -198,15 +223,13 @@ u8 PadGuitar::Constant2(u8 commandByte)
|
||||
|
||||
u8 PadGuitar::Constant3(u8 commandByte)
|
||||
{
|
||||
static bool stage;
|
||||
|
||||
switch (this->commandBytesReceived)
|
||||
{
|
||||
case 3:
|
||||
stage = commandByte;
|
||||
commandStage = (commandByte != 0);
|
||||
return 0x00;
|
||||
case 6:
|
||||
return (!stage ? 0x04 : 0x07);
|
||||
return (!commandStage ? 0x04 : 0x07);
|
||||
default:
|
||||
return 0x00;
|
||||
}
|
||||
@@ -214,11 +237,7 @@ u8 PadGuitar::Constant3(u8 commandByte)
|
||||
|
||||
u8 PadGuitar::VibrationMap(u8 commandByte)
|
||||
{
|
||||
switch (this->commandBytesReceived)
|
||||
{
|
||||
default:
|
||||
return 0xff;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
PadGuitar::PadGuitar(u8 unifiedSlot)
|
||||
@@ -240,14 +259,19 @@ void PadGuitar::Init()
|
||||
this->whammyDeadzone = 0.0f;
|
||||
}
|
||||
|
||||
Pad::ControllerType PadGuitar::GetType()
|
||||
Pad::ControllerType PadGuitar::GetType() const
|
||||
{
|
||||
return Pad::ControllerType::Guitar;
|
||||
}
|
||||
|
||||
const Pad::ControllerInfo& PadGuitar::GetInfo() const
|
||||
{
|
||||
return ControllerInfo;
|
||||
}
|
||||
|
||||
void PadGuitar::Set(u32 index, float value)
|
||||
{
|
||||
if (index > Guitar::Inputs::LENGTH)
|
||||
if (index > Inputs::LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -255,7 +279,7 @@ void PadGuitar::Set(u32 index, float value)
|
||||
// The whammy bar is a special kind of weird in that rather than resting at 0 and going to 255,
|
||||
// they chose to rest it at 127 like a normal analog, but then also make its full press 0, as if
|
||||
// it were the negative Y component of a normal analog. Fun!
|
||||
if (index == Guitar::Inputs::WHAMMY)
|
||||
if (index == Inputs::WHAMMY)
|
||||
{
|
||||
this->whammy = static_cast<u8>(std::clamp(127 - (value * this->whammyAxisScale) * 255.0f, 0.0f, 127.0f));
|
||||
|
||||
@@ -279,7 +303,7 @@ void PadGuitar::Set(u32 index, float value)
|
||||
this->rawInputs[index] = static_cast<u8>(std::clamp(dzValue * 255.0f, 0.0f, 255.0f));
|
||||
|
||||
// Since we reordered the buttons for better UI, we need to remap them here.
|
||||
static constexpr std::array<u8, Guitar::Inputs::LENGTH> bitmaskMapping = {{
|
||||
static constexpr std::array<u8, Inputs::LENGTH> bitmaskMapping = {{
|
||||
12, // STRUM_UP
|
||||
14, // STRUM_DOWN
|
||||
8, // SELECT
|
||||
@@ -318,7 +342,7 @@ void PadGuitar::SetTriggerScale(float deadzone, float scale)
|
||||
|
||||
}
|
||||
|
||||
float PadGuitar::GetVibrationScale(u32 motor)
|
||||
float PadGuitar::GetVibrationScale(u32 motor) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -327,7 +351,7 @@ void PadGuitar::SetVibrationScale(u32 motor, float scale)
|
||||
{
|
||||
}
|
||||
|
||||
float PadGuitar::GetPressureModifier()
|
||||
float PadGuitar::GetPressureModifier() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -349,54 +373,49 @@ void PadGuitar::SetAnalogInvertR(bool x, bool y)
|
||||
{
|
||||
}
|
||||
|
||||
u8 PadGuitar::GetRawInput(u32 index)
|
||||
u8 PadGuitar::GetRawInput(u32 index) const
|
||||
{
|
||||
return this->rawInputs[index];
|
||||
return rawInputs[index];
|
||||
}
|
||||
|
||||
std::tuple<u8, u8> PadGuitar::GetRawLeftAnalog()
|
||||
std::tuple<u8, u8> PadGuitar::GetRawLeftAnalog() const
|
||||
{
|
||||
return std::tuple<u8, u8>{0x7f, 0x7f};
|
||||
}
|
||||
|
||||
std::tuple<u8, u8> PadGuitar::GetRawRightAnalog()
|
||||
std::tuple<u8, u8> PadGuitar::GetRawRightAnalog() const
|
||||
{
|
||||
return std::tuple<u8, u8>{0x7f, 0x7f};
|
||||
}
|
||||
|
||||
u32 PadGuitar::GetButtons()
|
||||
u32 PadGuitar::GetButtons() const
|
||||
{
|
||||
return this->buttons;
|
||||
return buttons;
|
||||
}
|
||||
|
||||
u8 PadGuitar::GetPressure(u32 index)
|
||||
u8 PadGuitar::GetPressure(u32 index) const
|
||||
{
|
||||
if (index == Guitar::Inputs::WHAMMY)
|
||||
{
|
||||
return this->whammy;
|
||||
}
|
||||
if (index == Inputs::WHAMMY)
|
||||
return whammy;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PadGuitar::Freeze(StateWrapper& sw)
|
||||
bool PadGuitar::Freeze(StateWrapper& sw)
|
||||
{
|
||||
// Protected PadBase members
|
||||
sw.Do(&rawInputs);
|
||||
sw.Do(&unifiedSlot);
|
||||
sw.Do(&isInConfig);
|
||||
sw.Do(¤tMode);
|
||||
sw.Do(¤tCommand);
|
||||
sw.Do(&commandBytesReceived);
|
||||
if (!PadBase::Freeze(sw) || !sw.DoMarker("PadGuitar"))
|
||||
return false;
|
||||
|
||||
// Private PadGuitar members
|
||||
sw.Do(&buttons);
|
||||
sw.Do(&whammy);
|
||||
sw.Do(&analogLight);
|
||||
sw.Do(&analogLocked);
|
||||
sw.Do(&commandStage);
|
||||
sw.Do(&whammyAxisScale);
|
||||
sw.Do(&whammyDeadzone);
|
||||
sw.Do(&buttonDeadzone);
|
||||
return !sw.HasError();
|
||||
}
|
||||
|
||||
u8 PadGuitar::SendCommandByte(u8 commandByte)
|
||||
|
||||
@@ -17,8 +17,25 @@
|
||||
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
|
||||
class PadGuitar : public PadBase
|
||||
class PadGuitar final : public PadBase
|
||||
{
|
||||
public:
|
||||
enum Inputs
|
||||
{
|
||||
STRUM_UP, // Strum bar
|
||||
STRUM_DOWN, // Strum bar down
|
||||
SELECT, // Select button
|
||||
START, // Start button
|
||||
GREEN, // Green fret
|
||||
RED, // Red fret
|
||||
YELLOW, // Yellow fret
|
||||
BLUE, // Blue fret
|
||||
ORANGE, // Orange fret
|
||||
WHAMMY, // Whammy bar axis
|
||||
TILT, // Tilt sensor
|
||||
LENGTH,
|
||||
};
|
||||
|
||||
private:
|
||||
u32 buttons;
|
||||
u8 whammy;
|
||||
@@ -27,6 +44,7 @@ private:
|
||||
bool analogLight = false;
|
||||
// Guitars are also instructed to "lock" their "analog light", despite not having one.
|
||||
bool analogLocked = false;
|
||||
bool commandStage = false;
|
||||
float whammyAxisScale; // Guitars only have 1 axis on the whammy bar.
|
||||
float whammyDeadzone;
|
||||
float buttonDeadzone; // Button deadzone is still a good idea, in case a host analog stick is bound to a guitar button
|
||||
@@ -44,28 +62,31 @@ private:
|
||||
|
||||
public:
|
||||
PadGuitar(u8 unifiedSlot);
|
||||
virtual ~PadGuitar();
|
||||
~PadGuitar() override;
|
||||
|
||||
void Init() override;
|
||||
Pad::ControllerType GetType() override;
|
||||
Pad::ControllerType GetType() const override;
|
||||
const Pad::ControllerInfo& GetInfo() const override;
|
||||
void Set(u32 index, float value) override;
|
||||
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
|
||||
void SetAxisScale(float deadzone, float scale) override;
|
||||
void SetTriggerScale(float deadzone, float scale) override;
|
||||
float GetVibrationScale(u32 motor) override;
|
||||
float GetVibrationScale(u32 motor) const override;
|
||||
void SetVibrationScale(u32 motor, float scale) override;
|
||||
float GetPressureModifier() override;
|
||||
float GetPressureModifier() const override;
|
||||
void SetPressureModifier(float mod) override;
|
||||
void SetButtonDeadzone(float deadzone) override;
|
||||
void SetAnalogInvertL(bool x, bool y) override;
|
||||
void SetAnalogInvertR(bool x, bool y) override;
|
||||
u8 GetRawInput(u32 index) override;
|
||||
std::tuple<u8, u8> GetRawLeftAnalog() override;
|
||||
std::tuple<u8, u8> GetRawRightAnalog() override;
|
||||
u32 GetButtons() override;
|
||||
u8 GetPressure(u32 index) override;
|
||||
u8 GetRawInput(u32 index) const override;
|
||||
std::tuple<u8, u8> GetRawLeftAnalog() const override;
|
||||
std::tuple<u8, u8> GetRawRightAnalog() const override;
|
||||
u32 GetButtons() const override;
|
||||
u8 GetPressure(u32 index) const override;
|
||||
|
||||
void Freeze(StateWrapper& sw) override;
|
||||
bool Freeze(StateWrapper& sw) override;
|
||||
|
||||
u8 SendCommandByte(u8 commandByte) override;
|
||||
|
||||
static const Pad::ControllerInfo ControllerInfo;
|
||||
};
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
namespace Guitar
|
||||
{
|
||||
enum Inputs
|
||||
{
|
||||
STRUM_UP, // Strum bar
|
||||
STRUM_DOWN, // Strum bar down
|
||||
SELECT, // Select button
|
||||
START, // Start button
|
||||
GREEN, // Green fret
|
||||
RED, // Red fret
|
||||
YELLOW, // Yellow fret
|
||||
BLUE, // Blue fret
|
||||
ORANGE, // Orange fret
|
||||
WHAMMY, // Whammy bar axis
|
||||
TILT, // Tilt sensor
|
||||
LENGTH,
|
||||
};
|
||||
|
||||
// The generic input bindings on this might seem bizarre, but they are intended to match what DS2 buttons
|
||||
// would do what actions, if you played Guitar Hero on a PS2 with a DS2 instead of a controller.
|
||||
static const InputBindingInfo defaultBindings[] = {
|
||||
{"Up", "Strum Up", InputBindingInfo::Type::Button, Guitar::Inputs::STRUM_UP, GenericInputBinding::DPadUp},
|
||||
{"Down", "Strum Down", InputBindingInfo::Type::Button, Guitar::Inputs::STRUM_DOWN, GenericInputBinding::DPadDown},
|
||||
{"Select", "Select", InputBindingInfo::Type::Button, Guitar::Inputs::SELECT, GenericInputBinding::Select},
|
||||
{"Start", "Start", InputBindingInfo::Type::Button, Guitar::Inputs::START, GenericInputBinding::Start},
|
||||
{"Green", "Green Fret", InputBindingInfo::Type::Button, Guitar::Inputs::GREEN, GenericInputBinding::R2},
|
||||
{"Red", "Red Fret", InputBindingInfo::Type::Button, Guitar::Inputs::RED, GenericInputBinding::Circle},
|
||||
{"Yellow", "Yellow Fret", InputBindingInfo::Type::Button, Guitar::Inputs::YELLOW, GenericInputBinding::Triangle},
|
||||
{"Blue", "Blue Fret", InputBindingInfo::Type::Button, Guitar::Inputs::BLUE, GenericInputBinding::Cross},
|
||||
{"Orange", "Orange Fret", InputBindingInfo::Type::Button, Guitar::Inputs::ORANGE, GenericInputBinding::Square},
|
||||
{"Whammy", "Whammy Bar", InputBindingInfo::Type::HalfAxis, Guitar::Inputs::WHAMMY, GenericInputBinding::LeftStickUp},
|
||||
{"Tilt", "Tilt Up", InputBindingInfo::Type::Button, Guitar::Inputs::TILT, GenericInputBinding::L2},
|
||||
};
|
||||
|
||||
static const SettingInfo defaultSettings[] = {
|
||||
{SettingInfo::Type::Float, "Deadzone", "Whammy Bar Deadzone",
|
||||
"Sets the whammy bar deadzone. Inputs below this value will not be sent to the PS2.",
|
||||
"0.00", "0.00", "1.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "AxisScale", "Whammy Bar Sensitivity",
|
||||
"Sets the whammy bar axis scaling factor.",
|
||||
"1.0", "0.01", "2.00", "0.01", "%.0f%%", nullptr, nullptr, 100.0f},
|
||||
};
|
||||
} // namespace Guitar
|
||||
@@ -1,90 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "SIO/Pad/PadMacros.h"
|
||||
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
|
||||
PadMacros g_PadMacros;
|
||||
|
||||
PadMacros::PadMacros() = default;
|
||||
PadMacros::~PadMacros() = default;
|
||||
|
||||
void PadMacros::ClearMacros()
|
||||
{
|
||||
this->s_macro_buttons = {};
|
||||
}
|
||||
|
||||
PadMacros::MacroButton& PadMacros::GetMacroButton(u32 pad, u32 index)
|
||||
{
|
||||
return this->s_macro_buttons.at(pad).at(index);
|
||||
}
|
||||
|
||||
void PadMacros::SetMacroButtonState(u32 pad, u32 index, bool state)
|
||||
{
|
||||
if (pad >= Pad::NUM_CONTROLLER_PORTS || index >= NUM_MACRO_BUTTONS_PER_CONTROLLER)
|
||||
return;
|
||||
|
||||
PadMacros::MacroButton& mb = s_macro_buttons[pad][index];
|
||||
if (mb.buttons.empty() || mb.trigger_state == state)
|
||||
return;
|
||||
|
||||
mb.toggle_counter = mb.toggle_frequency;
|
||||
mb.trigger_state = state;
|
||||
if (mb.toggle_state != state)
|
||||
{
|
||||
mb.toggle_state = state;
|
||||
ApplyMacroButton(pad, mb);
|
||||
}
|
||||
}
|
||||
|
||||
void PadMacros::ApplyMacroButton(u32 controller, const PadMacros::MacroButton& mb)
|
||||
{
|
||||
const float value = mb.toggle_state ? 1.0f : 0.0f;
|
||||
PadBase* pad = g_PadManager.GetPad(controller);
|
||||
|
||||
for (const u32 btn : mb.buttons)
|
||||
pad->Set(btn, value);
|
||||
}
|
||||
|
||||
void PadMacros::UpdateMacroButtons()
|
||||
{
|
||||
for (u32 pad = 0; pad < Pad::NUM_CONTROLLER_PORTS; pad++)
|
||||
{
|
||||
for (u32 index = 0; index < NUM_MACRO_BUTTONS_PER_CONTROLLER; index++)
|
||||
{
|
||||
PadMacros::MacroButton& mb = this->s_macro_buttons[pad][index];
|
||||
|
||||
if (!mb.trigger_state || mb.toggle_frequency == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mb.toggle_counter--;
|
||||
|
||||
if (mb.toggle_counter > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mb.toggle_counter = mb.toggle_frequency;
|
||||
mb.toggle_state = !mb.toggle_state;
|
||||
ApplyMacroButton(pad, mb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SIO/Pad/PadTypes.h"
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
class PadMacros
|
||||
{
|
||||
public: // Constants
|
||||
struct MacroButton
|
||||
{
|
||||
std::vector<u32> buttons; ///< Buttons to activate.
|
||||
u32 toggle_frequency; ///< Interval at which the buttons will be toggled, if not 0.
|
||||
u32 toggle_counter; ///< When this counter reaches zero, buttons will be toggled.
|
||||
bool toggle_state; ///< Current state for turbo.
|
||||
bool trigger_state; ///< Whether the macro button is active.
|
||||
};
|
||||
|
||||
// Number of macro buttons per controller.
|
||||
static constexpr u32 NUM_MACRO_BUTTONS_PER_CONTROLLER = 16;
|
||||
|
||||
private: // Private members
|
||||
std::array<std::array<PadMacros::MacroButton, PadMacros::NUM_MACRO_BUTTONS_PER_CONTROLLER>, Pad::NUM_CONTROLLER_PORTS> s_macro_buttons;
|
||||
|
||||
public: // Public members
|
||||
PadMacros();
|
||||
~PadMacros();
|
||||
|
||||
// Sets the state of the specified macro button.
|
||||
void ClearMacros();
|
||||
PadMacros::MacroButton& GetMacroButton(u32 pad, u32 index);
|
||||
void SetMacroButtonState(u32 pad, u32 index, bool state);
|
||||
void ApplyMacroButton(u32 controller, const PadMacros::MacroButton& mb);
|
||||
void UpdateMacroButtons();
|
||||
};
|
||||
|
||||
extern PadMacros g_PadMacros;
|
||||
@@ -1,139 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
|
||||
#include "SIO/Pad/PadNotConnected.h"
|
||||
#include "SIO/Pad/PadDualshock2.h"
|
||||
#include "SIO/Pad/PadGuitar.h"
|
||||
|
||||
PadManager g_PadManager;
|
||||
|
||||
// Convert the PS2's port/slot addressing to a single value.
|
||||
// Physical ports 0 and 1 still correspond to unified slots 0 and 1.
|
||||
// The remaining unified slots are for multitapped slots.
|
||||
// Port 0's three multitap slots then occupy unified slots 2, 3 and 4.
|
||||
// Port 1's three multitap slots then occupy unified slots 5, 6 and 7.
|
||||
u8 PadManager::GetUnifiedSlot(u8 port, u8 slot)
|
||||
{
|
||||
if (slot == 0)
|
||||
{
|
||||
return port;
|
||||
}
|
||||
else if (port == 0) // slot=[0,1]
|
||||
{
|
||||
return slot + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return slot + 4;
|
||||
}
|
||||
}
|
||||
|
||||
PadManager::PadManager() = default;
|
||||
PadManager::~PadManager() = default;
|
||||
|
||||
bool PadManager::Initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PadManager::Shutdown()
|
||||
{
|
||||
for (u8 i = 0; i < 8; i++)
|
||||
{
|
||||
this->ps2Controllers.at(i) = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PadBase* PadManager::ChangePadType(u8 unifiedSlot, Pad::ControllerType controllerType)
|
||||
{
|
||||
switch (controllerType)
|
||||
{
|
||||
case Pad::ControllerType::DualShock2:
|
||||
this->ps2Controllers.at(unifiedSlot) = std::make_unique<PadDualshock2>(unifiedSlot);
|
||||
break;
|
||||
case Pad::ControllerType::Guitar:
|
||||
this->ps2Controllers.at(unifiedSlot) = std::make_unique<PadGuitar>(unifiedSlot);
|
||||
break;
|
||||
default:
|
||||
this->ps2Controllers.at(unifiedSlot) = std::make_unique<PadNotConnected>(unifiedSlot);
|
||||
break;
|
||||
}
|
||||
|
||||
return this->ps2Controllers.at(unifiedSlot).get();
|
||||
}
|
||||
|
||||
PadBase* PadManager::GetPad(u8 port, u8 slot)
|
||||
{
|
||||
const u8 unifiedSlot = this->GetUnifiedSlot(port, slot);
|
||||
return this->ps2Controllers.at(unifiedSlot).get();
|
||||
}
|
||||
|
||||
PadBase* PadManager::GetPad(const u8 unifiedSlot)
|
||||
{
|
||||
return this->ps2Controllers.at(unifiedSlot).get();
|
||||
}
|
||||
|
||||
void PadManager::SetControllerState(u32 controller, u32 bind, float value)
|
||||
{
|
||||
if (controller >= Pad::NUM_CONTROLLER_PORTS)
|
||||
return;
|
||||
|
||||
PadBase* pad = g_PadManager.GetPad(controller);
|
||||
pad->Set(bind, value);
|
||||
}
|
||||
|
||||
bool PadManager::PadFreeze(StateWrapper& sw)
|
||||
{
|
||||
if (sw.IsReading())
|
||||
{
|
||||
if (!sw.DoMarker("PAD"))
|
||||
{
|
||||
Console.Error("PAD state is invalid! Leaving the current state in place.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u32 unifiedSlot = 0; unifiedSlot < Pad::NUM_CONTROLLER_PORTS; unifiedSlot++)
|
||||
{
|
||||
Pad::ControllerType type;
|
||||
sw.Do(&type);
|
||||
|
||||
PadBase* pad = this->ChangePadType(unifiedSlot, type);
|
||||
pad->Freeze(sw);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sw.DoMarker("PAD"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u32 unifiedSlot = 0; unifiedSlot < Pad::NUM_CONTROLLER_PORTS; unifiedSlot++)
|
||||
{
|
||||
PadBase* pad = this->GetPad(unifiedSlot);
|
||||
Pad::ControllerType type = pad->GetType();
|
||||
sw.Do(&type);
|
||||
pad->Freeze(sw);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
class PadManager
|
||||
{
|
||||
private:
|
||||
std::array<std::unique_ptr<PadBase>, 8> ps2Controllers;
|
||||
|
||||
u8 GetUnifiedSlot(u8 port, u8 slot);
|
||||
|
||||
public:
|
||||
PadManager();
|
||||
~PadManager();
|
||||
|
||||
bool Initialize();
|
||||
bool Shutdown();
|
||||
|
||||
PadBase* ChangePadType(u8 unifiedSlot, Pad::ControllerType controllerType);
|
||||
PadBase* GetPad(u8 port, u8 slot);
|
||||
PadBase* GetPad(const u8 unifiedSlot);
|
||||
|
||||
// Sets the specified bind on a controller to the specified pressure (normalized to 0..1).
|
||||
void SetControllerState(u32 controller, u32 bind, float value);
|
||||
|
||||
bool PadFreeze(StateWrapper& sw);
|
||||
};
|
||||
|
||||
extern PadManager g_PadManager;
|
||||
@@ -17,6 +17,11 @@
|
||||
|
||||
#include "SIO/Pad/PadNotConnected.h"
|
||||
|
||||
#include "Host.h"
|
||||
|
||||
const Pad::ControllerInfo PadNotConnected::ControllerInfo = {Pad::ControllerType::NotConnected, "None",
|
||||
TRANSLATE_NOOP("Pad", "Not Connected"), {}, {}, Pad::VibrationCapabilities::NoVibration };
|
||||
|
||||
PadNotConnected::PadNotConnected(u8 unifiedSlot)
|
||||
: PadBase(unifiedSlot)
|
||||
{
|
||||
@@ -30,11 +35,16 @@ void PadNotConnected::Init()
|
||||
|
||||
}
|
||||
|
||||
Pad::ControllerType PadNotConnected::GetType()
|
||||
Pad::ControllerType PadNotConnected::GetType() const
|
||||
{
|
||||
return Pad::ControllerType::NotConnected;
|
||||
}
|
||||
|
||||
const Pad::ControllerInfo& PadNotConnected::GetInfo() const
|
||||
{
|
||||
return ControllerInfo;
|
||||
}
|
||||
|
||||
void PadNotConnected::Set(u32 index, float value)
|
||||
{
|
||||
|
||||
@@ -55,7 +65,7 @@ void PadNotConnected::SetTriggerScale(float deadzone, float scale)
|
||||
|
||||
}
|
||||
|
||||
float PadNotConnected::GetVibrationScale(u32 motor)
|
||||
float PadNotConnected::GetVibrationScale(u32 motor) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -65,7 +75,7 @@ void PadNotConnected::SetVibrationScale(u32 motor, float scale)
|
||||
|
||||
}
|
||||
|
||||
float PadNotConnected::GetPressureModifier()
|
||||
float PadNotConnected::GetPressureModifier() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -90,42 +100,31 @@ void PadNotConnected::SetAnalogInvertR(bool x, bool y)
|
||||
|
||||
}
|
||||
|
||||
u8 PadNotConnected::GetRawInput(u32 index)
|
||||
u8 PadNotConnected::GetRawInput(u32 index) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::tuple<u8, u8> PadNotConnected::GetRawLeftAnalog()
|
||||
std::tuple<u8, u8> PadNotConnected::GetRawLeftAnalog() const
|
||||
{
|
||||
return std::tuple<u8, u8>{0, 0};
|
||||
}
|
||||
|
||||
std::tuple<u8, u8> PadNotConnected::GetRawRightAnalog()
|
||||
std::tuple<u8, u8> PadNotConnected::GetRawRightAnalog() const
|
||||
{
|
||||
return std::tuple<u8, u8>{0, 0};
|
||||
}
|
||||
|
||||
u32 PadNotConnected::GetButtons()
|
||||
u32 PadNotConnected::GetButtons() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 PadNotConnected::GetPressure(u32 index)
|
||||
u8 PadNotConnected::GetPressure(u32 index) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PadNotConnected::Freeze(StateWrapper& sw)
|
||||
{
|
||||
// Protected PadBase members
|
||||
sw.Do(&rawInputs);
|
||||
sw.Do(&unifiedSlot);
|
||||
sw.Do(&isInConfig);
|
||||
sw.Do(¤tMode);
|
||||
sw.Do(¤tCommand);
|
||||
sw.Do(&commandBytesReceived);
|
||||
}
|
||||
|
||||
u8 PadNotConnected::SendCommandByte(u8 commandByte)
|
||||
{
|
||||
return 0xff;
|
||||
|
||||
@@ -17,32 +17,33 @@
|
||||
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
|
||||
class PadNotConnected : public PadBase
|
||||
class PadNotConnected final : public PadBase
|
||||
{
|
||||
public:
|
||||
PadNotConnected(u8 unifiedSlot);
|
||||
virtual ~PadNotConnected();
|
||||
~PadNotConnected() override;
|
||||
|
||||
void Init();
|
||||
Pad::ControllerType GetType();
|
||||
void Set(u32 index, float value);
|
||||
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right);
|
||||
void SetAxisScale(float deadzone, float scale);
|
||||
void Init() override;
|
||||
Pad::ControllerType GetType() const override;
|
||||
const Pad::ControllerInfo& GetInfo() const override;
|
||||
void Set(u32 index, float value) override;
|
||||
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
|
||||
void SetAxisScale(float deadzone, float scale) override;
|
||||
void SetTriggerScale(float deadzone, float scale) override;
|
||||
float GetVibrationScale(u32 motor);
|
||||
void SetVibrationScale(u32 motor, float scale);
|
||||
float GetPressureModifier();
|
||||
void SetPressureModifier(float mod);
|
||||
void SetButtonDeadzone(float deadzone);
|
||||
void SetAnalogInvertL(bool x, bool y);
|
||||
void SetAnalogInvertR(bool x, bool y);
|
||||
u8 GetRawInput(u32 index);
|
||||
std::tuple<u8, u8> GetRawLeftAnalog();
|
||||
std::tuple<u8, u8> GetRawRightAnalog();
|
||||
u32 GetButtons();
|
||||
u8 GetPressure(u32 index);
|
||||
|
||||
void Freeze(StateWrapper& sw) override;
|
||||
float GetVibrationScale(u32 motor) const override;
|
||||
void SetVibrationScale(u32 motor, float scale) override;
|
||||
float GetPressureModifier() const override;
|
||||
void SetPressureModifier(float mod) override;
|
||||
void SetButtonDeadzone(float deadzone) override;
|
||||
void SetAnalogInvertL(bool x, bool y) override;
|
||||
void SetAnalogInvertR(bool x, bool y) override;
|
||||
u8 GetRawInput(u32 index) const override;
|
||||
std::tuple<u8, u8> GetRawLeftAnalog() const override;
|
||||
std::tuple<u8, u8> GetRawRightAnalog() const override;
|
||||
u32 GetButtons() const override;
|
||||
u8 GetPressure(u32 index) const override;
|
||||
|
||||
u8 SendCommandByte(u8 commandByte) override;
|
||||
|
||||
static const Pad::ControllerInfo ControllerInfo;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <span>
|
||||
|
||||
namespace Pad
|
||||
{
|
||||
enum class Command : u8
|
||||
@@ -82,6 +86,19 @@ namespace Pad
|
||||
Count
|
||||
};
|
||||
|
||||
struct ControllerInfo
|
||||
{
|
||||
ControllerType type;
|
||||
const char* name;
|
||||
const char* display_name;
|
||||
std::span<const InputBindingInfo> bindings;
|
||||
std::span<const SettingInfo> settings;
|
||||
VibrationCapabilities vibration_caps;
|
||||
|
||||
// Returns localized controller type name.
|
||||
const char* GetLocalizedName() const;
|
||||
};
|
||||
|
||||
// Total number of pad ports, across both multitaps.
|
||||
static constexpr u32 NUM_CONTROLLER_PORTS = 8;
|
||||
|
||||
@@ -93,4 +110,7 @@ namespace Pad
|
||||
static constexpr float DEFAULT_MOTOR_SCALE = 1.0f;
|
||||
static constexpr float DEFAULT_PRESSURE_MODIFIER = 0.5f;
|
||||
static constexpr float DEFAULT_BUTTON_DEADZONE = 0.0f;
|
||||
|
||||
// Number of macro buttons per controller.
|
||||
static constexpr u32 NUM_MACRO_BUTTONS_PER_CONTROLLER = 16;
|
||||
} // namespace Pad
|
||||
|
||||
@@ -109,7 +109,11 @@ extern void sioNextFrame();
|
||||
/// Converts a global pad index to a multitap port and slot.
|
||||
extern std::tuple<u32, u32> sioConvertPadToPortAndSlot(u32 index);
|
||||
|
||||
/// Converts a multitap port and slot to a global pad index.
|
||||
/// Convert the PS2's port/slot addressing to a single value.
|
||||
/// Physical ports 0 and 1 still correspond to unified slots 0 and 1.
|
||||
/// The remaining unified slots are for multitapped slots.
|
||||
/// Port 0's three multitap slots then occupy unified slots 2, 3 and 4.
|
||||
/// Port 1's three multitap slots then occupy unified slots 5, 6 and 7.
|
||||
extern u32 sioConvertPortAndSlotToPad(u32 port, u32 slot);
|
||||
|
||||
/// Returns true if the given pad index is a multitap slot.
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "SIO/Sio0.h"
|
||||
|
||||
#include "SIO/Sio.h"
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Memcard/MemoryCardProtocol.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "IopHw.h"
|
||||
#include "IopDma.h"
|
||||
#include "IopHw.h"
|
||||
#include "R3000A.h"
|
||||
#include "SIO/Memcard/MemoryCardProtocol.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
#include "SIO/Sio.h"
|
||||
#include "SIO/Sio0.h"
|
||||
#include "StateWrapper.h"
|
||||
|
||||
#define SIO0LOG_ENABLE 0
|
||||
#define Sio0Log if (SIO0LOG_ENABLE) DevCon
|
||||
@@ -162,7 +162,7 @@ void Sio0::SetTxData(u8 cmd)
|
||||
stat |= SIO0_STAT::TX_READY | SIO0_STAT::TX_EMPTY;
|
||||
stat |= (SIO0_STAT::RX_FIFO_NOT_EMPTY);
|
||||
|
||||
if (!ctrl & SIO0_CTRL::TX_ENABLE)
|
||||
if (!(ctrl & SIO0_CTRL::TX_ENABLE))
|
||||
{
|
||||
Console.Warning("%s(%02X) CTRL in illegal state, exiting instantly", __FUNCTION__, cmd);
|
||||
return;
|
||||
@@ -176,13 +176,13 @@ void Sio0::SetTxData(u8 cmd)
|
||||
{
|
||||
case SioMode::NOT_SET:
|
||||
sioMode = cmd;
|
||||
currentPad = g_PadManager.GetPad(port, slot);
|
||||
currentPad = Pad::GetPad(port, slot);
|
||||
currentPad->SoftReset();
|
||||
mcd = &mcds[port][slot];
|
||||
SetAcknowledge(true);
|
||||
break;
|
||||
case SioMode::PAD:
|
||||
currentPad = g_PadManager.GetPad(port, slot);
|
||||
currentPad = Pad::GetPad(port, slot);
|
||||
pxAssertMsg(currentPad != nullptr, "Got nullptr when looking up pad");
|
||||
// Set ACK in advance of sending the command to the pad.
|
||||
// The pad will, if the command is done, set ACK to false.
|
||||
@@ -315,9 +315,25 @@ u8 Sio0::Memcard(u8 value)
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
bool SaveStateBase::Sio0Freeze()
|
||||
bool Sio0::DoState(StateWrapper& sw)
|
||||
{
|
||||
FreezeTag("sio0");
|
||||
Freeze(g_Sio0);
|
||||
return true;
|
||||
if (!sw.DoMarker("Sio0"))
|
||||
return false;
|
||||
|
||||
sw.Do(&txData);
|
||||
sw.Do(&rxData);
|
||||
sw.Do(&stat);
|
||||
sw.Do(&mode);
|
||||
sw.Do(&ctrl);
|
||||
sw.Do(&baud);
|
||||
sw.Do(&flag);
|
||||
sw.Do(&sioStage);
|
||||
sw.Do(&sioMode);
|
||||
sw.Do(&sioCommand);
|
||||
sw.Do(&padStarted);
|
||||
sw.Do(&rxDataSet);
|
||||
sw.Do(&port);
|
||||
sw.Do(&slot);
|
||||
|
||||
return sw.IsGood();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "SIO/SioTypes.h"
|
||||
|
||||
class StateWrapper;
|
||||
|
||||
class Sio0
|
||||
{
|
||||
private:
|
||||
@@ -48,6 +50,7 @@ public:
|
||||
bool Shutdown();
|
||||
|
||||
void SoftReset();
|
||||
bool DoState(StateWrapper& sw);
|
||||
|
||||
void SetAcknowledge(bool ack);
|
||||
void Interrupt(Sio0Interrupt sio0Interrupt);
|
||||
|
||||
@@ -15,18 +15,18 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "SIO/Sio2.h"
|
||||
|
||||
#include "SIO/Sio.h"
|
||||
#include "SIO/SioTypes.h"
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Memcard/MemoryCardProtocol.h"
|
||||
#include "SIO/Multitap/MultitapProtocol.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "Host.h"
|
||||
#include "IopDma.h"
|
||||
#include "Recording/InputRecording.h"
|
||||
#include "Host.h"
|
||||
#include "SIO/Memcard/MemoryCardProtocol.h"
|
||||
#include "SIO/Multitap/MultitapProtocol.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Pad/PadBase.h"
|
||||
#include "SIO/Sio.h"
|
||||
#include "SIO/Sio2.h"
|
||||
#include "SIO/SioTypes.h"
|
||||
#include "StateWrapper.h"
|
||||
|
||||
#define SIO2LOG_ENABLE 0
|
||||
#define Sio2Log if (SIO2LOG_ENABLE) DevCon
|
||||
@@ -45,13 +45,13 @@ bool Sio2::Initialize()
|
||||
|
||||
for (size_t i = 0; i < send3.size(); i++)
|
||||
{
|
||||
send3.at(i) = 0;
|
||||
send3[i] = 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < send1.size(); i++)
|
||||
{
|
||||
send1.at(i) = 0;
|
||||
send2.at(i) = 0;
|
||||
send1[i] = 0;
|
||||
send2[i] = 0;
|
||||
}
|
||||
|
||||
dataIn = 0;
|
||||
@@ -127,7 +127,7 @@ void Sio2::SetCtrl(u32 value)
|
||||
|
||||
void Sio2::SetSend3(size_t position, u32 value)
|
||||
{
|
||||
this->send3.at(position) = value;
|
||||
this->send3[position] = value;
|
||||
|
||||
if (position == 0)
|
||||
{
|
||||
@@ -143,7 +143,7 @@ void Sio2::SetRecv1(u32 value)
|
||||
void Sio2::Pad()
|
||||
{
|
||||
// Send PAD our current port, and get back whatever it says the first response byte should be.
|
||||
std::optional<PadBase*> padPtr = g_PadManager.GetPad(port, slot);
|
||||
PadBase* pad = Pad::GetPad(port, slot);
|
||||
|
||||
// RECV1 is set once per DMA; if any device is present at all, it should be set to connected.
|
||||
// For now, we will always report connected for pads.
|
||||
@@ -151,17 +151,14 @@ void Sio2::Pad()
|
||||
g_Sio2FifoOut.push_back(0xff);
|
||||
|
||||
// Then for every byte in g_Sio2FifoIn, pass to PAD and see what it kicks back to us.
|
||||
if (padPtr.has_value())
|
||||
{
|
||||
padPtr.value()->SoftReset();
|
||||
pad->SoftReset();
|
||||
|
||||
while (!g_Sio2FifoIn.empty())
|
||||
{
|
||||
const u8 commandByte = g_Sio2FifoIn.front();
|
||||
g_Sio2FifoIn.pop_front();
|
||||
const u8 responseByte = padPtr.value()->SendCommandByte(commandByte);
|
||||
g_Sio2FifoOut.push_back(responseByte);
|
||||
}
|
||||
while (!g_Sio2FifoIn.empty())
|
||||
{
|
||||
const u8 commandByte = g_Sio2FifoIn.front();
|
||||
g_Sio2FifoIn.pop_front();
|
||||
const u8 responseByte = pad->SendCommandByte(commandByte);
|
||||
g_Sio2FifoOut.push_back(responseByte);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +352,7 @@ void Sio2::Write(u8 data)
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 currentSend3 = send3.at(send3Position);
|
||||
const u32 currentSend3 = send3[send3Position];
|
||||
port = currentSend3 & Send3::PORT;
|
||||
commandLength = (currentSend3 >> 8) & Send3::COMMAND_LENGTH_MASK;
|
||||
send3Read = true;
|
||||
@@ -453,62 +450,39 @@ u8 Sio2::Read()
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SaveStateBase::Sio2Freeze()
|
||||
bool Sio2::DoState(StateWrapper& sw)
|
||||
{
|
||||
FreezeTag("sio2");
|
||||
if (!sw.DoMarker("Sio2"))
|
||||
return false;
|
||||
|
||||
if (IsSaving())
|
||||
{
|
||||
std::deque<u8>::iterator iter;
|
||||
size_t backupSize;
|
||||
sw.Do(&send3);
|
||||
sw.Do(&send1);
|
||||
sw.Do(&send2);
|
||||
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(&iStat);
|
||||
sw.Do(&port);
|
||||
sw.Do(&slot);
|
||||
sw.Do(&send3Read);
|
||||
sw.Do(&send3Position);
|
||||
sw.Do(&commandLength);
|
||||
sw.Do(&processedLength);
|
||||
sw.Do(&dmaBlockSize);
|
||||
sw.Do(&send3Complete);
|
||||
|
||||
// Copy g_Sio2FifoIn
|
||||
if (g_Sio2FifoIn.size())
|
||||
{
|
||||
g_Sio2.fifoInBackup = std::make_unique<u8[]>(g_Sio2FifoIn.size());
|
||||
iter = g_Sio2FifoIn.begin();
|
||||
backupSize = 0;
|
||||
|
||||
while (iter != g_Sio2FifoIn.end())
|
||||
{
|
||||
const u8 val = *iter++;
|
||||
g_Sio2.fifoInBackup.get()[backupSize++] = val;
|
||||
}
|
||||
|
||||
g_Sio2.fifoInBackupSize = backupSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Sio2.fifoInBackupSize = 0;
|
||||
}
|
||||
|
||||
// Copy g_Sio2FifoOut
|
||||
if (g_Sio2FifoOut.size())
|
||||
{
|
||||
g_Sio2.fifoOutBackup = std::make_unique<u8[]>(g_Sio2FifoOut.size());
|
||||
iter = g_Sio2FifoOut.begin();
|
||||
backupSize = 0;
|
||||
|
||||
while (iter != g_Sio2FifoOut.end())
|
||||
{
|
||||
const u8 val = *iter++;
|
||||
g_Sio2.fifoOutBackup.get()[backupSize++] = val;
|
||||
}
|
||||
|
||||
g_Sio2.fifoOutBackupSize = backupSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Sio2.fifoOutBackupSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Freeze(g_Sio2);
|
||||
sw.Do(&g_Sio2FifoIn);
|
||||
sw.Do(&g_Sio2FifoOut);
|
||||
|
||||
// CRCs for memory cards.
|
||||
// If the memory card hasn't changed when loading state, we can safely skip ejecting it.
|
||||
u64 mcdCrcs[SIO::PORTS][SIO::SLOTS];
|
||||
if (IsSaving())
|
||||
if (sw.IsWriting())
|
||||
{
|
||||
for (u32 port = 0; port < SIO::PORTS; port++)
|
||||
{
|
||||
@@ -516,9 +490,9 @@ bool SaveStateBase::Sio2Freeze()
|
||||
mcdCrcs[port][slot] = mcds[port][slot].GetChecksum();
|
||||
}
|
||||
}
|
||||
Freeze(mcdCrcs);
|
||||
sw.DoBytes(mcdCrcs, sizeof(mcdCrcs));
|
||||
|
||||
if (IsLoading())
|
||||
if (sw.IsReading())
|
||||
{
|
||||
bool ejected = false;
|
||||
for (u32 port = 0; port < SIO::PORTS && !ejected; port++)
|
||||
@@ -533,29 +507,7 @@ bool SaveStateBase::Sio2Freeze()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore g_Sio2FifoIn
|
||||
g_Sio2FifoIn.clear();
|
||||
|
||||
if (g_Sio2.fifoInBackupSize)
|
||||
{
|
||||
for (size_t i = 0; i < g_Sio2.fifoInBackupSize; i++)
|
||||
{
|
||||
g_Sio2FifoIn.push_back(g_Sio2.fifoInBackup.get()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore g_Sio2FifoOut
|
||||
g_Sio2FifoOut.clear();
|
||||
|
||||
if (g_Sio2.fifoOutBackupSize)
|
||||
{
|
||||
for (size_t j = 0; j < g_Sio2.fifoOutBackupSize; j++)
|
||||
{
|
||||
g_Sio2FifoOut.push_back(g_Sio2.fifoOutBackup.get()[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return sw.IsGood();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
class StateWrapper;
|
||||
|
||||
class Sio2
|
||||
{
|
||||
public:
|
||||
@@ -53,11 +55,6 @@ public:
|
||||
size_t dmaBlockSize = 0;
|
||||
bool send3Complete = false;
|
||||
|
||||
std::unique_ptr<u8[]> fifoInBackup;
|
||||
size_t fifoInBackupSize;
|
||||
std::unique_ptr<u8[]> fifoOutBackup;
|
||||
size_t fifoOutBackupSize;
|
||||
|
||||
Sio2();
|
||||
~Sio2();
|
||||
|
||||
@@ -65,6 +62,7 @@ public:
|
||||
bool Shutdown();
|
||||
|
||||
void SoftReset();
|
||||
bool DoState(StateWrapper& sw);
|
||||
|
||||
void Interrupt();
|
||||
|
||||
|
||||
@@ -28,9 +28,11 @@
|
||||
#include "Host.h"
|
||||
#include "MTGS.h"
|
||||
#include "MTVU.h"
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "Patch.h"
|
||||
#include "R3000A.h"
|
||||
#include "SIO/Sio0.h"
|
||||
#include "SIO/Sio2.h"
|
||||
#include "SPU2/spu2.h"
|
||||
#include "SaveState.h"
|
||||
#include "StateWrapper.h"
|
||||
@@ -237,8 +239,42 @@ bool SaveStateBase::FreezeInternals()
|
||||
FreezeMem(iopMem->Sif, sizeof(iopMem->Sif)); // iop's sif memory (not really needed, but oh well)
|
||||
|
||||
okay = okay && psxRcntFreeze();
|
||||
okay = okay && Sio0Freeze();
|
||||
okay = okay && Sio2Freeze();
|
||||
|
||||
// TODO: move all the others over to StateWrapper too...
|
||||
if (!okay)
|
||||
return false;
|
||||
{
|
||||
// This is horrible. We need to move the rest over...
|
||||
std::optional<StateWrapper::VectorMemoryStream> save_stream;
|
||||
std::optional<StateWrapper::ReadOnlyMemoryStream> load_stream;
|
||||
if (IsSaving())
|
||||
save_stream.emplace();
|
||||
else
|
||||
load_stream.emplace(&m_memory[m_idx], static_cast<int>(m_memory.size()) - m_idx);
|
||||
|
||||
StateWrapper sw(IsSaving() ? static_cast<StateWrapper::IStream*>(&save_stream.value()) :
|
||||
static_cast<StateWrapper::IStream*>(&load_stream.value()),
|
||||
IsSaving() ? StateWrapper::Mode::Write : StateWrapper::Mode::Read, g_SaveVersion);
|
||||
|
||||
okay = okay && g_Sio0.DoState(sw);
|
||||
okay = okay && g_Sio2.DoState(sw);
|
||||
if (!okay || !sw.IsGood())
|
||||
return false;
|
||||
|
||||
if (IsSaving())
|
||||
{
|
||||
FreezeMem(const_cast<u8*>(save_stream->GetBuffer().data()), save_stream->GetPosition());
|
||||
}
|
||||
else
|
||||
{
|
||||
const int new_idx = m_idx + static_cast<int>(load_stream->GetPosition());
|
||||
if (static_cast<size_t>(new_idx) >= m_memory.size())
|
||||
return false;
|
||||
|
||||
m_idx = new_idx;
|
||||
}
|
||||
}
|
||||
|
||||
okay = okay && cdrFreeze();
|
||||
okay = okay && cdvdFreeze();
|
||||
|
||||
@@ -314,11 +350,6 @@ static int SysState_MTGSFreeze(FreezeAction mode, freezeData* fP)
|
||||
return sstate.retval;
|
||||
}
|
||||
|
||||
static bool SysState_PadFreeze(StateWrapper& sw)
|
||||
{
|
||||
return g_PadManager.PadFreeze(sw);
|
||||
}
|
||||
|
||||
static constexpr SysState_Component SPU2_{ "SPU2", SPU2freeze };
|
||||
static constexpr SysState_Component GS{ "GS", SysState_MTGSFreeze };
|
||||
|
||||
@@ -604,8 +635,8 @@ public:
|
||||
~SavestateEntry_PAD() override = default;
|
||||
|
||||
const char* GetFilename() const override { return "PAD.bin"; }
|
||||
bool FreezeIn(zip_file_t* zf) const override { return SysState_ComponentFreezeInNew(zf, "PAD", &SysState_PadFreeze); }
|
||||
bool FreezeOut(SaveStateBase& writer) const override { return SysState_ComponentFreezeOutNew(writer, "PAD", 16 * 1024, &SysState_PadFreeze); }
|
||||
bool FreezeIn(zip_file_t* zf) const override { return SysState_ComponentFreezeInNew(zf, "PAD", &Pad::Freeze); }
|
||||
bool FreezeOut(SaveStateBase& writer) const override { return SysState_ComponentFreezeOutNew(writer, "PAD", 16 * 1024, &Pad::Freeze); }
|
||||
bool IsRequired() const override { return true; }
|
||||
};
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ enum class FreezeAction
|
||||
// [SAVEVERSION+]
|
||||
// This informs the auto updater that the users savestates will be invalidated.
|
||||
|
||||
static const u32 g_SaveVersion = (0x9A3A << 16) | 0x0000;
|
||||
static const u32 g_SaveVersion = (0x9A3B << 16) | 0x0000;
|
||||
|
||||
|
||||
// the freezing data between submodules and core
|
||||
@@ -222,8 +222,6 @@ protected:
|
||||
bool cdvdFreeze();
|
||||
bool psxRcntFreeze();
|
||||
bool deci2Freeze();
|
||||
bool Sio0Freeze();
|
||||
bool Sio2Freeze();
|
||||
|
||||
// Save or load PCSX2's global frame counter (g_FrameCount) along with each savestate
|
||||
//
|
||||
|
||||
@@ -107,6 +107,7 @@ public:
|
||||
|
||||
IStream* GetStream() const { return m_stream; }
|
||||
bool HasError() const { return m_error; }
|
||||
bool IsGood() const { return !m_error; }
|
||||
bool IsReading() const { return (m_mode == Mode::Read); }
|
||||
bool IsWriting() const { return (m_mode == Mode::Write); }
|
||||
Mode GetMode() const { return m_mode; }
|
||||
@@ -226,8 +227,8 @@ public:
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < length; i++)
|
||||
Do(&data[i]);
|
||||
for (T& ch : *data)
|
||||
Do(&ch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -671,6 +671,12 @@ std::string USB::GetConfigSubKey(const std::string_view& device, const std::stri
|
||||
return fmt::format("{}_{}", device, bind_name);
|
||||
}
|
||||
|
||||
bool USB::ConfigKeyExists(SettingsInterface& si, u32 port, const char* devname, const char* key)
|
||||
{
|
||||
const std::string real_key(fmt::format("{}_{}", devname, key));
|
||||
return si.ContainsValue(GetConfigSection(port).c_str(), real_key.c_str());
|
||||
}
|
||||
|
||||
bool USB::GetConfigBool(SettingsInterface& si, u32 port, const char* devname, const char* key, bool default_value)
|
||||
{
|
||||
const std::string real_key(fmt::format("{}_{}", devname, key));
|
||||
|
||||
@@ -79,6 +79,9 @@ namespace USB
|
||||
/// Identifies any device/subtype changes and recreates devices.
|
||||
void CheckForConfigChanges(const Pcsx2Config& old_config);
|
||||
|
||||
/// Returns true if a device-specific configuration key exists.
|
||||
bool ConfigKeyExists(SettingsInterface& si, u32 port, const char* devname, const char* key);
|
||||
|
||||
/// Reads a device-specific configuration boolean.
|
||||
bool GetConfigBool(SettingsInterface& si, u32 port, const char* devname, const char* key, bool default_value);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "GS/GS.h"
|
||||
#include "Host.h"
|
||||
#include "ImGui/ImGuiManager.h"
|
||||
#include "Input/InputManager.h"
|
||||
#include "StateWrapper.h"
|
||||
#include "USB/USB.h"
|
||||
@@ -26,6 +27,8 @@
|
||||
#include "USB/usb-lightgun/guncon2.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace usb_lightgun
|
||||
@@ -52,6 +55,10 @@ namespace usb_lightgun
|
||||
BID_START = 15,
|
||||
BID_SHOOT_OFFSCREEN = 16,
|
||||
BID_RECALIBRATE = 17,
|
||||
BID_RELATIVE_LEFT = 18,
|
||||
BID_RELATIVE_RIGHT = 19,
|
||||
BID_RELATIVE_UP = 20,
|
||||
BID_RELATIVE_DOWN = 21,
|
||||
};
|
||||
|
||||
// Right pain in the arse. Different games seem to have different scales..
|
||||
@@ -133,6 +140,7 @@ namespace usb_lightgun
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Configuration
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool has_relative_binds = false;
|
||||
bool custom_config = false;
|
||||
u32 screen_width = 640;
|
||||
u32 screen_height = 240;
|
||||
@@ -145,6 +153,10 @@ namespace usb_lightgun
|
||||
// Host State (Not Saved)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
u32 button_state = 0;
|
||||
std::string cursor_path;
|
||||
float cursor_scale = 1.0f;
|
||||
u32 cursor_color = 0xFFFFFFFF;
|
||||
float relative_pos[4] = {};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Device State (Saved)
|
||||
@@ -162,6 +174,11 @@ namespace usb_lightgun
|
||||
void AutoConfigure();
|
||||
|
||||
std::tuple<s16, s16> CalculatePosition();
|
||||
|
||||
// 0..1, not -1..1.
|
||||
std::pair<float, float> GetAbsolutePositionFromRelativeAxes() const;
|
||||
u32 GetSoftwarePointerIndex() const;
|
||||
void UpdateSoftwarePointerPosition();
|
||||
};
|
||||
|
||||
static const USBDescStrings desc_strings = {
|
||||
@@ -323,6 +340,10 @@ namespace usb_lightgun
|
||||
static void usb_hid_unrealize(USBDevice* dev)
|
||||
{
|
||||
GunCon2State* us = USB_CONTAINER_OF(dev, GunCon2State, dev);
|
||||
|
||||
if (!us->cursor_path.empty())
|
||||
ImGuiManager::ClearSoftwareCursor(us->GetSoftwarePointerIndex());
|
||||
|
||||
delete us;
|
||||
}
|
||||
|
||||
@@ -359,8 +380,9 @@ namespace usb_lightgun
|
||||
std::tuple<s16, s16> GunCon2State::CalculatePosition()
|
||||
{
|
||||
float pointer_x, pointer_y;
|
||||
const std::pair<float, float> abs_pos(InputManager::GetPointerAbsolutePosition(0));
|
||||
GSTranslateWindowToDisplayCoordinates(abs_pos.first, abs_pos.second, &pointer_x, &pointer_y);
|
||||
const auto& [window_x, window_y] =
|
||||
(has_relative_binds) ? GetAbsolutePositionFromRelativeAxes() : InputManager::GetPointerAbsolutePosition(0);
|
||||
GSTranslateWindowToDisplayCoordinates(window_x, window_y, &pointer_x, &pointer_y);
|
||||
|
||||
s16 pos_x, pos_y;
|
||||
if (pointer_x < 0.0f || pointer_y < 0.0f)
|
||||
@@ -403,6 +425,29 @@ namespace usb_lightgun
|
||||
return std::tie(pos_x, pos_y);
|
||||
}
|
||||
|
||||
std::pair<float, float> GunCon2State::GetAbsolutePositionFromRelativeAxes() const
|
||||
{
|
||||
const float screen_rel_x = (((relative_pos[1] > 0.0f) ? relative_pos[1] : -relative_pos[0]) + 1.0f) * 0.5f;
|
||||
const float screen_rel_y = (((relative_pos[3] > 0.0f) ? relative_pos[3] : -relative_pos[2]) + 1.0f) * 0.5f;
|
||||
return std::make_pair(
|
||||
screen_rel_x * ImGuiManager::GetWindowWidth(), screen_rel_y * ImGuiManager::GetWindowHeight());
|
||||
}
|
||||
|
||||
u32 GunCon2State::GetSoftwarePointerIndex() const
|
||||
{
|
||||
return has_relative_binds ? (InputManager::MAX_POINTER_DEVICES + port) : 0;
|
||||
}
|
||||
|
||||
void GunCon2State::UpdateSoftwarePointerPosition()
|
||||
{
|
||||
pxAssert(has_relative_binds);
|
||||
if (cursor_path.empty())
|
||||
return;
|
||||
|
||||
const auto& [window_x, window_y] = GetAbsolutePositionFromRelativeAxes();
|
||||
ImGuiManager::SetSoftwareCursorPosition(GetSoftwarePointerIndex(), window_x, window_y);
|
||||
}
|
||||
|
||||
const char* GunCon2Device::Name() const
|
||||
{
|
||||
return TRANSLATE_NOOP("USB", "GunCon 2");
|
||||
@@ -435,6 +480,8 @@ namespace usb_lightgun
|
||||
usb_desc_init(&s->dev);
|
||||
usb_ep_init(&s->dev);
|
||||
|
||||
UpdateSettings(&s->dev, si);
|
||||
|
||||
return &s->dev;
|
||||
fail:
|
||||
usb_hid_unrealize(&s->dev);
|
||||
@@ -457,6 +504,47 @@ namespace usb_lightgun
|
||||
s->scale_x = USB::GetConfigFloat(si, s->port, TypeName(), "scale_x", DEFAULT_SCALE_X) / 100.0f;
|
||||
s->scale_y = USB::GetConfigFloat(si, s->port, TypeName(), "scale_y", DEFAULT_SCALE_Y) / 100.0f;
|
||||
}
|
||||
|
||||
// Pointer settings.
|
||||
const std::string pointer_binding = USB::GetConfigString(si, s->port, TypeName(), "Pointer", "");
|
||||
std::string cursor_path(USB::GetConfigString(si, s->port, TypeName(), "cursor_path"));
|
||||
const float cursor_scale = USB::GetConfigFloat(si, s->port, TypeName(), "cursor_scale", 1.0f);
|
||||
u32 cursor_color = 0xFFFFFF;
|
||||
if (std::string cursor_color_str(USB::GetConfigString(si, s->port, TypeName(), "cursor_color")); !cursor_color_str.empty())
|
||||
{
|
||||
// Strip the leading hash, if it's a CSS style colour.
|
||||
const std::optional<u32> cursor_color_opt(
|
||||
StringUtil::FromChars<u32>(cursor_color_str[0] == '#' ?
|
||||
std::string_view(cursor_color_str).substr(1) : std::string_view(cursor_color_str), 16));
|
||||
if (cursor_color_opt.has_value())
|
||||
cursor_color = cursor_color_opt.value();
|
||||
}
|
||||
|
||||
const s32 prev_pointer_index = s->GetSoftwarePointerIndex();
|
||||
|
||||
s->has_relative_binds = (USB::ConfigKeyExists(si, s->port, TypeName(), "RelativeLeft") ||
|
||||
USB::ConfigKeyExists(si, s->port, TypeName(), "RelativeRight") ||
|
||||
USB::ConfigKeyExists(si, s->port, TypeName(), "RelativeUp") ||
|
||||
USB::ConfigKeyExists(si, s->port, TypeName(), "RelativeDown"));
|
||||
|
||||
const s32 new_pointer_index = s->GetSoftwarePointerIndex();
|
||||
|
||||
if (prev_pointer_index != new_pointer_index || s->cursor_path != cursor_path ||
|
||||
s->cursor_scale != cursor_scale || s->cursor_color != cursor_color)
|
||||
{
|
||||
if (prev_pointer_index != new_pointer_index)
|
||||
ImGuiManager::ClearSoftwareCursor(prev_pointer_index);
|
||||
|
||||
// Pointer changed, so need to update software cursor.
|
||||
if (!cursor_path.empty())
|
||||
ImGuiManager::SetSoftwareCursor(new_pointer_index, cursor_path, cursor_scale, cursor_color);
|
||||
else if (!s->cursor_path.empty())
|
||||
ImGuiManager::ClearSoftwareCursor(new_pointer_index);
|
||||
|
||||
s->cursor_path = std::move(cursor_path);
|
||||
s->cursor_scale = cursor_scale;
|
||||
s->cursor_color = cursor_color;
|
||||
}
|
||||
}
|
||||
|
||||
float GunCon2Device::GetBindingValue(const USBDevice* dev, u32 bind_index) const
|
||||
@@ -471,11 +559,23 @@ namespace usb_lightgun
|
||||
{
|
||||
GunCon2State* s = USB_CONTAINER_OF(dev, GunCon2State, dev);
|
||||
|
||||
const u32 bit = 1u << bind_index;
|
||||
if (value >= 0.5f)
|
||||
s->button_state |= bit;
|
||||
else
|
||||
s->button_state &= ~bit;
|
||||
if (bind_index < BID_RELATIVE_LEFT)
|
||||
{
|
||||
const u32 bit = 1u << bind_index;
|
||||
if (value >= 0.5f)
|
||||
s->button_state |= bit;
|
||||
else
|
||||
s->button_state &= ~bit;
|
||||
}
|
||||
else if (bind_index <= BID_RELATIVE_DOWN)
|
||||
{
|
||||
const u32 rel_index = bind_index - BID_RELATIVE_LEFT;
|
||||
if (s->relative_pos[rel_index] != value)
|
||||
{
|
||||
s->relative_pos[rel_index] = value;
|
||||
s->UpdateSoftwarePointerPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::span<const InputBindingInfo> GunCon2Device::Bindings(u32 subtype) const
|
||||
@@ -497,6 +597,10 @@ namespace usb_lightgun
|
||||
{"C", TRANSLATE_NOOP("USB", "C"), InputBindingInfo::Type::Button, BID_C, GenericInputBinding::Triangle},
|
||||
{"Select", TRANSLATE_NOOP("USB", "Select"), InputBindingInfo::Type::Button, BID_SELECT, GenericInputBinding::Select},
|
||||
{"Start", TRANSLATE_NOOP("USB", "Start"), InputBindingInfo::Type::Button, BID_START, GenericInputBinding::Start},
|
||||
{"RelativeLeft", TRANSLATE_NOOP("USB", "Relative Left"), InputBindingInfo::Type::HalfAxis, BID_RELATIVE_LEFT, GenericInputBinding::Unknown},
|
||||
{"RelativeRight", TRANSLATE_NOOP("USB", "Relative Right"), InputBindingInfo::Type::HalfAxis, BID_RELATIVE_RIGHT, GenericInputBinding::Unknown},
|
||||
{"RelativeUp", TRANSLATE_NOOP("USB", "Relative Up"), InputBindingInfo::Type::HalfAxis, BID_RELATIVE_UP, GenericInputBinding::Unknown},
|
||||
{"RelativeDown", TRANSLATE_NOOP("USB", "Relative Down"), InputBindingInfo::Type::HalfAxis, BID_RELATIVE_DOWN, GenericInputBinding::Unknown},
|
||||
};
|
||||
|
||||
return bindings;
|
||||
@@ -505,16 +609,27 @@ namespace usb_lightgun
|
||||
std::span<const SettingInfo> GunCon2Device::Settings(u32 subtype) const
|
||||
{
|
||||
static constexpr const SettingInfo info[] = {
|
||||
{SettingInfo::Type::Path, "cursor_path", "Cursor Path",
|
||||
TRANSLATE_NOOP("USB", "Sets the crosshair image that this lightgun will use. Setting a crosshair image "
|
||||
"will disable the system cursor."),
|
||||
""},
|
||||
{SettingInfo::Type::Float, "cursor_scale", TRANSLATE_NOOP("USB", "Cursor Scale"),
|
||||
TRANSLATE_NOOP("USB", "Scales the crosshair image set above."), "1", "0.01", "10", "0.01", "%.0f%%",
|
||||
nullptr, nullptr, 100.0f},
|
||||
{SettingInfo::Type::String, "cursor_color", TRANSLATE_NOOP("USB", "Cursor Color"),
|
||||
TRANSLATE_NOOP("USB", "Applys a color to the chosen crosshair images, can be used for multiple "
|
||||
"players. Specify in HTML/CSS format (e.g. #aabbcc)"),
|
||||
"#ffffff"},
|
||||
{SettingInfo::Type::Boolean, "custom_config", TRANSLATE_NOOP("USB", "Manual Screen Configuration"),
|
||||
TRANSLATE_NOOP("USB",
|
||||
"Forces the use of the screen parameters below, instead of automatic parameters if available."),
|
||||
"false"},
|
||||
{SettingInfo::Type::Float, "scale_x", TRANSLATE_NOOP("USB", "X Scale (Sensitivity)"),
|
||||
"Scales the position to simulate CRT curvature.", "100", "0", "200", "0.1", "%.2f%%", nullptr, nullptr,
|
||||
1.0f},
|
||||
TRANSLATE_NOOP("USB", "Scales the position to simulate CRT curvature."), "100", "0", "200", "0.1",
|
||||
"%.2f%%", nullptr, nullptr, 1.0f},
|
||||
{SettingInfo::Type::Float, "scale_y", TRANSLATE_NOOP("USB", "Y Scale (Sensitivity)"),
|
||||
"Scales the position to simulate CRT curvature.", "100", "0", "200", "0.1", "%.2f%%", nullptr, nullptr,
|
||||
1.0f},
|
||||
TRANSLATE_NOOP("USB", "Scales the position to simulate CRT curvature."), "100", "0", "200", "0.1",
|
||||
"%.2f%%", nullptr, nullptr, 1.0f},
|
||||
{SettingInfo::Type::Float, "center_x", TRANSLATE_NOOP("USB", "Center X"),
|
||||
TRANSLATE_NOOP("USB", "Sets the horizontal center position of the simulated screen."), "320", "0",
|
||||
"1024", "1", "%.0fpx", nullptr, nullptr, 1.0f},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -44,6 +44,11 @@
|
||||
#include "R5900.h"
|
||||
#include "Recording/InputRecording.h"
|
||||
#include "Recording/InputRecordingControls.h"
|
||||
#include "SIO/Memcard/MemoryCardFile.h"
|
||||
#include "SIO/Pad/Pad.h"
|
||||
#include "SIO/Sio.h"
|
||||
#include "SIO/Sio0.h"
|
||||
#include "SIO/Sio2.h"
|
||||
#include "SPU2/spu2.h"
|
||||
#include "USB/USB.h"
|
||||
#include "VMManager.h"
|
||||
@@ -58,13 +63,6 @@
|
||||
#include "common/Threading.h"
|
||||
#include "common/Timer.h"
|
||||
#include "common/emitter/tools.h"
|
||||
#include "SIO/Sio.h"
|
||||
#include "SIO/Sio0.h"
|
||||
#include "SIO/Sio2.h"
|
||||
#include "SIO/Pad/PadManager.h"
|
||||
#include "SIO/Pad/PadConfig.h"
|
||||
#include "SIO/Memcard/MemoryCardFile.h"
|
||||
|
||||
|
||||
#include "IconsFontAwesome5.h"
|
||||
#include "fmt/core.h"
|
||||
@@ -451,10 +449,12 @@ void VMManager::SetDefaultSettings(
|
||||
LogSink::SetDefaultLoggingSettings(si);
|
||||
}
|
||||
if (controllers)
|
||||
g_PadConfig.SetDefaultControllerConfig(si);
|
||||
{
|
||||
Pad::SetDefaultControllerConfig(si);
|
||||
USB::SetDefaultConfiguration(&si);
|
||||
}
|
||||
if (hotkeys)
|
||||
g_PadConfig.SetDefaultHotkeyConfig(si);
|
||||
Pad::SetDefaultHotkeyConfig(si);
|
||||
if (ui)
|
||||
Host::SetDefaultUISettings(si);
|
||||
}
|
||||
@@ -464,7 +464,7 @@ void VMManager::LoadSettings()
|
||||
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
||||
SettingsInterface* si = Host::GetSettingsInterface();
|
||||
LoadCoreSettings(si);
|
||||
g_PadConfig.LoadConfig(*si);
|
||||
Pad::LoadConfig(*si);
|
||||
Host::LoadSettings(*si, lock);
|
||||
InputManager::ReloadSources(*si, lock);
|
||||
InputManager::ReloadBindings(*si, *Host::GetSettingsInterfaceForBindings());
|
||||
@@ -1208,15 +1208,13 @@ bool VMManager::Initialize(VMBootParameters boot_params)
|
||||
ScopedGuard close_spu2(&SPU2::Close);
|
||||
|
||||
|
||||
Console.WriteLn("Initializing PAD...");
|
||||
if (!g_PadManager.Initialize())
|
||||
Console.WriteLn("Initializing Pad...");
|
||||
if (!Pad::Initialize())
|
||||
{
|
||||
Host::ReportErrorAsync("Startup Error", "Failed to initialize PAD");
|
||||
return false;
|
||||
}
|
||||
ScopedGuard close_pad = [](){
|
||||
g_PadManager.Shutdown();
|
||||
};
|
||||
ScopedGuard close_pad = &Pad::Shutdown;
|
||||
|
||||
Console.WriteLn("Initializing SIO2...");
|
||||
if (!g_Sio2.Initialize())
|
||||
@@ -1368,7 +1366,7 @@ void VMManager::Shutdown(bool save_resume_state)
|
||||
vtlb_Shutdown();
|
||||
USBclose();
|
||||
SPU2::Close();
|
||||
g_PadManager.Shutdown();
|
||||
Pad::Shutdown();
|
||||
g_Sio2.Shutdown();
|
||||
g_Sio0.Shutdown();
|
||||
DEV9close();
|
||||
@@ -1984,7 +1982,8 @@ void VMManager::Internal::EntryPointCompilingOnCPUThread()
|
||||
|
||||
void VMManager::Internal::VSyncOnCPUThread()
|
||||
{
|
||||
// TODO: Move frame limiting here to reduce CPU usage after sleeping...
|
||||
Pad::UpdateMacroButtons();
|
||||
|
||||
Patch::ApplyLoadedPatches(Patch::PPT_CONTINUOUSLY);
|
||||
Patch::ApplyLoadedPatches(Patch::PPT_COMBINED_0_1);
|
||||
|
||||
|
||||
@@ -243,11 +243,9 @@
|
||||
<ClCompile Include="SIO\Memcard\MemoryCardProtocol.cpp" />
|
||||
<ClCompile Include="SIO\Multitap\MultitapProtocol.cpp" />
|
||||
<ClCompile Include="SIO\Pad\PadBase.cpp" />
|
||||
<ClCompile Include="SIO\Pad\PadConfig.cpp" />
|
||||
<ClCompile Include="SIO\Pad\Pad.cpp" />
|
||||
<ClCompile Include="SIO\Pad\PadDualshock2.cpp" />
|
||||
<ClCompile Include="SIO\Pad\PadGuitar.cpp" />
|
||||
<ClCompile Include="SIO\Pad\PadMacros.cpp" />
|
||||
<ClCompile Include="SIO\Pad\PadManager.cpp" />
|
||||
<ClCompile Include="SIO\Pad\PadNotConnected.cpp" />
|
||||
<ClCompile Include="SIO\Sio.cpp" />
|
||||
<ClCompile Include="SIO\Sio0.cpp" />
|
||||
@@ -599,14 +597,10 @@
|
||||
<ClInclude Include="SIO\Memcard\MemoryCardFolder.h" />
|
||||
<ClInclude Include="SIO\Memcard\MemoryCardProtocol.h" />
|
||||
<ClInclude Include="SIO\Multitap\MultitapProtocol.h" />
|
||||
<ClInclude Include="SIO\Pad\PadDualshock2Types.h" />
|
||||
<ClInclude Include="SIO\Pad\PadGuitarTypes.h" />
|
||||
<ClInclude Include="SIO\Pad\PadBase.h" />
|
||||
<ClInclude Include="SIO\Pad\PadConfig.h" />
|
||||
<ClInclude Include="SIO\Pad\Pad.h" />
|
||||
<ClInclude Include="SIO\Pad\PadDualshock2.h" />
|
||||
<ClInclude Include="SIO\Pad\PadGuitar.h" />
|
||||
<ClInclude Include="SIO\Pad\PadMacros.h" />
|
||||
<ClInclude Include="SIO\Pad\PadManager.h" />
|
||||
<ClInclude Include="SIO\Pad\PadNotConnected.h" />
|
||||
<ClInclude Include="SIO\Pad\PadTypes.h" />
|
||||
<ClInclude Include="SIO\Sio.h" />
|
||||
|
||||
@@ -1418,9 +1418,6 @@
|
||||
<ClCompile Include="SIO\Pad\PadGuitar.cpp">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SIO\Pad\PadManager.cpp">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SIO\Pad\PadNotConnected.cpp">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClCompile>
|
||||
@@ -1433,10 +1430,7 @@
|
||||
<ClCompile Include="SIO\Sio2.cpp">
|
||||
<Filter>System\Ps2\Iop\SIO</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SIO\Pad\PadMacros.cpp">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SIO\Pad\PadConfig.cpp">
|
||||
<ClCompile Include="SIO\Pad\Pad.cpp">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
@@ -2345,12 +2339,6 @@
|
||||
<ClInclude Include="SIO\Memcard\MemoryCardProtocol.h">
|
||||
<Filter>System\Ps2\Iop\SIO\Memcard</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SIO\Pad\PadDualshock2Types.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SIO\Pad\PadGuitarTypes.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SIO\Pad\PadBase.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
@@ -2360,9 +2348,6 @@
|
||||
<ClInclude Include="SIO\Pad\PadGuitar.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SIO\Pad\PadManager.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SIO\Pad\PadNotConnected.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
@@ -2381,10 +2366,7 @@
|
||||
<ClInclude Include="SIO\SioTypes.h">
|
||||
<Filter>System\Ps2\Iop\SIO</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SIO\Pad\PadMacros.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SIO\Pad\PadConfig.h">
|
||||
<ClInclude Include="SIO\Pad\Pad.h">
|
||||
<Filter>System\Ps2\Iop\SIO\PAD</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -436,7 +436,7 @@ mem32_t iopHwRead32_Page8( u32 addr )
|
||||
if( masked_addr < 0x240 )
|
||||
{
|
||||
const int parm = (masked_addr-0x200) / 4;
|
||||
ret = g_Sio2.send3.at(parm);
|
||||
ret = g_Sio2.send3[parm];
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 SEND3 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
}
|
||||
else if( masked_addr < 0x260 )
|
||||
@@ -444,7 +444,7 @@ 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.at(parm) : g_Sio2.send1.at(parm);
|
||||
ret = (masked_addr & 4) ? g_Sio2.send2[parm] : g_Sio2.send1[parm];
|
||||
Sio2Log.WriteLn("%s(%08X) SIO2 SEND1/2 Read (%08X)", __FUNCTION__, addr, ret);
|
||||
}
|
||||
else if( masked_addr <= 0x280 )
|
||||
|
||||
@@ -615,12 +615,12 @@ 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.at(parm) = val;
|
||||
g_Sio2.send2[parm] = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
Sio2Log.WriteLn("%s(%08X, %08X) SIO2 SEND1 Write", __FUNCTION__, addr, val);
|
||||
g_Sio2.send1.at(parm) = val;
|
||||
g_Sio2.send1[parm] = val;
|
||||
}
|
||||
}
|
||||
else if( masked_addr <= 0x280 )
|
||||
|
||||
@@ -95,7 +95,7 @@ void Host::OnInputDeviceDisconnected(const std::string_view& identifier)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::SetRelativeMouseMode(bool enabled)
|
||||
void Host::SetMouseMode(bool relative_mode, bool hide_cursor)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||