Compare commits
77 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
f6d5f51d23 | |
![]() |
6a8b265f3d | |
![]() |
96ba75330e | |
![]() |
1358000d74 | |
![]() |
386c4a6cc5 | |
![]() |
7bf80d8089 | |
![]() |
7a8ac0212f | |
![]() |
065eba5c4f | |
![]() |
0291bd7ec1 | |
![]() |
5e73936ff0 | |
![]() |
4e2d05d5a4 | |
![]() |
e7aed37920 | |
![]() |
4eeadae8c5 | |
![]() |
2388342a1a | |
![]() |
28156e3a53 | |
![]() |
d70fbdc3a0 | |
![]() |
74d12585a3 | |
![]() |
e1f9099446 | |
![]() |
001d332d5b | |
![]() |
f3ae8f2143 | |
![]() |
806ce79f91 | |
![]() |
5aa17c6a24 | |
![]() |
2d87cc1cf2 | |
![]() |
ec9594887c | |
![]() |
8089cf8f5f | |
![]() |
0ce2972fe6 | |
![]() |
f84a8f78ff | |
![]() |
5d0f3092f7 | |
![]() |
821dbd4bd6 | |
![]() |
df0bb5cd48 | |
![]() |
0fc331e8ce | |
![]() |
6f5af7e744 | |
![]() |
9ccd83609a | |
![]() |
2d03ae73da | |
![]() |
745a12d00e | |
![]() |
31ef54ca9d | |
![]() |
135d1a10ca | |
![]() |
3d72ada282 | |
![]() |
3276ebcd10 | |
![]() |
8ede727c81 | |
![]() |
2232e7f65f | |
![]() |
0f51bc66fd | |
![]() |
631499e36c | |
![]() |
e932068baa | |
![]() |
973f6b819e | |
![]() |
62309ca5c5 | |
![]() |
53b8fdf856 | |
![]() |
679f36d7c0 | |
![]() |
56b0f95e6f | |
![]() |
338e4ec7a9 | |
![]() |
fdbb442bad | |
![]() |
fcdf6c53eb | |
![]() |
094fe8fec0 | |
![]() |
bd87563aa0 | |
![]() |
b8f410c0bd | |
![]() |
c9cbf185c1 | |
![]() |
a782e8b500 | |
![]() |
ce080027a4 | |
![]() |
043b37c51d | |
![]() |
f04311a22a | |
![]() |
89928b86ac | |
![]() |
91cfbbf676 | |
![]() |
3c25e66769 | |
![]() |
2029f7fc86 | |
![]() |
3d54fb6d02 | |
![]() |
86a57ed51f | |
![]() |
997e462a4f | |
![]() |
7740295a6c | |
![]() |
02b814d3bb | |
![]() |
fefe47d7dd | |
![]() |
927b70e6fd | |
![]() |
fee8255611 | |
![]() |
b6025e4108 | |
![]() |
4c0294d7ff | |
![]() |
c4aa0717b7 | |
![]() |
a325deb65e | |
![]() |
f75e18137f |
56
CHANGES
|
@ -1,3 +1,59 @@
|
|||
0.9.2: (2021-07-10)
|
||||
Emulation fixes:
|
||||
- GB Video: Clear VRAM on reset (fixes mgba.io/i/2152)
|
||||
- GBA SIO: Add missing NORMAL8 implementation bits (fixes mgba.io/i/2172)
|
||||
- GBA SIO: Fix missing interrupt on an unattached NORMAL transfer
|
||||
- GBA Memory: Fix prefetch mask when swapping modes within a region
|
||||
- GBA Serialize: Fix loading audio enable bit late (fixes mgba.io/i/2230)
|
||||
- GBA Video: Revert scanline latching changes (fixes mgba.io/i/2153, mgba.io/i/2149)
|
||||
Other fixes:
|
||||
- 3DS: Fix disabling "wide" mode on 2DS (fixes mgba.io/i/2167)
|
||||
- ARM Debugger: Fix disassembly alignment (fixes mgba.io/i/2204)
|
||||
- Core: Fix memory leak in opening games from the library
|
||||
- Core: Fix memory searches for relative values (fixes mgba.io/i/2135)
|
||||
- Core: Fix portable mode on macOS
|
||||
- GB Audio: Fix audio channel 4 being slow to deserialize
|
||||
- GB Core: Fix GBC colors setting breaking default model overrides (fixes mgba.io/i/2161)
|
||||
- mGUI: Cache save state screenshot validity in state menu (fixes mgba.io/i/2005)
|
||||
- Qt: Fix eventual deadlock when using sync to video
|
||||
- Qt: Fix applying savetype-only overrides
|
||||
- Qt: Fix crash in sprite view for partially out-of-bounds sprites (fixes mgba.io/i/2165)
|
||||
- Qt: Fix having to press controller buttons twice for menu items (fixes mgba.io/i/2143)
|
||||
- Qt: Redo sensor binding to be less fragile
|
||||
- Qt: Reuse timer when rescheduling missing frames (fixes mgba.io/i/2236)
|
||||
- Qt: Fix bounded fast forward with enhancement OpenGL renderer
|
||||
- Util: Fix loading UPS patches that affect the last byte of the file
|
||||
Misc:
|
||||
- Util: Improve speed of UPS patch loading
|
||||
|
||||
0.9.1: (2021-04-18)
|
||||
Emulation fixes:
|
||||
- ARM: Fix LDM^ with empty rlist (fixes mgba.io/i/2127)
|
||||
- Core: Fix first event scheduling after loading savestate
|
||||
- GB Serialize: Fix switching speed modes when loading a state (fixes mgba.io/i/2097)
|
||||
- GB: Fix skipping BIOS
|
||||
- GBA Memory: Fix loading Thumb savestates when in ARM mode
|
||||
- GBA Video: Fix window start on modes 3-5 with mosaic (fixes mgba.io/i/1690)
|
||||
- GBA Video: Fix mode 3-5 overflow with mosaic (fixes mgba.io/i/1691)
|
||||
Other fixes:
|
||||
- GBA: Fix non-USA 1.0 FireRed misdetecting as a ROM hack (fixes mgba.io/i/2100)
|
||||
- GBA: Fix crash when ROM loading fails
|
||||
- GBA e-Reader: Fix bitmap short strip scanning
|
||||
- GBA Video: Fix mode 5 frame 1 caching (fixes mgba.io/i/2075)
|
||||
- GBA Video: Don't attempt to copy invalid registers when switching renderer
|
||||
- Qt: Fix crash when switching from high-resolution OpenGL renderer to software
|
||||
- Qt: Fix OpenGL renderer lagging behind when fast-forwarding (fixes mgba.io/i/2094)
|
||||
- Qt: Fix smudged window icon on Windows
|
||||
- Qt: Fix saving settings enabling camera when camera name changes (fixes mgba.io/i/2125)
|
||||
- Qt: Fix frames getting backlogged (fixes mgba.io/i/2122)
|
||||
- Qt: Restore maximized state when starting (fixes mgba.io/i/487)
|
||||
Misc:
|
||||
- Core: Truncate preloading ROMs that slightly exceed max size (fixes mgba.io/i/2093)
|
||||
- GBA: Default-enable VBA bug compat for Ruby and Emerald ROM hacks
|
||||
- GBA Memory: Log GPIO writes on non-GPIO carts as Pak Hardware instead of Memory
|
||||
- Qt: Add ROM filename and size to bug reporter
|
||||
- Qt: Improve handling of disabling VBA bug compat mode (fixes mgba.io/i/2129)
|
||||
|
||||
0.9.0: (2021-03-28)
|
||||
Features:
|
||||
- e-Reader card scanning
|
||||
|
|
|
@ -228,7 +228,8 @@ endif()
|
|||
|
||||
if(APPLE)
|
||||
add_definitions(-D_DARWIN_C_SOURCE)
|
||||
if(CMAKE_SYSTEM_VERSION VERSION_GREATER "10.5.8")
|
||||
list(APPEND OS_LIB "-framework Foundation")
|
||||
if(NOT CMAKE_SYSTEM_VERSION VERSION_LESS "10.0") # Darwin 10.x is Mac OS X 10.6
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.6")
|
||||
endif()
|
||||
endif()
|
||||
|
@ -582,8 +583,7 @@ if(USE_FFMPEG)
|
|||
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libavcodec-extra|libavcodec-ffmpeg-extra${LIBAVCODEC_VERSION_MAJOR}")
|
||||
endif()
|
||||
if(APPLE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -framework VideoDecodeAcceleration -framework CoreVideo")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework VideoDecodeAcceleration -framework CoreVideo")
|
||||
list(APPEND DEPENDENCY_LIB "-framework VideoDecodeAcceleration" "-framework CoreVideo")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ The following mappers are partially supported:
|
|||
Supported Platforms
|
||||
-------------------
|
||||
|
||||
- Windows Vista or newer
|
||||
- Windows 7 or newer
|
||||
- OS X 10.8 (Mountain Lion)[<sup>[3]</sup>](#osxver) or newer
|
||||
- Linux
|
||||
- FreeBSD
|
||||
|
|
|
@ -79,7 +79,7 @@ Die folgenden Mapper werden teilweise unterstützt:
|
|||
Unterstützte Plattformen
|
||||
------------------------
|
||||
|
||||
- Windows Vista oder neuer
|
||||
- Windows 7 oder neuer
|
||||
- OS X 10.8 (Mountain Lion)[<sup>[3]</sup>](#osxver) oder neuer
|
||||
- Linux
|
||||
- FreeBSD
|
||||
|
|
|
@ -79,7 +79,7 @@ Estos mappers tienen soporte parcial:
|
|||
Plataformas soportadas
|
||||
-------------------
|
||||
|
||||
- Windows Vista o más reciente
|
||||
- Windows 7 o más reciente
|
||||
- OS X 10.8 (Mountain Lion)[<sup>[3]</sup>](#osxver) o más reciente
|
||||
- Linux
|
||||
- FreeBSD
|
||||
|
|
|
@ -77,7 +77,7 @@ mGBA 是一个运行 Game Boy Advance 游戏的模拟器。mGBA 的目标是比
|
|||
支持平台
|
||||
-------------------
|
||||
|
||||
- Windows Vista 或更新
|
||||
- Windows 7 或更新
|
||||
- OS X 10.8(山狮 / Mountain Lion)[<sup>[3]</sup>](#osxver) 或更新
|
||||
- Linux
|
||||
- FreeBSD
|
||||
|
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 465 KiB After Width: | Height: | Size: 460 KiB |
BIN
res/mgba-128.png
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
BIN
res/mgba-256.png
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 43 KiB |
BIN
res/mgba-32.png
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
res/mgba-512.png
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 126 KiB |
BIN
res/mgba-64.png
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.7 KiB |
|
@ -1,7 +1,7 @@
|
|||
clrmamepro (
|
||||
name "Nintendo - Game Boy Advance"
|
||||
description "Nintendo - Game Boy Advance"
|
||||
version 20210326-211504
|
||||
version 20210415-050230
|
||||
author "aci68, Aringon, Bent, BigFred, C. V. Reynolds, chillerecke, DeadSkullzJr, Densetsu, DeriLoko3, einstein95, ElBarto, Enker, fuzzball, Gefflon, Hiccup, hking0036, hydr0x, InternalLoss, Jack, jimmsu, kazumi213, Money_114, niemand, omonim2007, Powerpuff, PPLToast, relax, RetroGamer, Rifu, SonGoku, Tauwasser, Vallaine01, Whovian9369, xuom2, zg"
|
||||
homepage No-Intro
|
||||
url "http://www.no-intro.org"
|
||||
|
@ -11842,7 +11842,7 @@ game (
|
|||
game (
|
||||
name "Mother 3 (Japan) (Virtual Console)"
|
||||
description "Mother 3 (Japan) (Virtual Console)"
|
||||
rom ( name "Mother 3 (Japan) (Virtual Console).gba" size 33554432 crc c704a567 sha1 A9FB9C36DF3B0FB24B266826F5853C56122F9D36 )
|
||||
rom ( name "Mother 3 (Japan) (Virtual Console).gba" size 33554432 crc c704a567 sha1 A9FB9C36DF3B0FB24B266826F5853C56122F9D36 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
@ -13450,7 +13450,7 @@ game (
|
|||
game (
|
||||
name "Pokemon - Version Rouge Feu (France)"
|
||||
description "Pokemon - Version Rouge Feu (France)"
|
||||
rom ( name "Pokemon - Version Rouge Feu (France).gba" size 16777216 crc 5dc668f6 sha1 FC663907256F06A3A09E2D6B967BC9AF4919F111 )
|
||||
rom ( name "Pokemon - Version Rouge Feu (France).gba" size 16777216 crc 5dc668f6 sha1 FC663907256F06A3A09E2D6B967BC9AF4919F111 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
@ -19951,8 +19951,8 @@ game (
|
|||
clrmamepro (
|
||||
name "Nintendo - Game Boy"
|
||||
description "Nintendo - Game Boy"
|
||||
version 20210311-081758
|
||||
author "aci68, akubi, Aringon, Bent, BigFred, BitLooter, C. V. Reynolds, chillerecke, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, ElBarto, foxe, fuzzball, Gefflon, Hiccup, hking0036, jimmsu, kazumi213, leekindo, Money_114, NGEfreak, omonim2007, Powerpuff, PPLToast, relax, RetroUprising, rpg2813, SonGoku, Tauwasser, xNo, xuom2"
|
||||
version 20210412-150119
|
||||
author "aci68, akubi, Aringon, Bent, BigFred, BitLooter, C. V. Reynolds, chillerecke, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, ElBarto, foxe, fuzzball, Gefflon, Hiccup, hking0036, InternalLoss, jimmsu, kazumi213, leekindo, Money_114, NGEfreak, omonim2007, Powerpuff, PPLToast, relax, RetroUprising, rpg2813, SonGoku, Tauwasser, xNo, xuom2"
|
||||
homepage No-Intro
|
||||
url "http://www.no-intro.org"
|
||||
)
|
||||
|
@ -20170,7 +20170,7 @@ game (
|
|||
game (
|
||||
name "Akumajou Special - Boku Dracula-kun (Japan)"
|
||||
description "Akumajou Special - Boku Dracula-kun (Japan)"
|
||||
rom ( name "Akumajou Special - Boku Dracula-kun (Japan).gb" size 262144 crc e8335398 sha1 F2F15DA8ED94BC8652C23965428F6D767E506E38 )
|
||||
rom ( name "Akumajou Special - Boku Dracula-kun (Japan).gb" size 262144 crc e8335398 sha1 F2F15DA8ED94BC8652C23965428F6D767E506E38 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
@ -20185,6 +20185,12 @@ game (
|
|||
rom ( name "Aladdin (USA) (SGB Enhanced).gb" size 262144 crc af6bdc50 sha1 81B4E56AE235FBB123D7AD4BD7C1D96C3B69EB72 )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Aladdin (World) (Disney Classic Games) (SGB Enhanced)"
|
||||
description "Aladdin (World) (Disney Classic Games) (SGB Enhanced)"
|
||||
rom ( name "Aladdin (World) (Disney Classic Games) (SGB Enhanced).gb" size 262144 crc 53918941 sha1 C59C44051E41DC6AC8C2F693CFF2BA1FEFFD32F0 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Alfred Chicken (Europe)"
|
||||
description "Alfred Chicken (Europe)"
|
||||
|
@ -21518,9 +21524,15 @@ game (
|
|||
)
|
||||
|
||||
game (
|
||||
name "Contra (Japan)"
|
||||
description "Contra (Japan)"
|
||||
rom ( name "Contra (Japan).gb" size 131072 crc cde6de15 sha1 C8B34B5ABA3D448E357B59CDF106EE9B134713DB )
|
||||
name "Contra (Japan) (En)"
|
||||
description "Contra (Japan) (En)"
|
||||
rom ( name "Contra (Japan) (En).gb" size 131072 crc cde6de15 sha1 C8B34B5ABA3D448E357B59CDF106EE9B134713DB )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Contra (World) (Contra Anniversary Collection)"
|
||||
description "Contra (World) (Contra Anniversary Collection)"
|
||||
rom ( name "Contra (World) (Contra Anniversary Collection).gb" size 131072 crc cc67a046 sha1 6FEA1350AC04F418095CCA5F157A9C770A0505BC flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
@ -22435,18 +22447,36 @@ game (
|
|||
rom ( name "Final Fantasy Adventure (World) (Collection of Mana).gb" size 262144 crc 8e5e5097 sha1 BD8369977CFBBAF3CC57F6268B564D6B11C27D45 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Final Fantasy Legend (World) (Collection of SaGa)"
|
||||
description "Final Fantasy Legend (World) (Collection of SaGa)"
|
||||
rom ( name "Final Fantasy Legend (World) (Collection of SaGa).gb" size 131072 crc 00388844 sha1 42450483C9894863C7543F9695C0CBAFFDCB7E99 )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Final Fantasy Legend II (USA)"
|
||||
description "Final Fantasy Legend II (USA)"
|
||||
rom ( name "Final Fantasy Legend II (USA).gb" size 262144 crc 58314182 sha1 6AB6890E8F688BCD87E97886A1748A4D9D341909 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Final Fantasy Legend II (World) (Collection of SaGa)"
|
||||
description "Final Fantasy Legend II (World) (Collection of SaGa)"
|
||||
rom ( name "Final Fantasy Legend II (World) (Collection of SaGa).gb" size 262144 crc e84e051a sha1 EEDF962D01B733B5EAF2413905E59E671E04A51C )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Final Fantasy Legend III (USA)"
|
||||
description "Final Fantasy Legend III (USA)"
|
||||
rom ( name "Final Fantasy Legend III (USA).gb" size 262144 crc 3e454710 sha1 3864AFA48A97DB826FFDA1D31A7FF9C6C315D5C9 )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Final Fantasy Legend III (World) (Collection of SaGa)"
|
||||
description "Final Fantasy Legend III (World) (Collection of SaGa)"
|
||||
rom ( name "Final Fantasy Legend III (World) (Collection of SaGa).gb" size 262144 crc 0c5171ef sha1 5190B0EF6264E26AF21DC0097FD5608CB619FB63 )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Final Fantasy Legend, The (USA)"
|
||||
description "Final Fantasy Legend, The (USA)"
|
||||
|
@ -24511,6 +24541,12 @@ game (
|
|||
rom ( name "Lion King, The (Europe).gb" size 524288 crc 8fc3ca73 sha1 043D29EDE2AF013C000FF650231C10B3F62D7ACA flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Lion King, The (World) (Disney Classic Games)"
|
||||
description "Lion King, The (World) (Disney Classic Games)"
|
||||
rom ( name "Lion King, The (World) (Disney Classic Games).gb" size 524288 crc e435ed72 sha1 170C071DB25DA7A2B39DD1FB2675ACEB8EEB87A1 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Litti's Summer Sports (Germany)"
|
||||
description "Litti's Summer Sports (Germany)"
|
||||
|
@ -24697,6 +24733,12 @@ game (
|
|||
rom ( name "Makai Toushi Sa-Ga (Japan) (Rev 1).gb" size 131072 crc 1953820f sha1 CBF480BC92BD98BAE4FB79294B604D341FE58CBE flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Makai Toushi Sa-Ga (World) (Ja) (Rev 1) (Collection of SaGa)"
|
||||
description "Makai Toushi Sa-Ga (World) (Ja) (Rev 1) (Collection of SaGa)"
|
||||
rom ( name "Makai Toushi Sa-Ga (World) (Ja) (Rev 1) (Collection of SaGa).gb" size 131072 crc 0006612d sha1 3CE39646BFFE38A9C8FD4913F0E950BAE061D094 )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Makaimura Gaiden - The Demon Darkness (Japan)"
|
||||
description "Makaimura Gaiden - The Demon Darkness (Japan)"
|
||||
|
@ -26041,6 +26083,12 @@ game (
|
|||
rom ( name "Operation C (USA).gb" size 131072 crc 2ebbc1ae sha1 1DC3E1C62E62F77AC633408B544AC1D02B3761EB flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Operation C (World) (Contra Anniversary Collection)"
|
||||
description "Operation C (World) (Contra Anniversary Collection)"
|
||||
rom ( name "Operation C (World) (Contra Anniversary Collection).gb" size 131072 crc a7a5d9c2 sha1 BD528F1B20051502E2B4418845E0C6698E1C5B4B flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Osawagase! Penguin Boy (Japan)"
|
||||
description "Osawagase! Penguin Boy (Japan)"
|
||||
|
@ -26758,13 +26806,13 @@ game (
|
|||
game (
|
||||
name "Pokemon - Version Jaune - Edition Speciale Pikachu (France) (CGB+SGB Enhanced)"
|
||||
description "Pokemon - Version Jaune - Edition Speciale Pikachu (France) (CGB+SGB Enhanced)"
|
||||
rom ( name "Pokemon - Version Jaune - Edition Speciale Pikachu (France) (CGB+SGB Enhanced).gb" size 1048576 crc d03426e9 sha1 0ACEEC0EF7AA2CA5AA831554598D91F61A925591 )
|
||||
rom ( name "Pokemon - Version Jaune - Edition Speciale Pikachu (France) (CGB+SGB Enhanced).gb" size 1048576 crc d03426e9 sha1 0ACEEC0EF7AA2CA5AA831554598D91F61A925591 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Pokemon - Version Rouge (France) (SGB Enhanced)"
|
||||
description "Pokemon - Version Rouge (France) (SGB Enhanced)"
|
||||
rom ( name "Pokemon - Version Rouge (France) (SGB Enhanced).gb" size 1048576 crc 337fce11 sha1 47A7622FA30E6402A3891FE65B3A930BF9BD7AEC )
|
||||
rom ( name "Pokemon - Version Rouge (France) (SGB Enhanced).gb" size 1048576 crc 337fce11 sha1 47A7622FA30E6402A3891FE65B3A930BF9BD7AEC flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
@ -26983,6 +27031,12 @@ game (
|
|||
rom ( name "Probotector (Europe).gb" size 131072 crc c9acc4f4 sha1 45482A44CE0CDFA33FC58A8A8AFE2D7284DFA498 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Probotector (World) (Contra Anniversary Collection)"
|
||||
description "Probotector (World) (Contra Anniversary Collection)"
|
||||
rom ( name "Probotector (World) (Contra Anniversary Collection).gb" size 131072 crc 1c03c0ee sha1 BC58585F8A1B2E27712AE5D44E3D851F4535A53F flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Probotector 2 (Europe) (SGB Enhanced)"
|
||||
description "Probotector 2 (Europe) (SGB Enhanced)"
|
||||
|
@ -27505,12 +27559,24 @@ game (
|
|||
rom ( name "Sa-Ga 2 - Hihou Densetsu (Japan) (Rev 1).gb" size 262144 crc f6cfcfb1 sha1 96EF7D31AD098A620BA7AC57AFEF416972707EA3 flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Sa-Ga 2 - Hihou Densetsu (World) (Ja) (Rev 1) (Collection of SaGa)"
|
||||
description "Sa-Ga 2 - Hihou Densetsu (World) (Ja) (Rev 1) (Collection of SaGa)"
|
||||
rom ( name "Sa-Ga 2 - Hihou Densetsu (World) (Ja) (Rev 1) (Collection of SaGa).gb" size 262144 crc 2fe38e18 sha1 1DF1F6E277BF6406B865DD5A3E12C0277C3C65F2 )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Sa-Ga 3 - Jikuu no Hasha (Japan)"
|
||||
description "Sa-Ga 3 - Jikuu no Hasha (Japan)"
|
||||
rom ( name "Sa-Ga 3 - Jikuu no Hasha (Japan).gb" size 262144 crc 575d6d9d sha1 C8DCBEFC0352B0590FD85A683D983B5510A63519 )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Sa-Ga 3 - Jikuu no Hasha (World) (Ja) (Collection of SaGa)"
|
||||
description "Sa-Ga 3 - Jikuu no Hasha (World) (Ja) (Collection of SaGa)"
|
||||
rom ( name "Sa-Ga 3 - Jikuu no Hasha (World) (Ja) (Collection of SaGa).gb" size 262144 crc dc4f4e34 sha1 8125677EE63E9ABB4B956ED0BEE18FAE3E04193B )
|
||||
)
|
||||
|
||||
game (
|
||||
name "Sagaia (Japan)"
|
||||
description "Sagaia (Japan)"
|
||||
|
@ -28810,7 +28876,7 @@ game (
|
|||
game (
|
||||
name "Tecmo Bowl GB (Japan)"
|
||||
description "Tecmo Bowl GB (Japan)"
|
||||
rom ( name "Tecmo Bowl GB (Japan).gb" size 262144 crc cfd74e34 sha1 2447006C578E1DF0256E9155C8B65FA2A6B0004B )
|
||||
rom ( name "Tecmo Bowl GB (Japan).gb" size 262144 crc cfd74e34 sha1 2447006C578E1DF0256E9155C8B65FA2A6B0004B flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
@ -30004,8 +30070,8 @@ game (
|
|||
clrmamepro (
|
||||
name "Nintendo - Game Boy Color"
|
||||
description "Nintendo - Game Boy Color"
|
||||
version 20210303-092238
|
||||
author "akubi, Aringon, Bent, BigFred, BitLooter, C. V. Reynolds, chillerecke, coraz, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, foxe, fuzzball, Hiccup, hking0036, kazumi213, Money_114, NGEfreak, omonim2007, PPLToast, relax, Rifu, SonGoku, Tauwasser, Whovian9369, xuom2, zg"
|
||||
version 20210410-081930
|
||||
author "akubi, Aringon, Bent, BigFred, BitLooter, C. V. Reynolds, chillerecke, coraz, darthcloud, DeadSkullzJr, Densetsu, DeriLoko3, foxe, fuzzball, Hiccup, hking0036, InternalLoss, kazumi213, Money_114, NGEfreak, omonim2007, PPLToast, relax, Rifu, SonGoku, Tauwasser, Whovian9369, xuom2, zg"
|
||||
homepage No-Intro
|
||||
url "http://www.no-intro.org"
|
||||
)
|
||||
|
@ -34873,7 +34939,7 @@ game (
|
|||
game (
|
||||
name "Mobile Golf (Japan)"
|
||||
description "Mobile Golf (Japan)"
|
||||
rom ( name "Mobile Golf (Japan).gbc" size 4194304 crc 35fc5b32 sha1 FDE414FC9EFEF2C30D1A9E0A2ED35AD2EFC0EDEE )
|
||||
rom ( name "Mobile Golf (Japan).gbc" size 4194304 crc 35fc5b32 sha1 FDE414FC9EFEF2C30D1A9E0A2ED35AD2EFC0EDEE flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
@ -35887,7 +35953,7 @@ game (
|
|||
game (
|
||||
name "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible)"
|
||||
description "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible)"
|
||||
rom ( name "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 576f5ced sha1 76FA60D66B2F22A035ADC54C61AAD9A415C894CD )
|
||||
rom ( name "Pokemon - Silberne Edition (Germany) (Beta) (SGB Enhanced) (GB Compatible).gbc" size 2097152 crc 576f5ced sha1 76FA60D66B2F22A035ADC54C61AAD9A415C894CD flags verified )
|
||||
)
|
||||
|
||||
game (
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
Miras Absar
|
||||
Emily A. Bellows
|
||||
Jaime J. Denizard
|
||||
Benedikt Feih
|
||||
Emily A. Bellows
|
||||
gocha
|
||||
Jaime J. Denizard
|
||||
Jezzabel
|
||||
Lucas Towers
|
||||
MichaelK_
|
||||
Miras Absar
|
||||
NimbusFox
|
||||
Petru-Sebastian Toader
|
||||
SquidHominid
|
||||
Tyler Jenkins
|
||||
Zach
|
||||
|
|
|
@ -101,9 +101,10 @@ static inline uint32_t _printLine(struct CLIDebugger* debugger, uint32_t address
|
|||
struct mCore* core = debugger->d.core;
|
||||
char disassembly[64];
|
||||
struct ARMInstructionInfo info;
|
||||
address &= ~(WORD_SIZE_THUMB - 1);
|
||||
be->printf(be, "%08X: ", address);
|
||||
if (mode == MODE_ARM) {
|
||||
uint32_t instruction = core->busRead32(core, address);
|
||||
uint32_t instruction = core->busRead32(core, address & ~(WORD_SIZE_ARM - 1));
|
||||
ARMDecodeARM(instruction, &info);
|
||||
ARMDisassemble(&info, core->cpu, core->symbolTable, address + WORD_SIZE_ARM * 2, disassembly, sizeof(disassembly));
|
||||
be->printf(be, "%08X\t%s\n", instruction, disassembly);
|
||||
|
|
|
@ -421,7 +421,7 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) {
|
|||
|
||||
#define ARM_MS_PRE_load \
|
||||
enum PrivilegeMode privilegeMode; \
|
||||
if (!(rs & 0x8000)) { \
|
||||
if (!(rs & 0x8000) && rs) { \
|
||||
privilegeMode = cpu->privilegeMode; \
|
||||
ARMSetPrivilegeMode(cpu, MODE_SYSTEM); \
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) {
|
|||
#define ARM_MS_POST_store ARMSetPrivilegeMode(cpu, privilegeMode);
|
||||
|
||||
#define ARM_MS_POST_load \
|
||||
if (!(rs & 0x8000)) { \
|
||||
if (!(rs & 0x8000) && rs) { \
|
||||
ARMSetPrivilegeMode(cpu, privilegeMode); \
|
||||
} else if (_ARMModeHasSPSR(cpu->cpsr.priv)) { \
|
||||
cpu->cpsr = cpu->spsr; \
|
||||
|
|
|
@ -139,18 +139,18 @@ void mBitmapCacheCleanRow(struct mBitmapCache* cache, struct mBitmapCacheEntry*
|
|||
return;
|
||||
}
|
||||
|
||||
size_t offset = cache->bitsStart[cache->buffer] + y * mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
|
||||
size_t offset = y * mBitmapCacheSystemInfoGetWidth(cache->sysConfig);
|
||||
void* vram;
|
||||
int bpe = mBitmapCacheSystemInfoGetEntryBPP(cache->sysConfig);
|
||||
uint32_t (*lookupEntry)(void*, uint32_t);
|
||||
switch (bpe) {
|
||||
case 3:
|
||||
lookupEntry = _lookupEntry8;
|
||||
vram = &cache->vram[offset];
|
||||
vram = &cache->vram[offset + cache->bitsStart[cache->buffer]];
|
||||
break;
|
||||
case 4:
|
||||
lookupEntry = _lookupEntry15;
|
||||
vram = &cache->vram[offset << 1];
|
||||
vram = &cache->vram[offset * 2 + cache->bitsStart[cache->buffer]];
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
|
@ -184,4 +184,4 @@ bool mBitmapCacheCheckRow(struct mBitmapCache* cache, const struct mBitmapCacheE
|
|||
const color_t* mBitmapCacheGetRow(struct mBitmapCache* cache, unsigned y) {
|
||||
color_t* row = &cache->cache[(cache->buffer * mBitmapCacheSystemInfoGetHeight(cache->sysConfig) + y) * mBitmapCacheSystemInfoGetWidth(cache->sysConfig)];
|
||||
return row;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
#include <strsafe.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <CoreFoundation/CFURL.h>
|
||||
#endif
|
||||
|
||||
#ifdef PSP2
|
||||
#include <psp2/io/stat.h>
|
||||
#endif
|
||||
|
@ -274,6 +280,16 @@ void mCoreConfigPortablePath(char* out, size_t outLength) {
|
|||
out[0] = '\0';
|
||||
#else
|
||||
getcwd(out, outLength);
|
||||
#ifdef __APPLE__
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
if (strcmp(out, "/") == 0 && mainBundle) {
|
||||
CFURLRef url = CFBundleCopyBundleURL(mainBundle);
|
||||
CFURLRef suburl = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, url);
|
||||
CFRelease(url);
|
||||
CFURLGetFileSystemRepresentation(suburl, true, (UInt8*) out, outLength);
|
||||
CFRelease(suburl);
|
||||
}
|
||||
#endif
|
||||
strncat(out, PATH_SEP "portable.ini", outLength - strlen(out));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -159,7 +159,13 @@ bool mCorePreloadVFCB(struct mCore* core, struct VFile* vf, void (cb)(size_t, si
|
|||
extern uint32_t* romBuffer;
|
||||
extern size_t romBufferSize;
|
||||
if (size > romBufferSize) {
|
||||
return false;
|
||||
if (size - romBufferSize < romBufferSize / 2) {
|
||||
// Some ROM hacks accidentally overflow the size a bit, but since those are broken
|
||||
// on hardware anyway we can just silently truncate them without issue.
|
||||
size = romBufferSize;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
vfm = VFileFromMemory(romBuffer, size);
|
||||
#else
|
||||
|
|
|
@ -456,6 +456,11 @@ struct VFile* mLibraryOpenVFile(struct mLibrary* library, const struct mLibraryE
|
|||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < mLibraryListingSize(&entries); ++i) {
|
||||
struct mLibraryEntry* e = mLibraryListingGetPointer(&entries, i);
|
||||
mLibraryEntryFree(e);
|
||||
}
|
||||
mLibraryListingDeinit(&entries);
|
||||
return vf;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ static size_t _search32(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value32;
|
||||
res->oldValue = mem32[i >> 2];
|
||||
++found;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ static size_t _search16(const void* mem, size_t size, const struct mCoreMemoryBl
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value16;
|
||||
res->oldValue = mem16[i >> 1];
|
||||
++found;
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ static size_t _search8(const void* mem, size_t size, const struct mCoreMemoryBlo
|
|||
res->segment = -1; // TODO
|
||||
res->guessDivisor = 1;
|
||||
res->guessMultiplier = 1;
|
||||
res->oldValue = value8;
|
||||
res->oldValue = mem8[i];
|
||||
++found;
|
||||
}
|
||||
}
|
||||
|
@ -248,42 +248,46 @@ void mCoreMemorySearch(struct mCore* core, const struct mCoreMemorySearchParams*
|
|||
}
|
||||
}
|
||||
|
||||
bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) {
|
||||
int64_t value;
|
||||
bool _testSpecificGuess(struct mCore* core, struct mCoreMemorySearchResult* res, int64_t opValue, enum mCoreMemorySearchOp op) {
|
||||
int32_t offset = 0;
|
||||
char* end;
|
||||
if (params->op >= mCORE_MEMORY_SEARCH_DELTA) {
|
||||
if (op >= mCORE_MEMORY_SEARCH_DELTA) {
|
||||
offset = res->oldValue;
|
||||
}
|
||||
|
||||
value = strtoll(params->valueStr, &end, 10);
|
||||
if (end) {
|
||||
res->oldValue += value;
|
||||
if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
|
||||
res->oldValue += opValue;
|
||||
int64_t value = core->rawRead8(core, res->address, res->segment);
|
||||
if (_op(value * res->guessDivisor / res->guessMultiplier - offset, opValue, op)) {
|
||||
res->oldValue = value;
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 1) && (res->width >= 2 || res->width == -1)) {
|
||||
value = core->rawRead16(core, res->address, res->segment);
|
||||
if (_op(value * res->guessDivisor / res->guessMultiplier - offset, opValue, op)) {
|
||||
res->oldValue = value;
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
|
||||
}
|
||||
if (!(res->address & 3) && (res->width >= 4 || res->width == -1)) {
|
||||
value = core->rawRead32(core, res->address, res->segment);
|
||||
if (_op(value * res->guessDivisor / res->guessMultiplier - offset, opValue, op)) {
|
||||
res->oldValue = value;
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
|
||||
return true;
|
||||
}
|
||||
res->oldValue -= value;
|
||||
}
|
||||
res->oldValue -= opValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _testGuess(struct mCore* core, struct mCoreMemorySearchResult* res, const struct mCoreMemorySearchParams* params) {
|
||||
char* end;
|
||||
int64_t value = strtoll(params->valueStr, &end, 10);
|
||||
if (end && _testSpecificGuess(core, res, value, params->op)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
value = strtoll(params->valueStr, &end, 16);
|
||||
if (end) {
|
||||
res->oldValue += value;
|
||||
if (_op(core->rawRead8(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 1) && (res->width >= 2 || res->width == -1) && _op(core->rawRead16(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
|
||||
return true;
|
||||
}
|
||||
if (!(res->address & 3) && (res->width >= 4 || res->width == -1) && _op(core->rawRead32(core, res->address, res->segment) * res->guessDivisor / res->guessMultiplier - offset, value, params->op)) {
|
||||
return true;
|
||||
}
|
||||
res->oldValue -= value;
|
||||
if (end && _testSpecificGuess(core, res, value, params->op)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,10 @@ int32_t mTimingTick(struct mTiming* timing, int32_t cycles) {
|
|||
if (timing->reroot) {
|
||||
timing->root = timing->reroot;
|
||||
timing->reroot = NULL;
|
||||
*timing->nextEvent = mTimingNextEvent(timing);
|
||||
*timing->nextEvent = mTimingNextEvent(timing);
|
||||
if (*timing->nextEvent <= 0) {
|
||||
return mTimingTick(timing, 0);
|
||||
}
|
||||
}
|
||||
return *timing->nextEvent;
|
||||
}
|
||||
|
|
|
@ -380,4 +380,5 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
}
|
||||
}
|
||||
}
|
||||
GUIMenuItemListDeinit(&menu.items);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,11 @@ enum {
|
|||
|
||||
#define RUNNER_STATE(X) ((X) << 16)
|
||||
|
||||
enum {
|
||||
SCREENSHOT_VALID = 0x10000,
|
||||
SCREENSHOT_INVALID = 0x20000,
|
||||
};
|
||||
|
||||
static const struct mInputPlatformInfo _mGUIKeyInfo = {
|
||||
.platformName = "gui",
|
||||
.keyId = (const char*[GUI_INPUT_MAX]) {
|
||||
|
@ -105,39 +110,49 @@ static void _drawBackground(struct GUIBackground* background, void* context) {
|
|||
|
||||
static void _drawState(struct GUIBackground* background, void* id) {
|
||||
struct mGUIBackground* gbaBackground = (struct mGUIBackground*) background;
|
||||
int stateId = ((int) id) >> 16;
|
||||
unsigned stateId = ((uint32_t) id) >> 16;
|
||||
if (gbaBackground->p->drawScreenshot) {
|
||||
unsigned w, h;
|
||||
gbaBackground->p->core->desiredVideoDimensions(gbaBackground->p->core, &w, &h);
|
||||
if (gbaBackground->screenshot && gbaBackground->screenshotId == (int) id) {
|
||||
gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->screenshot, w, h, true);
|
||||
size_t size = w * h * BYTES_PER_PIXEL;
|
||||
if (size != gbaBackground->imageSize) {
|
||||
mappedMemoryFree(gbaBackground->image, gbaBackground->imageSize);
|
||||
gbaBackground->image = NULL;
|
||||
}
|
||||
if (gbaBackground->image && gbaBackground->screenshotId == (stateId | SCREENSHOT_VALID)) {
|
||||
gbaBackground->p->drawScreenshot(gbaBackground->p, gbaBackground->image, w, h, true);
|
||||
return;
|
||||
}
|
||||
struct VFile* vf = mCoreGetState(gbaBackground->p->core, stateId, false);
|
||||
color_t* pixels = gbaBackground->screenshot;
|
||||
if (!pixels) {
|
||||
pixels = anonymousMemoryMap(w * h * 4);
|
||||
gbaBackground->screenshot = pixels;
|
||||
}
|
||||
bool success = false;
|
||||
if (vf && isPNG(vf) && pixels) {
|
||||
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
png_infop end = png_create_info_struct(png);
|
||||
if (png && info && end) {
|
||||
success = PNGReadHeader(png, info);
|
||||
success = success && PNGReadPixels(png, info, pixels, w, h, w);
|
||||
success = success && PNGReadFooter(png, end);
|
||||
} else if (gbaBackground->screenshotId != (stateId | SCREENSHOT_INVALID)) {
|
||||
struct VFile* vf = mCoreGetState(gbaBackground->p->core, stateId, false);
|
||||
color_t* pixels = gbaBackground->image;
|
||||
if (!pixels) {
|
||||
pixels = anonymousMemoryMap(size);
|
||||
gbaBackground->image = pixels;
|
||||
gbaBackground->imageSize = size;
|
||||
}
|
||||
bool success = false;
|
||||
if (vf && isPNG(vf) && pixels) {
|
||||
png_structp png = PNGReadOpen(vf, PNG_HEADER_BYTES);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
png_infop end = png_create_info_struct(png);
|
||||
if (png && info && end) {
|
||||
success = PNGReadHeader(png, info);
|
||||
success = success && PNGReadPixels(png, info, pixels, w, h, w);
|
||||
success = success && PNGReadFooter(png, end);
|
||||
}
|
||||
PNGReadClose(png, info, end);
|
||||
}
|
||||
if (vf) {
|
||||
vf->close(vf);
|
||||
}
|
||||
if (success) {
|
||||
gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, w, h, true);
|
||||
gbaBackground->screenshotId = stateId | SCREENSHOT_VALID;
|
||||
} else {
|
||||
gbaBackground->screenshotId = stateId | SCREENSHOT_INVALID;
|
||||
}
|
||||
PNGReadClose(png, info, end);
|
||||
}
|
||||
if (vf) {
|
||||
vf->close(vf);
|
||||
}
|
||||
if (success) {
|
||||
gbaBackground->p->drawScreenshot(gbaBackground->p, pixels, w, h, true);
|
||||
gbaBackground->screenshotId = (int) id;
|
||||
} else if (gbaBackground->p->drawFrame) {
|
||||
if (gbaBackground->p->drawFrame && gbaBackground->screenshotId == (stateId | SCREENSHOT_INVALID)) {
|
||||
gbaBackground->p->drawFrame(gbaBackground->p, true);
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +328,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
.draw = _drawState
|
||||
},
|
||||
.p = runner,
|
||||
.screenshot = 0,
|
||||
.image = 0,
|
||||
.screenshotId = 0
|
||||
};
|
||||
struct GUIMenu pauseMenu = {
|
||||
|
@ -605,10 +620,10 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
runner->core->reset(runner->core);
|
||||
break;
|
||||
case RUNNER_SAVE_STATE:
|
||||
mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
|
||||
mCoreSaveState(runner->core, ((uint32_t) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_RTC | SAVESTATE_METADATA);
|
||||
break;
|
||||
case RUNNER_LOAD_STATE:
|
||||
mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
|
||||
mCoreLoadState(runner->core, ((uint32_t) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
|
||||
break;
|
||||
case RUNNER_SCREENSHOT:
|
||||
mCoreTakeScreenshot(runner->core);
|
||||
|
@ -663,10 +678,8 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
mLOG(GUI_RUNNER, DEBUG, "Unloading game...");
|
||||
runner->core->unloadROM(runner->core);
|
||||
drawState.screenshotId = 0;
|
||||
if (drawState.screenshot) {
|
||||
unsigned w, h;
|
||||
runner->core->desiredVideoDimensions(runner->core, &w, &h);
|
||||
mappedMemoryFree(drawState.screenshot, w * h * 4);
|
||||
if (drawState.image) {
|
||||
mappedMemoryFree(drawState.image, drawState.imageSize);
|
||||
}
|
||||
|
||||
if (runner->config.port) {
|
||||
|
|
|
@ -31,8 +31,10 @@ struct mGUIBackground {
|
|||
struct GUIBackground d;
|
||||
struct mGUIRunner* p;
|
||||
|
||||
color_t* screenshot;
|
||||
int screenshotId;
|
||||
color_t* image;
|
||||
size_t imageSize;
|
||||
|
||||
unsigned screenshotId;
|
||||
};
|
||||
|
||||
struct mCore;
|
||||
|
|
|
@ -84,4 +84,5 @@ void mGUIRemapKeys(struct GUIParams* params, struct mInputMap* map, const struct
|
|||
// TODO: Open remap menu
|
||||
}
|
||||
}
|
||||
GUIMenuItemListDeinit(&menu.items);
|
||||
}
|
||||
|
|
|
@ -446,7 +446,8 @@ static void _GBCoreReset(struct mCore* core) {
|
|||
bool modelOverride = GBOverrideFind(gbcore->overrides, &override) || (doColorOverride && GBOverrideColorFind(&override));
|
||||
if (modelOverride) {
|
||||
GBOverrideApply(gb, &override);
|
||||
} else {
|
||||
}
|
||||
if (!modelOverride || override.model == GB_MODEL_AUTODETECT) {
|
||||
const char* modelGB = mCoreConfigGetValue(&core->config, "gb.model");
|
||||
const char* modelSGB = mCoreConfigGetValue(&core->config, "sgb.model");
|
||||
const char* modelCGB = mCoreConfigGetValue(&core->config, "cgb.model");
|
||||
|
@ -770,13 +771,13 @@ void* _GBGetMemoryBlock(struct mCore* core, size_t id, size_t* sizeOut) {
|
|||
*sizeOut = gb->memory.romSize;
|
||||
return gb->memory.rom;
|
||||
case GB_REGION_VRAM:
|
||||
*sizeOut = GB_SIZE_WORKING_RAM_BANK0 * (isCgb ? 1 : 2);
|
||||
*sizeOut = GB_SIZE_VRAM_BANK0 * (isCgb ? 1 : 2);
|
||||
return gb->video.vram;
|
||||
case GB_REGION_EXTERNAL_RAM:
|
||||
*sizeOut = gb->sramSize;
|
||||
return gb->memory.sram;
|
||||
case GB_REGION_WORKING_RAM_BANK0:
|
||||
*sizeOut = GB_SIZE_VRAM * (isCgb ? 8 : 2);
|
||||
*sizeOut = GB_SIZE_WORKING_RAM_BANK0 * (isCgb ? 8 : 2);
|
||||
return gb->memory.wram;
|
||||
case GB_BASE_OAM:
|
||||
*sizeOut = GB_SIZE_OAM;
|
||||
|
|
|
@ -582,13 +582,13 @@ void GBSkipBIOS(struct GB* gb) {
|
|||
mTimingDeschedule(&gb->timing, &gb->timer.event);
|
||||
mTimingSchedule(&gb->timing, &gb->timer.event, gb->timer.nextDiv);
|
||||
|
||||
GBIOWrite(gb, GB_REG_LCDC, 0x91);
|
||||
gb->memory.io[GB_REG_BANK] = 0x1;
|
||||
GBVideoSkipBIOS(&gb->video);
|
||||
|
||||
if (gb->biosVf) {
|
||||
GBUnmapBIOS(gb);
|
||||
}
|
||||
|
||||
GBIOWrite(gb, GB_REG_LCDC, 0x91);
|
||||
gb->memory.io[GB_REG_BANK] = 0x1;
|
||||
GBVideoSkipBIOS(&gb->video);
|
||||
}
|
||||
|
||||
void GBMapBIOS(struct GB* gb) {
|
||||
|
|
|
@ -724,6 +724,7 @@ void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
|
||||
gb->audio.enable = GBAudioEnableGetEnable(*gb->audio.nr52);
|
||||
if (gb->audio.enable) {
|
||||
gb->audio.playingCh1 = false;
|
||||
GBIOWrite(gb, GB_REG_NR10, gb->memory.io[GB_REG_NR10]);
|
||||
GBIOWrite(gb, GB_REG_NR11, gb->memory.io[GB_REG_NR11]);
|
||||
GBIOWrite(gb, GB_REG_NR12, gb->memory.io[GB_REG_NR12]);
|
||||
|
@ -731,12 +732,14 @@ void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
gb->audio.ch1.control.frequency &= 0xFF;
|
||||
gb->audio.ch1.control.frequency |= GBAudioRegisterControlGetFrequency(gb->memory.io[GB_REG_NR14] << 8);
|
||||
gb->audio.ch1.control.stop = GBAudioRegisterControlGetStop(gb->memory.io[GB_REG_NR14] << 8);
|
||||
gb->audio.playingCh2 = false;
|
||||
GBIOWrite(gb, GB_REG_NR21, gb->memory.io[GB_REG_NR21]);
|
||||
GBIOWrite(gb, GB_REG_NR22, gb->memory.io[GB_REG_NR22]);
|
||||
GBIOWrite(gb, GB_REG_NR23, gb->memory.io[GB_REG_NR23]);
|
||||
gb->audio.ch2.control.frequency &= 0xFF;
|
||||
gb->audio.ch2.control.frequency |= GBAudioRegisterControlGetFrequency(gb->memory.io[GB_REG_NR24] << 8);
|
||||
gb->audio.ch2.control.stop = GBAudioRegisterControlGetStop(gb->memory.io[GB_REG_NR24] << 8);
|
||||
gb->audio.playingCh3 = false;
|
||||
GBIOWrite(gb, GB_REG_NR30, gb->memory.io[GB_REG_NR30]);
|
||||
GBIOWrite(gb, GB_REG_NR31, gb->memory.io[GB_REG_NR31]);
|
||||
GBIOWrite(gb, GB_REG_NR32, gb->memory.io[GB_REG_NR32]);
|
||||
|
@ -744,6 +747,7 @@ void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
gb->audio.ch3.rate &= 0xFF;
|
||||
gb->audio.ch3.rate |= GBAudioRegisterControlGetRate(gb->memory.io[GB_REG_NR34] << 8);
|
||||
gb->audio.ch3.stop = GBAudioRegisterControlGetStop(gb->memory.io[GB_REG_NR34] << 8);
|
||||
gb->audio.playingCh4 = false;
|
||||
GBIOWrite(gb, GB_REG_NR41, gb->memory.io[GB_REG_NR41]);
|
||||
GBIOWrite(gb, GB_REG_NR42, gb->memory.io[GB_REG_NR42]);
|
||||
GBIOWrite(gb, GB_REG_NR43, gb->memory.io[GB_REG_NR43]);
|
||||
|
|
|
@ -172,6 +172,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
gb->cpu->condition = GBSerializedCpuFlagsGetCondition(flags);
|
||||
gb->cpu->irqPending = GBSerializedCpuFlagsGetIrqPending(flags);
|
||||
gb->doubleSpeed = GBSerializedCpuFlagsGetDoubleSpeed(flags);
|
||||
gb->cpu->tMultiplier = 2 - gb->doubleSpeed;
|
||||
gb->cpu->halted = GBSerializedCpuFlagsGetHalted(flags);
|
||||
gb->cpuBlocked = GBSerializedCpuFlagsGetBlocked(flags);
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ void GBVideoReset(struct GBVideo* video) {
|
|||
video->frameskipCounter = 0;
|
||||
|
||||
GBVideoSwitchBank(video, 0);
|
||||
memset(video->vram, 0, GB_SIZE_VRAM);
|
||||
video->renderer->vram = video->vram;
|
||||
memset(&video->oam, 0, sizeof(video->oam));
|
||||
video->renderer->oam = &video->oam;
|
||||
|
|
|
@ -300,6 +300,7 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con
|
|||
mCoreConfigCopyValue(&core->config, config, "gba.bios");
|
||||
mCoreConfigCopyValue(&core->config, config, "gba.forceGbp");
|
||||
mCoreConfigCopyValue(&core->config, config, "gba.audioHle");
|
||||
mCoreConfigCopyValue(&core->config, config, "vbaBugCompat");
|
||||
|
||||
#ifndef DISABLE_THREADING
|
||||
mCoreConfigCopyValue(&core->config, config, "threadedVideo");
|
||||
|
@ -610,6 +611,10 @@ static void _GBACoreReset(struct mCore* core) {
|
|||
if (mCoreConfigGetIntValue(&core->config, "gba.forceGbp", &fakeBool)) {
|
||||
forceGbp = fakeBool;
|
||||
}
|
||||
bool vbaBugCompat = true;
|
||||
if (mCoreConfigGetIntValue(&core->config, "vbaBugCompat", &fakeBool)) {
|
||||
vbaBugCompat = fakeBool;
|
||||
}
|
||||
if (!forceGbp) {
|
||||
gba->memory.hw.devices &= ~HW_GB_PLAYER_DETECTION;
|
||||
}
|
||||
|
@ -617,6 +622,9 @@ static void _GBACoreReset(struct mCore* core) {
|
|||
if (forceGbp) {
|
||||
gba->memory.hw.devices |= HW_GB_PLAYER_DETECTION;
|
||||
}
|
||||
if (!vbaBugCompat) {
|
||||
gba->vbaBugCompat = false;
|
||||
}
|
||||
|
||||
#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
|
||||
if (!gba->biosVf && core->opts.useBios) {
|
||||
|
|
|
@ -370,6 +370,11 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
|
|||
// Bitmap sizes
|
||||
case 5456:
|
||||
bitmap = true;
|
||||
blocks = 124;
|
||||
break;
|
||||
case 3520:
|
||||
bitmap = true;
|
||||
blocks = 80;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
@ -380,9 +385,9 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s
|
|||
if (bitmap) {
|
||||
size_t x;
|
||||
for (i = 0; i < 40; ++i) {
|
||||
const uint8_t* line = &cdata[(i + 2) * 124];
|
||||
const uint8_t* line = &cdata[(i + 2) * blocks];
|
||||
uint8_t* origin = &hw->eReaderDots[EREADER_DOTCODE_STRIDE * i + 200];
|
||||
for (x = 0; x < 124; ++x) {
|
||||
for (x = 0; x < blocks; ++x) {
|
||||
uint8_t byte = line[x];
|
||||
if (x == 123) {
|
||||
byte &= 0xE0;
|
||||
|
|
|
@ -411,6 +411,7 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) {
|
|||
gba->memory.romSize = gba->pristineRomSize;
|
||||
}
|
||||
if (!gba->memory.rom) {
|
||||
gba->romVf = NULL;
|
||||
mLOG(GBA, WARN, "Couldn't map ROM");
|
||||
return false;
|
||||
}
|
||||
|
|
10
src/gba/io.c
|
@ -226,7 +226,7 @@ static const int _isValidRegister[REG_MAX >> 1] = {
|
|||
1, 1, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -268,7 +268,7 @@ static const int _isRSpecialRegister[REG_MAX >> 1] = {
|
|||
1, 1, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -309,7 +309,7 @@ static const int _isWSpecialRegister[REG_MAX >> 1] = {
|
|||
1, 1, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -973,6 +973,9 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||
}
|
||||
|
||||
void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
||||
LOAD_16(gba->memory.io[REG_SOUNDCNT_X >> 1], REG_SOUNDCNT_X, state->io);
|
||||
GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < REG_MAX; i += 2) {
|
||||
if (_isWSpecialRegister[i >> 1]) {
|
||||
|
@ -1003,7 +1006,6 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount);
|
||||
LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].when);
|
||||
}
|
||||
GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]);
|
||||
gba->sio.siocnt = gba->memory.io[REG_SIOCNT >> 1];
|
||||
GBASIOWriteRCNT(&gba->sio, gba->memory.io[REG_RCNT >> 1]);
|
||||
|
||||
|
|
|
@ -121,6 +121,7 @@ void GBAMemoryReset(struct GBA* gba) {
|
|||
memset(gba->memory.io, 0, sizeof(gba->memory.io));
|
||||
GBAAdjustWaitstates(gba, 0);
|
||||
|
||||
gba->memory.activeRegion = -1;
|
||||
gba->memory.agbPrintProtect = 0;
|
||||
gba->memory.agbPrintBase = 0;
|
||||
memset(&gba->memory.agbPrintCtx, 0, sizeof(gba->memory.agbPrintCtx));
|
||||
|
@ -260,6 +261,11 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
|||
gba->lastJump = address;
|
||||
memory->lastPrefetchedPc = 0;
|
||||
if (newRegion == memory->activeRegion) {
|
||||
if (cpu->cpsr.t) {
|
||||
cpu->memory.activeMask |= WORD_SIZE_THUMB;
|
||||
} else {
|
||||
cpu->memory.activeMask &= -WORD_SIZE_ARM;
|
||||
}
|
||||
if (newRegion < REGION_CART0 || (address & (SIZE_CART0 - 1)) < memory->romSize) {
|
||||
return;
|
||||
}
|
||||
|
@ -345,7 +351,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
|
|||
cpu->memory.activeSeqCycles16 = memory->waitstatesSeq16[memory->activeRegion];
|
||||
cpu->memory.activeNonseqCycles32 = memory->waitstatesNonseq32[memory->activeRegion];
|
||||
cpu->memory.activeNonseqCycles16 = memory->waitstatesNonseq16[memory->activeRegion];
|
||||
cpu->memory.activeMask &= -(cpu->executionMode == MODE_THUMB ? WORD_SIZE_THUMB : WORD_SIZE_ARM);
|
||||
cpu->memory.activeMask &= -(cpu->cpsr.t ? WORD_SIZE_THUMB : WORD_SIZE_ARM);
|
||||
}
|
||||
|
||||
#define LOAD_BAD \
|
||||
|
@ -912,7 +918,11 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
|
|||
}
|
||||
break;
|
||||
case REGION_CART0:
|
||||
if (memory->hw.devices != HW_NONE && IS_GPIO_REGISTER(address & 0xFFFFFE)) {
|
||||
if (IS_GPIO_REGISTER(address & 0xFFFFFE)) {
|
||||
if (memory->hw.devices == HW_NONE) {
|
||||
mLOG(GBA_HW, WARN, "Write to GPIO address %08X on cartridge without GPIO", address);
|
||||
break;
|
||||
}
|
||||
uint32_t reg = address & 0xFFFFFE;
|
||||
GBAHardwareGPIOWrite(&memory->hw, reg, value);
|
||||
break;
|
||||
|
@ -926,7 +936,6 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
|
|||
if ((address & 0x00FFFFFF) >= AGB_PRINT_BASE) {
|
||||
uint32_t agbPrintAddr = address & 0x00FFFFFF;
|
||||
if (agbPrintAddr == AGB_PRINT_PROTECT) {
|
||||
bool wasProtected = memory->agbPrintProtect != 0x20;
|
||||
memory->agbPrintProtect = value;
|
||||
|
||||
if (!memory->agbPrintBuffer) {
|
||||
|
|
|
@ -34,6 +34,9 @@ static const struct GBACartridgeOverride _overrides[] = {
|
|||
{ "AC8E", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
|
||||
{ "AC8P", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
|
||||
|
||||
// DigiCommunication Nyo - Datou! Black Gemagema Dan
|
||||
{ "BDKJ", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
|
||||
|
||||
// Dragon Ball Z - The Legacy of Goku
|
||||
{ "ALGP", SAVEDATA_EEPROM, HW_NONE, IDLE_LOOP_NONE, false },
|
||||
|
||||
|
@ -49,6 +52,7 @@ static const struct GBACartridgeOverride _overrides[] = {
|
|||
// Drill Dozer
|
||||
{ "V49J", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
|
||||
{ "V49E", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
|
||||
{ "V49P", SAVEDATA_SRAM, HW_RUMBLE, IDLE_LOOP_NONE, false },
|
||||
|
||||
// e-Reader
|
||||
{ "PEAJ", SAVEDATA_FLASH1M, HW_EREADER, IDLE_LOOP_NONE },
|
||||
|
@ -375,8 +379,45 @@ void GBAOverrideApplyDefaults(struct GBA* gba, const struct Configuration* overr
|
|||
if (cart) {
|
||||
memcpy(override.id, &cart->id, sizeof(override.id));
|
||||
|
||||
if (!strncmp("pokemon red version", &((const char*) gba->memory.rom)[0x108], 20) && gba->romCrc32 != 0xDD88761C) {
|
||||
// Enable FLASH1M and RTC on Pokémon FireRed ROM hacks
|
||||
static const uint32_t pokemonTable[] = {
|
||||
// Emerald
|
||||
0x4881F3F8, // BPEJ
|
||||
0x8C4D3108, // BPES
|
||||
0x1F1C08FB, // BPEE
|
||||
0x34C9DF89, // BPED
|
||||
0xA3FDCCB1, // BPEF
|
||||
0xA0AEC80A, // BPEI
|
||||
|
||||
// FireRed
|
||||
0x1A81EEDF, // BPRD
|
||||
0x3B2056E9, // BPRJ
|
||||
0x5DC668F6, // BPRF
|
||||
0x73A72167, // BPRI
|
||||
0x84EE4776, // BPRE rev 1
|
||||
0x9F08064E, // BPRS
|
||||
0xBB640DF7, // BPRJ rev 1
|
||||
0xDD88761C, // BPRE
|
||||
|
||||
// Ruby
|
||||
0x61641576, // AXVE rev 1
|
||||
0xAEAC73E6, // AXVE rev 2
|
||||
0xF0815EE7, // AXVE
|
||||
};
|
||||
|
||||
bool isPokemon = false;
|
||||
isPokemon = isPokemon || !strncmp("pokemon red version", &((const char*) gba->memory.rom)[0x108], 20);
|
||||
isPokemon = isPokemon || !strncmp("pokemon emerald version", &((const char*) gba->memory.rom)[0x108], 24);
|
||||
isPokemon = isPokemon || !strncmp("AXVE", &((const char*) gba->memory.rom)[0xAC], 4);
|
||||
bool isKnownPokemon = false;
|
||||
if (isPokemon) {
|
||||
size_t i;
|
||||
for (i = 0; !isKnownPokemon && i < sizeof(pokemonTable) / sizeof(*pokemonTable); ++i) {
|
||||
isKnownPokemon = gba->romCrc32 == pokemonTable[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (isPokemon && !isKnownPokemon) {
|
||||
// Enable FLASH1M and RTC on Pokémon ROM hacks
|
||||
override.savetype = SAVEDATA_FLASH1M;
|
||||
override.hardware = HW_RTC;
|
||||
override.vbaBugCompat = true;
|
||||
|
|
|
@ -13,15 +13,21 @@
|
|||
int32_t y = background->sy + (renderer->start - 1) * background->dy; \
|
||||
int mosaicH = 0; \
|
||||
int mosaicWait = 0; \
|
||||
if (background->mosaic) { \
|
||||
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \
|
||||
y -= (inY % mosaicV) * background->dmy; \
|
||||
x -= (inY % mosaicV) * background->dmx; \
|
||||
mosaicH = GBAMosaicControlGetBgH(renderer->mosaic); \
|
||||
mosaicWait = renderer->start % (mosaicH + 1); \
|
||||
} \
|
||||
int32_t localX; \
|
||||
int32_t localY; \
|
||||
if (background->mosaic) { \
|
||||
int mosaicV = GBAMosaicControlGetBgV(renderer->mosaic) + 1; \
|
||||
mosaicH = GBAMosaicControlGetBgH(renderer->mosaic) + 1; \
|
||||
mosaicWait = (mosaicH - renderer->start + GBA_VIDEO_HORIZONTAL_PIXELS * mosaicH) % mosaicH; \
|
||||
int32_t startX = renderer->start - (renderer->start % mosaicH); \
|
||||
--mosaicH; \
|
||||
localX = -(inY % mosaicV) * background->dmx; \
|
||||
localY = -(inY % mosaicV) * background->dmy; \
|
||||
x += localX; \
|
||||
y += localY; \
|
||||
localX += background->sx + startX * background->dx; \
|
||||
localY += background->sy + startX * background->dy; \
|
||||
} \
|
||||
\
|
||||
uint32_t flags = (background->priority << OFFSET_PRIORITY) | (background->index << OFFSET_INDEX) | FLAG_IS_BACKGROUND; \
|
||||
flags |= FLAG_TARGET_2 * background->target2; \
|
||||
|
@ -49,16 +55,14 @@
|
|||
UNUSED(palette); \
|
||||
PREPARE_OBJWIN;
|
||||
|
||||
#define BACKGROUND_BITMAP_ITERATE(W, H) \
|
||||
x += background->dx; \
|
||||
y += background->dy; \
|
||||
\
|
||||
if (x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) { \
|
||||
continue; \
|
||||
} else { \
|
||||
localX = x; \
|
||||
localY = y; \
|
||||
}
|
||||
#define BACKGROUND_BITMAP_ITERATE(W, H) \
|
||||
x += background->dx; \
|
||||
y += background->dy; \
|
||||
if ((x < 0 || y < 0 || (x >> 8) >= W || (y >> 8) >= H) && !mosaicWait) { \
|
||||
continue; \
|
||||
} \
|
||||
localX = x; \
|
||||
localY = y;
|
||||
|
||||
#define MODE_2_COORD_OVERFLOW \
|
||||
localX = x & (sizeAdjusted - 1); \
|
||||
|
@ -102,12 +106,20 @@
|
|||
#define DRAW_BACKGROUND_MODE_2(BLEND, OBJWIN) \
|
||||
if (background->overflow) { \
|
||||
if (mosaicH > 1) { \
|
||||
localX &= sizeAdjusted - 1; \
|
||||
localY &= sizeAdjusted - 1; \
|
||||
MODE_2_NO_MOSAIC(); \
|
||||
MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
|
||||
} else { \
|
||||
MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_OVERFLOW, BLEND, OBJWIN); \
|
||||
} \
|
||||
} else { \
|
||||
if (mosaicH > 1) { \
|
||||
if (!((x | y) & ~(sizeAdjusted - 1))) { \
|
||||
localX &= sizeAdjusted - 1; \
|
||||
localY &= sizeAdjusted - 1; \
|
||||
MODE_2_NO_MOSAIC(); \
|
||||
} \
|
||||
MODE_2_LOOP(MODE_2_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
|
||||
} else { \
|
||||
MODE_2_LOOP(MODE_2_NO_MOSAIC, MODE_2_COORD_NO_OVERFLOW, BLEND, OBJWIN); \
|
||||
|
@ -146,6 +158,10 @@ void GBAVideoSoftwareRendererDrawBackgroundMode3(struct GBAVideoSoftwareRenderer
|
|||
BACKGROUND_BITMAP_INIT;
|
||||
|
||||
uint32_t color = renderer->normalPalette[0];
|
||||
if (mosaicWait && localX >= 0 && localY >= 0) {
|
||||
LOAD_16(color, ((localX >> 8) + (localY >> 8) * GBA_VIDEO_HORIZONTAL_PIXELS) << 1, renderer->d.vram);
|
||||
color = mColorFrom555(color);
|
||||
}
|
||||
|
||||
int outX;
|
||||
uint32_t* pixel;
|
||||
|
@ -185,6 +201,9 @@ void GBAVideoSoftwareRendererDrawBackgroundMode4(struct GBAVideoSoftwareRenderer
|
|||
if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
|
||||
offset = 0xA000;
|
||||
}
|
||||
if (mosaicWait && localX >= 0 && localY >= 0) {
|
||||
color = ((uint8_t*)renderer->d.vram)[offset + (localX >> 8) + (localY >> 8) * GBA_VIDEO_HORIZONTAL_PIXELS];
|
||||
}
|
||||
|
||||
int outX;
|
||||
uint32_t* pixel;
|
||||
|
@ -223,6 +242,10 @@ void GBAVideoSoftwareRendererDrawBackgroundMode5(struct GBAVideoSoftwareRenderer
|
|||
if (GBARegisterDISPCNTIsFrameSelect(renderer->dispcnt)) {
|
||||
offset = 0xA000;
|
||||
}
|
||||
if (mosaicWait && localX >= 0 && localY >= 0) {
|
||||
LOAD_16(color, offset + (localX >> 8) * 2 + (localY >> 8) * 320, renderer->d.vram);
|
||||
color = mColorFrom555(color);
|
||||
}
|
||||
|
||||
int outX;
|
||||
uint32_t* pixel;
|
||||
|
|
|
@ -719,16 +719,16 @@ static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* rendere
|
|||
softwareRenderer->bg[3].sy = softwareRenderer->bg[3].refy;
|
||||
|
||||
if (softwareRenderer->bg[0].enabled > 0) {
|
||||
softwareRenderer->bg[0].enabled = 3;
|
||||
softwareRenderer->bg[0].enabled = 4;
|
||||
}
|
||||
if (softwareRenderer->bg[1].enabled > 0) {
|
||||
softwareRenderer->bg[1].enabled = 3;
|
||||
softwareRenderer->bg[1].enabled = 4;
|
||||
}
|
||||
if (softwareRenderer->bg[2].enabled > 0) {
|
||||
softwareRenderer->bg[2].enabled = 3;
|
||||
softwareRenderer->bg[2].enabled = 4;
|
||||
}
|
||||
if (softwareRenderer->bg[3].enabled > 0) {
|
||||
softwareRenderer->bg[3].enabled = 3;
|
||||
softwareRenderer->bg[3].enabled = 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -755,7 +755,7 @@ static void _enableBg(struct GBAVideoSoftwareRenderer* renderer, int bg, bool ac
|
|||
} else if (!wasActive && active) {
|
||||
if (renderer->nextY == 0 || GBARegisterDISPCNTGetMode(renderer->dispcnt) > 2) {
|
||||
// TODO: Investigate in more depth how switching background works in different modes
|
||||
renderer->bg[bg].enabled = 3;
|
||||
renderer->bg[bg].enabled = 4;
|
||||
} else {
|
||||
renderer->bg[bg].enabled = 1;
|
||||
}
|
||||
|
@ -830,7 +830,7 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer*
|
|||
|
||||
#define TEST_LAYER_ENABLED(X) \
|
||||
!renderer->d.disableBG[X] && \
|
||||
(renderer->bg[X].enabled == 3 && \
|
||||
(renderer->bg[X].enabled == 4 && \
|
||||
(GBAWindowControlIsBg ## X ## Enable(renderer->currentWindow.packed) || \
|
||||
(GBARegisterDISPCNTIsObjwinEnable(renderer->dispcnt) && GBAWindowControlIsBg ## X ## Enable (renderer->objwin.packed))) && \
|
||||
renderer->bg[X].priority == priority)
|
||||
|
@ -937,19 +937,19 @@ static void _drawScanline(struct GBAVideoSoftwareRenderer* renderer, int y) {
|
|||
renderer->bg[3].sy += renderer->bg[3].dmy;
|
||||
}
|
||||
|
||||
if (renderer->bg[0].enabled > 0 && renderer->bg[0].enabled < 3) {
|
||||
if (renderer->bg[0].enabled > 0 && renderer->bg[0].enabled < 4) {
|
||||
++renderer->bg[0].enabled;
|
||||
DIRTY_SCANLINE(renderer, y);
|
||||
}
|
||||
if (renderer->bg[1].enabled > 0 && renderer->bg[1].enabled < 3) {
|
||||
if (renderer->bg[1].enabled > 0 && renderer->bg[1].enabled < 4) {
|
||||
++renderer->bg[1].enabled;
|
||||
DIRTY_SCANLINE(renderer, y);
|
||||
}
|
||||
if (renderer->bg[2].enabled > 0 && renderer->bg[2].enabled < 3) {
|
||||
if (renderer->bg[2].enabled > 0 && renderer->bg[2].enabled < 4) {
|
||||
++renderer->bg[2].enabled;
|
||||
DIRTY_SCANLINE(renderer, y);
|
||||
}
|
||||
if (renderer->bg[3].enabled > 0 && renderer->bg[3].enabled < 3) {
|
||||
if (renderer->bg[3].enabled > 0 && renderer->bg[3].enabled < 4) {
|
||||
++renderer->bg[3].enabled;
|
||||
DIRTY_SCANLINE(renderer, y);
|
||||
}
|
||||
|
|
|
@ -158,6 +158,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
mLOG(GBA_STATE, WARN, "Savestate has unaligned PC and is probably corrupted");
|
||||
gba->cpu->gprs[ARM_PC] &= ~1;
|
||||
}
|
||||
gba->memory.activeRegion = -1;
|
||||
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
|
||||
if (state->biosPrefetch) {
|
||||
LOAD_32(gba->memory.biosPrefetch, 0, &state->biosPrefetch);
|
||||
|
|
|
@ -60,7 +60,9 @@ static void _switchMode(struct GBASIO* sio) {
|
|||
if (sio->activeDriver && sio->activeDriver->unload) {
|
||||
sio->activeDriver->unload(sio->activeDriver);
|
||||
}
|
||||
mLOG(GBA_SIO, DEBUG, "Switching mode from %s to %s", _modeName(sio->mode), _modeName(newMode));
|
||||
if (sio->mode != (enum GBASIOMode) -1) {
|
||||
mLOG(GBA_SIO, DEBUG, "Switching mode from %s to %s", _modeName(sio->mode), _modeName(newMode));
|
||||
}
|
||||
sio->mode = newMode;
|
||||
sio->activeDriver = _lookupDriver(sio, sio->mode);
|
||||
if (sio->activeDriver && sio->activeDriver->load) {
|
||||
|
|
|
@ -113,6 +113,7 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
|
|||
node->d.p->siocnt = GBASIOMultiplayerFillSlave(node->d.p->siocnt);
|
||||
}
|
||||
break;
|
||||
case SIO_NORMAL_8:
|
||||
case SIO_NORMAL_32:
|
||||
ATOMIC_ADD(node->p->attachedNormal, 1);
|
||||
node->d.writeRegister = GBASIOLockstepNodeNormalWriteRegister;
|
||||
|
@ -140,6 +141,7 @@ bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) {
|
|||
case SIO_MULTI:
|
||||
ATOMIC_SUB(node->p->attachedMulti, 1);
|
||||
break;
|
||||
case SIO_NORMAL_8:
|
||||
case SIO_NORMAL_32:
|
||||
ATOMIC_SUB(node->p->attachedNormal, 1);
|
||||
break;
|
||||
|
@ -441,11 +443,22 @@ static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
|
|||
struct GBASIOLockstepNode* node = user;
|
||||
mLockstepLock(&node->p->d);
|
||||
|
||||
int32_t cycles = 0;
|
||||
int32_t cycles = cycles = node->nextEvent;
|
||||
node->nextEvent -= cyclesLate;
|
||||
node->eventDiff += cyclesLate;
|
||||
if (node->p->d.attached < 2) {
|
||||
cycles = GBASIOCyclesPerTransfer[GBASIOMultiplayerGetBaud(node->d.p->siocnt)][0];
|
||||
switch (node->mode) {
|
||||
case SIO_MULTI:
|
||||
cycles = GBASIOCyclesPerTransfer[GBASIOMultiplayerGetBaud(node->d.p->siocnt)][0];
|
||||
break;
|
||||
case SIO_NORMAL_8:
|
||||
case SIO_NORMAL_32:
|
||||
if (node->nextEvent <= 0) {
|
||||
cycles = _masterUpdate(node);
|
||||
node->eventDiff = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (node->nextEvent <= 0) {
|
||||
if (!node->id) {
|
||||
cycles = _masterUpdate(node);
|
||||
|
@ -454,8 +467,6 @@ static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
|
|||
cycles += node->p->d.useCycles(&node->p->d, node->id, node->eventDiff);
|
||||
}
|
||||
node->eventDiff = 0;
|
||||
} else {
|
||||
cycles = node->nextEvent;
|
||||
}
|
||||
if (cycles > 0) {
|
||||
node->nextEvent = 0;
|
||||
|
@ -519,6 +530,8 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
|
|||
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04X", node->id, value);
|
||||
} else if (address == REG_SIODATA32_HI) {
|
||||
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04X", node->id, value);
|
||||
} else if (address == REG_SIODATA8) {
|
||||
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA8 <- %02X", node->id, value);
|
||||
}
|
||||
|
||||
mLockstepUnlock(&node->p->d);
|
||||
|
|
|
@ -130,7 +130,10 @@ void GBAVideoAssociateRenderer(struct GBAVideo* video, struct GBAVideoRenderer*
|
|||
renderer->writeVideoRegister(renderer, REG_DISPCNT, video->p->memory.io[REG_DISPCNT >> 1]);
|
||||
renderer->writeVideoRegister(renderer, REG_GREENSWP, video->p->memory.io[REG_GREENSWP >> 1]);
|
||||
int address;
|
||||
for (address = REG_BG0CNT; address < REG_SOUND1CNT_LO; address += 2) {
|
||||
for (address = REG_BG0CNT; address < 0x56; address += 2) {
|
||||
if (address == 0x4E) {
|
||||
continue;
|
||||
}
|
||||
renderer->writeVideoRegister(renderer, address, video->p->memory.io[address >> 1]);
|
||||
}
|
||||
}
|
||||
|
@ -156,9 +159,6 @@ void _startHdraw(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
video->p->memory.io[REG_VCOUNT >> 1] = video->vcount;
|
||||
|
||||
if (video->vcount < GBA_VIDEO_VERTICAL_PIXELS) {
|
||||
if (video->frameskipCounter <= 0) {
|
||||
video->renderer->drawScanline(video->renderer, video->vcount);
|
||||
}
|
||||
video->shouldStall = 1;
|
||||
}
|
||||
|
||||
|
@ -210,6 +210,9 @@ void _startHblank(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
|||
// Begin Hblank
|
||||
GBARegisterDISPSTAT dispstat = video->p->memory.io[REG_DISPSTAT >> 1];
|
||||
dispstat = GBARegisterDISPSTATFillInHblank(dispstat);
|
||||
if (video->vcount < GBA_VIDEO_VERTICAL_PIXELS && video->frameskipCounter <= 0) {
|
||||
video->renderer->drawScanline(video->renderer, video->vcount);
|
||||
}
|
||||
|
||||
if (video->vcount < GBA_VIDEO_VERTICAL_PIXELS) {
|
||||
GBADMARunHblank(video->p, -cyclesLate);
|
||||
|
|
|
@ -845,10 +845,12 @@ int main() {
|
|||
gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, true);
|
||||
|
||||
u8 model = 0;
|
||||
cfguInit();
|
||||
CFGU_GetSystemModel(&model);
|
||||
if (model != 3 /* o2DS */) {
|
||||
gfxSetWide(true);
|
||||
}
|
||||
cfguExit();
|
||||
|
||||
if (!_initGpu()) {
|
||||
outputTexture[0].data = 0;
|
||||
|
|
|
@ -618,8 +618,8 @@ static void _setupMaps(struct mCore* core) {
|
|||
i++;
|
||||
|
||||
/* Map External RAM */
|
||||
if (gb->memory.sram) {
|
||||
descs[i].ptr = gb->memory.sram;
|
||||
if (savedataSize) {
|
||||
descs[i].ptr = savedata;
|
||||
descs[i].start = GB_BASE_EXTERNAL_RAM;
|
||||
descs[i].len = savedataSize;
|
||||
i++;
|
||||
|
@ -690,6 +690,7 @@ bool retro_load_game(const struct retro_game_info* game) {
|
|||
blip_set_rates(core->getAudioChannel(core, 1), core->frequency(core), 32768);
|
||||
|
||||
core->setPeripheral(core, mPERIPH_RUMBLE, &rumble);
|
||||
core->setPeripheral(core, mPERIPH_ROTATION, &rotation);
|
||||
|
||||
savedata = anonymousMemoryMap(SIZE_CART_FLASH1M);
|
||||
memset(savedata, 0xFF, SIZE_CART_FLASH1M);
|
||||
|
|
|
@ -87,7 +87,13 @@ void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, QWidget* conte
|
|||
}
|
||||
});
|
||||
QObject::connect(action, &Action::enabled, qaction, &QAction::setEnabled);
|
||||
QObject::connect(action, &Action::activated, qaction, &QAction::setChecked);
|
||||
QObject::connect(action, &Action::activated, [qaction, action](bool active) {
|
||||
if (qaction->isCheckable()) {
|
||||
qaction->setChecked(active);
|
||||
} else if (active) {
|
||||
action->setActive(false);
|
||||
}
|
||||
});
|
||||
QObject::connect(action, &Action::destroyed, qaction, &QAction::deleteLater);
|
||||
if (shortcut) {
|
||||
QObject::connect(shortcut, &Shortcut::shortcutChanged, qaction, [qaction](int shortcut) {
|
||||
|
|
|
@ -22,6 +22,7 @@ void AssetInfo::addCustomProperty(const QString& id, const QString& visibleName)
|
|||
QLabel* value = new QLabel;
|
||||
value->setFont(GBAApp::app()->monospaceFont());
|
||||
value->setAlignment(Qt::AlignRight);
|
||||
value->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
newLayout->addWidget(value);
|
||||
m_customProperties[id] = value;
|
||||
int index = customLocation();
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -74,6 +74,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -96,7 +99,7 @@
|
|||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -162,6 +165,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">0x00 (00)</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -169,6 +175,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">0x00 (00)</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -176,6 +185,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">0x00 (00)</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -22,7 +22,7 @@ endif()
|
|||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
find_package(Qt5 COMPONENTS Core Widgets OpenGL Network Multimedia)
|
||||
find_package(Qt5 COMPONENTS Core Widgets Network Multimedia)
|
||||
|
||||
if(NOT BUILD_GL AND NOT BUILD_GLES2)
|
||||
message(WARNING "OpenGL is recommended to build the Qt port")
|
||||
|
@ -165,7 +165,7 @@ set(GB_SRC
|
|||
PrinterView.cpp)
|
||||
|
||||
set(QT_LIBRARIES)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5,libqt5opengl5")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libqt5widgets5")
|
||||
|
||||
set(AUDIO_SRC)
|
||||
if(BUILD_SDL)
|
||||
|
@ -301,7 +301,7 @@ endif()
|
|||
|
||||
list(APPEND QT_LIBRARIES Qt5::Widgets Qt5::Network)
|
||||
if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY)
|
||||
list(APPEND QT_LIBRARIES Qt5::OpenGL ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
list(APPEND QT_LIBRARIES ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
endif()
|
||||
if(QT_STATIC)
|
||||
find_library(QTPCRE NAMES qtpcre2 qtpcre)
|
||||
|
|
|
@ -799,7 +799,7 @@ void CoreController::scanCard(const QString& path) {
|
|||
QFile file(path);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
m_eReaderData = file.read(2912);
|
||||
} else if (image.size() == QSize(989, 44)) {
|
||||
} else if (image.size() == QSize(989, 44) || image.size() == QSize(639, 44)) {
|
||||
const uchar* bits = image.constBits();
|
||||
size_t size;
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "DebuggerConsole.h"
|
||||
|
||||
#include "DebuggerConsoleController.h"
|
||||
#include "GBAApp.h"
|
||||
|
||||
#include <QScrollBar>
|
||||
|
||||
|
@ -18,6 +19,8 @@ DebuggerConsole::DebuggerConsole(DebuggerConsoleController* controller, QWidget*
|
|||
m_ui.setupUi(this);
|
||||
|
||||
m_ui.prompt->installEventFilter(this);
|
||||
m_ui.log->setFont(GBAApp::app()->monospaceFont());
|
||||
m_ui.prompt->setFont(GBAApp::app()->monospaceFont());
|
||||
|
||||
connect(m_ui.prompt, &QLineEdit::returnPressed, this, &DebuggerConsole::postLine);
|
||||
connect(controller, &DebuggerConsoleController::log, this, &DebuggerConsole::log);
|
||||
|
@ -81,4 +84,4 @@ bool DebuggerConsole::eventFilter(QObject*, QEvent* event) {
|
|||
m_ui.prompt->setText(m_history[m_history.size() - m_historyOffset]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,6 @@
|
|||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="prompt">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Source Code Pro</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Enter command (try `help` for more info)</string>
|
||||
</property>
|
||||
|
@ -35,11 +30,6 @@
|
|||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QPlainTextEdit" name="log">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Source Code Pro</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
|
@ -50,7 +50,7 @@ DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent)
|
|||
|
||||
m_painter = std::make_unique<PainterGL>(windowHandle(), format);
|
||||
m_drawThread.setObjectName("Painter Thread");
|
||||
m_painter->moveToThread(&m_drawThread);
|
||||
m_painter->setThread(&m_drawThread);
|
||||
|
||||
connect(&m_drawThread, &QThread::started, m_painter.get(), &PainterGL::create);
|
||||
connect(m_painter.get(), &PainterGL::started, this, [this] {
|
||||
|
@ -158,7 +158,6 @@ void DisplayGL::stopDrawing() {
|
|||
void DisplayGL::pauseDrawing() {
|
||||
if (m_hasStarted) {
|
||||
m_isDrawing = false;
|
||||
CoreController::Interrupter interrupter(m_context);
|
||||
QMetaObject::invokeMethod(m_painter.get(), "pause", Qt::BlockingQueuedConnection);
|
||||
#ifndef Q_OS_MAC
|
||||
setUpdatesEnabled(true);
|
||||
|
@ -169,7 +168,6 @@ void DisplayGL::pauseDrawing() {
|
|||
void DisplayGL::unpauseDrawing() {
|
||||
if (m_hasStarted) {
|
||||
m_isDrawing = true;
|
||||
CoreController::Interrupter interrupter(m_context);
|
||||
QMetaObject::invokeMethod(m_painter.get(), "unpause", Qt::BlockingQueuedConnection);
|
||||
#ifndef Q_OS_MAC
|
||||
setUpdatesEnabled(false);
|
||||
|
@ -265,6 +263,8 @@ PainterGL::PainterGL(QWindow* surface, const QSurfaceFormat& format)
|
|||
for (auto& buf : m_buffers) {
|
||||
m_free.append(&buf.front());
|
||||
}
|
||||
connect(&m_drawTimer, &QTimer::timeout, this, &PainterGL::draw);
|
||||
m_drawTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
PainterGL::~PainterGL() {
|
||||
|
@ -273,6 +273,11 @@ PainterGL::~PainterGL() {
|
|||
}
|
||||
}
|
||||
|
||||
void PainterGL::setThread(QThread* thread) {
|
||||
moveToThread(thread);
|
||||
m_drawTimer.moveToThread(thread);
|
||||
}
|
||||
|
||||
void PainterGL::makeCurrent() {
|
||||
m_gl->makeCurrent(m_surface);
|
||||
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||
|
@ -368,6 +373,10 @@ void PainterGL::resizeContext() {
|
|||
m_interrupter.resume();
|
||||
|
||||
QSize size = m_context->screenDimensions();
|
||||
if (m_dims == size) {
|
||||
return;
|
||||
}
|
||||
dequeueAll(false);
|
||||
m_backend->setDimensions(m_backend, size.width(), size.height());
|
||||
}
|
||||
|
||||
|
@ -425,40 +434,50 @@ void PainterGL::start() {
|
|||
}
|
||||
|
||||
void PainterGL::draw() {
|
||||
if (!m_active || m_queue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (m_lagging >= 1) {
|
||||
if (!m_started || m_queue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
mCoreSync* sync = &m_context->thread()->impl->sync;
|
||||
if (!mCoreSyncWaitFrameStart(sync)) {
|
||||
mCoreSyncWaitFrameEnd(sync);
|
||||
++m_lagging;
|
||||
if ((sync->audioWait || sync->videoFrameWait) && m_delayTimer.elapsed() < 1000 / m_surface->screen()->refreshRate()) {
|
||||
QTimer::singleShot(1, this, &PainterGL::draw);
|
||||
if (!sync->audioWait && !sync->videoFrameWait) {
|
||||
return;
|
||||
}
|
||||
if (m_delayTimer.elapsed() >= 1000 / m_surface->screen()->refreshRate()) {
|
||||
return;
|
||||
}
|
||||
if (!m_drawTimer.isActive()) {
|
||||
m_drawTimer.start(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
dequeue();
|
||||
if (m_videoProxy) {
|
||||
// Only block on the next frame if we're trying to run at roughly 60fps via audio
|
||||
m_videoProxy->setBlocking(sync->audioWait && std::abs(60.f - sync->fpsTarget) < 0.1f);
|
||||
}
|
||||
bool forceRedraw = !m_videoProxy;
|
||||
if (!m_delayTimer.isValid()) {
|
||||
m_delayTimer.start();
|
||||
} else {
|
||||
if (sync->audioWait || sync->videoFrameWait) {
|
||||
while (m_delayTimer.nsecsElapsed() + 2000000 < 1000000000 / sync->fpsTarget) {
|
||||
while (m_delayTimer.nsecsElapsed() + 1'000'000 < 1'000'000'000 / sync->fpsTarget) {
|
||||
QThread::usleep(500);
|
||||
}
|
||||
forceRedraw = sync->videoFrameWait;
|
||||
}
|
||||
if (!forceRedraw) {
|
||||
forceRedraw = m_delayTimer.nsecsElapsed() + 1'000'000 >= 1'000'000'000 / m_surface->screen()->refreshRate();
|
||||
}
|
||||
m_delayTimer.restart();
|
||||
}
|
||||
mCoreSyncWaitFrameEnd(sync);
|
||||
|
||||
performDraw();
|
||||
m_backend->swap(m_backend);
|
||||
if (forceRedraw) {
|
||||
m_delayTimer.restart();
|
||||
performDraw();
|
||||
m_backend->swap(m_backend);
|
||||
}
|
||||
|
||||
QMutexLocker locker(&m_mutex);
|
||||
if (!m_queue.isEmpty()) {
|
||||
QTimer::singleShot(1, this, &PainterGL::draw);
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::forceDraw() {
|
||||
|
@ -473,9 +492,10 @@ void PainterGL::forceDraw() {
|
|||
}
|
||||
|
||||
void PainterGL::stop() {
|
||||
m_drawTimer.stop();
|
||||
m_active = false;
|
||||
m_started = false;
|
||||
dequeueAll();
|
||||
dequeueAll(false);
|
||||
if (m_context) {
|
||||
if (m_videoProxy) {
|
||||
m_videoProxy->detach(m_context.get());
|
||||
|
@ -496,11 +516,12 @@ void PainterGL::stop() {
|
|||
}
|
||||
|
||||
void PainterGL::pause() {
|
||||
m_drawTimer.stop();
|
||||
m_active = false;
|
||||
dequeueAll(true);
|
||||
}
|
||||
|
||||
void PainterGL::unpause() {
|
||||
m_lagging = 0;
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
|
@ -534,7 +555,6 @@ void PainterGL::enqueue(const uint32_t* backing) {
|
|||
memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL);
|
||||
}
|
||||
}
|
||||
m_lagging = 0;
|
||||
m_queue.enqueue(buffer);
|
||||
}
|
||||
|
||||
|
@ -551,23 +571,24 @@ void PainterGL::dequeue() {
|
|||
m_buffer = buffer;
|
||||
}
|
||||
|
||||
void PainterGL::dequeueAll() {
|
||||
void PainterGL::dequeueAll(bool keep) {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
uint32_t* buffer = 0;
|
||||
m_mutex.lock();
|
||||
while (!m_queue.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
if (buffer) {
|
||||
if (keep) {
|
||||
if (m_buffer && buffer) {
|
||||
m_free.append(m_buffer);
|
||||
m_buffer = buffer;
|
||||
}
|
||||
} else if (buffer) {
|
||||
m_free.append(buffer);
|
||||
}
|
||||
}
|
||||
if (buffer) {
|
||||
m_backend->postFrame(m_backend, buffer);
|
||||
}
|
||||
if (m_buffer) {
|
||||
if (m_buffer && !keep) {
|
||||
m_free.append(m_buffer);
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void PainterGL::setVideoProxy(std::shared_ptr<VideoProxy> proxy) {
|
||||
|
|
|
@ -96,11 +96,13 @@ public:
|
|||
PainterGL(QWindow* surface, const QSurfaceFormat& format);
|
||||
~PainterGL();
|
||||
|
||||
void setThread(QThread*);
|
||||
void setContext(std::shared_ptr<CoreController>);
|
||||
void setMessagePainter(MessagePainter*);
|
||||
void enqueue(const uint32_t* backing);
|
||||
|
||||
bool supportsShaders() const { return m_supportsShaders; }
|
||||
int glTex();
|
||||
|
||||
void setVideoProxy(std::shared_ptr<VideoProxy>);
|
||||
void interrupt();
|
||||
|
@ -127,8 +129,6 @@ public slots:
|
|||
void clearShaders();
|
||||
VideoShader* shaders();
|
||||
|
||||
int glTex();
|
||||
|
||||
signals:
|
||||
void started();
|
||||
|
||||
|
@ -136,13 +136,12 @@ private:
|
|||
void makeCurrent();
|
||||
void performDraw();
|
||||
void dequeue();
|
||||
void dequeueAll();
|
||||
void dequeueAll(bool keep = false);
|
||||
|
||||
std::array<std::array<uint32_t, 0x100000>, 3> m_buffers;
|
||||
QList<uint32_t*> m_free;
|
||||
QQueue<uint32_t*> m_queue;
|
||||
QAtomicInt m_lagging = 0;
|
||||
uint32_t* m_buffer;
|
||||
uint32_t* m_buffer = nullptr;
|
||||
QPainter m_painter;
|
||||
QMutex m_mutex;
|
||||
QWindow* m_surface;
|
||||
|
@ -151,6 +150,7 @@ private:
|
|||
std::unique_ptr<QOpenGLContext> m_gl;
|
||||
bool m_active = false;
|
||||
bool m_started = false;
|
||||
QTimer m_drawTimer;
|
||||
std::shared_ptr<CoreController> m_context;
|
||||
CoreController::Interrupter m_interrupter;
|
||||
bool m_supportsShaders;
|
||||
|
@ -158,6 +158,7 @@ private:
|
|||
VideoShader m_shader{};
|
||||
VideoBackend* m_backend = nullptr;
|
||||
QSize m_size;
|
||||
QSize m_dims;
|
||||
MessagePainter* m_messagePainter = nullptr;
|
||||
QElapsedTimer m_delayTimer;
|
||||
std::shared_ptr<VideoProxy> m_videoProxy;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "GBAOverride.h"
|
||||
|
||||
#include <mgba/core/core.h>
|
||||
#include <mgba/internal/gba/gba.h>
|
||||
|
||||
using namespace QGBA;
|
||||
|
||||
|
@ -13,7 +14,11 @@ void GBAOverride::apply(struct mCore* core) {
|
|||
if (core->platform(core) != mPLATFORM_GBA) {
|
||||
return;
|
||||
}
|
||||
GBAOverrideApply(static_cast<GBA*>(core->board), &override);
|
||||
GBA* gba = static_cast<GBA*>(core->board);
|
||||
if (!vbaBugCompatSet) {
|
||||
override.vbaBugCompat = gba->vbaBugCompat;
|
||||
}
|
||||
GBAOverrideApply(gba, &override);
|
||||
}
|
||||
|
||||
void GBAOverride::identify(const struct mCore* core) {
|
||||
|
|
|
@ -18,6 +18,7 @@ public:
|
|||
void save(struct Configuration*) const override;
|
||||
|
||||
struct GBACartridgeOverride override;
|
||||
bool vbaBugCompatSet;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
<property name="text">
|
||||
<string>0x0000</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -98,19 +98,19 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren
|
|||
image->image.load(":/res/no-cam.png");
|
||||
}
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
if (image->p->m_config->getQtOption("cameraDriver").toInt() == static_cast<int>(CameraDriver::QT_MULTIMEDIA)) {
|
||||
QByteArray camera = image->p->m_config->getQtOption("camera").toByteArray();
|
||||
if (!camera.isNull()) {
|
||||
QMetaObject::invokeMethod(image->p, "setCamera", Q_ARG(QByteArray, camera));
|
||||
}
|
||||
QMetaObject::invokeMethod(image->p, "setupCam");
|
||||
image->p->m_cameraActive = true;
|
||||
QByteArray camera = image->p->m_config->getQtOption("camera").toByteArray();
|
||||
if (!camera.isNull()) {
|
||||
image->p->m_cameraDevice = camera;
|
||||
}
|
||||
QMetaObject::invokeMethod(image->p, "setupCam");
|
||||
#endif
|
||||
};
|
||||
|
||||
m_image.stopRequestImage = [](mImageSource* context) {
|
||||
InputControllerImage* image = static_cast<InputControllerImage*>(context);
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
image->p->m_cameraActive = false;
|
||||
QMetaObject::invokeMethod(image->p, "teardownCam");
|
||||
#endif
|
||||
};
|
||||
|
@ -766,10 +766,18 @@ void InputController::setLuminanceValue(uint8_t value) {
|
|||
|
||||
void InputController::setupCam() {
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
if (m_config->getQtOption("cameraDriver").toInt() != static_cast<int>(CameraDriver::QT_MULTIMEDIA)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_camera) {
|
||||
m_camera = std::make_unique<QCamera>();
|
||||
m_camera = std::make_unique<QCamera>(m_cameraDevice);
|
||||
connect(m_camera.get(), &QCamera::statusChanged, this, &InputController::prepareCamSettings, Qt::QueuedConnection);
|
||||
}
|
||||
if (m_camera->status() == QCamera::UnavailableStatus) {
|
||||
m_camera.reset();
|
||||
return;
|
||||
}
|
||||
m_camera->setCaptureMode(QCamera::CaptureVideo);
|
||||
m_camera->setViewfinder(&m_videoDumper);
|
||||
m_camera->load();
|
||||
|
@ -820,20 +828,22 @@ void InputController::prepareCamSettings(QCamera::Status status) {
|
|||
void InputController::teardownCam() {
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
if (m_camera) {
|
||||
m_camera->stop();
|
||||
m_camera->unload();
|
||||
m_camera.reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputController::setCamera(const QByteArray& name) {
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
bool needsRestart = false;
|
||||
if (m_camera) {
|
||||
needsRestart = m_camera->state() == QCamera::ActiveState;
|
||||
if (m_cameraDevice == name) {
|
||||
return;
|
||||
}
|
||||
m_camera = std::make_unique<QCamera>(name);
|
||||
connect(m_camera.get(), &QCamera::statusChanged, this, &InputController::prepareCamSettings, Qt::QueuedConnection);
|
||||
if (needsRestart) {
|
||||
m_cameraDevice = name;
|
||||
if (m_camera && m_camera->state() == QCamera::ActiveState) {
|
||||
teardownCam();
|
||||
}
|
||||
if (m_cameraActive) {
|
||||
setupCam();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -158,6 +158,8 @@ private:
|
|||
} m_image;
|
||||
|
||||
#ifdef BUILD_QT_MULTIMEDIA
|
||||
bool m_cameraActive = false;
|
||||
QByteArray m_cameraDevice;
|
||||
std::unique_ptr<QCamera> m_camera;
|
||||
VideoDumper m_videoDumper;
|
||||
#endif
|
||||
|
|
|
@ -131,15 +131,19 @@ void ObjView::updateTilesGBA(bool force) {
|
|||
m_objInfo = newInfo;
|
||||
m_tileOffset = newInfo.tile;
|
||||
mTileCache* tileCache = mTileCacheSetGetPointer(&m_cacheSet->tiles, newInfo.paletteSet);
|
||||
|
||||
unsigned maxTiles = mTileCacheSystemInfoGetMaxTiles(tileCache->sysConfig);
|
||||
int i = 0;
|
||||
for (unsigned y = 0; y < newInfo.height; ++y) {
|
||||
for (unsigned x = 0; x < newInfo.width; ++x, ++i, ++tile, ++tileBase) {
|
||||
const color_t* data = mTileCacheGetTileIfDirty(tileCache, &m_tileStatus[16 * tileBase], tile, newInfo.paletteId);
|
||||
if (data) {
|
||||
m_ui.tiles->setTile(i, data);
|
||||
} else if (force) {
|
||||
m_ui.tiles->setTile(i, mTileCacheGetTile(tileCache, tile, newInfo.paletteId));
|
||||
if (tile < maxTiles) {
|
||||
const color_t* data = mTileCacheGetTileIfDirty(tileCache, &m_tileStatus[16 * tileBase], tile, newInfo.paletteId);
|
||||
if (data) {
|
||||
m_ui.tiles->setTile(i, data);
|
||||
} else if (force) {
|
||||
m_ui.tiles->setTile(i, mTileCacheGetTile(tileCache, tile, newInfo.paletteId));
|
||||
}
|
||||
} else {
|
||||
m_ui.tiles->clearTile(i);
|
||||
}
|
||||
}
|
||||
tile += newInfo.stride - newInfo.width;
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -173,6 +173,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -199,6 +202,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -246,6 +252,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -272,6 +281,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -283,6 +295,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">+0.00</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
|
@ -290,6 +305,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">+1.00</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
|
@ -304,6 +322,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">+1.00</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
|
@ -324,6 +345,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">+0.00</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -405,6 +429,9 @@
|
|||
<property name="text">
|
||||
<string>Off</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -439,6 +466,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -564,6 +594,9 @@
|
|||
<property name="text">
|
||||
<string>Normal</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -669,6 +702,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -144,7 +144,11 @@ void OverrideView::updateOverrides() {
|
|||
gba->override.idleLoop = IDLE_LOOP_NONE;
|
||||
gba->override.mirroring = false;
|
||||
gba->override.vbaBugCompat = false;
|
||||
gba->vbaBugCompatSet = false;
|
||||
|
||||
if (gba->override.savetype != SAVEDATA_AUTODETECT) {
|
||||
hasOverride = true;
|
||||
}
|
||||
if (!m_ui.hwAutodetect->isChecked()) {
|
||||
hasOverride = true;
|
||||
gba->override.hardware = HW_NONE;
|
||||
|
@ -168,9 +172,10 @@ void OverrideView::updateOverrides() {
|
|||
hasOverride = true;
|
||||
gba->override.hardware |= HW_GB_PLAYER_DETECTION;
|
||||
}
|
||||
if (m_ui.vbaBugCompat->isChecked()) {
|
||||
if (m_ui.vbaBugCompat->checkState() != Qt::PartiallyChecked) {
|
||||
hasOverride = true;
|
||||
gba->override.vbaBugCompat = true;
|
||||
gba->vbaBugCompatSet = true;
|
||||
gba->override.vbaBugCompat = m_ui.vbaBugCompat->isChecked();
|
||||
}
|
||||
|
||||
bool ok;
|
||||
|
@ -270,7 +275,7 @@ void OverrideView::gameStopped() {
|
|||
m_ui.tabWidget->setEnabled(true);
|
||||
m_ui.savetype->setCurrentIndex(0);
|
||||
m_ui.idleLoop->clear();
|
||||
m_ui.vbaBugCompat->setChecked(false);
|
||||
m_ui.vbaBugCompat->setCheckState(Qt::PartiallyChecked);
|
||||
|
||||
m_ui.mbc->setCurrentIndex(0);
|
||||
m_ui.gbModel->setCurrentIndex(0);
|
||||
|
|
|
@ -143,7 +143,12 @@
|
|||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>EEPROM</string>
|
||||
<string>EEPROM 8kB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>EEPROM 512 bytes</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
@ -186,6 +191,12 @@
|
|||
<property name="text">
|
||||
<string>VBA bug compatibility mode</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checkState">
|
||||
<enum>Qt::PartiallyChecked</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -211,6 +211,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">0x00 (00)</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -218,6 +221,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">0x00 (00)</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -225,6 +231,9 @@
|
|||
<property name="text">
|
||||
<string notr="true">0x00 (00)</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -274,6 +283,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -284,6 +296,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -294,6 +309,9 @@
|
|||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -53,7 +53,7 @@
|
|||
<string>{TITLE}</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -70,7 +70,7 @@
|
|||
<string>{ID}</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -87,7 +87,7 @@
|
|||
<string>{SIZE}</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -104,7 +104,7 @@
|
|||
<string>{CRC}</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -98,6 +98,7 @@ ReportView::ReportView(QWidget* parent)
|
|||
QString description = m_ui.description->text();
|
||||
description.replace("{projectName}", QLatin1String(projectName));
|
||||
m_ui.description->setText(description);
|
||||
m_ui.fileView->setFont(GBAApp::app()->monospaceFont());
|
||||
|
||||
connect(m_ui.fileList, &QListWidget::currentTextChanged, this, &ReportView::setShownReport);
|
||||
}
|
||||
|
@ -245,6 +246,11 @@ void ReportView::generateReport() {
|
|||
|
||||
{
|
||||
CoreController::Interrupter interrupter(controller);
|
||||
QFileInfo rom(window->windowFilePath());
|
||||
if (rom.exists()) {
|
||||
windowReport << QString("Filename: %1").arg(redact(rom.filePath()));
|
||||
windowReport << QString("Size: %1").arg(rom.size());
|
||||
}
|
||||
addROMInfo(windowReport, controller.get());
|
||||
|
||||
if (m_ui.includeSave->isChecked() && !m_ui.includeState->isChecked()) {
|
||||
|
|
|
@ -50,11 +50,6 @@
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Monospace</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextEditorInteraction</set>
|
||||
</property>
|
||||
|
|
|
@ -79,14 +79,11 @@ void SensorView::setController(std::shared_ptr<CoreController> controller) {
|
|||
void SensorView::jiggerer(QAbstractButton* button, void (InputController::*setter)(int)) {
|
||||
connect(button, &QAbstractButton::toggled, [this, button, setter](bool checked) {
|
||||
if (!checked) {
|
||||
m_jiggered = nullptr;
|
||||
m_button = nullptr;
|
||||
} else {
|
||||
button->setFocus();
|
||||
m_jiggered = [this, button, setter](int axis) {
|
||||
(m_input->*setter)(axis);
|
||||
button->setChecked(false);
|
||||
button->clearFocus();
|
||||
};
|
||||
m_button = button;
|
||||
m_setter = setter;
|
||||
}
|
||||
});
|
||||
button->installEventFilter(this);
|
||||
|
@ -106,8 +103,12 @@ bool SensorView::eventFilter(QObject*, QEvent* event) {
|
|||
if (event->type() == GamepadAxisEvent::Type()) {
|
||||
GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event);
|
||||
gae->accept();
|
||||
if (m_jiggered && gae->direction() != GamepadAxisEvent::NEUTRAL && gae->isNew()) {
|
||||
m_jiggered(gae->axis());
|
||||
if (m_button && gae->direction() != GamepadAxisEvent::NEUTRAL && gae->isNew()) {
|
||||
m_button->removeEventFilter(this);
|
||||
m_button->clearFocus();
|
||||
m_button->setChecked(false);
|
||||
(m_input->*m_setter)(gae->axis());
|
||||
m_button = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,9 @@ private slots:
|
|||
private:
|
||||
Ui::SensorView m_ui;
|
||||
|
||||
std::function<void(int)> m_jiggered;
|
||||
QAbstractButton* m_button = nullptr;
|
||||
void (InputController::*m_setter)(int);
|
||||
|
||||
std::shared_ptr<CoreController> m_controller;
|
||||
InputController* m_input;
|
||||
mRotationSource* m_rotation;
|
||||
|
|
|
@ -429,6 +429,7 @@ void SettingsView::updateConfig() {
|
|||
saveSetting("dynamicTitle", m_ui.dynamicTitle);
|
||||
saveSetting("videoScale", m_ui.videoScale);
|
||||
saveSetting("gba.forceGbp", m_ui.forceGbp);
|
||||
saveSetting("vbaBugCompat", m_ui.vbaBugCompat);
|
||||
|
||||
if (m_ui.audioBufferSize->currentText().toInt() > 8192) {
|
||||
m_ui.audioBufferSize->setCurrentText("8192");
|
||||
|
@ -503,9 +504,12 @@ void SettingsView::updateConfig() {
|
|||
}
|
||||
|
||||
QVariant camera = m_ui.camera->itemData(m_ui.camera->currentIndex());
|
||||
if (camera != m_controller->getQtOption("camera")) {
|
||||
QVariant oldCamera = m_controller->getQtOption("camera");
|
||||
if (camera != oldCamera) {
|
||||
m_controller->setQtOption("camera", camera);
|
||||
emit cameraChanged(camera.toByteArray());
|
||||
if (!oldCamera.isNull()) {
|
||||
emit cameraChanged(camera.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
QLocale language = m_ui.languages->itemData(m_ui.languages->currentIndex()).toLocale();
|
||||
|
@ -619,6 +623,7 @@ void SettingsView::reloadConfig() {
|
|||
loadSetting("gba.audioHle", m_ui.audioHle);
|
||||
loadSetting("dynamicTitle", m_ui.dynamicTitle, true);
|
||||
loadSetting("gba.forceGbp", m_ui.forceGbp);
|
||||
loadSetting("vbaBugCompat", m_ui.vbaBugCompat, true);
|
||||
|
||||
m_ui.libraryStyle->setCurrentIndex(loadSetting("libraryStyle").toInt());
|
||||
|
||||
|
|
|
@ -399,6 +399,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QPushButton" name="nativeGB">
|
||||
<property name="text">
|
||||
<string>Native (59.7275)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="2">
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
|
@ -445,20 +452,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="resampleVideo">
|
||||
<property name="text">
|
||||
<string>Bilinear filtering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QPushButton" name="nativeGB">
|
||||
<property name="text">
|
||||
<string>Native (59.7275)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<widget class="QCheckBox" name="interframeBlending">
|
||||
<property name="text">
|
||||
|
@ -466,6 +459,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="resampleVideo">
|
||||
<property name="text">
|
||||
<string>Bilinear filtering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="interface_2">
|
||||
|
@ -586,6 +586,16 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QCheckBox" name="showFps">
|
||||
<property name="text">
|
||||
<string>Show FPS in title bar</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QCheckBox" name="showFilename">
|
||||
<property name="text">
|
||||
|
@ -596,6 +606,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="2">
|
||||
<widget class="Line" name="line_18">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="showOSD">
|
||||
<property name="text">
|
||||
|
@ -667,23 +684,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QCheckBox" name="showFps">
|
||||
<property name="text">
|
||||
<string>Show FPS in title bar</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="2">
|
||||
<widget class="Line" name="line_18">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="emulation">
|
||||
|
@ -873,21 +873,38 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="2">
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="forceGbp">
|
||||
<property name="text">
|
||||
<string>Enable Game Boy Player features by default</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="vbaBugCompat">
|
||||
<property name="text">
|
||||
<string>Enable VBA bug compatibility in ROM hacks</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0" colspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>Save state extra data:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="12" column="1">
|
||||
<widget class="QCheckBox" name="saveStateScreenshot">
|
||||
<property name="text">
|
||||
<string>Screenshot</string>
|
||||
|
@ -897,7 +914,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="13" column="1">
|
||||
<widget class="QCheckBox" name="saveStateSave">
|
||||
<property name="text">
|
||||
<string>Save game</string>
|
||||
|
@ -907,7 +924,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QCheckBox" name="saveStateCheats">
|
||||
<property name="text">
|
||||
<string>Cheat codes</string>
|
||||
|
@ -917,21 +934,21 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0" colspan="2">
|
||||
<item row="15" column="0" colspan="2">
|
||||
<widget class="Line" name="line_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string>Load state extra data:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<item row="16" column="1">
|
||||
<widget class="QCheckBox" name="loadStateScreenshot">
|
||||
<property name="text">
|
||||
<string>Screenshot</string>
|
||||
|
@ -941,27 +958,20 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<item row="17" column="1">
|
||||
<widget class="QCheckBox" name="loadStateSave">
|
||||
<property name="text">
|
||||
<string>Save game</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<item row="18" column="1">
|
||||
<widget class="QCheckBox" name="loadStateCheats">
|
||||
<property name="text">
|
||||
<string>Cheat codes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="forceGbp">
|
||||
<property name="text">
|
||||
<string>Enable Game Boy Player features by default</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="enhancements">
|
||||
|
@ -987,6 +997,13 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="audioHle">
|
||||
<property name="text">
|
||||
<string>XQ GBA audio (experimental)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="oglEnhance">
|
||||
<property name="title">
|
||||
|
@ -1056,13 +1073,6 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="audioHle">
|
||||
<property name="text">
|
||||
<string>XQ GBA audio (experimental)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="bios">
|
||||
|
@ -1095,79 +1105,6 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="useBios">
|
||||
<property name="text">
|
||||
<string>Use BIOS file if found</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="skipBios">
|
||||
<property name="text">
|
||||
<string>Skip BIOS intro</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gbaBios">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="gbaBiosBrowse">
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>GBA BIOS file:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>GBC BIOS file:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_30">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gbcBios">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="gbcBiosBrowse">
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
|
@ -1196,6 +1133,79 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>GBC BIOS file:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_30">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gbcBios">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="gbcBiosBrowse">
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>GBA BIOS file:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="gbaBios">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="gbaBiosBrowse">
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="useBios">
|
||||
<property name="text">
|
||||
<string>Use BIOS file if found</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="skipBios">
|
||||
<property name="text">
|
||||
<string>Skip BIOS intro</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="paths">
|
||||
|
@ -1523,6 +1533,19 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="cgbHybridModel"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_39">
|
||||
<property name="text">
|
||||
<string>Super Game Boy/Game Boy Color model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="cgbSgbModel"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="Line" name="line_12">
|
||||
<property name="orientation">
|
||||
|
@ -1849,19 +1872,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="cgbHybridModel"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_39">
|
||||
<property name="text">
|
||||
<string>Super Game Boy/Game Boy Color model:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="cgbSgbModel"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
|
|
@ -44,6 +44,16 @@ void TilePainter::mousePressEvent(QMouseEvent* event) {
|
|||
emit indexPressed(y * (width() / m_size) + x);
|
||||
}
|
||||
|
||||
void TilePainter::clearTile(int index) {
|
||||
QPainter painter(&m_backing);
|
||||
int w = width() / m_size;
|
||||
int x = index % w;
|
||||
int y = index / w;
|
||||
QRect r(x * m_size, y * m_size, m_size, m_size);
|
||||
painter.eraseRect(r);
|
||||
update(r);
|
||||
}
|
||||
|
||||
void TilePainter::setTile(int index, const color_t* data) {
|
||||
QPainter painter(&m_backing);
|
||||
int w = width() / m_size;
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
QPixmap backing() const { return m_backing; }
|
||||
|
||||
public slots:
|
||||
void clearTile(int index);
|
||||
void setTile(int index, const color_t*);
|
||||
void setTileCount(int tiles);
|
||||
void setTileMagnification(int mag);
|
||||
|
|
|
@ -14,7 +14,7 @@ using namespace QGBA;
|
|||
VideoProxy::VideoProxy() {
|
||||
mVideoLoggerRendererCreate(&m_logger.d, false);
|
||||
m_logger.d.block = true;
|
||||
m_logger.d.waitOnFlush = false;
|
||||
m_logger.d.waitOnFlush = true;
|
||||
|
||||
m_logger.d.init = &cbind<&VideoProxy::init>;
|
||||
m_logger.d.reset = &cbind<&VideoProxy::reset>;
|
||||
|
|
|
@ -620,6 +620,7 @@ void Window::showEvent(QShowEvent* event) {
|
|||
m_wasOpened = true;
|
||||
resizeFrame(m_screenWidget->sizeHint());
|
||||
QVariant windowPos = m_config->getQtOption("windowPos");
|
||||
bool maximized = m_config->getQtOption("maximized").toBool();
|
||||
QRect geom = windowHandle()->screen()->availableGeometry();
|
||||
if (!windowPos.isNull() && geom.contains(windowPos.toPoint())) {
|
||||
move(windowPos.toPoint());
|
||||
|
@ -628,6 +629,9 @@ void Window::showEvent(QShowEvent* event) {
|
|||
rect.moveCenter(geom.center());
|
||||
move(rect.topLeft());
|
||||
}
|
||||
if (maximized) {
|
||||
showMaximized();
|
||||
}
|
||||
if (m_fullscreenOnStart) {
|
||||
enterFullScreen();
|
||||
m_fullscreenOnStart = false;
|
||||
|
@ -652,6 +656,7 @@ void Window::hideEvent(QHideEvent* event) {
|
|||
void Window::closeEvent(QCloseEvent* event) {
|
||||
emit shutdown();
|
||||
m_config->setQtOption("windowPos", pos());
|
||||
m_config->setQtOption("maximized", isMaximized());
|
||||
|
||||
if (m_savedScale > 0) {
|
||||
m_config->setOption("height", GBA_VIDEO_VERTICAL_PIXELS * m_savedScale);
|
||||
|
|
|
@ -13,20 +13,14 @@
|
|||
|
||||
using namespace QGBA;
|
||||
|
||||
LibraryEntry::LibraryEntry(mLibraryEntry* entry)
|
||||
: entry(entry)
|
||||
, m_fullpath(QString("%1/%2").arg(entry->base, entry->filename))
|
||||
{
|
||||
}
|
||||
|
||||
void AbstractGameList::addEntries(QList<LibraryEntryRef> items) {
|
||||
for (LibraryEntryRef o : items) {
|
||||
addEntry(o);
|
||||
void AbstractGameList::addEntries(QList<mLibraryEntry*> items) {
|
||||
for (auto item : items) {
|
||||
addEntry(item);
|
||||
}
|
||||
}
|
||||
void AbstractGameList::removeEntries(QList<LibraryEntryRef> items) {
|
||||
for (LibraryEntryRef o : items) {
|
||||
removeEntry(o);
|
||||
void AbstractGameList::removeEntries(QList<mLibraryEntry*> items) {
|
||||
for (auto item : items) {
|
||||
removeEntry(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,39 +74,42 @@ void LibraryController::setViewStyle(LibraryStyle newStyle) {
|
|||
m_currentList = newCurrentList;
|
||||
}
|
||||
|
||||
void LibraryController::selectEntry(LibraryEntryRef entry) {
|
||||
void LibraryController::selectEntry(mLibraryEntry* entry) {
|
||||
if (!m_currentList) {
|
||||
return;
|
||||
}
|
||||
m_currentList->selectEntry(entry);
|
||||
}
|
||||
|
||||
LibraryEntryRef LibraryController::selectedEntry() {
|
||||
mLibraryEntry* LibraryController::selectedEntry() {
|
||||
if (!m_currentList) {
|
||||
return LibraryEntryRef();
|
||||
return nullptr;
|
||||
}
|
||||
return m_currentList->selectedEntry();
|
||||
}
|
||||
|
||||
VFile* LibraryController::selectedVFile() {
|
||||
LibraryEntryRef entry = selectedEntry();
|
||||
mLibraryEntry* entry = selectedEntry();
|
||||
if (entry) {
|
||||
return mLibraryOpenVFile(m_library.get(), entry->entry);
|
||||
return mLibraryOpenVFile(m_library.get(), entry);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
QPair<QString, QString> LibraryController::selectedPath() {
|
||||
LibraryEntryRef e = selectedEntry();
|
||||
return e ? qMakePair(e->base(), e->filename()) : qMakePair<QString, QString>("", "");
|
||||
mLibraryEntry* entry = selectedEntry();
|
||||
if (entry) {
|
||||
return qMakePair(QString(entry->base), QString(entry->filename));
|
||||
} else {
|
||||
return qMakePair(QString(), QString());
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryController::addDirectory(const QString& dir, bool recursive) {
|
||||
// The worker thread temporarily owns the library
|
||||
std::shared_ptr<mLibrary> library = m_library;
|
||||
m_libraryJob = GBAApp::app()->submitWorkerJob(std::bind(&LibraryController::loadDirectory, this, dir, recursive), this, [this, library]() {
|
||||
m_libraryJob = -1;
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
|
@ -133,26 +130,23 @@ void LibraryController::refresh() {
|
|||
|
||||
setDisabled(true);
|
||||
|
||||
QStringList allEntries;
|
||||
QList<LibraryEntryRef> newEntries;
|
||||
QSet<QString> allEntries;
|
||||
QList<mLibraryEntry*> newEntries;
|
||||
|
||||
freeLibrary();
|
||||
mLibraryGetEntries(m_library.get(), &m_listing, 0, 0, nullptr);
|
||||
for (size_t i = 0; i < mLibraryListingSize(&m_listing); i++) {
|
||||
mLibraryEntry* entry = mLibraryListingGetPointer(&m_listing, i);
|
||||
QString fullpath = QString("%1/%2").arg(entry->base, entry->filename);
|
||||
if (m_entries.contains(fullpath)) {
|
||||
m_entries.value(fullpath)->entry = entry;
|
||||
} else {
|
||||
LibraryEntryRef libentry = std::make_shared<LibraryEntry>(entry);
|
||||
m_entries.insert(fullpath, libentry);
|
||||
newEntries.append(libentry);
|
||||
if (!m_entries.contains(fullpath)) {
|
||||
newEntries.append(entry);
|
||||
}
|
||||
allEntries.append(fullpath);
|
||||
m_entries[fullpath] = entry;
|
||||
allEntries.insert(fullpath);
|
||||
}
|
||||
|
||||
// Check for entries that were removed
|
||||
QList<LibraryEntryRef> removedEntries;
|
||||
QList<mLibraryEntry*> removedEntries;
|
||||
for (QString& path : m_entries.keys()) {
|
||||
if (!allEntries.contains(path)) {
|
||||
removedEntries.append(m_entries.value(path));
|
||||
|
@ -184,7 +178,9 @@ void LibraryController::selectLastBootedGame() {
|
|||
void LibraryController::loadDirectory(const QString& dir, bool recursive) {
|
||||
// This class can get deleted during this function (sigh) so we need to hold onto this
|
||||
std::shared_ptr<mLibrary> library = m_library;
|
||||
qint64 libraryJob = m_libraryJob;
|
||||
mLibraryLoadDirectory(library.get(), dir.toUtf8().constData(), recursive);
|
||||
m_libraryJob.testAndSetOrdered(libraryJob, -1);
|
||||
}
|
||||
|
||||
void LibraryController::freeLibrary() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (c) 2014-2017 waddlesplash
|
||||
* Copyright (c) 2014-2020 Jeffrey Pfau
|
||||
* Copyright (c) 2014-2021 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
|
@ -8,8 +8,9 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include <QAtomicInteger>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include <mgba/core/library.h>
|
||||
|
@ -28,40 +29,18 @@ enum class LibraryStyle {
|
|||
STYLE_ICON
|
||||
};
|
||||
|
||||
class LibraryEntry final {
|
||||
public:
|
||||
LibraryEntry(mLibraryEntry* entry);
|
||||
|
||||
QString displayTitle() const { return title().isNull() ? filename() : title(); }
|
||||
|
||||
QString base() const { return QString(entry->base); }
|
||||
QString filename() const { return QString(entry->filename); }
|
||||
QString fullpath() const { return m_fullpath; }
|
||||
QString title() const { return QString(entry->title); }
|
||||
QByteArray internalTitle() const { return QByteArray(entry->internalTitle); }
|
||||
QByteArray internalCode() const { return QByteArray(entry->internalCode); }
|
||||
mPlatform platform() const { return entry->platform; }
|
||||
size_t filesize() const { return entry->filesize; }
|
||||
uint32_t crc32() const { return entry->crc32; }
|
||||
|
||||
const mLibraryEntry* entry;
|
||||
private:
|
||||
const QString m_fullpath;
|
||||
};
|
||||
typedef std::shared_ptr<LibraryEntry> LibraryEntryRef;
|
||||
|
||||
class AbstractGameList {
|
||||
public:
|
||||
virtual LibraryEntryRef selectedEntry() = 0;
|
||||
virtual void selectEntry(LibraryEntryRef game) = 0;
|
||||
virtual mLibraryEntry* selectedEntry() = 0;
|
||||
virtual void selectEntry(mLibraryEntry* game) = 0;
|
||||
|
||||
virtual void setViewStyle(LibraryStyle newStyle) = 0;
|
||||
|
||||
virtual void addEntry(LibraryEntryRef item) = 0;
|
||||
virtual void addEntries(QList<LibraryEntryRef> items);
|
||||
virtual void addEntry(mLibraryEntry* item) = 0;
|
||||
virtual void addEntries(QList<mLibraryEntry*> items);
|
||||
|
||||
virtual void removeEntry(LibraryEntryRef item) = 0;
|
||||
virtual void removeEntries(QList<LibraryEntryRef> items);
|
||||
virtual void removeEntry(mLibraryEntry* item) = 0;
|
||||
virtual void removeEntries(QList<mLibraryEntry*> items);
|
||||
|
||||
virtual QWidget* widget() = 0;
|
||||
};
|
||||
|
@ -77,8 +56,8 @@ public:
|
|||
LibraryStyle viewStyle() const { return m_currentStyle; }
|
||||
void setViewStyle(LibraryStyle newStyle);
|
||||
|
||||
void selectEntry(LibraryEntryRef entry);
|
||||
LibraryEntryRef selectedEntry();
|
||||
void selectEntry(mLibraryEntry* entry);
|
||||
mLibraryEntry* selectedEntry();
|
||||
VFile* selectedVFile();
|
||||
QPair<QString, QString> selectedPath();
|
||||
|
||||
|
@ -102,9 +81,9 @@ private:
|
|||
|
||||
ConfigController* m_config = nullptr;
|
||||
std::shared_ptr<mLibrary> m_library;
|
||||
qint64 m_libraryJob = -1;
|
||||
QAtomicInteger<qint64> m_libraryJob = -1;
|
||||
mLibraryListing m_listing;
|
||||
QMap<QString, LibraryEntryRef> m_entries;
|
||||
QHash<QString, mLibraryEntry*> m_entries;
|
||||
|
||||
LibraryStyle m_currentStyle;
|
||||
AbstractGameList* m_currentList = nullptr;
|
||||
|
|
|
@ -23,15 +23,15 @@ LibraryGrid::~LibraryGrid() {
|
|||
delete m_widget;
|
||||
}
|
||||
|
||||
LibraryEntryRef LibraryGrid::selectedEntry() {
|
||||
mLibraryEntry* LibraryGrid::selectedEntry() {
|
||||
if (!m_widget->selectedItems().empty()) {
|
||||
return m_items.key(m_widget->selectedItems().at(0));
|
||||
} else {
|
||||
return LibraryEntryRef();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryGrid::selectEntry(LibraryEntryRef game) {
|
||||
void LibraryGrid::selectEntry(mLibraryEntry* game) {
|
||||
if (!game) {
|
||||
return;
|
||||
}
|
||||
|
@ -56,19 +56,19 @@ void LibraryGrid::setViewStyle(LibraryStyle newStyle) {
|
|||
m_widget->setDragEnabled(false);
|
||||
}
|
||||
|
||||
void LibraryGrid::addEntry(LibraryEntryRef item) {
|
||||
void LibraryGrid::addEntry(mLibraryEntry* item) {
|
||||
if (m_items.contains(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QListWidgetItem* i = new QListWidgetItem;
|
||||
i->setText(item->displayTitle());
|
||||
i->setText(item->title ? item->title : item->filename);
|
||||
|
||||
m_widget->addItem(i);
|
||||
m_items.insert(item, i);
|
||||
}
|
||||
|
||||
void LibraryGrid::removeEntry(LibraryEntryRef entry) {
|
||||
void LibraryGrid::removeEntry(mLibraryEntry* entry) {
|
||||
if (!m_items.contains(entry)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -17,13 +17,13 @@ public:
|
|||
~LibraryGrid();
|
||||
|
||||
// AbstractGameList stuff
|
||||
virtual LibraryEntryRef selectedEntry() override;
|
||||
virtual void selectEntry(LibraryEntryRef game) override;
|
||||
virtual mLibraryEntry* selectedEntry() override;
|
||||
virtual void selectEntry(mLibraryEntry* game) override;
|
||||
|
||||
virtual void setViewStyle(LibraryStyle newStyle) override;
|
||||
|
||||
virtual void addEntry(LibraryEntryRef item) override;
|
||||
virtual void removeEntry(LibraryEntryRef entry) override;
|
||||
virtual void addEntry(mLibraryEntry* item) override;
|
||||
virtual void removeEntry(mLibraryEntry* entry) override;
|
||||
|
||||
virtual QWidget* widget() override { return m_widget; }
|
||||
|
||||
|
@ -40,7 +40,7 @@ private:
|
|||
const quint32 ICON_BANNER_WIDTH = 64;
|
||||
const quint32 ICON_BANNER_HEIGHT = 64;
|
||||
|
||||
QMap<LibraryEntryRef, QListWidgetItem*> m_items;
|
||||
QHash<mLibraryEntry*, QListWidgetItem*> m_items;
|
||||
LibraryStyle m_currentStyle;
|
||||
};
|
||||
|
||||
|
|
|
@ -74,15 +74,15 @@ void LibraryTree::resizeAllCols() {
|
|||
}
|
||||
}
|
||||
|
||||
LibraryEntryRef LibraryTree::selectedEntry() {
|
||||
mLibraryEntry* LibraryTree::selectedEntry() {
|
||||
if (!m_widget->selectedItems().empty()) {
|
||||
return m_items.key(m_widget->selectedItems().at(0));
|
||||
} else {
|
||||
return LibraryEntryRef();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LibraryTree::selectEntry(LibraryEntryRef game) {
|
||||
void LibraryTree::selectEntry(mLibraryEntry* game) {
|
||||
if (!game) {
|
||||
return;
|
||||
}
|
||||
|
@ -104,19 +104,19 @@ void LibraryTree::setViewStyle(LibraryStyle newStyle) {
|
|||
}
|
||||
}
|
||||
|
||||
void LibraryTree::addEntries(QList<LibraryEntryRef> items) {
|
||||
void LibraryTree::addEntries(QList<mLibraryEntry*> items) {
|
||||
m_deferredTreeRebuild = true;
|
||||
AbstractGameList::addEntries(items);
|
||||
m_deferredTreeRebuild = false;
|
||||
rebuildTree();
|
||||
}
|
||||
|
||||
void LibraryTree::addEntry(LibraryEntryRef item) {
|
||||
void LibraryTree::addEntry(mLibraryEntry* item) {
|
||||
if (m_items.contains(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString folder = item->base();
|
||||
QString folder = item->base;
|
||||
if (!m_pathNodes.contains(folder)) {
|
||||
QTreeWidgetItem* i = new TreeWidgetItem;
|
||||
i->setText(0, folder.section("/", -1));
|
||||
|
@ -127,18 +127,18 @@ void LibraryTree::addEntry(LibraryEntryRef item) {
|
|||
}
|
||||
|
||||
TreeWidgetItem* i = new TreeWidgetItem;
|
||||
i->setText(COL_NAME, item->displayTitle());
|
||||
i->setText(COL_LOCATION, QDir::toNativeSeparators(item->base()));
|
||||
i->setText(COL_PLATFORM, nicePlatformFormat(item->platform()));
|
||||
i->setFilesize(item->filesize());
|
||||
i->setText(COL_NAME, item->title ? item->title : item->filename);
|
||||
i->setText(COL_LOCATION, QDir::toNativeSeparators(item->base));
|
||||
i->setText(COL_PLATFORM, nicePlatformFormat(item->platform));
|
||||
i->setFilesize(item->filesize);
|
||||
i->setTextAlignment(COL_SIZE, Qt::AlignRight);
|
||||
i->setText(COL_CRC32, QString("%0").arg(item->crc32(), 8, 16, QChar('0')));
|
||||
i->setText(COL_CRC32, QString("%0").arg(item->crc32, 8, 16, QChar('0')));
|
||||
m_items.insert(item, i);
|
||||
|
||||
rebuildTree();
|
||||
}
|
||||
|
||||
void LibraryTree::removeEntry(LibraryEntryRef item) {
|
||||
void LibraryTree::removeEntry(mLibraryEntry* item) {
|
||||
if (!m_items.contains(item)) {
|
||||
return;
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ void LibraryTree::rebuildTree() {
|
|||
return;
|
||||
}
|
||||
|
||||
LibraryEntryRef currentGame = selectedEntry();
|
||||
mLibraryEntry* currentGame = selectedEntry();
|
||||
|
||||
int count = m_widget->topLevelItemCount();
|
||||
for (int a = count - 1; a >= 0; --a) {
|
||||
|
@ -166,7 +166,7 @@ void LibraryTree::rebuildTree() {
|
|||
m_widget->addTopLevelItem(i);
|
||||
}
|
||||
for (QTreeWidgetItem* i : m_items.values()) {
|
||||
m_pathNodes.value(m_items.key(i)->base())->addChild(i);
|
||||
m_pathNodes.value(m_items.key(i)->base)->addChild(i);
|
||||
}
|
||||
} else {
|
||||
for (QTreeWidgetItem* i : m_items.values()) {
|
||||
|
|
|
@ -26,14 +26,14 @@ public:
|
|||
~LibraryTree();
|
||||
|
||||
// AbstractGameList stuff
|
||||
virtual LibraryEntryRef selectedEntry() override;
|
||||
virtual void selectEntry(LibraryEntryRef game) override;
|
||||
virtual mLibraryEntry* selectedEntry() override;
|
||||
virtual void selectEntry(mLibraryEntry* game) override;
|
||||
|
||||
virtual void setViewStyle(LibraryStyle newStyle) override;
|
||||
|
||||
virtual void addEntries(QList<LibraryEntryRef> items) override;
|
||||
virtual void addEntry(LibraryEntryRef item) override;
|
||||
virtual void removeEntry(LibraryEntryRef item) override;
|
||||
virtual void addEntries(QList<mLibraryEntry*> items) override;
|
||||
virtual void addEntry(mLibraryEntry* item) override;
|
||||
virtual void removeEntry(mLibraryEntry* item) override;
|
||||
|
||||
virtual QWidget* widget() override { return m_widget; }
|
||||
|
||||
|
@ -44,8 +44,8 @@ private:
|
|||
LibraryController* m_controller;
|
||||
|
||||
bool m_deferredTreeRebuild = false;
|
||||
QMap<LibraryEntryRef, QTreeWidgetItem*> m_items;
|
||||
QMap<QString, QTreeWidgetItem*> m_pathNodes;
|
||||
QHash<mLibraryEntry*, QTreeWidgetItem*> m_items;
|
||||
QHash<QString, QTreeWidgetItem*> m_pathNodes;
|
||||
|
||||
void rebuildTree();
|
||||
void resizeAllCols();
|
||||
|
|
|
@ -61,9 +61,17 @@ int main(int argc, char* argv[]) {
|
|||
mSubParser subparser;
|
||||
initParserForGraphics(&subparser, &graphicsOpts);
|
||||
bool loaded = configController.parseArguments(&args, argc, argv, &subparser);
|
||||
if (loaded && args.showHelp) {
|
||||
usage(argv[0], subparser.usage);
|
||||
return 0;
|
||||
if (loaded) {
|
||||
if (args.showHelp) {
|
||||
usage(argv[0], subparser.usage);
|
||||
freeArguments(&args);
|
||||
return 0;
|
||||
}
|
||||
if (args.showVersion) {
|
||||
version(argv[0]);
|
||||
freeArguments(&args);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
QApplication::setApplicationName(projectName);
|
||||
|
@ -79,7 +87,7 @@ int main(int argc, char* argv[]) {
|
|||
GBAApp application(argc, argv, &configController);
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
QApplication::setWindowIcon(QIcon(":/res/mgba-1024.png"));
|
||||
QApplication::setWindowIcon(QIcon(":/res/mgba-256.png"));
|
||||
#endif
|
||||
|
||||
QTranslator qtTranslator;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<RCC version="1.0">
|
||||
<qresource>
|
||||
<file>../../../res/mgba-1024.png</file>
|
||||
<file>../../../res/mgba-256.png</file>
|
||||
<file>../../../res/keymap.qpic</file>
|
||||
<file>../../../res/patrons.txt</file>
|
||||
<file>../../../res/no-cam.png</file>
|
||||
|
|
|
@ -48,8 +48,10 @@ endif()
|
|||
if(WIN32)
|
||||
list(APPEND SDL_LIBRARY imm32 setupapi version winmm)
|
||||
elseif(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit -framework AudioUnit -framework Carbon -framework CoreAudio -framework AudioToolbox -framework ForceFeedback -framework IOKit")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" PARENT_SCOPE)
|
||||
list(APPEND SDL_LIBRARY "-framework AppKit" "-framework AudioUnit" "-framework Carbon" "-framework CoreAudio" "-framework AudioToolbox" "-framework ForceFeedback" "-framework IOKit")
|
||||
if(NOT CMAKE_SYSTEM_VERSION VERSION_LESS "17.0") # Darwin 17.x is macOS 10.13
|
||||
list(APPEND SDL_LIBRARY "-framework Metal")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT SDLMAIN_LIBRARY)
|
||||
|
|
|
@ -124,7 +124,7 @@ static enum ScreenMode {
|
|||
SM_MAX
|
||||
} screenMode = SM_PA;
|
||||
|
||||
static bool initEgl() {
|
||||
static bool eglInit() {
|
||||
s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (!s_display) {
|
||||
goto _fail0;
|
||||
|
@ -173,7 +173,7 @@ _fail0:
|
|||
return false;
|
||||
}
|
||||
|
||||
static void deinitEgl() {
|
||||
static void eglDeinit() {
|
||||
if (s_display) {
|
||||
eglMakeCurrent(s_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (s_context) {
|
||||
|
@ -186,7 +186,7 @@ static void deinitEgl() {
|
|||
}
|
||||
}
|
||||
|
||||
static void _mapKey(struct mInputMap* map, uint32_t binding, int nativeKey, enum GBAKey key) {
|
||||
static void _mapKey(struct mInputMap* map, uint32_t binding, int nativeKey, int key) {
|
||||
mInputBindKey(map, binding, __builtin_ctz(nativeKey), key);
|
||||
}
|
||||
|
||||
|
@ -659,7 +659,7 @@ static int _batteryState(void) {
|
|||
} else {
|
||||
return BATTERY_NOT_PRESENT;
|
||||
}
|
||||
ChargerType type;
|
||||
PsmChargerType type;
|
||||
if (R_SUCCEEDED(psmGetChargerType(&type)) && type) {
|
||||
state |= BATTERY_CHARGING;
|
||||
}
|
||||
|
@ -674,29 +674,7 @@ static void _guiFinish(void) {
|
|||
GUIFontDrawSubmit(font);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
NWindow* window = nwindowGetDefault();
|
||||
nwindowSetDimensions(window, 1920, 1080);
|
||||
|
||||
socketInitializeDefault();
|
||||
nxlinkStdio();
|
||||
initEgl();
|
||||
romfsInit();
|
||||
audoutInitialize();
|
||||
psmInitialize();
|
||||
|
||||
font = GUIFontCreate();
|
||||
|
||||
vmode = appletGetOperationMode();
|
||||
if (vmode == AppletOperationMode_Console) {
|
||||
vwidth = 1920;
|
||||
vheight = 1080;
|
||||
} else {
|
||||
vwidth = 1280;
|
||||
vheight = 720;
|
||||
}
|
||||
nwindowSetCrop(window, 0, 0, vwidth, vheight);
|
||||
|
||||
static void glInit(void) {
|
||||
glViewport(0, 1080 - vheight, vwidth, vheight);
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
|
@ -783,7 +761,23 @@ int main(int argc, char* argv[]) {
|
|||
glVertexAttribPointer(offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
||||
glEnableVertexAttribArray(offsetLocation);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
static void glDeinit(void) {
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &pbo);
|
||||
|
||||
glDeleteFramebuffers(1, ©Fbo);
|
||||
glDeleteTextures(1, &tex);
|
||||
glDeleteTextures(1, &oldTex);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteProgram(program);
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
}
|
||||
|
||||
static void hidSetup(void) {
|
||||
hidInitializeTouchScreen();
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
padInitializeDefault(&pad);
|
||||
|
@ -808,6 +802,40 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
lightSensor.d.readLuminance = _lightSensorRead;
|
||||
lightSensor.d.sample = _lightSensorSample;
|
||||
}
|
||||
|
||||
static void hidTeardown(void) {
|
||||
hidStopSixAxisSensor(sixaxisHandles[0]);
|
||||
hidStopSixAxisSensor(sixaxisHandles[1]);
|
||||
hidStopSixAxisSensor(sixaxisHandles[2]);
|
||||
hidStopSixAxisSensor(sixaxisHandles[3]);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
NWindow* window = nwindowGetDefault();
|
||||
nwindowSetDimensions(window, 1920, 1080);
|
||||
|
||||
socketInitializeDefault();
|
||||
nxlinkStdio();
|
||||
eglInit();
|
||||
romfsInit();
|
||||
audoutInitialize();
|
||||
psmInitialize();
|
||||
|
||||
font = GUIFontCreate();
|
||||
|
||||
vmode = appletGetOperationMode();
|
||||
if (vmode == AppletOperationMode_Console) {
|
||||
vwidth = 1920;
|
||||
vheight = 1080;
|
||||
} else {
|
||||
vwidth = 1280;
|
||||
vheight = 720;
|
||||
}
|
||||
nwindowSetCrop(window, 0, 0, vwidth, vheight);
|
||||
|
||||
glInit();
|
||||
hidSetup();
|
||||
|
||||
stream.videoDimensionsChanged = NULL;
|
||||
stream.postVideoFrame = NULL;
|
||||
|
@ -1028,27 +1056,13 @@ int main(int argc, char* argv[]) {
|
|||
audoutStopAudioOut();
|
||||
GUIFontDestroy(font);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glDeleteBuffers(1, &pbo);
|
||||
|
||||
glDeleteFramebuffers(1, ©Fbo);
|
||||
glDeleteTextures(1, &tex);
|
||||
glDeleteTextures(1, &oldTex);
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteProgram(program);
|
||||
glDeleteVertexArrays(1, &vao);
|
||||
|
||||
hidStopSixAxisSensor(sixaxisHandles[0]);
|
||||
hidStopSixAxisSensor(sixaxisHandles[1]);
|
||||
hidStopSixAxisSensor(sixaxisHandles[2]);
|
||||
hidStopSixAxisSensor(sixaxisHandles[3]);
|
||||
glDeinit();
|
||||
hidTeardown();
|
||||
|
||||
psmExit();
|
||||
audoutExit();
|
||||
romfsExit();
|
||||
deinitEgl();
|
||||
eglDeinit();
|
||||
socketExit();
|
||||
return 0;
|
||||
}
|
||||
|
|