Compare commits

...
47 Commits
Author SHA1 Message Date
JordanTheToasterandrefractionpcsx2 655241aed3 Translations: Add Latvija to the menu
Adds missing Latvija option to the menu of selectable languages.
2023-07-28 16:28:29 +01:00
refractionpcsx2 60a2b246e2 GS: Correct alpha test for RGB Only and non-32bit colours 2023-07-28 15:57:28 +01:00
Tyler WildingandGitHub ebd60d93f3 translations: Syncing Crowdin translations (#9655) 2023-07-28 14:50:23 +01:00
Connor McLaughlinandGitHub cc4ba935b5 CI/Linux: Fetch tags for Flatpak scheduled builds
Regression from #9224.
2023-07-28 21:48:35 +10:00
RedPanda4552andrefractionpcsx2 824147fd7d [SAVEVERSION+] Fix vibration motors backwards and too low power delivery to small motor
Also fix inconsequential but (technically) incorrect return values for vibration mapping command
2023-07-28 11:27:51 +01:00
refractionpcsx2 c3446a16cc GS: Kill SMT Nocturne CRC hack 2023-07-28 01:48:45 +01:00
Stenzekandrefractionpcsx2 82135d1892 GS/OGL: Fix depth state in MultiStretchRects 2023-07-28 01:48:27 +01:00
refractionpcsx2 1cff63bc01 UI: Add some missing string translations 2023-07-27 20:25:17 +01:00
refractionpcsx2 e488e74313 UI: Fix minor typo 2023-07-27 20:25:17 +01:00
refractionpcsx2 1a17c9da86 GameDB: Add Preload Frame to remaining versions of Keroro Gunsou 2023-07-27 20:25:17 +01:00
refractionpcsx2 20e1f773fc GS/HW: Mark alpha invalid on framebuffer resize. 2023-07-27 20:25:17 +01:00
refractionpcsx2 56d80ff293 GS/HW: Update Blue Tongue CRC and remove frame width hacks 2023-07-27 20:25:17 +01:00
refractionpcsx2 80e176136a GS/HW: Adjust Burnout bloom CRC to work better with upscaling 2023-07-27 20:23:21 +01:00
RedPanda4552andrefractionpcsx2 0ae66d3e24 Pad: Set data low when no pad present
Fixes uLaunchELF spinning waiting for second pad to come online.
2023-07-27 20:19:45 +01:00
RedDevilusandrefractionpcsx2 802ab8238e GameDB: Beeg fixing about everything
Sims M6 to M8 (more languages)
Tarzan (Slight Blurring)
Winnie Poo (Misaligned sprites and models)
Blood Will Tell: More vibrant text with medium blending
Recommended blending for SSX series

etc Because I keep forgetting to PR this otherwise
2023-07-27 17:09:31 +01:00
refractionpcsx2 ec9c07a646 GS/HW: Tweak Burnout bloom CRC coords 2023-07-27 14:50:29 +01:00
refractionpcsx2 b75ad663f2 USB/UI: Fix small typo 2023-07-27 13:08:08 +01:00
Stenzek e4a017fc00 Qt: Add callback for forcing achievements re-login 2023-07-27 20:40:58 +10:00
SilentandConnor McLaughlin 5b486ca6b8 Achievements: Log-in explicitly on startup to refresh the token 2023-07-27 20:40:58 +10:00
PCSX2 BotandConnor McLaughlin 1c39ed6130 Qt: Update Base Translation 2023-07-27 12:50:26 +10:00
lightningterror a47563b12f GSRunner: Fixes runner compile.
Pad include from previous refactor.
2023-07-26 21:56:56 +02:00
refractionpcsx2 84491ff655 GS/HW: Modify Burnout IO CRC hack to not affect online mode screen 2023-07-26 20:23:37 +01:00
refractionpcsx2 e5991a4379 GameDB: Add Partial Target Invalidation to Racing Simulation 3 2023-07-26 16:07:57 +01:00
JordanTheToasterandrefractionpcsx2 0b3d4615b8 ImGuiOverlays: Fix missing space
Text gets bunched up otherwise with no space.
2023-07-26 14:38:18 +01:00
JordanTheToasterandrefractionpcsx2 a8f6336b47 GameDB: Various fixes
Fixes for flickering lights in Area 51 and missing fixes for Burnout Revenge and Dominator.
2023-07-26 14:38:18 +01:00
RedPanda4552andConnor McLaughlin 0b33df3341 Pad: Change button query response depending on current mode
Fixes CoD 3 not understanding which buttons the controller has available
2023-07-26 21:23:21 +10:00
kamfretozandConnor McLaughlin 744cc4b705 Qt: Add an instruction to the autoupdater pop up. 2023-07-26 15:03:11 +10:00
kamfretozandConnor McLaughlin 9d3cd5784f Qt: Further icon refinement and additions 2023-07-26 13:28:23 +10:00
Stenzek 06ea58198a GameDB: Use nearest dirty upload for Burnout 3 and Onimusha 3
Burnout 3: Fixes sun banding in some stages.
Onimusha 3: Fixes vertical line down screen.
2023-07-26 13:21:35 +10:00
Stenzek 3692d7d090 GS/HW: Extend bilinear dirty upscale fix to force nearest 2023-07-26 13:21:35 +10:00
Stenzek 460a2dbbd3 Qt: Add custom binding widget for GunCon2 2023-07-26 13:20:44 +10:00
Stenzek 228f4f1010 USB-GunCon2: Support binding to controller 2023-07-26 13:20:44 +10:00
Stenzek 2703b91e41 USB: Add ConfigKeyExists() 2023-07-26 13:20:44 +10:00
Stenzek 24171787f8 ImGuiManager: Add software cursor support
Can be used to render a crosshair for GunCon.
2023-07-26 13:20:44 +10:00
PCSX2 BotandConnor McLaughlin 49d3338d4a Qt: Update Base Translation 2023-07-26 13:19:37 +10:00
Stenzek a9d693e1c3 GS/HW: Improve readback-avoiding CLUT heuristics
Use target overlap instead of exact match.
2023-07-26 13:18:04 +10:00
Stenzek 4ef69248d0 GSRunner: Add readbacks to stats 2023-07-26 13:18:04 +10:00
Stenzek 247b3ed740 GS/HW: HLE the Burnout games bloom effect 2023-07-26 13:18:04 +10:00
Stenzekandrefractionpcsx2 1edca6235c Sio: Migrate to StateWrapper
Also fixes the crash due to serializing pointers.

[SAVEVERSION+] and actually bump the save version.
2023-07-26 01:22:11 +01:00
Connor McLaughlinandGitHub ab5c03b1d9 Pad: Fixes and cleanup (#9623)
* Pad: Get rid of redundant object lookup

* Pad: Serialize 'stage' state

[SAVEVERSION+]

* Pad: Reduce Freeze duplication and add markers

Catch any possible unhandled device type change.

[SAVEVERSION+]

* Pad: Localize controller type names

* Pad: Handle mismatch between state and current config

* Misc: Drop .at() from vector/array access

We don't use exceptions.

* Pad: Remove redundant GetUnifiedSlot()

Sio has routines for converting these.

* Sio2: Remove redundant optional in Pad()

* Pad: Constify and finalize controller classes

* Pad: Move PadManager to Pad namespace

No point having a class when there's only a single instance.

* Pad: Move PadConfig to Pad namespace

* Pad: Move PadMacros to Pad namespace

* Pad: Re-localize controller bindings/settings

* Pad: Make controller info local

Don't want to create duplicates.

* Pad: Use span for ControllerInfo settings/bindings

* Pad: Fix auto-toggled macro buttons

* Pad: Fix pressure for macros

* Pad: Merge PadConfig/PadManager/PadMacros

Faster compile time.

* Pad: Fix incorrect condition in Sio0::SetTxData()

* Pad: Add deadzone for macro triggers
2023-07-26 01:10:02 +10:00
TheLastRarandrefractionpcsx2 d4cb35469d DEV9: Perform a null check on ifa_addr when searching adapters 2023-07-25 13:23:01 +01:00
Stenzek fd1b1d0c24 GS/HW: Improve Basic blending
- Don't assume no overlap = free. Reduces a number of barriers.
 - Prefer SW blend for Ad blends, except when it's constant. It's
   impossible to emulate accurately in HW, because 128 is 1, not 255.
 - Prefer SW blend for AFIX > 128 on no-overlap sprites.
2023-07-25 13:04:45 +10:00
Stenzek bf96ceeacc GS/HW: Assume primitive does not overlap if it is a single quad
Enables one-barrier software blending for fullscreen quads.
We can also use tex-is-fb safely in these scenarios too.

Fixes Persona 4 menu background, Hard Hitter Tennis shadows at
Basic blending.
2023-07-25 13:04:45 +10:00
RedPanda4552andrefractionpcsx2 2c08b385e5 Pad: Revert back to old Constant 1 behavior
Fixes pad detection in NBA 2K7, possibly others.
2023-07-25 00:27:53 +01:00
JordanTheToasterandrefractionpcsx2 051d13ec7a GameDB: Various fixes
Adds missing fixes and game entry's for guitar hero and re fixes LOTR Third Age.
2023-07-24 23:18:30 +01:00
refractionpcsx2 a2a9643123 GameDB: Move Haunting Ground over to HPO Special + Round Sprite Half 2023-07-24 21:44:24 +01:00
refractionpcsx2 1286bfe75b UI/UX: Added popup when updating if savestate version changes 2023-07-24 19:42:36 +01:00
132 changed files with 115163 additions and 57585 deletions
@@ -37,5 +37,6 @@ jobs:
cmakeflags: ""
publish: true
branch: stable
fetchTags: true
secrets: inherit
+215 -19
View File
@@ -1587,6 +1587,8 @@ SCAJ-25045:
SCAJ-25047:
name: "Dororo"
region: "NTSC-Unk"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes dark font to more bright like software mode.
SCAJ-30001:
name: "Xenosaga - Episode I - Der Wille zur Macht [PlayStation 2 The Best]"
region: "NTSC-Unk"
@@ -3225,6 +3227,8 @@ SCES-50408:
gsHWFixes:
mipmap: 2 # Fixes missing floor texture.
trilinearFiltering: 1 # Fixes fog effect.
wildArmsHack: 1 # Fixes misaligment depth of field effect.
roundSprite: 2 # Fixes misaligment depth of field effect even more.
SCES-50409:
name: "MotoGP 2"
region: "PAL-M5"
@@ -4252,6 +4256,9 @@ SCES-53300:
region: "PAL-M5"
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
minimumBlendingLevel: 4 # Mitigates grayer text font in bottom left.
partialTargetInvalidation: 1 # Fixes loading screen picture.
SCES-53304:
name: "Buzz! The Music Quiz"
region: "PAL-E"
@@ -4666,6 +4673,9 @@ SCES-54477:
compat: 5
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
recommendedBlendingLevel: 4 # Mitigates grayer text font in bottom left but stuff in front can lower or increase opacity.
partialTargetInvalidation: 1 # Fixes loading screen picture.
SCES-54496:
name: "Buzz! The Mega Quiz"
region: "PAL-E"
@@ -5569,6 +5579,9 @@ SCKA-20064:
region: "NTSC-K"
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
minimumBlendingLevel: 4 # Mitigates grayer text font in bottom left.
partialTargetInvalidation: 1 # Fixes loading screen picture.
SCKA-20065:
name: "Urban Reign"
region: "NTSC-K"
@@ -6053,6 +6066,8 @@ SCPS-15017:
gsHWFixes:
mipmap: 2 # Fixes missing floor texture.
trilinearFiltering: 1 # Fixes fog effect.
wildArmsHack: 1 # Fixes misaligment depth of field effect.
roundSprite: 2 # Fixes misaligment depth of field effect even more.
SCPS-15018:
name: "Train Simulator Real, The - Yamanote Sen"
region: "NTSC-J"
@@ -6728,6 +6743,8 @@ SCPS-19201:
gsHWFixes:
mipmap: 2 # Fixes missing floor texture.
trilinearFiltering: 1 # Fixes fog effect.
wildArmsHack: 1 # Fixes misaligment depth of field effect.
roundSprite: 2 # Fixes misaligment depth of field effect even more.
SCPS-19202:
name: "Extermination [PlayStation 2 The Best]"
region: "NTSC-J"
@@ -7832,6 +7849,8 @@ SCUS-97167:
gsHWFixes:
mipmap: 2 # Fixes missing floor texture.
trilinearFiltering: 1 # Fixes fog effect.
wildArmsHack: 1 # Fixes misaligment depth of field effect.
roundSprite: 2 # Fixes misaligment depth of field effect even more.
SCUS-97169:
name: "Drakan - The Ancients' Gates [Demo]"
region: "NTSC-U"
@@ -8892,6 +8911,9 @@ SCUS-97474:
compat: 5
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
minimumBlendingLevel: 4 # Mitigates grayer text font in bottom left.
partialTargetInvalidation: 1 # Fixes loading screen picture.
patches:
75ED4282:
content: |-
@@ -8905,6 +8927,9 @@ SCUS-97475:
region: "NTSC-U"
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
minimumBlendingLevel: 4 # Mitigates grayer text font in bottom left.
partialTargetInvalidation: 1 # Fixes loading screen picture.
patches:
314F0905:
content: |-
@@ -9007,6 +9032,9 @@ SCUS-97489:
region: "NTSC-U"
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
minimumBlendingLevel: 4 # Mitigates grayer text font in bottom left.
partialTargetInvalidation: 1 # Fixes loading screen picture.
SCUS-97490:
name: "Rogue Galaxy"
region: "NTSC-U"
@@ -9234,6 +9262,9 @@ SCUS-97545:
compat: 5
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
recommendedBlendingLevel: 4 # Mitigates grayer text font in bottom left but stuff in front can lower or increase opacity.
partialTargetInvalidation: 1 # Fixes loading screen picture.
patches:
D7CFDCCF:
content: |-
@@ -9279,6 +9310,9 @@ SCUS-97560:
region: "NTSC-U"
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
recommendedBlendingLevel: 4 # Mitigates grayer text font in bottom left but stuff in front can lower or increase opacity.
partialTargetInvalidation: 1 # Fixes loading screen picture.
SCUS-97564:
name: "Jampack Demo Disc Vol.15 [T-Rated]"
region: "NTSC-U"
@@ -9575,6 +9609,8 @@ SLAJ-25046:
SLAJ-25047:
name: "Dororo"
region: "NTSC-Ch-J"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes dark font to more bright like software mode.
SLAJ-25048:
name: "Sengoku Musou Mushoden"
region: "NTSC-Unk"
@@ -9583,9 +9619,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 +9639,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 +9678,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 +9813,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 +10051,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 +10153,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 +10286,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"
@@ -11134,6 +11180,8 @@ SLES-50341:
SLES-50350:
name: "Disney's Tarzan - Freeride"
region: "PAL-M5"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurriness and misaligned shadows.
SLES-50351:
name: "Lake Masters EX"
region: "PAL-M3"
@@ -11537,6 +11585,8 @@ SLES-50545:
region: "PAL-M3"
roundModes:
eeRoundMode: 0 # Fixes riders vanish into the floor.
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLES-50546:
name: "LMA Manager 2002"
region: "PAL-E"
@@ -13287,7 +13337,7 @@ SLES-51256:
vuClampMode: 3 # Fix white shiny weapons.
SLES-51257:
name: "Sims, The"
region: "PAL-M6"
region: "PAL-M8"
compat: 3
speedHacks:
mtvu: 0 # Fixes bad graphics due to bad T-Bit handling.
@@ -14010,6 +14060,8 @@ SLES-51630:
SLES-51633:
name: "Racing Simulation 3"
region: "PAL-M5"
gsHWFixes:
partialTargetInvalidation: 1 # Fixes crash during loading screen due to bad download.
SLES-51636:
name: "XGRA - Extreme G Racing Association"
region: "PAL-M5"
@@ -14136,6 +14188,7 @@ SLES-51697:
gsHWFixes:
textureInsideRT: 1 # Fixes rainbow effect in the pause menu before a jump.
halfPixelOffset: 2 # Fixes depth lines.
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLES-51698:
name: "Mobile Light Force 2"
region: "PAL-M5"
@@ -14691,6 +14744,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 +16168,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 +16208,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 +16223,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:
@@ -16585,6 +16641,8 @@ SLES-52746:
SLES-52747:
name: "Dukes of Hazzard, The - The Return of General Lee"
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 1 # Fixes misaligned post-processing.
SLES-52749:
name: "Habitrail - Hamster Ball"
region: "PAL-E"
@@ -16608,6 +16666,8 @@ SLES-52754:
SLES-52755:
name: "Blood Will Tell - Tezuka Osamu's Dororo"
region: "PAL-M5"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes dark font to more bright like software mode.
SLES-52760:
name: "Pro Evolution Soccer 4"
region: "PAL-M4"
@@ -16703,25 +16763,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 +16987,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"
@@ -16955,6 +17018,8 @@ SLES-52888:
SLES-52889:
name: "Disney's Winnie the Pooh Rumbly Tumbly Adventure"
region: "PAL-M6"
gsHWFixes:
autoFlush: 1 # Fixes bloomlike-offsets.
SLES-52894:
name: "Bard's Tale, The"
region: "PAL-E"
@@ -17540,7 +17605,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"
@@ -17973,6 +18038,9 @@ SLES-53300:
region: "PAL-Unk"
clampModes:
vuClampMode: 3 # Fixes SPS ingame and prevents flickering or invisible characters.
gsHWFixes:
minimumBlendingLevel: 4 # Mitigates grayer text font in bottom left.
partialTargetInvalidation: 1 # Fixes loading screen picture.
SLES-53301:
name: "Bomberman Hardball"
region: "PAL-E"
@@ -18081,6 +18149,8 @@ SLES-53350:
SLES-53351:
name: "SSX On Tour"
region: "PAL-E"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLES-53353:
name: "Shounen Jump's Shaman King - Power of Spirit"
region: "PAL-M3"
@@ -18335,6 +18405,8 @@ SLES-53419:
SLES-53420:
name: "Winnie the Pooh's Rumbly Tumbly Adventure"
region: "PAL-PL"
gsHWFixes:
autoFlush: 1 # Fixes bloomlike-offsets.
SLES-53424:
name: "Dead to Rights 2"
region: "PAL-M4"
@@ -18545,6 +18617,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 +18639,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 +18769,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 +18781,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"
@@ -18795,9 +18871,13 @@ SLES-53548:
SLES-53551:
name: "SSX On Tour"
region: "PAL-E"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLES-53552:
name: "SSX On Tour"
region: "PAL-M8"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLES-53553:
name: "007 - From Russia with Love"
region: "PAL-M7"
@@ -20452,6 +20532,8 @@ SLES-54164:
SLES-54165:
name: "One Piece - Grand Adventure"
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 1 # Fixes character outlines, shadow misaligment and more.
SLES-54166:
name: "Call of Duty 3"
region: "PAL-E"
@@ -21426,7 +21508,7 @@ SLES-54519:
region: "PAL-A"
SLES-54520:
name: "Agent Hugo - RoboRumble"
region: "PAL"
region: "PAL-PL"
SLES-54521:
name: "Nickelodeon SpongeBob and Friends - Battle for Volcano Island"
region: "PAL-M5"
@@ -21679,6 +21761,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 +21942,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 +22731,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 +22764,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"
@@ -23309,6 +23397,7 @@ SLES-55215:
compat: 5
gsHWFixes:
moveHandler: "MV_Growlanser" # Fixes precomputed depth buffer.
textureInsideRT: 1 # Fixes character layering issue.
SLES-55216:
name: "Baroque"
region: "PAL-E"
@@ -24111,6 +24200,7 @@ SLES-55579:
vu0ClampMode: 0 # Fixes black textures and SPS.
gsHWFixes:
deinterlace: 8 # Game requires AdaptiveTFF de-interlacing when auto for the (starter) FMVs.
minimumBlendingLevel: 3 # Fixes missing colortints like on faces and models being too dark.
SLES-55581:
name: "FIFA 10"
region: "PAL-M5"
@@ -24174,6 +24264,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 +25091,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"
@@ -25061,6 +25153,7 @@ SLKA-25118:
gsHWFixes:
textureInsideRT: 1 # Fixes rainbow effect in the pause menu before a jump.
halfPixelOffset: 2 # Fixes depth lines.
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLKA-25120:
name: "Prince of Persia - The Sands of Time"
region: "NTSC-K"
@@ -25288,6 +25381,7 @@ SLKA-25200:
gsHWFixes:
textureInsideRT: 1 # Fixes rainbow effect in the pause menu before a jump.
halfPixelOffset: 2 # Fixes depth lines.
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLKA-25201:
name: "Armored Core - Nexus [Disc 1]"
region: "NTSC-K"
@@ -25329,6 +25423,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:
@@ -25418,6 +25513,8 @@ SLKA-25225:
name: "Dororo"
region: "NTSC-K"
compat: 5
gsHWFixes:
minimumBlendingLevel: 2 # Fixes dark font to more bright like software mode.
SLKA-25226:
name: "Incredibles, The"
region: "NTSC-K"
@@ -25445,7 +25542,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 +25751,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:
@@ -25711,9 +25809,13 @@ SLKA-25322:
SLKA-25323:
name: "SSX On Tour"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLKA-25325:
name: "SSX On Tour"
region: "NTSC-K"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLKA-25327:
name: "Harry Potter and the Goblet of Fire"
region: "NTSC-K"
@@ -25834,6 +25936,8 @@ SLKA-25359:
SLKA-25361:
name: "Keroro Gunsou MeroMero Battle Royale Z"
region: "NTSC-K"
gsHWFixes:
preloadFrameData: 1 # Fixes invisible text.
SLKA-25363:
name: "Guitar Hero III - Legends of Rock"
region: "NTSC-K"
@@ -25887,6 +25991,8 @@ SLKA-25388:
name: "One Piece - Grand Adventure"
region: "NTSC-K"
compat: 5
gsHWFixes:
halfPixelOffset: 1 # Fixes character outlines, shadow misaligment and more.
SLKA-25389:
name: "Shinobido Imashime"
region: "NTSC-K"
@@ -25933,6 +26039,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 +26130,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 +26182,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 +26807,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:
@@ -26962,6 +27078,7 @@ SLPM-61148:
region: "NTSC-J"
gsHWFixes:
moveHandler: "MV_Growlanser" # Fixes precomputed depth buffer.
textureInsideRT: 1 # Fixes character layering issue.
SLPM-61153:
name: "Dengeki PS2 PlayStation D92"
region: "NTSC-J"
@@ -30740,6 +30857,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"
@@ -30876,6 +30994,7 @@ SLPM-65449:
gsHWFixes:
textureInsideRT: 1 # Fixes rainbow effect in the pause menu before a jump.
halfPixelOffset: 2 # Fixes depth lines.
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLPM-65450:
name: "Tantei Gakuen Q - Kiokan no Satsui [First Limited Edition]"
region: "NTSC-J"
@@ -31118,6 +31237,8 @@ SLPM-65525:
SLPM-65526:
name: "Dororo"
region: "NTSC-J"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes dark font to more bright like software mode.
SLPM-65527:
name: "FIFA Total Football"
region: "NTSC-J"
@@ -31758,6 +31879,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:
@@ -32044,6 +32166,7 @@ SLPM-65793:
gsHWFixes:
textureInsideRT: 1 # Fixes rainbow effect in the pause menu before a jump.
halfPixelOffset: 2 # Fixes depth lines.
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLPM-65794:
name: "Capcom Fighting Jam"
region: "NTSC-J"
@@ -32250,6 +32373,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 +32761,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 +33325,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:
@@ -33547,6 +33674,8 @@ SLPM-66187:
SLPM-66189:
name: "SSX On Tour"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLPM-66190:
name: "Star Wars Battlefront II"
region: "NTSC-J"
@@ -33618,6 +33747,8 @@ SLPM-66206:
SLPM-66207:
name: "Dororo [Sega the Best 2800]"
region: "NTSC-J"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes dark font to more bright like software mode.
SLPM-66208:
name: "Sakura Taisen V - Episode 0 - Samurai Girl of Wild [Sega the Best]"
region: "NTSC-J"
@@ -33820,6 +33951,7 @@ SLPM-66249:
compat: 5
gsHWFixes:
moveHandler: "MV_Growlanser" # Fixes precomputed depth buffer.
textureInsideRT: 1 # Fixes character layering issue.
SLPM-66250:
name: "Choro Q HG 4 [Takara Best]"
region: "NTSC-J"
@@ -34446,6 +34578,7 @@ SLPM-66418:
compat: 5
gsHWFixes:
moveHandler: "MV_Growlanser" # Fixes precomputed depth buffer.
textureInsideRT: 1 # Fixes character layering issue.
SLPM-66419:
name: "Valkyrie Profile 2 - Silmeria"
region: "NTSC-J"
@@ -34670,7 +34803,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"
@@ -35187,6 +35320,8 @@ SLPM-66600:
SLPM-66601:
name: "SSX On Tour [EA Best Hits]"
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLPM-66602:
name: "Ryu ga Gotoku 2 [Disc 1 of 2]"
region: "NTSC-J"
@@ -35388,6 +35523,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:
@@ -35674,6 +35810,7 @@ SLPM-66716:
compat: 5
gsHWFixes:
moveHandler: "MV_Growlanser" # Fixes precomputed depth buffer.
textureInsideRT: 1 # Fixes character layering issue.
SLPM-66717:
name: "Standard Daisenryaku - Dengekisen [Sega the Best]"
region: "NTSC-J"
@@ -35776,6 +35913,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 +36680,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:
@@ -36734,6 +36873,8 @@ SLPM-67504:
region: "NTSC-K"
roundModes:
eeRoundMode: 0 # Fixes riders vanish into the floor.
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLPM-67505:
name: "007 - Agent Under Fire"
region: "NTSC-K"
@@ -36793,6 +36934,11 @@ SLPM-67519:
region: "NTSC-K"
roundModes:
eeRoundMode: 0 # Fixes game hanging in the "Clark running away" ingame cutscene.
SLPM-67520:
name: "Disney's Tarzan - Freeride"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurriness and misaligned shadows.
SLPM-67521:
name: "E.O.E. - Eve of Extinction"
region: "NTSC-K"
@@ -36909,6 +37055,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:
@@ -37796,6 +37943,11 @@ SLPS-20150:
SLPS-20158:
name: "Yamasa Digi World 2 LCD Edition - Time Cross, Qlogos, Trigger Zone"
region: "NTSC-J"
SLPS-20160:
name: "Disney's Tarzan - Freeride"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurriness and misaligned shadows.
SLPS-20161:
name: "Saikyou Toudai Shogi Special"
region: "NTSC-J"
@@ -39091,6 +39243,8 @@ SLPS-25078:
region: "NTSC-J"
roundModes:
eeRoundMode: 0 # Fixes riders vanish into the floor.
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLPS-25079:
name: "Madden NFL 2002"
region: "NTSC-J"
@@ -40875,6 +41029,8 @@ SLPS-25567:
SLPS-25568:
name: "Keroro Gunsou - Mero Mero Battle Royale [Bandai The Best]"
region: "NTSC-J"
gsHWFixes:
preloadFrameData: 1 # Fixes invisible text.
SLPS-25569:
name: "Kidou Senshi Gundam SEED - Rengou vs. Z.A.F.T."
region: "NTSC-J"
@@ -40901,6 +41057,8 @@ SLPS-25575:
name: "Keroro Gunsou - Mero Mero Battle Royale Z"
region: "NTSC-J"
compat: 5
gsHWFixes:
preloadFrameData: 1 # Fixes invisible text.
SLPS-25576:
name: "One Piece - Pirates Carnival"
region: "NTSC-J"
@@ -41914,6 +42072,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 +42086,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 +42260,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"
@@ -43239,9 +43402,11 @@ SLUS-20075:
region: "NTSC-U"
compat: 5
SLUS-20076:
name: "Disney's Tarzan Untamed"
name: "Disney's Tarzan - Untamed"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 1 # Fixes blurriness and misaligned shadows.
SLUS-20077:
name: "Donald Duck Goin' Quackers"
region: "NTSC-U"
@@ -44308,6 +44473,8 @@ SLUS-20326:
compat: 5
roundModes:
eeRoundMode: 0 # Fixes riders vanish into the floor.
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLUS-20327:
name: "Aggressive Inline"
region: "NTSC-U"
@@ -45660,7 +45827,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 +46311,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"
@@ -46574,6 +46742,7 @@ SLUS-20772:
gsHWFixes:
textureInsideRT: 1 # Fixes rainbow effect in the pause menu before a jump.
halfPixelOffset: 2 # Fixes depth lines.
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLUS-20773:
name: "Legacy of Kain - Defiance"
region: "NTSC-U"
@@ -46611,6 +46780,8 @@ SLUS-20782:
name: "Blood Will Tell"
region: "NTSC-U"
compat: 5
gsHWFixes:
minimumBlendingLevel: 2 # Fixes dark font to more bright like software mode.
SLUS-20784:
name: "Italian Job, The"
region: "NTSC-U"
@@ -47515,6 +47686,8 @@ SLUS-20959:
name: "Dukes of Hazzard, The - Return of the General Lee"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 1 # Fixes misaligned post-processing.
SLUS-20960:
name: "Mega Man X8"
region: "NTSC-U"
@@ -47932,7 +48105,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 +48252,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 +48364,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"
@@ -48240,6 +48415,8 @@ SLUS-21083:
SLUS-21084:
name: "Winnie the Pooh's Rumbly Tumbly Adventure"
region: "NTSC-U"
gsHWFixes:
autoFlush: 1 # Fixes bloomlike-offsets.
SLUS-21086:
name: "Big Mutha Truckers 2"
region: "NTSC-U"
@@ -48869,6 +49046,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 +49274,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.
@@ -49342,9 +49521,11 @@ SLUS-21277:
autoFlush: 2 # Needed for recursive mipmap rendering.
getSkipCount: "GSC_BlueTongueGames" # Render mipmaps on the CPU.
SLUS-21278:
name: "SSX on Tour"
name: "SSX On Tour"
region: "NTSC-U"
compat: 5
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLUS-21279:
name: "NBA Live '06"
region: "NTSC-U"
@@ -49445,6 +49626,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:
@@ -50313,6 +50495,8 @@ SLUS-21435:
name: "One Piece - Grand Adventure"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 1 # Fixes character outlines, shadow misaligment and more.
SLUS-21436:
name: "Just Cause"
region: "NTSC-U"
@@ -50875,6 +51059,7 @@ SLUS-21571:
compat: 5
gsHWFixes:
moveHandler: "MV_Growlanser" # Fixes precomputed depth buffer.
textureInsideRT: 1 # Fixes character layering issue.
SLUS-21572:
name: "Surf's Up"
region: "NTSC-U"
@@ -50993,6 +51178,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:
@@ -52496,6 +52682,7 @@ SLUS-21902:
vu0ClampMode: 0 # Fixes black textures and SPS.
gsHWFixes:
deinterlace: 8 # Game requires AdaptiveTFF de-interlacing when auto for the (starter) FMVs.
minimumBlendingLevel: 3 # Fixes missing colortints like on faces and models being too dark.
SLUS-21904:
name: "Teenage Mutant Ninja Turtles - Smash-Up"
region: "NTSC-U"
@@ -53259,6 +53446,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 +53598,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:
@@ -53446,6 +53635,8 @@ SLUS-29160:
SLUS-29161:
name: "SSX On Tour [Demo]"
region: "NTSC-U"
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes missing lighting and makes snow not look like snow sludge.
SLUS-29162:
name: "NBA Live '06 [Demo]"
region: "NTSC-U"
@@ -53502,6 +53693,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"
+12 -5
View File
@@ -48,7 +48,7 @@
#include "pcsx2/Input/InputManager.h"
#include "pcsx2/LogSink.h"
#include "pcsx2/MTGS.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/SIO/Pad/Pad.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/VMManager.h"
@@ -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()
@@ -115,7 +117,7 @@ bool GSRunner::InitializeConfig()
si.SetStringValue("SPU2/Output", "OutputModule", "nullout");
// none of the bindings are going to resolve to anything
PAD::ClearPortBindings(si, 0);
Pad::ClearPortBindings(si, 0);
si.ClearSection("Hotkeys");
// make sure any gamesettings inis in your tree don't get loaded
@@ -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);
}
@@ -382,12 +385,15 @@ void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool def
VMManager::SetState(VMState::Stopping);
}
#ifdef ENABLE_ACHIEVEMENTS
void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason)
{
// noop
}
void Host::OnAchievementsRefreshed()
{
// noop
}
#endif
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::string_view& str)
{
@@ -641,6 +647,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("============================================");
}
+19
View File
@@ -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);
+1
View File
@@ -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
+17 -5
View File
@@ -25,6 +25,7 @@
#include "QtHost.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#include "Settings/AchievementLoginDialog.h"
#include "Settings/ControllerSettingsDialog.h"
#include "Settings/GameListSettingsWidget.h"
#include "Settings/InterfaceSettingsWidget.h"
@@ -414,7 +415,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);
@@ -423,6 +424,7 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
connect(thread, &EmuThread::onGameChanged, this, &MainWindow::onGameChanged);
connect(thread, &EmuThread::onCaptureStarted, this, &MainWindow::onCaptureStarted);
connect(thread, &EmuThread::onCaptureStopped, this, &MainWindow::onCaptureStopped);
connect(thread, &EmuThread::onAchievementsLoginRequested, this, &MainWindow::onAchievementsLoginRequested);
connect(m_ui.actionReset, &QAction::triggered, thread, &EmuThread::resetVM);
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
@@ -628,6 +630,14 @@ void MainWindow::onCaptureStopped()
m_ui.actionToolsVideoCapture->setChecked(false);
}
void MainWindow::onAchievementsLoginRequested(Achievements::LoginRequestReason reason)
{
auto lock = pauseAndLockVM();
AchievementLoginDialog dlg(this, reason);
dlg.exec();
}
void MainWindow::onSettingsTriggeredFromToolbar()
{
if (s_vm_valid)
@@ -887,7 +897,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 +2014,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();
}
+9 -1
View File
@@ -39,6 +39,11 @@ class ControllerSettingsDialog;
class EmuThread;
namespace Achievements
{
enum class LoginRequestReason;
}
namespace GameList
{
struct Entry;
@@ -124,7 +129,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();
@@ -186,6 +191,8 @@ private Q_SLOTS:
void onCaptureStarted(const QString& filename);
void onCaptureStopped();
void onAchievementsLoginRequested(Achievements::LoginRequestReason reason);
protected:
void showEvent(QShowEvent* event) override;
void closeEvent(QCloseEvent* event) override;
@@ -293,6 +300,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;
+16
View File
@@ -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">
+8 -2
View File
@@ -1079,6 +1079,11 @@ void Host::OnSaveStateSaved(const std::string_view& filename)
}
#ifdef ENABLE_ACHIEVEMENTS
void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason)
{
emit g_emu_thread->onAchievementsLoginRequested(reason);
}
void Host::OnAchievementsRefreshed()
{
u32 game_id = 0;
@@ -1468,9 +1473,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);
}
//////////////////////////////////////////////////////////////////////////
@@ -1778,6 +1783,7 @@ void QtHost::RegisterTypes()
qRegisterMetaType<InputBindingKey>();
qRegisterMetaType<CDVD_SourceType>();
qRegisterMetaType<const GameList::Entry*>();
qRegisterMetaType<Achievements::LoginRequestReason>();
}
bool QtHost::RunSetupWizard()
+10 -1
View File
@@ -41,11 +41,17 @@ struct VMBootParameters;
enum class CDVD_SourceType : uint8_t;
namespace Achievements
{
enum class LoginRequestReason;
}
Q_DECLARE_METATYPE(std::shared_ptr<VMBootParameters>);
Q_DECLARE_METATYPE(std::optional<bool>);
Q_DECLARE_METATYPE(GSRendererType);
Q_DECLARE_METATYPE(InputBindingKey);
Q_DECLARE_METATYPE(CDVD_SourceType);
Q_DECLARE_METATYPE(Achievements::LoginRequestReason);
class EmuThread : public QThread
{
@@ -119,7 +125,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();
@@ -155,6 +161,9 @@ Q_SIGNALS:
/// just signifies that the save has started, not necessarily completed.
void onSaveStateSaved(const QString& path);
/// Called when achievements login is requested.
void onAchievementsLoginRequested(Achievements::LoginRequestReason reason);
/// Called when achievements are reloaded/refreshed (e.g. game change, login, option change).
void onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
+10 -1
View File
@@ -22,13 +22,22 @@
#include <QtWidgets/QMessageBox>
AchievementLoginDialog::AchievementLoginDialog(QWidget* parent)
AchievementLoginDialog::AchievementLoginDialog(QWidget* parent, Achievements::LoginRequestReason reason)
: QDialog(parent)
{
m_ui.setupUi(this);
m_ui.loginIcon->setPixmap(QIcon::fromTheme("login-box-line").pixmap(32));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
// Adjust text if needed based on reason.
if (reason == Achievements::LoginRequestReason::TokenInvalid)
{
m_ui.instructionText->setText(
tr("<strong>Your RetroAchievements login token is no longer valid.</strong> You must re-enter your "
"credentials for achievements to be tracked. Your password will not be saved in PCSX2, an access token "
"will be generated and used instead."));
}
m_login = m_ui.buttonBox->addButton(tr("&Login"), QDialogButtonBox::AcceptRole);
m_login->setEnabled(false);
connectUi();
+7 -1
View File
@@ -18,12 +18,17 @@
#include <QtWidgets/QDialog>
#include <QtWidgets/QPushButton>
namespace Achievements
{
enum class LoginRequestReason;
}
class AchievementLoginDialog : public QDialog
{
Q_OBJECT
public:
AchievementLoginDialog(QWidget* parent);
AchievementLoginDialog(QWidget* parent, Achievements::LoginRequestReason reason);
~AchievementLoginDialog();
private Q_SLOTS:
@@ -38,4 +43,5 @@ private:
Ui::AchievementLoginDialog m_ui;
QPushButton* m_login;
Achievements::LoginRequestReason m_reason;
};
+1 -1
View File
@@ -51,7 +51,7 @@
</layout>
</item>
<item>
<widget class="QLabel" name="label_3">
<widget class="QLabel" name="instructionText">
<property name="text">
<string>Please enter user name and password for retroachievements.org below. Your password will not be saved in PCSX2, an access token will be generated and used instead.</string>
</property>
@@ -173,7 +173,7 @@ void AchievementSettingsWidget::onLoginLogoutPressed()
return;
}
AchievementLoginDialog login(this);
AchievementLoginDialog login(this, Achievements::LoginRequestReason::UserInitiated);
int res = login.exec();
if (res != 0)
return;
+37 -25
View File
@@ -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);
+3 -2
View File
@@ -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();
+44 -1
View File
@@ -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();
+2 -2
View File
@@ -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));
}
+1 -1
View File
@@ -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
+36 -17
View File
@@ -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">
@@ -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>&lt;p&gt;By default, GunCon2 will use the mouse pointer. To use the mouse, you &lt;strong&gt;do not&lt;/strong&gt; need to configure any bindings apart from the trigger and buttons.&lt;/p&gt;
&lt;p&gt;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 &lt;strong&gt;left unbound&lt;/strong&gt;.&lt;/p&gt;</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>
+5 -5
View File
@@ -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;
+1
View File
@@ -258,6 +258,7 @@ std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
{QStringLiteral("Italiano (it-IT)"), QStringLiteral("it-IT")},
{QStringLiteral("日本語 (ja-JP)"), QStringLiteral("ja-JP")},
{QStringLiteral("한국어 (ko-KR)"), QStringLiteral("ko-KR")},
{QStringLiteral("Latvija (lv-LV)"), QStringLiteral("lv-LV")},
{QStringLiteral("Nederlands (nl-NL)"), QStringLiteral("nl-NL")},
{QStringLiteral("Norsk (no-NO)"), QStringLiteral("no-NO")},
{QStringLiteral("Polski (pl-PL)"), QStringLiteral("pl-PL")},
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+9 -2
View File
@@ -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>
+9 -6
View File
@@ -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

