mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' into medusa
This commit is contained in:
commit
bf97b7b52e
20
CHANGES
20
CHANGES
|
@ -38,24 +38,44 @@ Features:
|
|||
- Presets for Game Boy palettes
|
||||
- Add Super Game Boy palettes for original Game Boy games
|
||||
- Tool for converting scanned pictures of e-Reader cards to raw dotcode data
|
||||
- Options for muting when inactive, minimized, or for different players in multiplayer
|
||||
- Cheat code support in homebrew ports
|
||||
- Support for combo "Super Game Boy Color" SGB + GBC ROM hacks
|
||||
- Support for 64 kiB SRAM saves used in some bootlegs
|
||||
- Discord Rich Presence now supports time elapsed
|
||||
- Additional scaling shaders
|
||||
Emulation fixes:
|
||||
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
|
||||
- GB Video: Clear VRAM on reset (fixes mgba.io/i/2152)
|
||||
- GBA: Improve timing when not booting from BIOS
|
||||
- GBA SIO: Add missing NORMAL8 implementation bits (fixes mgba.io/i/2172)
|
||||
- GBA SIO: Fix missing interrupt on an unattached NORMAL transfer
|
||||
- GBA SIO: Fix SI value for unattached MULTI mode
|
||||
- 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
|
||||
- Core: Don't attempt to restore rewind diffs past start of rewind
|
||||
- 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)
|
||||
- GBA: Fix out of bounds ROM accesses on patched ROMs smaller than 32 MiB
|
||||
- mGUI: Cache save state screenshot validity in state menu (fixes mgba.io/i/2005)
|
||||
- Qt: Fix infrequent 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
|
||||
- Util: Fix loading UPS patches that affect the last byte of the file
|
||||
Misc:
|
||||
- Core: Suspend runloop when a core crashes
|
||||
- Qt: Rearrange menus some
|
||||
- Qt: Clean up cheats dialog
|
||||
- Qt: Only set default controller bindings if loading fails (fixes mgba.io/i/799)
|
||||
- Util: Improve speed of UPS patch loading
|
||||
|
||||
0.9.1: (2021-04-18)
|
||||
|
|
|
@ -232,7 +232,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()
|
||||
|
@ -599,8 +600,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()
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ The following mappers are partially supported:
|
|||
Supported Platforms
|
||||
-------------------
|
||||
|
||||
- Windows Vista or newer
|
||||
- Windows 7 or newer
|
||||
- OS X 10.8 (Mountain Lion)[<sup>[4]</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: 528 B After Width: | Height: | Size: 528 B |
Binary file not shown.
|
@ -1,17 +1,17 @@
|
|||
; this file was created with wlalink by ville helin <vhelin@iki.fi>.
|
||||
; wla symbolic information for "/home/vicki/Scratch/mooneye-gb/tests/build/emulator-only/mbc1/ram_256Kb.gb".
|
||||
; wla symbolic information for "/home/vicki/Scratch/mooneye-gb/tests/build/emulator-only/mbc1/ram_256kb.gb".
|
||||
|
||||
[labels]
|
||||
01:48bd clear_vram
|
||||
01:487a disable_lcd_safe
|
||||
01:4880 disable_lcd_safe@wait_ly_0
|
||||
01:4898 memcmp
|
||||
01:48c7 memcpy
|
||||
01:48d0 memset
|
||||
01:48e0 print_inline_string
|
||||
01:48a6 print_load_font
|
||||
01:48b2 print_newline
|
||||
01:48d9 print_string
|
||||
01:48c7 clear_vram
|
||||
01:4884 disable_lcd_safe
|
||||
01:488a disable_lcd_safe@wait_ly_0
|
||||
01:48a2 memcmp
|
||||
01:48d1 memcpy
|
||||
01:48da memset
|
||||
01:48ea print_inline_string
|
||||
01:48b0 print_load_font
|
||||
01:48bc print_newline
|
||||
01:48e3 print_string
|
||||
01:47f0 quit
|
||||
01:4805 quit@cb_return
|
||||
01:480a quit@wait_ly_1
|
||||
|
@ -20,24 +20,24 @@
|
|||
01:481c quit@wait_ly_4
|
||||
01:4826 quit@success
|
||||
01:484d quit@failure
|
||||
01:4862 quit@halt
|
||||
01:4863 quit@halt_execution_0
|
||||
01:4866 reset_screen
|
||||
01:4889 serial_send_byte
|
||||
01:486c quit@halt
|
||||
01:486d quit@halt_execution_0
|
||||
01:4870 reset_screen
|
||||
01:4893 serial_send_byte
|
||||
01:4000 font
|
||||
00:0150 main
|
||||
00:0150 test_round1
|
||||
00:016e test_round2
|
||||
00:01d2 test_round3
|
||||
00:0232 test_round4
|
||||
00:02a0 test_round5
|
||||
00:02fc test_round6
|
||||
00:0330 test_finish
|
||||
00:033a test_finish@quit_inline_1
|
||||
00:034b copy_bank_data
|
||||
00:036a check_bank_data
|
||||
00:038a all_ff
|
||||
00:039a all_00
|
||||
00:015f test_round1
|
||||
00:017d test_round2
|
||||
00:01e1 test_round3
|
||||
00:0241 test_round4
|
||||
00:02af test_round5
|
||||
00:030b test_round6
|
||||
00:033f test_finish
|
||||
00:0349 test_finish@quit_inline_1
|
||||
00:035a copy_bank_data
|
||||
00:0379 check_bank_data
|
||||
00:0399 all_ff
|
||||
00:03a9 all_00
|
||||
00:1000 bank_data
|
||||
00:1040 clear_ram
|
||||
00:1062 fail_round1
|
||||
|
@ -52,6 +52,7 @@
|
|||
00:10f0 fail_round5@quit_inline_6
|
||||
00:1107 fail_round6
|
||||
00:1111 fail_round6@quit_inline_7
|
||||
00:ff80 memcmp_hram
|
||||
|
||||
[definitions]
|
||||
0000000a _sizeof_clear_vram
|
||||
|
@ -63,12 +64,13 @@
|
|||
0000000c _sizeof_print_load_font
|
||||
0000000b _sizeof_print_newline
|
||||
00000007 _sizeof_print_string
|
||||
00000076 _sizeof_quit
|
||||
00000080 _sizeof_quit
|
||||
00000014 _sizeof_reset_screen
|
||||
0000000f _sizeof_serial_send_byte
|
||||
000007f0 _sizeof_font
|
||||
00000000 _sizeof_test_round1
|
||||
0000001e _sizeof_main
|
||||
00000020 _sizeof_memcmp_hram
|
||||
0000000f _sizeof_main
|
||||
0000001e _sizeof_test_round1
|
||||
00000064 _sizeof_test_round2
|
||||
00000060 _sizeof_test_round3
|
||||
0000006e _sizeof_test_round4
|
||||
|
@ -78,7 +80,7 @@
|
|||
0000001f _sizeof_copy_bank_data
|
||||
00000020 _sizeof_check_bank_data
|
||||
00000010 _sizeof_all_ff
|
||||
00000c66 _sizeof_all_00
|
||||
00000c57 _sizeof_all_00
|
||||
00000040 _sizeof_bank_data
|
||||
00000022 _sizeof_clear_ram
|
||||
00000021 _sizeof_fail_round1
|
Before Width: | Height: | Size: 528 B After Width: | Height: | Size: 528 B |
Binary file not shown.
|
@ -1,17 +1,17 @@
|
|||
; this file was created with wlalink by ville helin <vhelin@iki.fi>.
|
||||
; wla symbolic information for "/home/vicki/Scratch/mooneye-gb/tests/build/emulator-only/mbc1/ram_64Kb.gb".
|
||||
; wla symbolic information for "/home/vicki/Scratch/mooneye-gb/tests/build/emulator-only/mbc1/ram_64kb.gb".
|
||||
|
||||
[labels]
|
||||
01:48bd clear_vram
|
||||
01:487a disable_lcd_safe
|
||||
01:4880 disable_lcd_safe@wait_ly_0
|
||||
01:4898 memcmp
|
||||
01:48c7 memcpy
|
||||
01:48d0 memset
|
||||
01:48e0 print_inline_string
|
||||
01:48a6 print_load_font
|
||||
01:48b2 print_newline
|
||||
01:48d9 print_string
|
||||
01:48c7 clear_vram
|
||||
01:4884 disable_lcd_safe
|
||||
01:488a disable_lcd_safe@wait_ly_0
|
||||
01:48a2 memcmp
|
||||
01:48d1 memcpy
|
||||
01:48da memset
|
||||
01:48ea print_inline_string
|
||||
01:48b0 print_load_font
|
||||
01:48bc print_newline
|
||||
01:48e3 print_string
|
||||
01:47f0 quit
|
||||
01:4805 quit@cb_return
|
||||
01:480a quit@wait_ly_1
|
||||
|
@ -20,23 +20,23 @@
|
|||
01:481c quit@wait_ly_4
|
||||
01:4826 quit@success
|
||||
01:484d quit@failure
|
||||
01:4862 quit@halt
|
||||
01:4863 quit@halt_execution_0
|
||||
01:4866 reset_screen
|
||||
01:4889 serial_send_byte
|
||||
01:486c quit@halt
|
||||
01:486d quit@halt_execution_0
|
||||
01:4870 reset_screen
|
||||
01:4893 serial_send_byte
|
||||
01:4000 font
|
||||
00:0150 main
|
||||
00:0150 test_round1
|
||||
00:016e test_round2
|
||||
00:01c2 test_round3
|
||||
00:01cb test_round4
|
||||
00:01fb test_round5
|
||||
00:022c test_finish
|
||||
00:0236 test_finish@quit_inline_1
|
||||
00:0247 copy_bank_data
|
||||
00:025f check_bank_data
|
||||
00:0278 all_ff
|
||||
00:0288 all_00
|
||||
00:015f test_round1
|
||||
00:017d test_round2
|
||||
00:01d1 test_round3
|
||||
00:01da test_round4
|
||||
00:020a test_round5
|
||||
00:023b test_finish
|
||||
00:0245 test_finish@quit_inline_1
|
||||
00:0256 copy_bank_data
|
||||
00:026e check_bank_data
|
||||
00:0287 all_ff
|
||||
00:0297 all_00
|
||||
00:1000 bank_data
|
||||
00:1010 clear_ram
|
||||
00:1032 fail_round1
|
||||
|
@ -49,6 +49,7 @@
|
|||
00:109f fail_round4@quit_inline_5
|
||||
00:10b6 fail_round5
|
||||
00:10c0 fail_round5@quit_inline_6
|
||||
00:ff80 memcmp_hram
|
||||
|
||||
[definitions]
|
||||
0000000a _sizeof_clear_vram
|
||||
|
@ -60,12 +61,13 @@
|
|||
0000000c _sizeof_print_load_font
|
||||
0000000b _sizeof_print_newline
|
||||
00000007 _sizeof_print_string
|
||||
00000076 _sizeof_quit
|
||||
00000080 _sizeof_quit
|
||||
00000014 _sizeof_reset_screen
|
||||
0000000f _sizeof_serial_send_byte
|
||||
000007f0 _sizeof_font
|
||||
00000000 _sizeof_test_round1
|
||||
0000001e _sizeof_main
|
||||
00000020 _sizeof_memcmp_hram
|
||||
0000000f _sizeof_main
|
||||
0000001e _sizeof_test_round1
|
||||
00000054 _sizeof_test_round2
|
||||
00000009 _sizeof_test_round3
|
||||
00000030 _sizeof_test_round4
|
||||
|
@ -74,7 +76,7 @@
|
|||
00000018 _sizeof_copy_bank_data
|
||||
00000019 _sizeof_check_bank_data
|
||||
00000010 _sizeof_all_ff
|
||||
00000d78 _sizeof_all_00
|
||||
00000d69 _sizeof_all_00
|
||||
00000010 _sizeof_bank_data
|
||||
00000022 _sizeof_clear_ram
|
||||
00000021 _sizeof_fail_round1
|
|
@ -17,13 +17,27 @@ CXX_GUARD_START
|
|||
#define GUI_V_I(I) (struct GUIVariant) { .type = GUI_VARIANT_INT, .v.i = (I) }
|
||||
#define GUI_V_F(F) (struct GUIVariant) { .type = GUI_VARIANT_FLOAT, .v.f = (F) }
|
||||
#define GUI_V_S(S) (struct GUIVariant) { .type = GUI_VARIANT_STRING, .v.s = (S) }
|
||||
#define GUI_V_P(P) (struct GUIVariant) { .type = GUI_VARIANT_POINTER, .v.p = (P) }
|
||||
|
||||
#define GUIVariantIs(V, T) ((V).type == GUI_VARIANT_##T)
|
||||
#define GUIVariantIsVoid(V) GUIVariantIs(V, VOID)
|
||||
#define GUIVariantIsUInt(V) GUIVariantIs(V, UNSIGNED)
|
||||
#define GUIVariantIsInt(V) GUIVariantIs(V, INT)
|
||||
#define GUIVariantIsFloat(V) GUIVariantIs(V, FLOAT)
|
||||
#define GUIVariantIsString(V) GUIVariantIs(V, STRING)
|
||||
#define GUIVariantIsPointer(V) GUIVariantIs(V, POINTER)
|
||||
|
||||
#define GUIVariantCompareUInt(V, X) (GUIVariantIsUInt(V) && (V).v.u == (X))
|
||||
#define GUIVariantCompareInt(V, X) (GUIVariantIsInt(V) && (V).v.i == (X))
|
||||
#define GUIVariantCompareString(V, X) (GUIVariantIsString(V) && strcmp((V).v.s, (X)) == 0)
|
||||
|
||||
enum GUIVariantType {
|
||||
GUI_VARIANT_VOID = 0,
|
||||
GUI_VARIANT_UNSIGNED,
|
||||
GUI_VARIANT_INT,
|
||||
GUI_VARIANT_FLOAT,
|
||||
GUI_VARIANT_STRING
|
||||
GUI_VARIANT_STRING,
|
||||
GUI_VARIANT_POINTER,
|
||||
};
|
||||
|
||||
struct GUIVariant {
|
||||
|
@ -33,13 +47,14 @@ struct GUIVariant {
|
|||
int i;
|
||||
float f;
|
||||
const char* s;
|
||||
void* p;
|
||||
} v;
|
||||
};
|
||||
|
||||
struct GUIMenu;
|
||||
struct GUIMenuItem {
|
||||
const char* title;
|
||||
void* data;
|
||||
struct GUIVariant data;
|
||||
unsigned state;
|
||||
const char* const* validStates;
|
||||
const struct GUIVariant* stateMappings;
|
||||
|
|
|
@ -70,7 +70,7 @@ bool mInputQueryHat(const struct mInputMap*, uint32_t type, int id, struct mInpu
|
|||
void mInputUnbindHat(struct mInputMap*, uint32_t type, int id);
|
||||
void mInputUnbindAllHats(struct mInputMap*, uint32_t type);
|
||||
|
||||
void mInputMapLoad(struct mInputMap*, uint32_t type, const struct Configuration*);
|
||||
bool mInputMapLoad(struct mInputMap*, uint32_t type, const struct Configuration*);
|
||||
void mInputMapSave(const struct mInputMap*, uint32_t type, struct Configuration*);
|
||||
|
||||
bool mInputProfileLoad(struct mInputMap*, uint32_t type, const struct Configuration*, const char* profile);
|
||||
|
|
|
@ -181,6 +181,9 @@ struct GBMemory {
|
|||
union GBMBCState mbcState;
|
||||
int currentBank;
|
||||
int currentBank0;
|
||||
unsigned cartBusDecay;
|
||||
uint16_t cartBusPc;
|
||||
uint8_t cartBus;
|
||||
|
||||
uint8_t* wram;
|
||||
uint8_t* wramBank;
|
||||
|
|
|
@ -157,9 +157,11 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
|
|||
* | bit 3: IME
|
||||
* | bit 4: Is HDMA active?
|
||||
* | bits 5 - 7: Active RTC register
|
||||
* | 0x00196 - 0x00197: Reserved (leave zero)
|
||||
* | 0x00196: Cartridge bus value
|
||||
* | 0x00197: Reserved (leave zero)
|
||||
* 0x00198 - 0x0019F: Global cycle counter
|
||||
* 0x001A0 - 0x0025F: Reserved (leave zero)
|
||||
* 0x001A0 - 0x001A1: Program counter for last cartridge read
|
||||
* 0x001A2 - 0x0025F: Reserved (leave zero)
|
||||
* 0x00260 - 0x002FF: OAM
|
||||
* 0x00300 - 0x0037F: I/O memory
|
||||
* 0x00380 - 0x003FE: HRAM
|
||||
|
@ -401,12 +403,14 @@ struct GBSerializedState {
|
|||
};
|
||||
|
||||
GBSerializedMemoryFlags flags;
|
||||
uint16_t reserved;
|
||||
uint8_t cartBus;
|
||||
uint8_t reserved;
|
||||
} memory;
|
||||
|
||||
uint64_t globalCycles;
|
||||
|
||||
uint32_t reserved[48];
|
||||
uint16_t cartBusPc;
|
||||
uint16_t reserved[95];
|
||||
|
||||
uint8_t oam[GB_SIZE_OAM];
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ enum {
|
|||
SIZE_CART1 = 0x02000000,
|
||||
SIZE_CART2 = 0x02000000,
|
||||
SIZE_CART_SRAM = 0x00008000,
|
||||
SIZE_CART_SRAM512 = 0x00010000,
|
||||
SIZE_CART_FLASH512 = 0x00010000,
|
||||
SIZE_CART_FLASH1M = 0x00020000,
|
||||
SIZE_CART_EEPROM = 0x00002000,
|
||||
|
|
|
@ -24,7 +24,8 @@ enum SavedataType {
|
|||
SAVEDATA_FLASH512 = 2,
|
||||
SAVEDATA_FLASH1M = 3,
|
||||
SAVEDATA_EEPROM = 4,
|
||||
SAVEDATA_EEPROM512 = 5
|
||||
SAVEDATA_EEPROM512 = 5,
|
||||
SAVEDATA_SRAM512 = 6,
|
||||
};
|
||||
|
||||
enum SavedataCommand {
|
||||
|
@ -110,6 +111,7 @@ void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type);
|
|||
void GBASavedataInitFlash(struct GBASavedata* savedata);
|
||||
void GBASavedataInitEEPROM(struct GBASavedata* savedata);
|
||||
void GBASavedataInitSRAM(struct GBASavedata* savedata);
|
||||
void GBASavedataInitSRAM512(struct GBASavedata* savedata);
|
||||
|
||||
uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address);
|
||||
void GBASavedataWriteFlash(struct GBASavedata* savedata, uint16_t address, uint8_t value);
|
||||
|
|
BIN
res/font-new.png
BIN
res/font-new.png
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,11 @@
|
|||
[shader]
|
||||
name=Scale2x
|
||||
author=singron
|
||||
description=AdvanceMAME's Scale2x algorithm
|
||||
passes=1
|
||||
|
||||
[pass.0]
|
||||
fragmentShader=scale2x.fs
|
||||
blend=1
|
||||
width=-2
|
||||
height=-2
|
|
@ -0,0 +1,39 @@
|
|||
/* Shader implementation of Scale2x is adapted from https://gist.github.com/singron/3161079 */
|
||||
varying vec2 texCoord;
|
||||
uniform sampler2D tex;
|
||||
uniform vec2 texSize;
|
||||
|
||||
void main() {
|
||||
// o = offset, the width of a pixel
|
||||
vec2 o = 1.0 / texSize;
|
||||
|
||||
// texel arrangement
|
||||
// A B C
|
||||
// D E F
|
||||
// G H I
|
||||
vec4 B = texture2D(tex, texCoord + vec2( 0.0, o.y));
|
||||
vec4 D = texture2D(tex, texCoord + vec2( -o.x, 0.0));
|
||||
vec4 E = texture2D(tex, texCoord + vec2( 0.0, 0.0));
|
||||
vec4 F = texture2D(tex, texCoord + vec2( o.x, 0.0));
|
||||
vec4 H = texture2D(tex, texCoord + vec2( 0.0, -o.y));
|
||||
vec2 p = texCoord * texSize;
|
||||
// p = the texCoord within a pixel [0...1]
|
||||
p = fract(p);
|
||||
if (p.x > .5) {
|
||||
if (p.y > .5) {
|
||||
// Top Right
|
||||
gl_FragColor = B == F && B != D && F != H ? F : E;
|
||||
} else {
|
||||
// Bottom Right
|
||||
gl_FragColor = H == F && D != H && B != F ? F : E;
|
||||
}
|
||||
} else {
|
||||
if (p.y > .5) {
|
||||
// Top Left
|
||||
gl_FragColor = D == B && B != F && D != H ? D : E;
|
||||
} else {
|
||||
// Bottom Left
|
||||
gl_FragColor = D == H && D != B && H != F ? D : E;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
[shader]
|
||||
name=Scale4x
|
||||
author=singron, endrift
|
||||
description=AdvanceMAME's Scale4x algorithm
|
||||
passes=1
|
||||
|
||||
[pass.0]
|
||||
fragmentShader=scale4x.fs
|
||||
blend=1
|
||||
width=-4
|
||||
height=-4
|
|
@ -0,0 +1,54 @@
|
|||
/* Shader implementation of Scale2x is adapted from https://gist.github.com/singron/3161079 */
|
||||
varying vec2 texCoord;
|
||||
uniform sampler2D tex;
|
||||
uniform vec2 texSize;
|
||||
|
||||
vec4 scale2x(vec4 pixels[5], vec2 p) {
|
||||
// texel arrangement
|
||||
// x 0 x
|
||||
// 1 2 3
|
||||
// x 4 x
|
||||
// p = the texCoord within a pixel [0...1]
|
||||
p = fract(p);
|
||||
if (p.x > .5) {
|
||||
if (p.y > .5) {
|
||||
// Top Right
|
||||
return pixels[0] == pixels[3] && pixels[0] != pixels[1] && pixels[3] != pixels[4] ? pixels[3] : pixels[2];
|
||||
} else {
|
||||
// Bottom Right
|
||||
return pixels[4] == pixels[3] && pixels[1] != pixels[4] && pixels[0] != pixels[3] ? pixels[3] : pixels[2];
|
||||
}
|
||||
} else {
|
||||
if (p.y > .5) {
|
||||
// Top Left
|
||||
return pixels[1] == pixels[0] && pixels[0] != pixels[3] && pixels[1] != pixels[4] ? pixels[1] : pixels[2];
|
||||
} else {
|
||||
// Bottom Left
|
||||
return pixels[1] == pixels[4] && pixels[1] != pixels[0] && pixels[4] != pixels[3] ? pixels[1] : pixels[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec4 scaleNeighborhood(vec2 p, vec2 x, vec2 o) {
|
||||
vec4 neighborhood[5];
|
||||
neighborhood[0] = texture2D(tex, texCoord + x + vec2( 0.0, o.y));
|
||||
neighborhood[1] = texture2D(tex, texCoord + x + vec2(-o.x, 0.0));
|
||||
neighborhood[2] = texture2D(tex, texCoord + x + vec2( 0.0, 0.0));
|
||||
neighborhood[3] = texture2D(tex, texCoord + x + vec2( o.x, 0.0));
|
||||
neighborhood[4] = texture2D(tex, texCoord + x + vec2( 0.0, -o.y));
|
||||
return scale2x(neighborhood, p + x * texSize);
|
||||
}
|
||||
|
||||
void main() {
|
||||
// o = offset, the width of a pixel
|
||||
vec2 o = 1.0 / texSize;
|
||||
|
||||
vec2 p = texCoord * texSize;
|
||||
vec4 pixels[5];
|
||||
pixels[0] = scaleNeighborhood(p, vec2( 0.0, o.y / 2.0), o);
|
||||
pixels[1] = scaleNeighborhood(p, vec2(-o.x / 2.0, 0.0), o);
|
||||
pixels[2] = scaleNeighborhood(p, vec2( 0.0, 0.0), o);
|
||||
pixels[3] = scaleNeighborhood(p, vec2( o.x / 2.0, 0.0), o);
|
||||
pixels[4] = scaleNeighborhood(p, vec2( 0.0, -o.y / 2.0), o);
|
||||
gl_FragColor = scale2x(pixels, p * 2.0);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -578,10 +578,10 @@ void mInputUnbindAllHats(struct mInputMap* map, uint32_t type) {
|
|||
}
|
||||
}
|
||||
|
||||
void mInputMapLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config) {
|
||||
bool mInputMapLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config) {
|
||||
char sectionName[SECTION_NAME_MAX];
|
||||
_makeSectionName(map->info->platformName, sectionName, SECTION_NAME_MAX, type);
|
||||
_loadAll(map, type, sectionName, config);
|
||||
return _loadAll(map, type, sectionName, config);
|
||||
}
|
||||
|
||||
void mInputMapSave(const struct mInputMap* map, uint32_t type, struct Configuration* config) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
DEFINE_VECTOR(mCoreRewindPatches, struct PatchFast);
|
||||
|
||||
void _rewindDiff(struct mCoreRewindContext* context);
|
||||
static void _rewindDiff(struct mCoreRewindContext* context);
|
||||
|
||||
#ifndef DISABLE_THREADING
|
||||
THREAD_ENTRY _rewindThread(void* context);
|
||||
|
@ -136,17 +136,19 @@ bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core)
|
|||
}
|
||||
--context->current;
|
||||
|
||||
struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
|
||||
size_t size2 = context->previousState->size(context->previousState);
|
||||
size_t size = context->currentState->size(context->currentState);
|
||||
if (size2 < size) {
|
||||
size = size2;
|
||||
if (context->size) {
|
||||
struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current);
|
||||
size_t size2 = context->previousState->size(context->previousState);
|
||||
size_t size = context->currentState->size(context->currentState);
|
||||
if (size2 < size) {
|
||||
size = size2;
|
||||
}
|
||||
void* current = context->currentState->map(context->currentState, size, MAP_READ);
|
||||
void* previous = context->previousState->map(context->previousState, size, MAP_WRITE);
|
||||
patch->d.applyPatch(&patch->d, previous, size, current, size);
|
||||
context->currentState->unmap(context->currentState, current, size);
|
||||
context->previousState->unmap(context->previousState, previous, size);
|
||||
}
|
||||
void* current = context->currentState->map(context->currentState, size, MAP_READ);
|
||||
void* previous = context->previousState->map(context->previousState, size, MAP_WRITE);
|
||||
patch->d.applyPatch(&patch->d, previous, size, current, size);
|
||||
context->currentState->unmap(context->currentState, current, size);
|
||||
context->previousState->unmap(context->previousState, previous, size);
|
||||
struct VFile* nextState = context->previousState;
|
||||
context->previousState = context->currentState;
|
||||
context->currentState = nextState;
|
||||
|
|
|
@ -35,19 +35,19 @@ static void mGUIShowCheatSet(struct mGUIRunner* runner, struct mCheatDevice* dev
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Add line",
|
||||
.data = (void*) CHEAT_ADD_LINE,
|
||||
.data = GUI_V_U(CHEAT_ADD_LINE),
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Rename",
|
||||
.data = (void*) CHEAT_RENAME,
|
||||
.data = GUI_V_U(CHEAT_RENAME),
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Delete",
|
||||
.data = (void*) CHEAT_DELETE,
|
||||
.data = GUI_V_U(CHEAT_DELETE),
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Back",
|
||||
.data = 0,
|
||||
.data = GUI_V_V,
|
||||
};
|
||||
|
||||
while (true) {
|
||||
|
@ -56,11 +56,11 @@ static void mGUIShowCheatSet(struct mGUIRunner* runner, struct mCheatDevice* dev
|
|||
struct GUIMenuItem* item;
|
||||
enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &menu, &item);
|
||||
set->enabled = GUIMenuItemListGetPointer(&menu.items, 0)->state;
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || !item->data) {
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || GUIVariantIsVoid(item->data)) {
|
||||
break;
|
||||
}
|
||||
|
||||
enum mGUICheatAction action = (enum mGUICheatAction) item->data;
|
||||
enum mGUICheatAction action = (enum mGUICheatAction) item->data.v.u;
|
||||
switch (action) {
|
||||
case CHEAT_ADD_LINE:
|
||||
strlcpy(keyboard.title, "Add line", sizeof(keyboard.title));
|
||||
|
@ -108,7 +108,7 @@ void mGUIShowCheats(struct mGUIRunner* runner) {
|
|||
struct mCheatSet* set = *mCheatSetsGetPointer(&device->cheats, i);
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = set->name,
|
||||
.data = set,
|
||||
.data = GUI_V_P(set),
|
||||
.state = set->enabled,
|
||||
.validStates = offOn,
|
||||
.nStates = 2
|
||||
|
@ -116,11 +116,11 @@ void mGUIShowCheats(struct mGUIRunner* runner) {
|
|||
}
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Add new cheat set",
|
||||
.data = 0,
|
||||
.data = GUI_V_V,
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Back",
|
||||
.data = (void*) -1,
|
||||
.data = GUI_V_I(-1),
|
||||
};
|
||||
|
||||
struct GUIMenuItem* item;
|
||||
|
@ -131,11 +131,11 @@ void mGUIShowCheats(struct mGUIRunner* runner) {
|
|||
set->enabled = item->state;
|
||||
}
|
||||
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || item->data == (void*) -1) {
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || GUIVariantCompareInt(item->data, -1)) {
|
||||
break;
|
||||
}
|
||||
struct mCheatSet* set = NULL;
|
||||
if (!item->data) {
|
||||
if (GUIVariantIsVoid(item->data)) {
|
||||
struct GUIKeyboardParams keyboard;
|
||||
GUIKeyboardParamsInit(&keyboard);
|
||||
keyboard.maxLen = 50;
|
||||
|
@ -146,7 +146,7 @@ void mGUIShowCheats(struct mGUIRunner* runner) {
|
|||
mCheatAddSet(device, set);
|
||||
}
|
||||
} else {
|
||||
set = item->data;
|
||||
set = item->data.v.p;
|
||||
}
|
||||
if (set) {
|
||||
mGUIShowCheatSet(runner, device, set);
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
#define GUI_MAX_INPUTS 7
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CONFIG_REMAP,
|
||||
CONFIG_SAVE,
|
||||
};
|
||||
|
||||
static bool _biosNamed(const char* name) {
|
||||
char ext[PATH_MAX + 1] = {};
|
||||
separatePath(name, NULL, NULL, ext);
|
||||
|
@ -45,7 +50,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
GUIMenuItemListInit(&menu.items, 0);
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Frameskip",
|
||||
.data = "frameskip",
|
||||
.data = GUI_V_S("frameskip"),
|
||||
.submenu = 0,
|
||||
.state = 0,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -55,7 +60,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Show framerate",
|
||||
.data = "fpsCounter",
|
||||
.data = GUI_V_S("fpsCounter"),
|
||||
.submenu = 0,
|
||||
.state = false,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -65,7 +70,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Show status OSD",
|
||||
.data = "showOSD",
|
||||
.data = GUI_V_S("showOSD"),
|
||||
.submenu = 0,
|
||||
.state = true,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -75,7 +80,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Autosave state",
|
||||
.data = "autosave",
|
||||
.data = GUI_V_S("autosave"),
|
||||
.submenu = 0,
|
||||
.state = true,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -85,7 +90,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Autoload state",
|
||||
.data = "autoload",
|
||||
.data = GUI_V_S("autoload"),
|
||||
.submenu = 0,
|
||||
.state = true,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -95,7 +100,17 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Mute",
|
||||
.data = "mute",
|
||||
.data = GUI_V_S("mute"),
|
||||
.submenu = 0,
|
||||
.state = false,
|
||||
.validStates = (const char*[]) {
|
||||
"Off", "On"
|
||||
},
|
||||
.nStates = 2
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Fast forward mute",
|
||||
.data = GUI_V_S("fastForwardMute"),
|
||||
.submenu = 0,
|
||||
.state = false,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -105,7 +120,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Use BIOS if found",
|
||||
.data = "useBios",
|
||||
.data = GUI_V_S("useBios"),
|
||||
.submenu = 0,
|
||||
.state = true,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -116,26 +131,26 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
#ifdef M_CORE_GBA
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Select GBA BIOS path",
|
||||
.data = "gba.bios",
|
||||
.data = GUI_V_S("gba.bios"),
|
||||
};
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Select GB BIOS path",
|
||||
.data = "gb.bios",
|
||||
.data = GUI_V_S("gb.bios"),
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Select GBC BIOS path",
|
||||
.data = "gbc.bios",
|
||||
.data = GUI_V_S("gbc.bios"),
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Select SGB BIOS path",
|
||||
.data = "sgb.bios",
|
||||
.data = GUI_V_S("sgb.bios"),
|
||||
};
|
||||
struct GUIMenuItem* palette = GUIMenuItemListAppend(&menu.items);
|
||||
*palette = (struct GUIMenuItem) {
|
||||
.title = "GB palette",
|
||||
.data = "gb.pal",
|
||||
.data = GUI_V_S("gb.pal"),
|
||||
};
|
||||
const struct GBColorPreset* colorPresets;
|
||||
palette->nStates = GBColorPresetList(&colorPresets);
|
||||
|
@ -147,7 +162,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
#endif
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Interframe blending",
|
||||
.data = "interframeBlending",
|
||||
.data = GUI_V_S("interframeBlending"),
|
||||
.submenu = 0,
|
||||
.state = false,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -158,7 +173,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
#if defined(M_CORE_GBA) && (defined(GEKKO) || defined(__SWITCH__) || defined(PSP2))
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Enable GBP features",
|
||||
.data = "gba.forceGbp",
|
||||
.data = GUI_V_S("gba.forceGbp"),
|
||||
.submenu = 0,
|
||||
.state = false,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -170,7 +185,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
#ifdef M_CORE_GB
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Enable SGB features",
|
||||
.data = "sgb.model",
|
||||
.data = GUI_V_S("sgb.model"),
|
||||
.submenu = 0,
|
||||
.state = true,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -184,7 +199,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Enable SGB borders",
|
||||
.data = "sgb.borders",
|
||||
.data = GUI_V_S("sgb.borders"),
|
||||
.submenu = 0,
|
||||
.state = true,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -194,7 +209,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Crop SGB borders",
|
||||
.data = "sgb.borderCrop",
|
||||
.data = GUI_V_S("sgb.borderCrop"),
|
||||
.submenu = 0,
|
||||
.state = false,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -214,7 +229,7 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
}
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Remap controls",
|
||||
.data = "*REMAP",
|
||||
.data = GUI_V_U(CONFIG_REMAP),
|
||||
.state = 0,
|
||||
.validStates = i ? mapNames : 0,
|
||||
.nStates = i
|
||||
|
@ -225,11 +240,11 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
}
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Save",
|
||||
.data = "*SAVE",
|
||||
.data = GUI_V_U(CONFIG_SAVE),
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Cancel",
|
||||
.data = 0,
|
||||
.data = GUI_V_V,
|
||||
};
|
||||
enum GUIMenuExitReason reason;
|
||||
char gbaBiosPath[256] = "";
|
||||
|
@ -242,59 +257,63 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
struct GUIMenuItem* item;
|
||||
for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) {
|
||||
item = GUIMenuItemListGetPointer(&menu.items, i);
|
||||
if (!item->validStates || !item->data) {
|
||||
if (!item->validStates || GUIVariantIsVoid(item->data)) {
|
||||
continue;
|
||||
}
|
||||
if (item->stateMappings) {
|
||||
size_t j;
|
||||
for (j = 0; j < item->nStates; ++j) {
|
||||
const struct GUIVariant* v = &item->stateMappings[j];
|
||||
struct GUIVariant test;
|
||||
switch (v->type) {
|
||||
case GUI_VARIANT_VOID:
|
||||
if (!mCoreConfigGetValue(&runner->config, item->data)) {
|
||||
item->state = j;
|
||||
if (GUIVariantIsString(item->data)) {
|
||||
if (item->stateMappings) {
|
||||
size_t j;
|
||||
for (j = 0; j < item->nStates; ++j) {
|
||||
const struct GUIVariant* v = &item->stateMappings[j];
|
||||
struct GUIVariant test;
|
||||
switch (v->type) {
|
||||
case GUI_VARIANT_VOID:
|
||||
if (!mCoreConfigGetValue(&runner->config, item->data.v.s)) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_UNSIGNED:
|
||||
if (mCoreConfigGetUIntValue(&runner->config, item->data.v.s, &test.v.u) && test.v.u == v->v.u) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_INT:
|
||||
if (mCoreConfigGetIntValue(&runner->config, item->data.v.s, &test.v.i) && test.v.i == v->v.i) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_FLOAT:
|
||||
if (mCoreConfigGetFloatValue(&runner->config, item->data.v.s, &test.v.f) && fabsf(test.v.f - v->v.f) <= 1e-3f) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_STRING:
|
||||
test.v.s = mCoreConfigGetValue(&runner->config, item->data.v.s);
|
||||
if (test.v.s && strcmp(test.v.s, v->v.s) == 0) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_POINTER:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_UNSIGNED:
|
||||
if (mCoreConfigGetUIntValue(&runner->config, item->data, &test.v.u) && test.v.u == v->v.u) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_INT:
|
||||
if (mCoreConfigGetIntValue(&runner->config, item->data, &test.v.i) && test.v.i == v->v.i) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_FLOAT:
|
||||
if (mCoreConfigGetFloatValue(&runner->config, item->data, &test.v.f) && fabsf(test.v.f - v->v.f) <= 1e-3f) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GUI_VARIANT_STRING:
|
||||
test.v.s = mCoreConfigGetValue(&runner->config, item->data);
|
||||
if (test.v.s && strcmp(test.v.s, v->v.s) == 0) {
|
||||
item->state = j;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
mCoreConfigGetUIntValue(&runner->config, item->data.v.s, &item->state);
|
||||
}
|
||||
} else {
|
||||
mCoreConfigGetUIntValue(&runner->config, item->data, &item->state);
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
reason = GUIShowMenu(&runner->params, &menu, &item);
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || !item->data) {
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || GUIVariantIsVoid(item->data)) {
|
||||
break;
|
||||
}
|
||||
if (!strcmp(item->data, "*SAVE")) {
|
||||
if (GUIVariantCompareUInt(item->data, CONFIG_SAVE)) {
|
||||
if (gbaBiosPath[0]) {
|
||||
mCoreConfigSetValue(&runner->config, "gba.bios", gbaBiosPath);
|
||||
}
|
||||
|
@ -309,30 +328,32 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
}
|
||||
for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) {
|
||||
item = GUIMenuItemListGetPointer(&menu.items, i);
|
||||
if (!item->validStates || !item->data || ((const char*) item->data)[0] == '*') {
|
||||
if (!item->validStates || !GUIVariantIsString(item->data)) {
|
||||
continue;
|
||||
}
|
||||
if (item->stateMappings) {
|
||||
const struct GUIVariant* v = &item->stateMappings[item->state];
|
||||
switch (v->type) {
|
||||
case GUI_VARIANT_VOID:
|
||||
mCoreConfigSetValue(&runner->config, item->data, NULL);
|
||||
mCoreConfigSetValue(&runner->config, item->data.v.s, NULL);
|
||||
break;
|
||||
case GUI_VARIANT_UNSIGNED:
|
||||
mCoreConfigSetUIntValue(&runner->config, item->data, v->v.u);
|
||||
mCoreConfigSetUIntValue(&runner->config, item->data.v.s, v->v.u);
|
||||
break;
|
||||
case GUI_VARIANT_INT:
|
||||
mCoreConfigSetUIntValue(&runner->config, item->data, v->v.i);
|
||||
mCoreConfigSetUIntValue(&runner->config, item->data.v.s, v->v.i);
|
||||
break;
|
||||
case GUI_VARIANT_FLOAT:
|
||||
mCoreConfigSetFloatValue(&runner->config, item->data, v->v.f);
|
||||
mCoreConfigSetFloatValue(&runner->config, item->data.v.s, v->v.f);
|
||||
break;
|
||||
case GUI_VARIANT_STRING:
|
||||
mCoreConfigSetValue(&runner->config, item->data, v->v.s);
|
||||
mCoreConfigSetValue(&runner->config, item->data.v.s, v->v.s);
|
||||
break;
|
||||
case GUI_VARIANT_POINTER:
|
||||
break;
|
||||
}
|
||||
#ifdef M_CORE_GB
|
||||
} else if (!strcmp(item->data, "gb.pal")) {
|
||||
} else if (GUIVariantCompareString(item->data, "gb.pal")) {
|
||||
const struct GBColorPreset* preset = &colorPresets[item->state];
|
||||
mCoreConfigSetUIntValue(&runner->config, "gb.pal[0]", preset->colors[0] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&runner->config, "gb.pal[1]", preset->colors[1] & 0xFFFFFF);
|
||||
|
@ -346,10 +367,10 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
mCoreConfigSetUIntValue(&runner->config, "gb.pal[9]", preset->colors[9] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&runner->config, "gb.pal[10]", preset->colors[10] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&runner->config, "gb.pal[11]", preset->colors[11] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&runner->config, item->data, item->state);
|
||||
mCoreConfigSetUIntValue(&runner->config, "gb.pal", item->state);
|
||||
#endif
|
||||
} else {
|
||||
mCoreConfigSetUIntValue(&runner->config, item->data, item->state);
|
||||
mCoreConfigSetUIntValue(&runner->config, item->data.v.s, item->state);
|
||||
}
|
||||
}
|
||||
if (runner->keySources) {
|
||||
|
@ -363,11 +384,11 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
mCoreLoadForeignConfig(runner->core, &runner->config);
|
||||
break;
|
||||
}
|
||||
if (!strcmp(item->data, "*REMAP")) {
|
||||
if (GUIVariantCompareUInt(item->data, CONFIG_REMAP)) {
|
||||
mGUIRemapKeys(&runner->params, &runner->core->inputMap, &runner->keySources[item->state]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(item->data, "gba.bios")) {
|
||||
if (GUIVariantCompareString(item->data, "gba.bios")) {
|
||||
// TODO: show box if failed
|
||||
if (!GUISelectFile(&runner->params, gbaBiosPath, sizeof(gbaBiosPath), _biosNamed, GBAIsBIOS, NULL)) {
|
||||
gbaBiosPath[0] = '\0';
|
||||
|
@ -375,21 +396,21 @@ void mGUIShowConfig(struct mGUIRunner* runner, struct GUIMenuItem* extra, size_t
|
|||
continue;
|
||||
}
|
||||
#ifdef M_CORE_GB
|
||||
if (!strcmp(item->data, "gb.bios")) {
|
||||
if (GUIVariantCompareString(item->data, "gb.bios")) {
|
||||
// TODO: show box if failed
|
||||
if (!GUISelectFile(&runner->params, gbBiosPath, sizeof(gbBiosPath), _biosNamed, GBIsBIOS, NULL)) {
|
||||
gbBiosPath[0] = '\0';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(item->data, "gbc.bios")) {
|
||||
if (GUIVariantCompareString(item->data, "gbc.bios")) {
|
||||
// TODO: show box if failed
|
||||
if (!GUISelectFile(&runner->params, gbcBiosPath, sizeof(gbcBiosPath), _biosNamed, GBIsBIOS, NULL)) {
|
||||
gbcBiosPath[0] = '\0';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(item->data, "sgb.bios")) {
|
||||
if (GUIVariantCompareString(item->data, "sgb.bios")) {
|
||||
// TODO: show box if failed
|
||||
if (!GUISelectFile(&runner->params, sgbBiosPath, sizeof(sgbBiosPath), _biosNamed, GBIsBIOS, NULL)) {
|
||||
sgbBiosPath[0] = '\0';
|
||||
|
|
|
@ -42,6 +42,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]) {
|
||||
|
@ -107,39 +112,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);
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +330,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
.draw = _drawState
|
||||
},
|
||||
.p = runner,
|
||||
.screenshot = 0,
|
||||
.image = 0,
|
||||
.screenshotId = 0
|
||||
};
|
||||
struct GUIMenu pauseMenu = {
|
||||
|
@ -336,38 +351,38 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
GUIMenuItemListInit(&pauseMenu.items, 0);
|
||||
GUIMenuItemListInit(&stateSaveMenu.items, 9);
|
||||
GUIMenuItemListInit(&stateLoadMenu.items, 10);
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = (void*) RUNNER_CONTINUE };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Unpause", .data = GUI_V_U(RUNNER_CONTINUE) };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Save state", .submenu = &stateSaveMenu };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Load state", .submenu = &stateLoadMenu };
|
||||
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(1)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(2)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(3)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(4)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(5)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(6)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(7)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(8)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_SAVE_STATE | RUNNER_STATE(9)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(1)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(2)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(3)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(4)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(5)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(6)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(7)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(8)) };
|
||||
*GUIMenuItemListAppend(&stateSaveMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = GUI_V_U(RUNNER_SAVE_STATE | RUNNER_STATE(9)) };
|
||||
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "Autosave", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(0)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(1)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(2)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(3)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(4)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(5)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(6)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(7)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(8)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = (void*) (RUNNER_LOAD_STATE | RUNNER_STATE(9)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "Autosave", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(0)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 1", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(1)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 2", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(2)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 3", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(3)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 4", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(4)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 5", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(5)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 6", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(6)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 7", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(7)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 8", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(8)) };
|
||||
*GUIMenuItemListAppend(&stateLoadMenu.items) = (struct GUIMenuItem) { .title = "State 9", .data = GUI_V_U(RUNNER_LOAD_STATE | RUNNER_STATE(9)) };
|
||||
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = (void*) RUNNER_SCREENSHOT };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Take screenshot", .data = GUI_V_U(RUNNER_SCREENSHOT) };
|
||||
if (runner->params.getText) {
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Cheats", .data = (void*) RUNNER_CHEATS };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Cheats", .data = GUI_V_U(RUNNER_CHEATS) };
|
||||
}
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = (void*) RUNNER_CONFIG };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Reset game", .data = (void*) RUNNER_RESET };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = (void*) RUNNER_EXIT };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Configure", .data = GUI_V_U(RUNNER_CONFIG) };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Reset game", .data = GUI_V_U(RUNNER_RESET) };
|
||||
*GUIMenuItemListAppend(&pauseMenu.items) = (struct GUIMenuItem) { .title = "Exit game", .data = GUI_V_U(RUNNER_EXIT) };
|
||||
|
||||
runner->params.drawStart();
|
||||
if (runner->params.guiPrepare) {
|
||||
|
@ -455,6 +470,12 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
int drawFps = false;
|
||||
mCoreConfigGetIntValue(&runner->config, "fpsCounter", &drawFps);
|
||||
|
||||
int mute = false;
|
||||
mCoreConfigGetIntValue(&runner->config, "mute", &mute);
|
||||
|
||||
int fastForwardMute = false;
|
||||
mCoreConfigGetIntValue(&runner->config, "fastForwardMute", &fastForwardMute);
|
||||
|
||||
bool running = true;
|
||||
|
||||
#ifndef DISABLE_THREADING
|
||||
|
@ -506,21 +527,33 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
if (guiKeys & (1 << mGUI_INPUT_SCREENSHOT)) {
|
||||
mCoreTakeScreenshot(runner->core);
|
||||
}
|
||||
bool muteTogglePressed = guiKeys & (1 << mGUI_INPUT_MUTE_TOGGLE);
|
||||
if (muteTogglePressed) {
|
||||
mute = !mute;
|
||||
mCoreConfigSetUIntValue(&runner->config, "mute", mute);
|
||||
runner->core->reloadConfigOption(runner->core, "mute", &runner->config);
|
||||
}
|
||||
if (runner->setFrameLimiter) {
|
||||
if (guiKeys & (1 << mGUI_INPUT_FAST_FORWARD_TOGGLE)) {
|
||||
fastForward = !fastForward;
|
||||
}
|
||||
if (fastForward || (heldKeys & (1 << mGUI_INPUT_FAST_FORWARD_HELD))) {
|
||||
bool fastForwarding = fastForward || (heldKeys & (1 << mGUI_INPUT_FAST_FORWARD_HELD));
|
||||
if (fastForwarding) {
|
||||
if (fastForwardMute && !mute && !muteTogglePressed) {
|
||||
mCoreConfigSetUIntValue(&runner->core->config, "mute", fastForwardMute);
|
||||
runner->core->reloadConfigOption(runner->core, "mute", NULL);
|
||||
}
|
||||
|
||||
runner->setFrameLimiter(runner, false);
|
||||
} else {
|
||||
runner->setFrameLimiter(runner, true);
|
||||
|
||||
if (fastForwardMute && !mute && !muteTogglePressed) {
|
||||
mCoreConfigSetUIntValue(&runner->core->config, "mute", !fastForwardMute);
|
||||
runner->core->reloadConfigOption(runner->core, "mute", NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (guiKeys & (1 << mGUI_INPUT_MUTE_TOGGLE)) {
|
||||
int mute = !runner->core->opts.mute;
|
||||
mCoreConfigSetUIntValue(&runner->config, "mute", mute);
|
||||
runner->core->reloadConfigOption(runner->core, "mute", &runner->config);
|
||||
}
|
||||
uint16_t keys = runner->pollGameInput(runner);
|
||||
if (runner->prepareForFrame) {
|
||||
runner->prepareForFrame(runner);
|
||||
|
@ -600,8 +633,8 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
uint32_t keys = 0xFFFFFFFF; // Huge hack to avoid an extra variable!
|
||||
struct GUIMenuItem* item;
|
||||
enum GUIMenuExitReason reason = GUIShowMenu(&runner->params, &pauseMenu, &item);
|
||||
if (reason == GUI_MENU_EXIT_ACCEPT) {
|
||||
switch (((int) item->data) & RUNNER_COMMAND_MASK) {
|
||||
if (reason == GUI_MENU_EXIT_ACCEPT && item->data.type == GUI_VARIANT_UNSIGNED) {
|
||||
switch (item->data.v.u & RUNNER_COMMAND_MASK) {
|
||||
case RUNNER_EXIT:
|
||||
running = false;
|
||||
keys = 0;
|
||||
|
@ -610,10 +643,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, item->data.v.u >> 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, item->data.v.u >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_RTC);
|
||||
break;
|
||||
case RUNNER_SCREENSHOT:
|
||||
mCoreTakeScreenshot(runner->core);
|
||||
|
@ -651,6 +684,8 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) {
|
|||
}
|
||||
mCoreConfigGetIntValue(&runner->config, "fpsCounter", &drawFps);
|
||||
mCoreConfigGetIntValue(&runner->config, "showOSD", &showOSD);
|
||||
mCoreConfigGetIntValue(&runner->config, "mute", &mute);
|
||||
mCoreConfigGetIntValue(&runner->config, "fastForwardMute", &fastForwardMute);
|
||||
#ifdef M_CORE_GB
|
||||
if (runner->core->platform(runner->core) == mPLATFORM_GB) {
|
||||
runner->core->reloadConfigOption(runner->core, "gb.pal", &runner->config);
|
||||
|
@ -676,10 +711,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;
|
||||
|
|
|
@ -21,12 +21,12 @@ void mGUIRemapKeys(struct GUIParams* params, struct mInputMap* map, const struct
|
|||
size_t i;
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Game keys:",
|
||||
.data = 0,
|
||||
.data = GUI_V_V,
|
||||
};
|
||||
for (i = 0; i < map->info->nKeys; ++i) {
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = map->info->keyId[i],
|
||||
.data = (void*) (GUI_INPUT_MAX + i + 1),
|
||||
.data = GUI_V_U(GUI_INPUT_MAX + i + 1),
|
||||
.submenu = 0,
|
||||
.state = mInputQueryBinding(map, keys->id, i) + 1,
|
||||
.validStates = keyNames,
|
||||
|
@ -35,7 +35,7 @@ void mGUIRemapKeys(struct GUIParams* params, struct mInputMap* map, const struct
|
|||
}
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Interface keys:",
|
||||
.data = 0,
|
||||
.data = GUI_V_V,
|
||||
};
|
||||
for (i = 0; i < params->keyMap.info->nKeys; ++i) {
|
||||
if (!params->keyMap.info->keyId[i]) {
|
||||
|
@ -43,7 +43,7 @@ void mGUIRemapKeys(struct GUIParams* params, struct mInputMap* map, const struct
|
|||
}
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = params->keyMap.info->keyId[i],
|
||||
.data = (void*) i + 1,
|
||||
.data = GUI_V_U(i + 1),
|
||||
.submenu = 0,
|
||||
.state = mInputQueryBinding(¶ms->keyMap, keys->id, i) + 1,
|
||||
.validStates = keyNames,
|
||||
|
@ -52,30 +52,30 @@ void mGUIRemapKeys(struct GUIParams* params, struct mInputMap* map, const struct
|
|||
}
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Save",
|
||||
.data = (void*) (GUI_INPUT_MAX + map->info->nKeys + 2),
|
||||
.data = GUI_V_I(-2),
|
||||
};
|
||||
*GUIMenuItemListAppend(&menu.items) = (struct GUIMenuItem) {
|
||||
.title = "Cancel",
|
||||
.data = 0,
|
||||
.data = GUI_V_I(-1),
|
||||
};
|
||||
|
||||
struct GUIMenuItem* item;
|
||||
while (true) {
|
||||
enum GUIMenuExitReason reason;
|
||||
reason = GUIShowMenu(params, &menu, &item);
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || !item->data) {
|
||||
if (reason != GUI_MENU_EXIT_ACCEPT || GUIVariantCompareInt(item->data, -1)) {
|
||||
break;
|
||||
}
|
||||
if (item->data == (void*) (GUI_INPUT_MAX + map->info->nKeys + 2)) {
|
||||
if (GUIVariantCompareInt(item->data, -2)) {
|
||||
for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) {
|
||||
item = GUIMenuItemListGetPointer(&menu.items, i);
|
||||
if ((uintptr_t) item->data < 1) {
|
||||
if (!GUIVariantIsUInt(item->data)) {
|
||||
continue;
|
||||
}
|
||||
if ((uintptr_t) item->data < GUI_INPUT_MAX + 1) {
|
||||
mInputBindKey(¶ms->keyMap, keys->id, item->state - 1, (uintptr_t) item->data - 1);
|
||||
} else if ((uintptr_t) item->data < GUI_INPUT_MAX + map->info->nKeys + 1) {
|
||||
mInputBindKey(map, keys->id, item->state - 1, (uintptr_t) item->data - GUI_INPUT_MAX - 1);
|
||||
if (item->data.v.u < GUI_INPUT_MAX + 1) {
|
||||
mInputBindKey(¶ms->keyMap, keys->id, item->state - 1, item->data.v.u - 1);
|
||||
} else if (item->data.v.u < GUI_INPUT_MAX + map->info->nKeys + 1) {
|
||||
mInputBindKey(map, keys->id, item->state - 1, item->data.v.u - GUI_INPUT_MAX - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -322,6 +322,7 @@ void GBMBCInit(struct GB* gb) {
|
|||
}
|
||||
gb->memory.mbcRead = NULL;
|
||||
gb->memory.directSramAccess = true;
|
||||
gb->memory.cartBusDecay = 4;
|
||||
switch (gb->memory.mbcType) {
|
||||
case GB_MBC_NONE:
|
||||
gb->memory.mbcWrite = _GBMBCNone;
|
||||
|
@ -442,6 +443,9 @@ void GBMBCInit(struct GB* gb) {
|
|||
void GBMBCReset(struct GB* gb) {
|
||||
gb->memory.currentBank0 = 0;
|
||||
gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
|
||||
gb->memory.cartBus = 0xFF;
|
||||
gb->memory.cartBusPc = 0;
|
||||
gb->memory.cartBusDecay = 1;
|
||||
|
||||
memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));
|
||||
GBMBCInit(gb);
|
||||
|
|
|
@ -51,12 +51,17 @@ static const uint8_t _blockedRegion[1] = { 0xFF };
|
|||
|
||||
static void _pristineCow(struct GB* gba);
|
||||
|
||||
static uint8_t GBFastLoad8(struct SM83Core* cpu, uint16_t address) {
|
||||
static uint8_t GBCartLoad8(struct SM83Core* cpu, uint16_t address) {
|
||||
if (UNLIKELY(address >= cpu->memory.activeRegionEnd)) {
|
||||
cpu->memory.setActiveRegion(cpu, address);
|
||||
return cpu->memory.cpuLoad8(cpu, address);
|
||||
}
|
||||
return cpu->memory.activeRegion[address & cpu->memory.activeMask];
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
memory->cartBusPc = address;
|
||||
uint8_t value = cpu->memory.activeRegion[address & cpu->memory.activeMask];
|
||||
memory->cartBus = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
|
||||
|
@ -67,7 +72,7 @@ static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
|
|||
case GB_REGION_CART_BANK0 + 1:
|
||||
case GB_REGION_CART_BANK0 + 2:
|
||||
case GB_REGION_CART_BANK0 + 3:
|
||||
cpu->memory.cpuLoad8 = GBFastLoad8;
|
||||
cpu->memory.cpuLoad8 = GBCartLoad8;
|
||||
cpu->memory.activeRegion = memory->romBase;
|
||||
cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1;
|
||||
cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1;
|
||||
|
@ -88,7 +93,7 @@ static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
|
|||
cpu->memory.cpuLoad8 = GBLoad8;
|
||||
break;
|
||||
}
|
||||
cpu->memory.cpuLoad8 = GBFastLoad8;
|
||||
cpu->memory.cpuLoad8 = GBCartLoad8;
|
||||
if (gb->memory.mbcType != GB_MBC6) {
|
||||
cpu->memory.activeRegion = memory->romBank;
|
||||
cpu->memory.activeRegionEnd = GB_BASE_VRAM;
|
||||
|
@ -238,24 +243,31 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
|
|||
case GB_REGION_CART_BANK0 + 2:
|
||||
case GB_REGION_CART_BANK0 + 3:
|
||||
if (address >= memory->romSize) {
|
||||
return 0xFF;
|
||||
memory->cartBus = 0xFF;
|
||||
} else {
|
||||
memory->cartBus = memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||
}
|
||||
return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||
memory->cartBusPc = cpu->pc;
|
||||
return memory->cartBus;
|
||||
case GB_REGION_CART_BANK1 + 2:
|
||||
case GB_REGION_CART_BANK1 + 3:
|
||||
if (memory->mbcType == GB_MBC6) {
|
||||
return memory->mbcState.mbc6.romBank1[address & (GB_SIZE_CART_HALFBANK - 1)];
|
||||
memory->cartBus = memory->mbcState.mbc6.romBank1[address & (GB_SIZE_CART_HALFBANK - 1)];
|
||||
memory->cartBusPc = cpu->pc;
|
||||
return memory->cartBus;
|
||||
}
|
||||
// Fall through
|
||||
case GB_REGION_CART_BANK1:
|
||||
case GB_REGION_CART_BANK1 + 1:
|
||||
if (address >= memory->romSize) {
|
||||
return 0xFF;
|
||||
memory->cartBus = 0xFF;
|
||||
} else if ((memory->mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
|
||||
memory->cartBus = memory->mbcRead(memory, address);
|
||||
} else {
|
||||
memory->cartBus = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||
}
|
||||
if ((memory->mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
|
||||
return memory->mbcRead(memory, address);
|
||||
}
|
||||
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||
memory->cartBusPc = cpu->pc;
|
||||
return memory->cartBus;
|
||||
case GB_REGION_VRAM:
|
||||
case GB_REGION_VRAM + 1:
|
||||
if (gb->video.mode != 3) {
|
||||
|
@ -265,15 +277,18 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
|
|||
case GB_REGION_EXTERNAL_RAM:
|
||||
case GB_REGION_EXTERNAL_RAM + 1:
|
||||
if (memory->rtcAccess) {
|
||||
return memory->rtcRegs[memory->activeRtcReg];
|
||||
memory->cartBus = memory->rtcRegs[memory->activeRtcReg];
|
||||
} else if (memory->mbcRead) {
|
||||
return memory->mbcRead(memory, address);
|
||||
memory->cartBus = memory->mbcRead(memory, address);
|
||||
} else if (memory->sramAccess && memory->sram) {
|
||||
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
|
||||
memory->cartBus = memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
|
||||
} else if (memory->mbcType == GB_HuC3) {
|
||||
return 0x01; // TODO: Is this supposed to be the current SRAM bank?
|
||||
memory->cartBus = 0x01; // TODO: Is this supposed to be the current SRAM bank?
|
||||
} else if (cpu->tMultiplier * (cpu->pc - memory->cartBusPc) >= memory->cartBusDecay) {
|
||||
memory->cartBus = 0xFF;
|
||||
}
|
||||
return 0xFF;
|
||||
memory->cartBusPc = cpu->pc;
|
||||
return memory->cartBus;
|
||||
case GB_REGION_WORKING_RAM_BANK0:
|
||||
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
||||
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
||||
|
@ -705,6 +720,9 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
|
|||
flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg);
|
||||
STORE_16LE(flags, 0, &state->memory.flags);
|
||||
|
||||
state->memory.cartBus = memory->cartBus;
|
||||
STORE_16LE(memory->cartBusPc, 0, &state->cartBusPc);
|
||||
|
||||
switch (memory->mbcType) {
|
||||
case GB_MBC1:
|
||||
state->memory.mbc1.mode = memory->mbcState.mbc1.mode;
|
||||
|
@ -784,6 +802,9 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
memory->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags);
|
||||
memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags);
|
||||
|
||||
memory->cartBus = state->memory.cartBus;
|
||||
LOAD_16LE(memory->cartBusPc, 0, &state->cartBusPc);
|
||||
|
||||
switch (memory->mbcType) {
|
||||
case GB_MBC1:
|
||||
memory->mbcState.mbc1.mode = state->memory.mbc1.mode;
|
||||
|
|
|
@ -265,8 +265,10 @@ void GBASkipBIOS(struct GBA* gba) {
|
|||
} else {
|
||||
cpu->gprs[ARM_PC] = BASE_WORKING_RAM + 0xC0;
|
||||
}
|
||||
gba->video.vcount = 0x7D;
|
||||
gba->memory.io[REG_VCOUNT >> 1] = 0x7D;
|
||||
gba->video.vcount = 0x7E;
|
||||
gba->memory.io[REG_VCOUNT >> 1] = 0x7E;
|
||||
mTimingDeschedule(&gba->timing, &gba->video.event);
|
||||
mTimingSchedule(&gba->timing, &gba->video.event, 117);
|
||||
gba->memory.io[REG_POSTFLG >> 1] = 1;
|
||||
ARMWritePC(cpu);
|
||||
}
|
||||
|
|
|
@ -973,6 +973,8 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||
}
|
||||
|
||||
void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
||||
GBAAudioWriteSOUNDCNT_X(&gba->audio, state->io[REG_SOUNDCNT_X >> 1]);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < REG_MAX; i += 2) {
|
||||
if (_isWSpecialRegister[i >> 1]) {
|
||||
|
@ -1003,7 +1005,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]);
|
||||
|
||||
|
|
|
@ -127,6 +127,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));
|
||||
|
@ -266,6 +267,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;
|
||||
}
|
||||
|
@ -717,6 +723,8 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
|
|||
value = GBASavedataReadFlash(&memory->savedata, address);
|
||||
} else if (memory->hw.devices & HW_TILT) {
|
||||
value = GBAHardwareTiltRead(&memory->hw, address & OFFSET_MASK);
|
||||
} else if (memory->savedata.type == SAVEDATA_SRAM512) {
|
||||
value = memory->savedata.data[address & (SIZE_CART_SRAM512 - 1)];
|
||||
} else {
|
||||
mLOG(GBA_MEM, GAME_ERROR, "Reading from non-existent SRAM: 0x%08X", address);
|
||||
value = 0xFF;
|
||||
|
@ -1070,6 +1078,9 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
|
|||
memory->savedata.dirty |= SAVEDATA_DIRT_NEW;
|
||||
} else if (memory->hw.devices & HW_TILT) {
|
||||
GBAHardwareTiltWrite(&memory->hw, address & OFFSET_MASK, value);
|
||||
} else if (memory->savedata.type == SAVEDATA_SRAM512) {
|
||||
memory->savedata.data[address & (SIZE_CART_SRAM512 - 1)] = value;
|
||||
memory->savedata.dirty |= SAVEDATA_DIRT_NEW;
|
||||
} else {
|
||||
mLOG(GBA_MEM, GAME_ERROR, "Writing to non-existent SRAM: 0x%08X", address);
|
||||
}
|
||||
|
|
|
@ -241,6 +241,9 @@ bool GBAOverrideFind(const struct Configuration* config, struct GBACartridgeOver
|
|||
if (strcasecmp(savetype, "SRAM") == 0) {
|
||||
found = true;
|
||||
override->savetype = SAVEDATA_SRAM;
|
||||
} else if (strcasecmp(savetype, "SRAM512") == 0) {
|
||||
found = true;
|
||||
override->savetype = SAVEDATA_SRAM512;
|
||||
} else if (strcasecmp(savetype, "EEPROM") == 0) {
|
||||
found = true;
|
||||
override->savetype = SAVEDATA_EEPROM;
|
||||
|
@ -288,6 +291,9 @@ void GBAOverrideSave(struct Configuration* config, const struct GBACartridgeOver
|
|||
case SAVEDATA_SRAM:
|
||||
savetype = "SRAM";
|
||||
break;
|
||||
case SAVEDATA_SRAM512:
|
||||
savetype = "SRAM512";
|
||||
break;
|
||||
case SAVEDATA_EEPROM:
|
||||
savetype = "EEPROM";
|
||||
break;
|
||||
|
|
|
@ -68,6 +68,9 @@ void GBASavedataDeinit(struct GBASavedata* savedata) {
|
|||
case SAVEDATA_SRAM:
|
||||
mappedMemoryFree(savedata->data, SIZE_CART_SRAM);
|
||||
break;
|
||||
case SAVEDATA_SRAM512:
|
||||
mappedMemoryFree(savedata->data, SIZE_CART_SRAM512);
|
||||
break;
|
||||
case SAVEDATA_FLASH512:
|
||||
mappedMemoryFree(savedata->data, SIZE_CART_FLASH512);
|
||||
break;
|
||||
|
@ -124,6 +127,8 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) {
|
|||
switch (savedata->type) {
|
||||
case SAVEDATA_SRAM:
|
||||
return out->write(out, savedata->data, SIZE_CART_SRAM) == SIZE_CART_SRAM;
|
||||
case SAVEDATA_SRAM512:
|
||||
return out->write(out, savedata->data, SIZE_CART_SRAM512) == SIZE_CART_SRAM512;
|
||||
case SAVEDATA_FLASH512:
|
||||
return out->write(out, savedata->data, SIZE_CART_FLASH512) == SIZE_CART_FLASH512;
|
||||
case SAVEDATA_FLASH1M:
|
||||
|
@ -153,6 +158,8 @@ size_t GBASavedataSize(const struct GBASavedata* savedata) {
|
|||
switch (savedata->type) {
|
||||
case SAVEDATA_SRAM:
|
||||
return SIZE_CART_SRAM;
|
||||
case SAVEDATA_SRAM512:
|
||||
return SIZE_CART_SRAM512;
|
||||
case SAVEDATA_FLASH512:
|
||||
return SIZE_CART_FLASH512;
|
||||
case SAVEDATA_FLASH1M:
|
||||
|
@ -233,6 +240,9 @@ void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type)
|
|||
case SAVEDATA_SRAM:
|
||||
GBASavedataInitSRAM(savedata);
|
||||
break;
|
||||
case SAVEDATA_SRAM512:
|
||||
GBASavedataInitSRAM512(savedata);
|
||||
break;
|
||||
case SAVEDATA_FORCE_NONE:
|
||||
savedata->type = SAVEDATA_FORCE_NONE;
|
||||
break;
|
||||
|
@ -322,6 +332,30 @@ void GBASavedataInitSRAM(struct GBASavedata* savedata) {
|
|||
}
|
||||
}
|
||||
|
||||
void GBASavedataInitSRAM512(struct GBASavedata* savedata) {
|
||||
if (savedata->type == SAVEDATA_AUTODETECT) {
|
||||
savedata->type = SAVEDATA_SRAM512;
|
||||
} else {
|
||||
mLOG(GBA_SAVE, WARN, "Can't re-initialize savedata");
|
||||
return;
|
||||
}
|
||||
off_t end;
|
||||
if (!savedata->vf) {
|
||||
end = 0;
|
||||
savedata->data = anonymousMemoryMap(SIZE_CART_SRAM512);
|
||||
} else {
|
||||
end = savedata->vf->size(savedata->vf);
|
||||
if (end < SIZE_CART_SRAM512) {
|
||||
savedata->vf->truncate(savedata->vf, SIZE_CART_SRAM512);
|
||||
}
|
||||
savedata->data = savedata->vf->map(savedata->vf, SIZE_CART_SRAM512, savedata->mapMode);
|
||||
}
|
||||
|
||||
if (end < SIZE_CART_SRAM512) {
|
||||
memset(&savedata->data[end], 0xFF, SIZE_CART_SRAM512 - end);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t GBASavedataReadFlash(struct GBASavedata* savedata, uint16_t address) {
|
||||
if (savedata->command == FLASH_COMMAND_ID) {
|
||||
if (savedata->type == SAVEDATA_FLASH512) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -141,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;
|
||||
|
@ -179,10 +180,14 @@ static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver
|
|||
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04X", node->id, value);
|
||||
|
||||
enum mLockstepPhase transferActive;
|
||||
int attached;
|
||||
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
|
||||
ATOMIC_LOAD(attached, node->p->d.attached);
|
||||
|
||||
driver->p->siocnt = GBASIOMultiplayerSetSlave(driver->p->siocnt, node->id || attached < 2);
|
||||
|
||||
if (value & 0x0080 && transferActive == TRANSFER_IDLE) {
|
||||
if (!node->id && GBASIOMultiplayerIsReady(node->d.p->siocnt)) {
|
||||
if (!node->id && attached > 1 && GBASIOMultiplayerIsReady(node->d.p->siocnt)) {
|
||||
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id);
|
||||
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
|
||||
ATOMIC_STORE(node->p->d.transferCycles, GBASIOCyclesPerTransfer[GBASIOMultiplayerGetBaud(node->d.p->siocnt)][node->p->d.attached - 1]);
|
||||
|
@ -442,11 +447,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);
|
||||
|
@ -455,8 +471,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;
|
||||
|
|
|
@ -72,7 +72,7 @@ void GBAVideoReset(struct GBAVideo* video) {
|
|||
} else {
|
||||
// TODO: Verify exact scanline on hardware
|
||||
video->vcount = 0x7E;
|
||||
nextEvent = 170;
|
||||
nextEvent = 117;
|
||||
}
|
||||
video->p->memory.io[REG_VCOUNT >> 1] = video->vcount;
|
||||
|
||||
|
|
|
@ -954,7 +954,7 @@ int main() {
|
|||
.configExtra = (struct GUIMenuItem[]) {
|
||||
{
|
||||
.title = "Screen mode",
|
||||
.data = "screenMode",
|
||||
.data = GUI_V_S("screenMode"),
|
||||
.submenu = 0,
|
||||
.state = SM_PA_TOP,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -969,7 +969,7 @@ int main() {
|
|||
},
|
||||
{
|
||||
.title = "Filtering",
|
||||
.data = "filterMode",
|
||||
.data = GUI_V_S("filterMode"),
|
||||
.submenu = 0,
|
||||
.state = FM_LINEAR_2x,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -981,7 +981,7 @@ int main() {
|
|||
},
|
||||
{
|
||||
.title = "Screen darkening",
|
||||
.data = "darkenMode",
|
||||
.data = GUI_V_S("darkenMode"),
|
||||
.submenu = 0,
|
||||
.state = DM_NATIVE,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -994,7 +994,7 @@ int main() {
|
|||
},
|
||||
{
|
||||
.title = "Camera",
|
||||
.data = "camera",
|
||||
.data = GUI_V_S("camera"),
|
||||
.submenu = 0,
|
||||
.state = 1,
|
||||
.validStates = (const char*[]) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <mgba/gb/core.h>
|
||||
#include <mgba/internal/gb/gb.h>
|
||||
#include <mgba/internal/gb/mbc.h>
|
||||
#include <mgba/internal/gb/overrides.h>
|
||||
#endif
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/gba/core.h>
|
||||
|
@ -146,6 +147,38 @@ static void _initRumble(void) {
|
|||
rumbleInitDone = true;
|
||||
}
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
static void _updateGbPal(void) {
|
||||
struct retro_variable var;
|
||||
var.key = "mgba_gb_colors";
|
||||
var.value = 0;
|
||||
if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
|
||||
const struct GBColorPreset* presets;
|
||||
size_t listSize = GBColorPresetList(&presets);
|
||||
size_t i;
|
||||
for (i = 0; i < listSize; ++i) {
|
||||
if (strcmp(presets[i].name, var.value) != 0) {
|
||||
continue;
|
||||
}
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[0]", presets[i].colors[0] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[1]", presets[i].colors[1] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[2]", presets[i].colors[2] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[3]", presets[i].colors[3] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[4]", presets[i].colors[4] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[5]", presets[i].colors[5] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[6]", presets[i].colors[6] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[7]", presets[i].colors[7] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[8]", presets[i].colors[8] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[9]", presets[i].colors[9] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[10]", presets[i].colors[10] & 0xFFFFFF);
|
||||
mCoreConfigSetUIntValue(&core->config, "gb.pal[11]", presets[i].colors[11] & 0xFFFFFF);
|
||||
core->reloadConfigOption(core, "gb.pal", NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void _reloadSettings(void) {
|
||||
struct mCoreOptions opts = {
|
||||
.useBios = true,
|
||||
|
@ -177,6 +210,14 @@ static void _reloadSettings(void) {
|
|||
mCoreConfigSetDefaultValue(&core->config, "sgb.model", modelName);
|
||||
mCoreConfigSetDefaultValue(&core->config, "cgb.model", modelName);
|
||||
}
|
||||
|
||||
var.key = "mgba_sgb_borders";
|
||||
var.value = 0;
|
||||
if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
|
||||
mCoreConfigSetDefaultIntValue(&core->config, "sgb.borders", strcmp(var.value, "ON") == 0);
|
||||
}
|
||||
|
||||
_updateGbPal();
|
||||
#endif
|
||||
|
||||
var.key = "mgba_use_bios";
|
||||
|
@ -191,14 +232,6 @@ static void _reloadSettings(void) {
|
|||
opts.skipBios = strcmp(var.value, "ON") == 0;
|
||||
}
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
var.key = "mgba_sgb_borders";
|
||||
var.value = 0;
|
||||
if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
|
||||
mCoreConfigSetDefaultIntValue(&core->config, "sgb.borders", strcmp(var.value, "ON") == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
var.key = "mgba_frameskip";
|
||||
var.value = 0;
|
||||
if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
|
||||
|
@ -248,6 +281,22 @@ unsigned retro_api_version(void) {
|
|||
void retro_set_environment(retro_environment_t env) {
|
||||
environCallback = env;
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
const struct GBColorPreset* presets;
|
||||
size_t listSize = GBColorPresetList(&presets);
|
||||
|
||||
size_t colorOpt;
|
||||
for (colorOpt = 0; option_defs_us[colorOpt].key; ++colorOpt) {
|
||||
if (strcmp(option_defs_us[colorOpt].key, "mgba_gb_colors") == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
size_t i;
|
||||
for (i = 0; i < listSize && i < RETRO_NUM_CORE_OPTION_VALUES_MAX; ++i) {
|
||||
option_defs_us[colorOpt].values[i].value = presets[i].name;
|
||||
}
|
||||
#endif
|
||||
|
||||
libretro_set_core_options(environCallback);
|
||||
}
|
||||
|
||||
|
@ -429,6 +478,10 @@ void retro_run(void) {
|
|||
mCoreConfigSetIntValue(&core->config, "frameskip", strtol(var.value, NULL, 10));
|
||||
core->reloadConfigOption(core, "frameskip", NULL);
|
||||
}
|
||||
|
||||
#ifdef M_CORE_GB
|
||||
_updateGbPal();
|
||||
#endif
|
||||
}
|
||||
|
||||
keys = 0;
|
||||
|
|
|
@ -186,6 +186,17 @@ struct retro_core_option_definition option_defs_us[] = {
|
|||
},
|
||||
"OFF"
|
||||
},
|
||||
{
|
||||
"mgba_gb_colors",
|
||||
"Set default Game Boy palette",
|
||||
"Selects which palette is used for Game Boy games that are not Game Boy Color or Super Game Boy compatible, or if the model is forced to Game Boy.",
|
||||
{
|
||||
// This list is populated at runtime
|
||||
{ "Grayscale", NULL },
|
||||
{ NULL, NULL },
|
||||
},
|
||||
"Grayscale"
|
||||
},
|
||||
{ NULL, NULL, NULL, {{0}}, NULL },
|
||||
};
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ int main() {
|
|||
.configExtra = (struct GUIMenuItem[]) {
|
||||
{
|
||||
.title = "Screen mode",
|
||||
.data = "screenMode",
|
||||
.data = GUI_V_S("screenMode"),
|
||||
.submenu = 0,
|
||||
.state = 0,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -173,7 +173,7 @@ int main() {
|
|||
},
|
||||
{
|
||||
.title = "Camera",
|
||||
.data = "camera",
|
||||
.data = GUI_V_S("camera"),
|
||||
.submenu = 0,
|
||||
.state = 1,
|
||||
.validStates = (const char*[]) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -142,7 +142,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="QRadioButton" name="gateBattleChip">
|
||||
<property name="text">
|
||||
<string>Ba&ttleChip Gate</string>
|
||||
<string notr="true">Ba&ttleChip Gate</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
|
@ -152,14 +152,14 @@
|
|||
<item row="2" column="1">
|
||||
<widget class="QRadioButton" name="gateProgress">
|
||||
<property name="text">
|
||||
<string>Progress &Gate</string>
|
||||
<string notr="true">Progress &Gate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QRadioButton" name="gateBeastLink">
|
||||
<property name="text">
|
||||
<string>Beast &Link Gate</string>
|
||||
<string notr="true">Beast &Link Gate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
#include "GBAApp.h"
|
||||
#include "CoreController.h"
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QButtonGroup>
|
||||
#include <QClipboard>
|
||||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
|
||||
#include <mgba/core/cheats.h>
|
||||
#ifdef M_CORE_GBA
|
||||
|
@ -30,58 +32,30 @@ CheatsView::CheatsView(std::shared_ptr<CoreController> controller, QWidget* pare
|
|||
|
||||
m_ui.cheatList->installEventFilter(this);
|
||||
m_ui.cheatList->setModel(&m_model);
|
||||
m_ui.codeEntry->setFont(GBAApp::app()->monospaceFont());
|
||||
|
||||
connect(m_ui.load, &QPushButton::clicked, this, &CheatsView::load);
|
||||
connect(m_ui.save, &QPushButton::clicked, this, &CheatsView::save);
|
||||
connect(m_ui.addSet, &QPushButton::clicked, this, &CheatsView::addSet);
|
||||
connect(m_ui.remove, &QPushButton::clicked, this, &CheatsView::removeSet);
|
||||
connect(m_ui.load, &QAbstractButton::clicked, this, &CheatsView::load);
|
||||
connect(m_ui.save, &QAbstractButton::clicked, this, &CheatsView::save);
|
||||
connect(m_ui.addSet, &QAbstractButton::clicked, this, &CheatsView::addSet);
|
||||
connect(m_ui.remove, &QAbstractButton::clicked, this, &CheatsView::removeSet);
|
||||
connect(m_ui.add, &QAbstractButton::clicked, this, &CheatsView::enterCheat);
|
||||
connect(controller.get(), &CoreController::stopping, this, &CheatsView::close);
|
||||
connect(controller.get(), &CoreController::stateLoaded, &m_model, &CheatsModel::invalidated);
|
||||
|
||||
QPushButton* add;
|
||||
switch (controller->platform()) {
|
||||
#ifdef M_CORE_GBA
|
||||
case mPLATFORM_GBA:
|
||||
connect(m_ui.add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBA_CHEAT_AUTODETECT);
|
||||
});
|
||||
|
||||
add = new QPushButton(tr("Add GameShark"));
|
||||
m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2);
|
||||
connect(add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBA_CHEAT_GAMESHARK);
|
||||
});
|
||||
|
||||
add = new QPushButton(tr("Add Pro Action Replay"));
|
||||
m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2);
|
||||
connect(add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBA_CHEAT_PRO_ACTION_REPLAY);
|
||||
});
|
||||
|
||||
add = new QPushButton(tr("Add CodeBreaker"));
|
||||
m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2);
|
||||
connect(add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GBA_CHEAT_CODEBREAKER);
|
||||
});
|
||||
registerCodeType(tr("Autodetect (recommended)"), GBA_CHEAT_AUTODETECT);
|
||||
registerCodeType(QLatin1String("GameShark"), GBA_CHEAT_GAMESHARK);
|
||||
registerCodeType(QLatin1String("Action Replay MAX"), GBA_CHEAT_PRO_ACTION_REPLAY);
|
||||
registerCodeType(QLatin1String("CodeBreaker"), GBA_CHEAT_CODEBREAKER);
|
||||
break;
|
||||
#endif
|
||||
#ifdef M_CORE_GB
|
||||
case mPLATFORM_GB:
|
||||
connect(m_ui.add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GB_CHEAT_AUTODETECT);
|
||||
});
|
||||
|
||||
add = new QPushButton(tr("Add GameShark"));
|
||||
m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2);
|
||||
connect(add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GB_CHEAT_GAMESHARK);
|
||||
});
|
||||
|
||||
add = new QPushButton(tr("Add GameGenie"));
|
||||
m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2);
|
||||
connect(add, &QPushButton::clicked, [this]() {
|
||||
enterCheat(GB_CHEAT_GAME_GENIE);
|
||||
});
|
||||
registerCodeType(tr("Autodetect (recommended)"), GB_CHEAT_AUTODETECT);
|
||||
registerCodeType(QLatin1String("GameShark"), GB_CHEAT_GAMESHARK);
|
||||
registerCodeType(QLatin1String("Game Genie"), GB_CHEAT_GAME_GENIE);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
@ -127,6 +101,7 @@ void CheatsView::addSet() {
|
|||
mCheatSet* set = m_controller->cheatDevice()->createSet(m_controller->cheatDevice(), nullptr);
|
||||
m_model.addSet(set);
|
||||
m_ui.cheatList->selectionModel()->select(m_model.index(m_model.rowCount() - 1, 0, QModelIndex()), QItemSelectionModel::ClearAndSelect);
|
||||
enterCheat();
|
||||
}
|
||||
|
||||
void CheatsView::removeSet() {
|
||||
|
@ -140,7 +115,21 @@ void CheatsView::removeSet() {
|
|||
}
|
||||
}
|
||||
|
||||
void CheatsView::enterCheat(int codeType) {
|
||||
void CheatsView::registerCodeType(const QString& label, int type) {
|
||||
QRadioButton* add = new QRadioButton(label);
|
||||
m_ui.typeLayout->addWidget(add);
|
||||
connect(add, &QAbstractButton::clicked, [this, type]() {
|
||||
m_codeType = type;
|
||||
});
|
||||
if (!m_typeGroup) {
|
||||
m_typeGroup = new QButtonGroup(this);
|
||||
m_codeType = type;
|
||||
add->setChecked(true);
|
||||
}
|
||||
m_typeGroup->addButton(add);
|
||||
}
|
||||
|
||||
void CheatsView::enterCheat() {
|
||||
mCheatSet* set = nullptr;
|
||||
QModelIndexList selection = m_ui.cheatList->selectionModel()->selectedIndexes();
|
||||
QModelIndex index;
|
||||
|
@ -163,7 +152,7 @@ void CheatsView::enterCheat(int codeType) {
|
|||
QStringList cheats = m_ui.codeEntry->toPlainText().split('\n', QString::SkipEmptyParts);
|
||||
for (const QString& string : cheats) {
|
||||
m_model.beginAppendRow(index);
|
||||
mCheatAddLine(set, string.toUtf8().constData(), codeType);
|
||||
mCheatAddLine(set, string.toUtf8().constData(), m_codeType);
|
||||
m_model.endAppendRow();
|
||||
}
|
||||
if (set->refresh) {
|
||||
|
|
|
@ -33,13 +33,17 @@ private slots:
|
|||
void save();
|
||||
void addSet();
|
||||
void removeSet();
|
||||
void enterCheat();
|
||||
|
||||
private:
|
||||
void enterCheat(int codeType);
|
||||
void registerCodeType(const QString& label, int type);
|
||||
|
||||
Ui::CheatsView m_ui;
|
||||
std::shared_ptr<CoreController> m_controller;
|
||||
CheatsModel m_model;
|
||||
QButtonGroup* m_typeGroup = nullptr;
|
||||
|
||||
int m_codeType = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -6,60 +6,18 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>629</width>
|
||||
<height>428</height>
|
||||
<width>520</width>
|
||||
<height>455</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Cheats</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="3,0,0,0">
|
||||
<item row="2" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="remove">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="save">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="load">
|
||||
<property name="text">
|
||||
<string>Load</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="addSet">
|
||||
<property name="text">
|
||||
<string>Add New Set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2" colspan="2">
|
||||
<widget class="QPushButton" name="add">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="7" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,1,0,0" columnstretch="4,0,0">
|
||||
<item row="0" column="0" rowspan="7">
|
||||
<widget class="QTreeView" name="cheatList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
@ -75,18 +33,51 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2" rowspan="2" colspan="2">
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QPushButton" name="addSet">
|
||||
<property name="text">
|
||||
<string>Add New Code</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="load">
|
||||
<property name="text">
|
||||
<string>Load</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="save">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QPushButton" name="remove">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QPlainTextEdit" name="codeEntry">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Courier New</family>
|
||||
</font>
|
||||
<property name="tabChangesFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
|
@ -96,6 +87,21 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="2">
|
||||
<widget class="QPushButton" name="add">
|
||||
<property name="text">
|
||||
<string>Add Lines</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="2">
|
||||
<widget class="QGroupBox" name="typeBox">
|
||||
<property name="title">
|
||||
<string>Code type</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="typeLayout"/>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
|
|
|
@ -529,6 +529,21 @@ void CoreController::forceFastForward(bool enable) {
|
|||
emit fastForwardChanged(enable || m_fastForward);
|
||||
}
|
||||
|
||||
void CoreController::overrideMute(bool override) {
|
||||
m_mute = override;
|
||||
|
||||
Interrupter interrupter(this);
|
||||
mCore* core = m_threadContext.core;
|
||||
if (m_mute) {
|
||||
core->opts.mute = true;
|
||||
} else {
|
||||
int fakeBool = 0;
|
||||
mCoreConfigGetIntValue(&core->config, "mute", &fakeBool);
|
||||
core->opts.mute = fakeBool;
|
||||
}
|
||||
core->reloadConfigOption(core, NULL, NULL);
|
||||
}
|
||||
|
||||
void CoreController::loadState(int slot) {
|
||||
if (slot > 0 && slot != m_stateSlot) {
|
||||
m_stateSlot = slot;
|
||||
|
@ -1046,7 +1061,7 @@ void CoreController::updateFastForward() {
|
|||
m_threadContext.core->opts.volume = m_fastForwardVolume;
|
||||
}
|
||||
if (m_fastForwardMute >= 0) {
|
||||
m_threadContext.core->opts.mute = m_fastForwardMute;
|
||||
m_threadContext.core->opts.mute = m_fastForwardMute || m_mute;
|
||||
}
|
||||
|
||||
// If we aren't holding the fast forward button
|
||||
|
|
|
@ -141,6 +141,8 @@ public slots:
|
|||
void setFastForward(bool);
|
||||
void forceFastForward(bool);
|
||||
|
||||
void overrideMute(bool);
|
||||
|
||||
void loadState(int slot = 0);
|
||||
void loadState(const QString& path, int flags = -1);
|
||||
void loadState(QIODevice* iodev, int flags = -1);
|
||||
|
@ -272,6 +274,8 @@ private:
|
|||
float m_fastForwardHeldRatio = -1.f;
|
||||
float m_fpsTarget;
|
||||
|
||||
bool m_mute;
|
||||
|
||||
InputController* m_inputController = nullptr;
|
||||
LogController* m_log = nullptr;
|
||||
MultiplayerController* m_multiplayer = nullptr;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "DiscordCoordinator.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
#include "CoreController.h"
|
||||
#include "GBAApp.h"
|
||||
|
||||
|
@ -31,6 +33,11 @@ static void updatePresence() {
|
|||
discordPresence.details = s_title.toUtf8().constData();
|
||||
discordPresence.instance = 1;
|
||||
discordPresence.largeImageKey = "mgba";
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
|
||||
discordPresence.startTimestamp = QDateTime::currentSecsSinceEpoch();
|
||||
#else
|
||||
discordPresence.startTimestamp = QDateTime::currentMSecsSinceEpoch() / 1000;
|
||||
#endif
|
||||
Discord_UpdatePresence(&discordPresence);
|
||||
} else {
|
||||
Discord_ClearPresence();
|
||||
|
|
|
@ -447,12 +447,12 @@ void PainterGL::draw() {
|
|||
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 = true;
|
||||
} else if (!forceRedraw) {
|
||||
forceRedraw = m_delayTimer.nsecsElapsed() + 2000000 >= 1000000000 / m_surface->screen()->refreshRate();
|
||||
forceRedraw = m_delayTimer.nsecsElapsed() + 1'000'000 >= 1'000'000'000 / m_surface->screen()->refreshRate();
|
||||
}
|
||||
}
|
||||
mCoreSyncWaitFrameEnd(sync);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
@ -473,9 +503,6 @@
|
|||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Return, Ctrl+R</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -564,6 +591,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 +699,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>
|
||||
|
|
|
@ -143,7 +143,17 @@
|
|||
</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>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>SRAM 64kB (bootlegs only)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -423,6 +423,8 @@ void SettingsView::updateConfig() {
|
|||
saveSetting("suspendScreensaver", m_ui.suspendScreensaver);
|
||||
saveSetting("pauseOnFocusLost", m_ui.pauseOnFocusLost);
|
||||
saveSetting("pauseOnMinimize", m_ui.pauseOnMinimize);
|
||||
saveSetting("muteOnFocusLost", m_ui.muteOnFocusLost);
|
||||
saveSetting("muteOnMinimize", m_ui.muteOnMinimize);
|
||||
saveSetting("savegamePath", m_ui.savegamePath);
|
||||
saveSetting("savestatePath", m_ui.savestatePath);
|
||||
saveSetting("screenshotPath", m_ui.screenshotPath);
|
||||
|
@ -534,6 +536,14 @@ void SettingsView::updateConfig() {
|
|||
emit languageChanged();
|
||||
}
|
||||
|
||||
if (m_ui.multiplayerAudioAll->isChecked()) {
|
||||
m_controller->setQtOption("multiplayerAudio", "all");
|
||||
} else if (m_ui.multiplayerAudio1->isChecked()) {
|
||||
m_controller->setQtOption("multiplayerAudio", "p1");
|
||||
} else if (m_ui.multiplayerAudioActive->isChecked()) {
|
||||
m_controller->setQtOption("multiplayerAudio", "active");
|
||||
}
|
||||
|
||||
int hwaccelVideo = m_controller->getOption("hwaccelVideo").toInt();
|
||||
saveSetting("hwaccelVideo", m_ui.hwaccelVideo->currentIndex());
|
||||
if (hwaccelVideo != m_ui.hwaccelVideo->currentIndex()) {
|
||||
|
@ -767,6 +777,15 @@ void SettingsView::reloadConfig() {
|
|||
m_ui.videoScaleSize->setText(tr("(%1×%2)").arg(GBA_VIDEO_HORIZONTAL_PIXELS * value).arg(GBA_VIDEO_VERTICAL_PIXELS * value));
|
||||
});
|
||||
loadSetting("videoScale", m_ui.videoScale, 1);
|
||||
|
||||
QString multiplayerAudio = m_controller->getQtOption("multiplayerAudio").toString();
|
||||
if (multiplayerAudio == QLatin1String("p1")) {
|
||||
m_ui.multiplayerAudio1->setChecked(true);
|
||||
} else if (multiplayerAudio == QLatin1String("active")) {
|
||||
m_ui.multiplayerAudioActive->setChecked(true);
|
||||
} else {
|
||||
m_ui.multiplayerAudioAll->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsView::addPage(const QString& name, QWidget* view, Page index) {
|
||||
|
|
|
@ -313,21 +313,61 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_43">
|
||||
<property name="text">
|
||||
<string>Audio in multiplayer:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QRadioButton" name="multiplayerAudioAll">
|
||||
<property name="text">
|
||||
<string>All windows</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">multiplayerAudio</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QRadioButton" name="multiplayerAudio1">
|
||||
<property name="text">
|
||||
<string>Player 1 window only</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">multiplayerAudio</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QRadioButton" name="multiplayerAudioActive">
|
||||
<property name="text">
|
||||
<string>Currently active player window</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">multiplayerAudio</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Display driver:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="9" column="1">
|
||||
<widget class="QComboBox" name="displayDriver">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
|
@ -337,14 +377,14 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Frameskip:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="10" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_16">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
|
@ -365,14 +405,14 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>FPS target:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="11" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="fpsTarget">
|
||||
|
@ -399,28 +439,28 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="12" 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">
|
||||
<item row="13" column="0" colspan="2">
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Sync:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="14" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="videoSync">
|
||||
|
@ -438,28 +478,28 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="lockAspectRatio">
|
||||
<property name="text">
|
||||
<string>Lock aspect ratio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="16" column="1">
|
||||
<widget class="QCheckBox" name="lockIntegerScaling">
|
||||
<property name="text">
|
||||
<string>Force integer scaling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="17" column="1">
|
||||
<widget class="QCheckBox" name="interframeBlending">
|
||||
<property name="text">
|
||||
<string>Interframe blending</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<item row="18" column="1">
|
||||
<widget class="QCheckBox" name="resampleVideo">
|
||||
<property name="text">
|
||||
<string>Bilinear filtering</string>
|
||||
|
@ -556,18 +596,22 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QCheckBox" name="pauseOnFocusLost">
|
||||
<property name="text">
|
||||
<string>Pause when inactive</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="pauseOnMinimize">
|
||||
<property name="text">
|
||||
<string>Pause when minimized</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="pauseOnFocusLost">
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="muteOnFocusLost">
|
||||
<property name="text">
|
||||
<string>Mute</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="2">
|
||||
<widget class="Line" name="line_17">
|
||||
|
@ -684,6 +728,38 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_24">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="pauseOnMinimize">
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="muteOnMinimize">
|
||||
<property name="text">
|
||||
<string>Mute</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_41">
|
||||
<property name="text">
|
||||
<string>When inactive:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_42">
|
||||
<property name="text">
|
||||
<string>When minimized:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="emulation">
|
||||
|
@ -2218,5 +2294,6 @@
|
|||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="gbColors"/>
|
||||
<buttongroup name="multiplayerAudio"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
|
|
@ -250,6 +250,11 @@ void Window::resizeFrame(const QSize& size) {
|
|||
}
|
||||
}
|
||||
|
||||
void Window::updateMultiplayerActive(bool active) {
|
||||
m_multiActive = active;
|
||||
updateMute();
|
||||
}
|
||||
|
||||
void Window::setConfig(ConfigController* config) {
|
||||
m_config = config;
|
||||
}
|
||||
|
@ -282,6 +287,7 @@ void Window::reloadConfig() {
|
|||
if (m_audioProcessor) {
|
||||
m_audioProcessor->configure(m_config);
|
||||
}
|
||||
updateMute();
|
||||
m_display->resizeContext();
|
||||
}
|
||||
|
||||
|
@ -673,12 +679,17 @@ void Window::resizeEvent(QResizeEvent*) {
|
|||
|
||||
void Window::showEvent(QShowEvent* event) {
|
||||
if (m_wasOpened) {
|
||||
if (event->spontaneous() && m_config->getOption("pauseOnMinimize").toInt() && m_controller) {
|
||||
if (event->spontaneous() && m_controller) {
|
||||
focusCheck();
|
||||
if (m_autoresume) {
|
||||
if (m_config->getOption("pauseOnMinimize").toInt() && m_autoresume) {
|
||||
m_controller->setPaused(false);
|
||||
m_autoresume = false;
|
||||
}
|
||||
|
||||
if (m_config->getOption("muteOnMinimize").toInt()) {
|
||||
m_inactiveMute = false;
|
||||
updateMute();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -709,13 +720,18 @@ void Window::hideEvent(QHideEvent* event) {
|
|||
if (!event->spontaneous()) {
|
||||
return;
|
||||
}
|
||||
if (!m_config->getOption("pauseOnMinimize").toInt() || !m_controller) {
|
||||
if (!m_controller) {
|
||||
return;
|
||||
}
|
||||
if (!m_controller->isPaused()) {
|
||||
|
||||
if (m_config->getOption("pauseOnMinimize").toInt() && !m_controller->isPaused()) {
|
||||
m_autoresume = true;
|
||||
m_controller->setPaused(true);
|
||||
}
|
||||
if (m_config->getOption("muteOnMinimize").toInt()) {
|
||||
m_inactiveMute = true;
|
||||
updateMute();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::closeEvent(QCloseEvent* event) {
|
||||
|
@ -737,6 +753,13 @@ void Window::closeEvent(QCloseEvent* event) {
|
|||
}
|
||||
|
||||
void Window::focusInEvent(QFocusEvent*) {
|
||||
for (Window* window : GBAApp::app()->windows()) {
|
||||
if (window != this) {
|
||||
window->updateMultiplayerActive(false);
|
||||
} else {
|
||||
updateMultiplayerActive(true);
|
||||
}
|
||||
}
|
||||
m_display->forceDraw();
|
||||
}
|
||||
|
||||
|
@ -1873,15 +1896,25 @@ Action* Window::addGameAction(const QString& visibleName, const QString& name, A
|
|||
}
|
||||
|
||||
void Window::focusCheck() {
|
||||
if (!m_config->getOption("pauseOnFocusLost").toInt() || !m_controller) {
|
||||
if (!m_controller) {
|
||||
return;
|
||||
}
|
||||
if (QGuiApplication::focusWindow() && m_autoresume) {
|
||||
m_controller->setPaused(false);
|
||||
m_autoresume = false;
|
||||
} else if (!QGuiApplication::focusWindow() && !m_controller->isPaused()) {
|
||||
m_autoresume = true;
|
||||
m_controller->setPaused(true);
|
||||
if (m_config->getOption("pauseOnFocusLost").toInt()) {
|
||||
if (QGuiApplication::focusWindow() && m_autoresume) {
|
||||
m_controller->setPaused(false);
|
||||
m_autoresume = false;
|
||||
} else if (!QGuiApplication::focusWindow() && !m_controller->isPaused()) {
|
||||
m_autoresume = true;
|
||||
m_controller->setPaused(true);
|
||||
}
|
||||
}
|
||||
if (m_config->getOption("muteOnFocusLost").toInt()) {
|
||||
if (QGuiApplication::focusWindow()) {
|
||||
m_inactiveMute = false;
|
||||
} else {
|
||||
m_inactiveMute = true;
|
||||
}
|
||||
updateMute();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2020,6 +2053,26 @@ void Window::attachDisplay() {
|
|||
m_display->startDrawing(m_controller);
|
||||
}
|
||||
|
||||
void Window::updateMute() {
|
||||
if (!m_controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool mute = m_inactiveMute;
|
||||
|
||||
if (!mute) {
|
||||
QString multiplayerAudio = m_config->getQtOption("multiplayerAudio").toString();
|
||||
if (multiplayerAudio == QLatin1String("p1")) {
|
||||
MultiplayerController* multiplayer = m_controller->multiplayerController();
|
||||
mute = multiplayer && multiplayer->attached() > 1 && multiplayer->playerId(m_controller.get());
|
||||
} else if (multiplayerAudio == QLatin1String("active")) {
|
||||
mute = !m_multiActive;
|
||||
}
|
||||
}
|
||||
|
||||
m_controller->overrideMute(mute);
|
||||
}
|
||||
|
||||
void Window::setLogo() {
|
||||
m_screenWidget->setPixmap(m_logo);
|
||||
m_screenWidget->setCenteredAspectRatio(m_logo.width(), m_logo.height());
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
void resizeFrame(const QSize& size);
|
||||
|
||||
void updateMultiplayerStatus(bool canOpenAnother) { m_multiWindow->setEnabled(canOpenAnother); }
|
||||
void updateMultiplayerActive(bool active);
|
||||
|
||||
signals:
|
||||
void startDrawing();
|
||||
|
@ -145,6 +146,7 @@ private slots:
|
|||
void focusCheck();
|
||||
|
||||
void updateFrame();
|
||||
void updateMute();
|
||||
|
||||
void setLogo();
|
||||
|
||||
|
@ -224,6 +226,9 @@ private:
|
|||
|
||||
bool m_hitUnimplementedBiosCall;
|
||||
|
||||
bool m_inactiveMute = false;
|
||||
bool m_multiActive = true;
|
||||
|
||||
std::unique_ptr<OverrideView> m_overrideView;
|
||||
std::unique_ptr<SensorView> m_sensorView;
|
||||
std::unique_ptr<DolphinConnector> m_dolphinView;
|
||||
|
|
|
@ -59,6 +59,7 @@ InputController::InputController(int playerId, QWidget* topLevel, QObject* paren
|
|||
mSDLInitEvents(&s_sdlEvents);
|
||||
}
|
||||
++s_sdlInited;
|
||||
m_sdlPlayer.bindings = &m_inputMap;
|
||||
updateJoysticks();
|
||||
#endif
|
||||
|
||||
|
@ -272,34 +273,45 @@ void InputController::setConfiguration(ConfigController* config) {
|
|||
if (!m_playerAttached) {
|
||||
m_playerAttached = mSDLAttachPlayer(&s_sdlEvents, &m_sdlPlayer);
|
||||
}
|
||||
loadConfiguration(SDL_BINDING_BUTTON);
|
||||
if (!loadConfiguration(SDL_BINDING_BUTTON)) {
|
||||
mSDLInitBindingsGBA(&m_inputMap);
|
||||
}
|
||||
loadProfile(SDL_BINDING_BUTTON, profileForType(SDL_BINDING_BUTTON));
|
||||
#endif
|
||||
restoreModel();
|
||||
}
|
||||
|
||||
void InputController::loadConfiguration(uint32_t type) {
|
||||
bool InputController::loadConfiguration(uint32_t type) {
|
||||
if (!m_activeKeyInfo) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!mInputMapLoad(&m_inputMap, type, m_config->input())) {
|
||||
return false;
|
||||
}
|
||||
mInputMapLoad(&m_inputMap, type, m_config->input());
|
||||
#ifdef BUILD_SDL
|
||||
if (m_playerAttached) {
|
||||
mSDLPlayerLoadConfig(&m_sdlPlayer, m_config->input());
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputController::loadProfile(uint32_t type, const QString& profile) {
|
||||
bool InputController::loadProfile(uint32_t type, const QString& profile) {
|
||||
if (profile.isEmpty()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const InputProfile* ip = InputProfile::findProfile(profile);
|
||||
if (ip) {
|
||||
ip->apply(this);
|
||||
bool loaded = mInputProfileLoad(&m_inputMap, type, m_config->input(), profile.toUtf8().constData());
|
||||
recalibrateAxes();
|
||||
if (!loaded) {
|
||||
const InputProfile* ip = InputProfile::findProfile(profile);
|
||||
if (ip) {
|
||||
ip->apply(this);
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
recalibrateAxes();
|
||||
emit profileLoaded(profile);
|
||||
return loaded;
|
||||
}
|
||||
|
||||
void InputController::saveConfiguration() {
|
||||
|
|
|
@ -73,8 +73,8 @@ public:
|
|||
|
||||
void setConfiguration(ConfigController* config);
|
||||
void saveConfiguration();
|
||||
void loadConfiguration(uint32_t type);
|
||||
void loadProfile(uint32_t type, const QString& profile);
|
||||
bool loadConfiguration(uint32_t type);
|
||||
bool loadProfile(uint32_t type, const QString& profile);
|
||||
void saveConfiguration(uint32_t type);
|
||||
void saveProfile(uint32_t type, const QString& profile);
|
||||
const char* profileForType(uint32_t type);
|
||||
|
|
|
@ -106,6 +106,7 @@ VFile* LibraryController::selectedVFile() {
|
|||
QByteArray filenameUtf8(entry.filename.toUtf8());
|
||||
libentry.base = baseUtf8.constData();
|
||||
libentry.filename = filenameUtf8.constData();
|
||||
libentry.platform = mPLATFORM_NONE;
|
||||
return mLibraryOpenVFile(m_library.get(), &libentry);
|
||||
} else {
|
||||
return nullptr;
|
||||
|
|
|
@ -56,12 +56,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
|
|||
<message>
|
||||
<location filename="../ArchiveInspector.ui" line="14"/>
|
||||
<source>Open in archive...</source>
|
||||
<translation>In Archiv öffnen …</translation>
|
||||
<translation>In Archiv öffnen …</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ArchiveInspector.ui" line="20"/>
|
||||
<source>Loading...</source>
|
||||
<translation>Laden …</translation>
|
||||
<translation>Laden …</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -69,12 +69,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
|
|||
<message>
|
||||
<location filename="../AssetTile.ui" line="41"/>
|
||||
<source>Tile #</source>
|
||||
<translation>Tile Nr.</translation>
|
||||
<translation>Tile #</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../AssetTile.ui" line="65"/>
|
||||
<source>Palette #</source>
|
||||
<translation>Palette Nr.</translation>
|
||||
<translation>Palette #</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../AssetTile.ui" line="86"/>
|
||||
|
@ -1071,7 +1071,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
|
|||
<message>
|
||||
<location filename="../OverrideView.ui" line="519"/>
|
||||
<source>Palette preset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Paletten-Voreinstellung</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -4252,7 +4252,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
|
|||
<message>
|
||||
<location filename="../Window.cpp" line="1184"/>
|
||||
<source>Convert e-Reader card image to raw...</source>
|
||||
<translation>Lesegerät-Kartenbild in Rohdaten umwandeln …</translation>
|
||||
<translation>Lesegerät-Kartenbild in Rohdaten umwandeln …</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Window.cpp" line="1188"/>
|
||||
|
@ -5357,37 +5357,37 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="1852"/>
|
||||
<source>Default color palette only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nur Standard-Farbpalette</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1862"/>
|
||||
<source>SGB color palette if available</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>SGB-Farbpalette, sofern verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1872"/>
|
||||
<source>GBC color palette if available</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>GBC-Farbpalette, sofern verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1882"/>
|
||||
<source>SGB (preferred) or GBC color palette if available</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>SGB (bevorzugt) oder GBC-Farbpalette, sofern verfügbar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1895"/>
|
||||
<source>Game Boy Camera</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Game Boy Camera</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1901"/>
|
||||
<source>Driver:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Treiber:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1918"/>
|
||||
<source>Source:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Quelle:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="405"/>
|
||||
|
@ -5448,42 +5448,42 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="1502"/>
|
||||
<source>Models</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Modelle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1508"/>
|
||||
<source>GB only:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nur GB:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1518"/>
|
||||
<source>SGB compatible:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>SGB-kompatibel:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1528"/>
|
||||
<source>GBC only:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nur GBC:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1538"/>
|
||||
<source>GBC compatible:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>GBC-kompatibel:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1548"/>
|
||||
<source>SGB and GBC compatible:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>SGB- und GBC-kompatibel:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1568"/>
|
||||
<source>Game Boy palette</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Game Boy-Palette</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1574"/>
|
||||
<source>Preset:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Voreinstellungen:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="879"/>
|
||||
|
@ -5538,7 +5538,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd.</translation
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="886"/>
|
||||
<source>Enable VBA bug compatibility in ROM hacks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>VBA-Bug-Kompatibilität in ROM-Hacks aktivieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="982"/>
|
||||
|
|
|
@ -5286,37 +5286,37 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="1852"/>
|
||||
<source>Default color palette only</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sólo paleta de colores predeterminada</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1862"/>
|
||||
<source>SGB color palette if available</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Paleta de color SGB si está disponible</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1872"/>
|
||||
<source>GBC color palette if available</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Paleta de color GBC si está disponible</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1882"/>
|
||||
<source>SGB (preferred) or GBC color palette if available</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Paleta de colores SGB (preferida) o GBC si está disponible</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1895"/>
|
||||
<source>Game Boy Camera</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Cámara Game Boy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1901"/>
|
||||
<source>Driver:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Controlador:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1918"/>
|
||||
<source>Source:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Fuente:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="405"/>
|
||||
|
@ -5362,12 +5362,12 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="886"/>
|
||||
<source>Enable VBA bug compatibility in ROM hacks</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Activar modo de compatibilidad VBA en ROM hacks</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1574"/>
|
||||
<source>Preset:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ajustes:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="602"/>
|
||||
|
@ -5662,37 +5662,37 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation>
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="1502"/>
|
||||
<source>Models</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Modelos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1508"/>
|
||||
<source>GB only:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sólo GB:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1518"/>
|
||||
<source>SGB compatible:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Compatible con SGB:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1528"/>
|
||||
<source>GBC only:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Sólo GBC:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1538"/>
|
||||
<source>GBC compatible:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Compatible con GBC:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1548"/>
|
||||
<source>SGB and GBC compatible:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Compatible con SGB y GBC:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1568"/>
|
||||
<source>Game Boy palette</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Paleta de Game Boy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1584"/>
|
||||
|
|
|
@ -1047,12 +1047,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../OverrideView.ui" line="342"/>
|
||||
<source>Sprite Colors 1</source>
|
||||
<translation>Couleurs du Sprite nº 1</translation>
|
||||
<translation>Couleurs du Sprite nº 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../OverrideView.ui" line="349"/>
|
||||
<source>Sprite Colors 2</source>
|
||||
<translation>Couleurs du Sprite nº 2</translation>
|
||||
<translation>Couleurs du Sprite nº 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../OverrideView.ui" line="519"/>
|
||||
|
@ -1184,7 +1184,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../AboutScreen.cpp" line="77"/>
|
||||
<source>2021</source>
|
||||
<translation type="unfinished">2021</translation>
|
||||
<translation>2021</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1446,17 +1446,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../IOViewer.cpp" line="40"/>
|
||||
<source>Mode 0: 4 tile layers</source>
|
||||
<translation>Mode 0 : 4 couches de tuile</translation>
|
||||
<translation>Mode 0 : 4 couches de tuile</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="41"/>
|
||||
<source>Mode 1: 2 tile layers + 1 rotated/scaled tile layer</source>
|
||||
<translation>Mode 1 : 2 couches de tuiles + 1 couche de tuiles pivotée / mise à l'échelle</translation>
|
||||
<translation>Mode 1 : 2 couches de tuiles + 1 couche de tuiles pivotée / mise à l'échelle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="42"/>
|
||||
<source>Mode 2: 2 rotated/scaled tile layers</source>
|
||||
<translation>Mode 2 : 2 couches de tuiles pivotées / mises à l'échelle</translation>
|
||||
<translation>Mode 2 : 2 couches de tuiles pivotées / mises à l'échelle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="43"/>
|
||||
|
@ -1501,22 +1501,22 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../IOViewer.cpp" line="54"/>
|
||||
<source>Enable background 0</source>
|
||||
<translation>Activer l'arrière-plan nº 0</translation>
|
||||
<translation>Activer l'arrière-plan nº 0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="55"/>
|
||||
<source>Enable background 1</source>
|
||||
<translation>Activer l'arrière-plan nº 1</translation>
|
||||
<translation>Activer l'arrière-plan nº 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="56"/>
|
||||
<source>Enable background 2</source>
|
||||
<translation>Activer l'arrière-plan nº 2</translation>
|
||||
<translation>Activer l'arrière-plan nº 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="57"/>
|
||||
<source>Enable background 3</source>
|
||||
<translation>Activer l'arrière-plan nº 3</translation>
|
||||
<translation>Activer l'arrière-plan nº 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="58"/>
|
||||
|
@ -1526,12 +1526,12 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../IOViewer.cpp" line="59"/>
|
||||
<source>Enable Window 0</source>
|
||||
<translation>Activer la fenêtre nº 0</translation>
|
||||
<translation>Activer la fenêtre nº 0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="60"/>
|
||||
<source>Enable Window 1</source>
|
||||
<translation>Actvier la fenêtre nº 1</translation>
|
||||
<translation>Actvier la fenêtre nº 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="61"/>
|
||||
|
@ -1728,82 +1728,82 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../IOViewer.cpp" line="249"/>
|
||||
<source>Window 0 enable BG 0</source>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 0</translation>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="250"/>
|
||||
<source>Window 0 enable BG 1</source>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 1</translation>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="251"/>
|
||||
<source>Window 0 enable BG 2</source>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 2</translation>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="252"/>
|
||||
<source>Window 0 enable BG 3</source>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 3</translation>
|
||||
<translation>La fenêtre nº 0 active l'arrière plan nº 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="253"/>
|
||||
<source>Window 0 enable OBJ</source>
|
||||
<translation>La fenêtre nº 0 active l'OBJ</translation>
|
||||
<translation>La fenêtre nº 0 active l'OBJ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="254"/>
|
||||
<source>Window 0 enable blend</source>
|
||||
<translation>La fenêtre nº 0 active le mixage</translation>
|
||||
<translation>La fenêtre nº 0 active le mixage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="255"/>
|
||||
<source>Window 1 enable BG 0</source>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 0</translation>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="256"/>
|
||||
<source>Window 1 enable BG 1</source>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 1</translation>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="257"/>
|
||||
<source>Window 1 enable BG 2</source>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 2</translation>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="258"/>
|
||||
<source>Window 1 enable BG 3</source>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 3</translation>
|
||||
<translation>La fenêtre nº 1 active l'arrière plan nº 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="259"/>
|
||||
<source>Window 1 enable OBJ</source>
|
||||
<translation>La fenêtre nº 1 active l'OBJ</translation>
|
||||
<translation>La fenêtre nº 1 active l'OBJ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="260"/>
|
||||
<source>Window 1 enable blend</source>
|
||||
<translation>La fenêtre nº 1 active le mixage</translation>
|
||||
<translation>La fenêtre nº 1 active le mixage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="264"/>
|
||||
<source>Outside window enable BG 0</source>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 0</translation>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 0</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="265"/>
|
||||
<source>Outside window enable BG 1</source>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 1</translation>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="266"/>
|
||||
<source>Outside window enable BG 2</source>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 2</translation>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="267"/>
|
||||
<source>Outside window enable BG 3</source>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 3</translation>
|
||||
<translation>La fenêtre extérieure active l'arrière plan nº 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="268"/>
|
||||
|
@ -1981,7 +1981,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<location filename="../IOViewer.cpp" line="330"/>
|
||||
<location filename="../IOViewer.cpp" line="1101"/>
|
||||
<source>Sweep time (in 1/128s)</source>
|
||||
<translation>Durée de balayage (en 1/128 s)</translation>
|
||||
<translation>Durée de balayage (en 1/128 s)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="334"/>
|
||||
|
@ -2090,28 +2090,28 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<location filename="../IOViewer.cpp" line="376"/>
|
||||
<location filename="../IOViewer.cpp" line="1158"/>
|
||||
<source>0%</source>
|
||||
<translation>0 %</translation>
|
||||
<translation>0 %</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="377"/>
|
||||
<location filename="../IOViewer.cpp" line="434"/>
|
||||
<location filename="../IOViewer.cpp" line="1159"/>
|
||||
<source>100%</source>
|
||||
<translation>100 %</translation>
|
||||
<translation>100 %</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="378"/>
|
||||
<location filename="../IOViewer.cpp" line="433"/>
|
||||
<location filename="../IOViewer.cpp" line="1160"/>
|
||||
<source>50%</source>
|
||||
<translation>50 %</translation>
|
||||
<translation>50 %</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="379"/>
|
||||
<location filename="../IOViewer.cpp" line="432"/>
|
||||
<location filename="../IOViewer.cpp" line="1161"/>
|
||||
<source>25%</source>
|
||||
<translation>25 %</translation>
|
||||
<translation>25 %</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="380"/>
|
||||
|
@ -2119,7 +2119,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<location filename="../IOViewer.cpp" line="382"/>
|
||||
<location filename="../IOViewer.cpp" line="383"/>
|
||||
<source>75%</source>
|
||||
<translation>75 %</translation>
|
||||
<translation>75 %</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="405"/>
|
||||
|
@ -2944,17 +2944,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../IOViewer.cpp" line="1016"/>
|
||||
<source>4.19MHz</source>
|
||||
<translation>4,19 MHz</translation>
|
||||
<translation>4,19 MHz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="1017"/>
|
||||
<source>8.38MHz</source>
|
||||
<translation>8,38 MHz</translation>
|
||||
<translation>8,38 MHz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="1018"/>
|
||||
<source>16.78MHz</source>
|
||||
<translation>16,78 MHz</translation>
|
||||
<translation>16,78 MHz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../IOViewer.cpp" line="1020"/>
|
||||
|
@ -3407,7 +3407,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../LogController.cpp" line="68"/>
|
||||
<source>[%1] %2: %3</source>
|
||||
<translation>[%1] %2 : %3</translation>
|
||||
<translation>[%1] %2 : %3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../LogController.cpp" line="79"/>
|
||||
|
@ -4836,7 +4836,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../ROMInfo.ui" line="26"/>
|
||||
<source>Game name:</source>
|
||||
<translation>Nom du jeu :</translation>
|
||||
<translation>Nom du jeu :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ROMInfo.ui" line="33"/>
|
||||
|
@ -5271,7 +5271,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="371"/>
|
||||
<source>FPS target:</source>
|
||||
<translation>IPS ciblée :</translation>
|
||||
<translation>IPS ciblée :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="396"/>
|
||||
|
@ -5727,7 +5727,7 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="1671"/>
|
||||
<source>Default sprite colors 1:</source>
|
||||
<translation>Couleurs par défaut de la sprite nº 1 :</translation>
|
||||
<translation>Couleurs par défaut de la sprite nº 1 :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1758"/>
|
||||
|
@ -5737,17 +5737,17 @@ Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd.</
|
|||
<message>
|
||||
<location filename="../SettingsView.ui" line="1502"/>
|
||||
<source>Game Boy-only model:</source>
|
||||
<translation>Modèle Game Boy uniquement :</translation>
|
||||
<translation>Modèle Game Boy uniquement :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1522"/>
|
||||
<source>Game Boy Color-only model:</source>
|
||||
<translation>Modèle Game Boy uniquement :</translation>
|
||||
<translation>Modèle Game Boy uniquement :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../SettingsView.ui" line="1532"/>
|
||||
<source>Game Boy/Game Boy Color model:</source>
|
||||
<translation>Modèle Game Boy / Game Boy Color :</translation>
|
||||
<translation>Modèle Game Boy / Game Boy Color :</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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)
|
||||
|
|
|
@ -924,7 +924,7 @@ int main(int argc, char* argv[]) {
|
|||
.configExtra = (struct GUIMenuItem[]) {
|
||||
{
|
||||
.title = "Screen mode",
|
||||
.data = "screenMode",
|
||||
.data = GUI_V_S("screenMode"),
|
||||
.submenu = 0,
|
||||
.state = SM_PA,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -936,7 +936,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "Fast forward cap",
|
||||
.data = "fastForwardCap",
|
||||
.data = GUI_V_S("fastForwardCap"),
|
||||
.submenu = 0,
|
||||
.state = 7,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -966,7 +966,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "GPU-accelerated renderer",
|
||||
.data = "hwaccelVideo",
|
||||
.data = GUI_V_S("hwaccelVideo"),
|
||||
.submenu = 0,
|
||||
.state = 0,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -977,7 +977,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "Hi-res scaling (requires GPU rendering)",
|
||||
.data = "videoScale",
|
||||
.data = GUI_V_S("videoScale"),
|
||||
.submenu = 0,
|
||||
.state = 0,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -1000,7 +1000,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "Use built-in brightness sensor for Boktai",
|
||||
.data = "useLightSensor",
|
||||
.data = GUI_V_S("useLightSensor"),
|
||||
.submenu = 0,
|
||||
.state = illuminanceAvailable,
|
||||
.validStates = (const char*[]) {
|
||||
|
|
|
@ -490,7 +490,7 @@ int main(int argc, char* argv[]) {
|
|||
.configExtra = (struct GUIMenuItem[]) {
|
||||
{
|
||||
.title = "Video mode",
|
||||
.data = "videoMode",
|
||||
.data = GUI_V_S("videoMode"),
|
||||
.submenu = 0,
|
||||
.state = 0,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -503,7 +503,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "Screen mode",
|
||||
.data = "screenMode",
|
||||
.data = GUI_V_S("screenMode"),
|
||||
.submenu = 0,
|
||||
.state = 0,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -514,7 +514,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "Filtering",
|
||||
.data = "filter",
|
||||
.data = GUI_V_S("filter"),
|
||||
.submenu = 0,
|
||||
.state = 0,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -526,7 +526,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "Horizontal stretch",
|
||||
.data = "stretchWidth",
|
||||
.data = GUI_V_S("stretchWidth"),
|
||||
.submenu = 0,
|
||||
.state = 7,
|
||||
.validStates = (const char*[]) {
|
||||
|
@ -546,7 +546,7 @@ int main(int argc, char* argv[]) {
|
|||
},
|
||||
{
|
||||
.title = "Vertical stretch",
|
||||
.data = "stretchHeight",
|
||||
.data = GUI_V_S("stretchHeight"),
|
||||
.submenu = 0,
|
||||
.state = 6,
|
||||
.validStates = (const char*[]) {
|
||||
|
|
|
@ -94,7 +94,7 @@ static bool _refreshDirectory(struct GUIParams* params, const char* currentPath,
|
|||
} else {
|
||||
name = strdup(name);
|
||||
}
|
||||
*GUIMenuItemListAppend(currentFiles) = (struct GUIMenuItem) { .title = name, .data = (void*) de->type(de) };
|
||||
*GUIMenuItemListAppend(currentFiles) = (struct GUIMenuItem) { .title = name, .data = GUI_V_U(de->type(de)) };
|
||||
++items;
|
||||
}
|
||||
qsort(GUIMenuItemListGetPointer(currentFiles, 1), GUIMenuItemListSize(currentFiles) - 1, sizeof(struct GUIMenuItem), _strpcmp);
|
||||
|
@ -124,7 +124,7 @@ static bool _refreshDirectory(struct GUIParams* params, const char* currentPath,
|
|||
params->drawEnd();
|
||||
}
|
||||
struct GUIMenuItem* testItem = GUIMenuItemListGetPointer(currentFiles, item);
|
||||
if (testItem->data != (void*) VFS_FILE) {
|
||||
if (!GUIVariantCompareUInt(testItem->data, VFS_FILE)) {
|
||||
++item;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men
|
|||
if (reason != GUI_MENU_EXIT_BACK) {
|
||||
return reason;
|
||||
}
|
||||
} else if ((*item)->validStates && !(*item)->data) {
|
||||
} else if ((*item)->validStates && !(*item)->data.v.p) {
|
||||
_itemNext(*item, true);
|
||||
} else {
|
||||
return GUI_MENU_EXIT_ACCEPT;
|
||||
|
@ -152,7 +152,7 @@ enum GUIMenuExitReason GUIShowMenu(struct GUIParams* params, struct GUIMenu* men
|
|||
|
||||
params->drawStart();
|
||||
if (menu->background) {
|
||||
menu->background->draw(menu->background, GUIMenuItemListGetPointer(&menu->items, menu->index)->data);
|
||||
menu->background->draw(menu->background, GUIMenuItemListGetPointer(&menu->items, menu->index)->data.v.p);
|
||||
}
|
||||
if (params->guiPrepare) {
|
||||
params->guiPrepare();
|
||||
|
|
Loading…
Reference in New Issue