+50 -10
View File
@@ -106,7 +106,8 @@ namespace Achievements
static void EndLoadingScreen(bool was_running_idle);
static void LoginCallback(s32 status_code, const std::string& content_type, Common::HTTPDownloader::Request::Data data);
static void LoginASyncCallback(s32 status_code, const std::string& content_type, Common::HTTPDownloader::Request::Data data);
static void SendLogin(const char* username, const char* password, Common::HTTPDownloader* http_downloader,
static void LoginWithTokenCallback(s32 status_code, const std::string& content_type, Common::HTTPDownloader::Request::Data data);
static void SendLogin(const char* username, const char* password, const char* api_token, Common::HTTPDownloader* http_downloader,
Common::HTTPDownloader::Request::Callback callback);
static void DownloadImage(std::string url, std::string cache_filename);
static void DisplayAchievementSummary();
@@ -445,6 +446,11 @@ bool Achievements::IsLoggedIn()
return s_logged_in;
}
bool Achievements::HasSavedCredentials()
{
return !s_username.empty() && !s_api_token.empty();
}
bool Achievements::ChallengeModeActive()
{
#ifdef ENABLE_RAINTEGRATION
@@ -513,7 +519,7 @@ void Achievements::Initialize()
s_last_ping_time.Reset();
s_username = Host::GetBaseStringSettingValue("Achievements", "Username");
s_api_token = Host::GetBaseStringSettingValue("Achievements", "Token");
s_logged_in = (!s_username.empty() && !s_api_token.empty());
s_logged_in = false; // We are not logged in until we confirm those credentials
if (VMManager::HasValidVM())
GameChanged(VMManager::GetDiscCRC(), VMManager::GetCurrentCRC());
@@ -634,7 +640,7 @@ void Achievements::SetChallengeMode(bool enabled)
s_challenge_mode = enabled;
if (HasActiveGame())
ImGuiFullscreen::ShowToast(std::string(), enabled ? "Hardcore mode is now enabled." : "Hardcore mode is now disabled.", 10.0f);
ImGuiFullscreen::ShowToast(std::string(), enabled ? TRANSLATE("Achievements", "Hardcore mode is now enabled.") : TRANSLATE("Achievements", "Hardcore mode is now disabled."), 10.0f);
if (HasActiveGame() && !IsTestModeActive())
{
@@ -953,13 +959,36 @@ void Achievements::LoginASyncCallback(s32 status_code, const std::string& conten
LoginCallback(status_code, std::move(content_type), std::move(data));
}
void Achievements::LoginWithTokenCallback(s32 status_code, const std::string& content_type, Common::HTTPDownloader::Request::Data data)
{
std::unique_lock lock(s_achievements_mutex);
RAPIResponse<rc_api_login_response_t, rc_api_process_login_response, rc_api_destroy_login_response> response(status_code, data);
if (!response)
{
lock.unlock();
Logout();
Host::OnAchievementsLoginRequested(LoginRequestReason::TokenInvalid);
return;
}
if (s_active)
{
s_logged_in = true;
// If we have a game running, set it up.
if (!s_game_hash.empty())
SendGetGameId();
}
}
void Achievements::SendLogin(
const char* username, const char* password, Common::HTTPDownloader* http_downloader, Common::HTTPDownloader::Request::Callback callback)
const char* username, const char* password, const char* api_token, Common::HTTPDownloader* http_downloader, Common::HTTPDownloader::Request::Callback callback)
{
RAPIRequest<rc_api_login_request_t, rc_api_init_login_request> request;
request.username = username;
request.password = password;
request.api_token = nullptr;
request.api_token = api_token;
request.Send(http_downloader, std::move(callback));
}
@@ -975,7 +1004,7 @@ bool Achievements::LoginAsync(const char* username, const char* password)
ImGuiFullscreen::OpenBackgroundProgressDialog("cheevos_async_login", "Logging in to RetroAchievements...", 0, 0, 0);
}
SendLogin(username, password, s_http_downloader.get(), LoginASyncCallback);
SendLogin(username, password, nullptr, s_http_downloader.get(), LoginASyncCallback);
return true;
}
@@ -989,7 +1018,7 @@ bool Achievements::Login(const char* username, const char* password)
if (s_active)
{
SendLogin(username, password, s_http_downloader.get(), LoginCallback);
SendLogin(username, password, nullptr, s_http_downloader.get(), LoginCallback);
s_http_downloader->WaitForAllRequests();
return IsLoggedIn();
}
@@ -1000,12 +1029,21 @@ bool Achievements::Login(const char* username, const char* password)
if (!http_downloader)
return false;
SendLogin(username, password, http_downloader.get(), LoginCallback);
SendLogin(username, password, nullptr, http_downloader.get(), LoginCallback);
http_downloader->WaitForAllRequests();
return !Host::GetBaseStringSettingValue("Achievements", "Token").empty();
}
bool Achievements::LoginWithTokenAsync(const char* username, const char* api_token)
{
if (s_logged_in || std::strlen(username) == 0 || std::strlen(api_token) == 0 || IsUsingRAIntegration())
return false;
SendLogin(username, nullptr, api_token, s_http_downloader.get(), LoginWithTokenCallback);
return true;
}
void Achievements::Logout()
{
if (s_active)
@@ -1015,11 +1053,11 @@ void Achievements::Logout()
if (s_logged_in)
{
ClearGameInfo();
std::string().swap(s_username);
std::string().swap(s_api_token);
s_logged_in = false;
Host::OnAchievementsRefreshed();
}
std::string().swap(s_username);
std::string().swap(s_api_token);
}
// remove from config
@@ -1477,6 +1515,8 @@ void Achievements::GameChanged(u32 disc_crc, u32 crc)
if (IsLoggedIn())
SendGetGameId();
else if (HasSavedCredentials())
LoginWithTokenAsync(s_username.c_str(), s_api_token.c_str());
}
void Achievements::SendGetGameId()
+9 -1
View File
@@ -31,6 +31,12 @@
namespace Achievements
{
enum class LoginRequestReason
{
UserInitiated,
TokenInvalid,
};
enum class AchievementCategory : u8
{
Local = 0,
@@ -88,6 +94,7 @@ namespace Achievements
bool IsActive();
bool IsLoggedIn();
bool HasSavedCredentials();
bool ChallengeModeActive();
bool LeaderboardsActive();
bool IsTestModeActive();
@@ -131,6 +138,7 @@ namespace Achievements
bool LoginAsync(const char* username, const char* password);
bool Login(const char* username, const char* password);
bool LoginWithTokenAsync(const char* username, const char* api_token);
void Logout();
void GameChanged(u32 disc_crc, u32 crc);
@@ -253,6 +261,6 @@ namespace Achievements
/// Functions implemented in the frontend.
namespace Host
{
void OnAchievementsLoginRequested(Achievements::LoginRequestReason reason);
void OnAchievementsRefreshed();
void OnAchievementsChallengeModeChanged();
} // namespace Host
+2 -8
View File
@@ -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
)
+9 -1
View File
@@ -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;
+8 -18
View File
@@ -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()
+3 -1
View File
@@ -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;
+1 -1
View File
@@ -175,7 +175,7 @@
"bilinearUpscale": {
"type": "integer",
"minimum": 0,
"maximum": 1
"maximum": 2
},
"nativePaletteDraw": {
"type": "integer",
-8
View File
@@ -31,14 +31,6 @@ const CRC::Game CRC::m_games[] =
{0x1F88BECD, Tekken5 /* EU */}, // language selector...
{0x652050D2, Tekken5 /* US */},
{0xEA64EF39, Tekken5 /* KO */},
{0xE8FCF8EC, SMTNocturne /* US */},
{0xF0A31EE3, SMTNocturne /* EU */}, // SMTNocturne (Lucifers Call in EU)
{0xAE0DE7B7, SMTNocturne /* EU */}, // SMTNocturne (Lucifers Call in EU)
{0xD60DA6D4, SMTNocturne /* JP */}, // SMTNocturne
{0x0E762E8D, SMTNocturne /* JP */}, // SMTNocturne Maniacs
{0x47BA9034, SMTNocturne /* JP */}, // SMTNocturne Maniacs Chronicle
{0xD3FFC263, SMTNocturne /* KO */},
{0x84D1A8DA, SMTNocturne /* KO */},
};
const CRC::Game& CRC::Lookup(u32 crc)
-1
View File
@@ -23,7 +23,6 @@ public:
enum Title : u32
{
NoTitle,
SMTNocturne,
Tekken5,
TitleCount,
};
+1
View File
@@ -792,6 +792,7 @@ REG_END2
__forceinline bool DoFirstPass() const { return !ATE || ATST != ATST_NEVER; } // not all pixels fail automatically
__forceinline bool DoSecondPass() const { return ATE && ATST != ATST_ALWAYS && AFAIL != AFAIL_KEEP; } // pixels may fail, write fb/z
__forceinline bool NoSecondPass() const { return ATE && ATST != ATST_ALWAYS && AFAIL == AFAIL_KEEP; } // pixels may fail, no output
__forceinline u32 GetAFAIL(u32 fpsm) const { return (AFAIL == AFAIL_RGB_ONLY && (fpsm & 0xF) != 0) ? AFAIL_FB_ONLY : AFAIL; } // FB Only when not 32bit Framebuffer
REG_END2
REG64_(GIFReg, TEX0)
+56 -26
View File
@@ -1696,28 +1696,6 @@ void GSState::Write(const u8* mem, int len)
GIFRegBITBLTBUF& blit = m_tr.m_blit;
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[blit.DPSM];
// The game uses a resolution of 512x244. RT is located at 0x700 and depth at 0x0
//
// #Bug number 1. (bad top bar)
// The game saves the depth buffer in the EE but with a resolution of
// 512x255. So it is ending to 0x7F8, ouch it saves the top of the RT too.
//
// #Bug number 2. (darker screen)
// The game will restore the previously saved buffer at position 0x0 to
// 0x7F8. Because of the extra RT pixels, GS will partialy invalidate
// the texture located at 0x700. Next access will generate a cache miss
//
// The no-solution: instead to handle garbage (aka RT) at the end of the
// depth buffer. Let's reduce the size of the transfer
if (m_game.title == CRC::SMTNocturne) // TODO: hack
{
if (blit.DBP == 0 && blit.DPSM == PSMZ32 && w == 512 && h > 224)
{
h = 224;
m_env.TRXREG.RRH = 224;
}
}
if (!m_tr.Update(w, h, psm.trbpp, len))
return;
@@ -2720,6 +2698,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 +2754,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
@@ -3759,9 +3788,10 @@ bool GSState::TryAlphaTest(u32& fm, const u32 fm_mask, u32& zm)
const u32 framemask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk;
const u32 framemaskalpha = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk & 0xFF000000;
const u32 fail_type = m_context->TEST.GetAFAIL(m_context->FRAME.PSM);
// Alpha test can only control the write of some channels. If channels are already masked
// the alpha test is therefore a nop.
switch (m_context->TEST.AFAIL)
switch (fail_type)
{
case AFAIL_KEEP:
break;
@@ -3774,7 +3804,7 @@ bool GSState::TryAlphaTest(u32& fm, const u32 fm_mask, u32& zm)
return true;
break;
case AFAIL_RGB_ONLY:
if (zm == 0xFFFFFFFF && ((fm & framemaskalpha) == framemaskalpha || GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt == 1))
if (zm == 0xFFFFFFFF && (fm & framemaskalpha) == framemaskalpha)
return true;
break;
default:
@@ -3858,7 +3888,7 @@ bool GSState::TryAlphaTest(u32& fm, const u32 fm_mask, u32& zm)
if (!pass)
{
switch (m_context->TEST.AFAIL)
switch (fail_type)
{
case AFAIL_KEEP:
fm = zm = 0xffffffff;
+1
View File
@@ -418,6 +418,7 @@ public:
void DumpVertices(const std::string& filename);
bool TrianglesAreQuads() const;
PRIM_OVERLAP PrimitiveOverlap();
GIFRegTEX0 GetTex0Layer(u32 lod);
};
+140 -12
View File
@@ -216,20 +216,104 @@ 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) - 1), ((main_fb_size.y / 2) - 1));
const GSVector4i uv_rect = GSVector4i(0, 0, (downsample_rect.z * 2) - std::min(r.GetUpscaleMultiplier()-1.0f, 4.0f) * 3 , (downsample_rect.w * 2) - std::min(r.GetUpscaleMultiplier()-1.0f, 4.0f) * 3);
r.ReplaceVerticesWithSprite(downsample_rect, uv_rect, 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);
@@ -638,6 +722,48 @@ bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
{
GSDrawingContext* context = r.m_context;
// Nicktoons does its weird dithered depth pattern during FMV's also, which really screws the frame width up, which is wider for FMV's
// and so fails to work correctly in the HW renderer and makes a mess of the width, so let's expand the draw to match the proper width.
if (RPRIM->TME && RTEX0.TW == 3 && RTEX0.TH == 3 && RTEX0.PSM == 0 && RFRAME.FBMSK == 0x00FFFFFF && RFRAME.FBW == 8 && r.PCRTCDisplays.GetResolution().x > 512)
{
// Check we are drawing stripes
for (u32 i = 1; i < r.m_vertex.tail; i+=2)
{
int value = (((r.m_vertex.buff[i].XYZ.X - r.m_vertex.buff[i - 1].XYZ.X) + 8) >> 4);
if (value != 32)
return false;
}
r.m_r.x = r.m_vt.m_min.p.x;
r.m_r.y = r.m_vt.m_min.p.y;
r.m_r.z = r.PCRTCDisplays.GetResolution().x;
r.m_r.w = r.m_vt.m_max.p.y;
for (int vert = 32; vert < 40; vert+=2)
{
r.m_vertex.buff[vert].XYZ.X = context->XYOFFSET.OFX + (((vert * 16) << 4) - 8);
r.m_vertex.buff[vert].XYZ.Y = context->XYOFFSET.OFY;
r.m_vertex.buff[vert].U = (vert * 16) << 4;
r.m_vertex.buff[vert].V = 0;
r.m_vertex.buff[vert+1].XYZ.X = context->XYOFFSET.OFX + ((((vert * 16) + 32) << 4) - 8);
r.m_vertex.buff[vert+1].XYZ.Y = context->XYOFFSET.OFY + 8184; //511.5
r.m_vertex.buff[vert+1].U = ((vert * 16) + 32) << 4;
r.m_vertex.buff[vert+1].V = 512 << 4;
}
/*r.m_vertex.head = r.m_vertex.tail = r.m_vertex.next = 2;
r.m_index.tail = 2;*/
r.m_vt.m_max.p.x = r.m_r.z;
r.m_vt.m_max.p.y = r.m_r.w;
r.m_vt.m_max.t.x = r.m_r.z;
r.m_vt.m_max.t.y = r.m_r.w;
context->scissor.in.z = r.m_r.z;
context->scissor.in.w = r.m_r.w;
RFRAME.FBW = 10;
}
// Whoever wrote this was kinda nuts. They draw a stipple/dither pattern to a framebuffer, then reuse that as
// the depth buffer. Textures are then drawn repeatedly on top of one another, each with a slight offset.
// Depth testing is enabled, and that determines which pixels make it into the final texture. Kinda like an
@@ -971,6 +1097,8 @@ bool GSHwHack::OI_BurnoutGames(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GS
if (!r.CanUseSwSpriteRender())
return true;
if (!r.PRIM->TME)
return true;
// Render palette via CPU.
r.SwSpriteRender();
+90 -96
View File
@@ -2381,25 +2381,21 @@ void GSRendererHW::Draw()
const bool can_update_size = !is_possible_mem_clear && !m_texture_shuffle && !m_channel_shuffle;
if (!m_texture_shuffle && !m_channel_shuffle)
{
if (rt)
if (rt && (!is_possible_mem_clear || rt->m_TEX0.PSM != FRAME_TEX0.PSM))
{
// Nicktoons Unite tries to change the width from 640 to 512 and breaks FMVs.
// Haunting ground has some messed textures if you don't modify the rest.
// Champions of Norrath expands the width from 512 to 1024, picture cut in half if you don't.
// The safest option is to probably let it expand but not retract.
if (!rt->m_is_frame || rt->m_TEX0.TBW < FRAME_TEX0.TBW)
if (rt->m_TEX0.TBW != FRAME_TEX0.TBW && !m_cached_ctx.ZBUF.ZMSK && (m_cached_ctx.FRAME.FBMSK & 0xFF000000))
{
rt->m_TEX0 = FRAME_TEX0;
}
else
{
const u32 width = rt->m_TEX0.TBW;
rt->m_TEX0 = FRAME_TEX0;
rt->m_TEX0.TBW = std::max(width, FRAME_TEX0.TBW);
// Alpha could be a font, and since the width is changing it's no longer valid.
// Be careful of downsize copies or other effects, checking Z MSK should hopefully be enough.. (Okami).
if (m_cached_ctx.FRAME.FBMSK & 0x0F000000)
rt->m_valid_alpha_low = false;
if (m_cached_ctx.FRAME.FBMSK & 0xF0000000)
rt->m_valid_alpha_high = false;
}
rt->m_TEX0 = FRAME_TEX0;
}
if (ds)
if (ds && (!is_possible_mem_clear || ds->m_TEX0.PSM != ZBUF_TEX0.PSM))
ds->m_TEX0 = ZBUF_TEX0;
}
else if (!m_texture_shuffle)
@@ -3345,7 +3341,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 +3373,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 +3399,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 +3423,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 +3449,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 +3512,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 +3548,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 +4422,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 +4470,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 +4504,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 +4617,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 +4719,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 +4754,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 +4769,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 +4786,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
{
@@ -4900,8 +4933,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const bool commutative_depth = (m_conf.depth.ztst == ZTST_GEQUAL && m_vt.m_eq.z) || (m_conf.depth.ztst == ZTST_ALWAYS);
const bool commutative_alpha = (m_context->ALPHA.C != 1); // when either Alpha Src or a constant
ate_RGBA_then_Z = (m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY) && commutative_depth;
ate_RGB_then_ZA = (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY) && commutative_depth && commutative_alpha;
ate_RGBA_then_Z = m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM) == AFAIL_FB_ONLY && commutative_depth;
ate_RGB_then_ZA = m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM) == AFAIL_RGB_ONLY && commutative_depth && commutative_alpha;
}
if (ate_RGBA_then_Z)
@@ -4997,8 +5030,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
bool g = m_conf.colormask.wg;
bool b = m_conf.colormask.wb;
bool a = m_conf.colormask.wa;
switch (m_cached_ctx.TEST.AFAIL)
const int fail_type = m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM);
switch (fail_type)
{
case AFAIL_KEEP: z = r = g = b = a = false; break; // none
case AFAIL_FB_ONLY: z = false; break; // rgba
@@ -5126,7 +5159,7 @@ GSRendererHW::CLUTDrawTestResult GSRendererHW::PossibleCLUTDraw()
return CLUTDrawTestResult::NotCLUTDraw;
// Keep the draws simple, no alpha testing, blending, mipmapping, Z writes, and make sure it's flat.
const bool fb_only = m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.AFAIL == 1 && m_cached_ctx.TEST.ATST == ATST_NEVER;
const bool fb_only = m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM) == AFAIL_FB_ONLY && m_cached_ctx.TEST.ATST == ATST_NEVER;
// No Z writes, unless it's points, then it's quite likely to be a palette and they left it on.
if (!m_cached_ctx.ZBUF.ZMSK && !fb_only && !(m_vt.m_primclass == GS_POINT_CLASS))
@@ -5204,12 +5237,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 +5831,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)
{
+2 -2
View File
@@ -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);
@@ -132,7 +132,7 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc, b
if (!hw.TryAlphaTest(fm, fm_mask, zm))
{
gd.sel.atst = context->TEST.ATST;
gd.sel.afail = context->TEST.AFAIL;
gd.sel.afail = context->TEST.GetAFAIL(context->FRAME.PSM);
gd.aref = GSVector4i((int)context->TEST.AREF);
+24 -10
View File
@@ -1353,12 +1353,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
}
}
}
if (dst)
{
dst->m_TEX0.TBW = TEX0.TBW; // Fix Jurassic Park - Operation Genesis loading disk logo.
dst->m_is_frame |= is_frame; // Nicktoons Unite tries to change the width from 10 to 8 and breaks FMVs.
}
}
if (dst)
@@ -3339,6 +3333,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 +5125,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 +5837,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
+2
View File
@@ -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);
+1 -1
View File
@@ -1634,7 +1634,7 @@ void GSDeviceOGL::DrawMultiStretchRects(
{
IASetVAO(m_vao);
IASetPrimitiveTopology(GL_TRIANGLE_STRIP);
OMSetDepthStencilState(m_convert.dss);
OMSetDepthStencilState(HasDepthOutput(shader) ? m_convert.dss_write : m_convert.dss);
OMSetBlendState(false);
OMSetColorMaskState();
if (!dTex->IsDepthStencil())
+1 -1
View File
@@ -990,7 +990,7 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
if (!TryAlphaTest(fm, fm_mask, zm))
{
gd.sel.atst = context->TEST.ATST;
gd.sel.afail = context->TEST.AFAIL;
gd.sel.afail = context->TEST.GetAFAIL(context->FRAME.PSM);
gd.aref = GSVector4i((int)context->TEST.AREF);
+6 -3
View File
@@ -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);
@@ -1197,7 +1200,7 @@ const GameDatabase::HashDatabaseEntry* GameDatabase::lookupHash(
if (getTrackIndex(candidate->tracks.data(), candidate->tracks.size(), tracks[track]) != track)
{
fmt::format_to(std::back_inserter(*match_error),
TRANSLATE_FS("GameDatabase", "Track {} with hash {} does not match database track..\n"), track + 1,
TRANSLATE_FS("GameDatabase", "Track {} with hash {} does not match database track.\n"), track + 1,
tracks[track].toString());
tracks_matched[track] = false;
all_okay = false;
+38 -38
View File
@@ -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));
@@ -6990,7 +6990,7 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
Achievements::ProcessPendingHTTPRequestsFromGSThread();
MenuHeading("Account");
if (Achievements::IsLoggedIn())
if (Achievements::HasSavedCredentials())
{
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]);
ActiveButton(fmt::format(ICON_FA_USER " Username: {}", Achievements::GetUsername()).c_str(), false, false,
+147 -1
View File
@@ -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;
}
+12
View File
@@ -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
+49 -69
View File
@@ -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 -13
View File
@@ -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);
}
// ------------------------------------------------------------------------
+9 -2
View File
@@ -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
+1 -1
View File
@@ -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;
}
}
+5 -4
View File
@@ -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;
+48 -48
View File
@@ -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)
+2 -2
View File
@@ -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

Some files were not shown because too many files have changed in this diff Show More