all repos — mgba @ 3d27d1d7fe6fbce0334a7411eb4f709e2b17c040

mGBA Game Boy Advance Emulator

Merge branch 'master' (early part) into medusa
Vicki Pfau vi@endrift.com
Fri, 28 Jun 2019 16:54:30 -0700
commit

3d27d1d7fe6fbce0334a7411eb4f709e2b17c040

parent

e6aa23f19cdfe97161f3696fbb3dbc4e3794edd5

62 files changed, 1803 insertions(+), 1080 deletions(-)

jump to
M .travis.yml.travis.yml

@@ -6,8 +6,8 @@ - docker

os: linux env: - DOCKER_TAG=ubuntu:xenial -- DOCKER_TAG=ubuntu:artful - DOCKER_TAG=ubuntu:bionic +- DOCKER_TAG=ubuntu:cosmic - DOCKER_TAG=3ds - DOCKER_TAG=wii - DOCKER_TAG=vita
M CHANGESCHANGES

@@ -18,6 +18,10 @@ - DS GX: Clean up and unify texture mapping

- DS Core: Add symbol loading - DS Video: Simplify VRAM mapping +0.8.0: (Future) +Bugfixes: + - GBA: All IRQs have 7 cycle delay (fixes mgba.io/i/539, mgba.io/i/1208) + 0.7.0: (Future) Features: - ELF support

@@ -121,15 +125,40 @@ - mGUI: Add fast forward toggle

Changes from beta 1: Features: - Libretro: Add Game Boy cheat support + - Qt: Separate fast forward volume control (fixes mgba.io/i/846, mgba.io/i/1143) + - Switch: Rumble support + - Switch: Rotation support + - Qt: State file load/save menu options + - Windows installer + - Tile viewer now has adjustable width Bugfixes: - PSP2: Fix audio crackling after fast forward - PSP2: Fix audio crackling when buffer is full - 3DS: Fix unused screens not clearing (fixes mgba.io/i/1184) + - GBA Video: Fix caching with background toggling (fixes mgba.io/i/1118) + - Wii: Fix drawing caching regression (fixes mgba.io/i/1185) + - Switch: Fix incorrect mapping for fast forward cap + - GB, GBA: Fix broken opposing button filter (fixes mgba.io/i/1191) + - Qt: Fix jumbled background when paused + - Qt: Fix FPS counter on Windows + - GB, GBA Savedata: Fix leaks when loading masked save (fixes mgba.io/i/1197) + - Qt: Fix focus issues with load/save state overlay + - GB Video: Fix SGB border hole size Misc: - mGUI: Add SGB border configuration option + - mGUI: Add support for different settings types + - Wii: Define _GNU_SOURCE (fixes mgba.io/i/1106) + - Wii: Expose stretch configuration in settings + - Wii: Stretch now sets pixel-accurate mode size cap + - Qt: Ensure camera image is valid + - GB: Improved SGB2 support + - Libretro: Reduce rumble callbacks + - Debugger: Minor text fixes + - Qt: Debugger console history + - Qt: Detect presence of GL_ARB_framebuffer_object -0.6 beta 1: (2018-09-24) -- Initial beta for 0.6 +0.7 beta 1: (2018-09-24) +- Initial beta for 0.7 0.6.3: (2018-04-14) Bugfixes:
M CMakeLists.txtCMakeLists.txt

@@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.1)

if(POLICY CMP0025) cmake_policy(SET CMP0025 NEW) endif() +if(POLICY CMP0072) + cmake_policy(SET CMP0072 NEW) +endif() project(medusa) set(BINARY_NAME medusa-emu CACHE INTERNAL "Name of output binaries") if(NOT MSVC)

@@ -326,7 +329,7 @@ if(WII)

add_definitions(-U__STRICT_ANSI__) endif() -if(DEFINED 3DS) +if(3DS OR WII) add_definitions(-D_GNU_SOURCE) endif()

@@ -550,7 +553,11 @@ set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavcodec${LIBAVCODEC_VERSION_MAJOR}|libavcodec-extra-${LIBAVCODEC_VERSION_MAJOR}|libavcodec-ffmpeg${LIBAVCODEC_VERSION_MAJOR}|libavcodec-ffmpeg-extra${LIBAVCODEC_VERSION_MAJOR}")

set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libavformat${LIBAVFORMAT_VERSION_MAJOR}|libavformat-ffmpeg${LIBAVFORMAT_VERSION_MAJOR}") if(USE_LIBSWRESAMPLE) string(REGEX MATCH "^[0-9]+" LIBSWRESAMPLE_VERSION_MAJOR ${libswresample_VERSION}) - math(EXPR LIBSWRESAMPLE_VERSION_DEBIAN "${LIBSWRESAMPLE_VERSION_MAJOR} - 1") + if(${libswresample_VERSION} EQUAL "3.1.100") + set(LIBSWRESAMPLE_VERSION_DEBIAN 3) + else() + math(EXPR LIBSWRESAMPLE_VERSION_DEBIAN "${LIBSWRESAMPLE_VERSION_MAJOR} - 1") + endif() set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libswresample${LIBSWRESAMPLE_VERSION_DEBIAN}|libswresample-ffmpeg${LIBSWRESAMPLE_VERSION_DEBIAN}") else() string(REGEX MATCH "^[0-9]+" LIBAVRESAMPLE_VERSION_MAJOR ${libavresample_VERSION})

@@ -577,6 +584,8 @@ string(REGEX MATCH "^[0-9]+\\.[0-9]+" MAGICKWAND_VERSION_PARTIAL ${MagickWand_VERSION})

string(REGEX MATCH "^[0-9]+" MAGICKWAND_VERSION_MAJOR ${MagickWand_VERSION}) if(${MAGICKWAND_VERSION_PARTIAL} EQUAL "6.7") set(MAGICKWAND_DEB_VERSION "5") + elseif(${MagickWand_VERSION} EQUAL "6.9.10") + set(MAGICKWAND_DEB_VERSION "-6.q16-6") elseif(${MagickWand_VERSION} EQUAL "6.9.7") set(MAGICKWAND_DEB_VERSION "-6.q16-3") else()

@@ -944,7 +953,11 @@ file(GLOB RETRO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/libretro/*.c)

add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC}) set_target_properties(${BINARY_NAME}_libretro PROPERTIES PREFIX "" COMPILE_DEFINITIONS "COLOR_16_BIT;COLOR_5_6_5;DISABLE_THREADING;${OS_DEFINES};${FUNCTION_DEFINES};MINIMAL_CORE=2") target_link_libraries(${BINARY_NAME}_libretro ${OS_LIB}) - install(TARGETS ${BINARY_NAME}_libretro LIBRARY DESTINATION ${LIBRETRO_LIBDIR} COMPONENT ${BINARY_NAME}_libretro NAMELINK_SKIP) + if(MSVC) + install(TARGETS ${BINARY_NAME}_libretro RUNTIME DESTINATION ${LIBRETRO_LIBDIR} COMPONENT ${BINARY_NAME}_libretro) + else() + install(TARGETS ${BINARY_NAME}_libretro LIBRARY DESTINATION ${LIBRETRO_LIBDIR} COMPONENT ${BINARY_NAME}_libretro NAMELINK_SKIP) + endif() endif() if(BUILD_OPENEMU)

@@ -1030,6 +1043,26 @@

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/core/flags.h.in ${CMAKE_CURRENT_BINARY_DIR}/flags.h) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/flags.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mgba COMPONENT lib${BINARY_NAME}) +if(WIN32) + set(BIN_DIR ".\\") + string(REGEX REPLACE "[^-A-Za-z0-9_.]" "-" CLEAN_VERSION_STRING "${VERSION_STRING}") + file(RELATIVE_PATH SETUP_DIR_SLASH "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/src/platform/windows/setup") + file(RELATIVE_PATH RES_DIR_SLASH "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/res") + string(REPLACE "/" "\\" SETUP_DIR "${SETUP_DIR_SLASH}") + string(REPLACE "/" "\\" RES_DIR "${RES_DIR_SLASH}") + if(CMAKE_SYSTEM_PROCESSOR MATCHES ".*64$") + set(WIN_BITS 64) + else() + set(WIN_BITS 32) + endif() + if(GIT_TAG) + set(IS_RELEASE 1) + else() + set(IS_RELEASE 0) + endif() + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/platform/windows/setup/setup.iss.in" ${CMAKE_CURRENT_BINARY_DIR}/setup.iss) +endif() + # Packaging install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/res/licenses DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT ${BINARY_NAME}) if(EXTRA_LICENSES)

@@ -1038,20 +1071,45 @@ endif()

file(GLOB READMES ${CMAKE_CURRENT_SOURCE_DIR}/README*.md) -find_program(DOS2UNIX NAMES dos2unix) +find_program(UNIX2DOS NAMES unix2dos) find_program(MARKDOWN NAMES markdown kramdown pandoc) -if(UNIX OR NOT DOS2UNIX) +if(UNIX OR NOT UNIX2DOS) if(UNIX OR NOT MARKDOWN) install(FILES ${READMES} DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT ${BINARY_NAME}) endif() install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/CHANGES" "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT ${BINARY_NAME}) else() - add_custom_command(OUTPUT CHANGES.txt COMMAND ${DOS2UNIX} -n "${CMAKE_CURRENT_SOURCE_DIR}/CHANGES" "${CMAKE_CURRENT_BINARY_DIR}/CHANGES.txt" MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/CHANGES") - add_custom_command(OUTPUT LICENSE.txt COMMAND ${DOS2UNIX} -n "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" "${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt" MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") + add_custom_command(OUTPUT CHANGES.txt COMMAND ${UNIX2DOS} -n "${CMAKE_CURRENT_SOURCE_DIR}/CHANGES" "${CMAKE_CURRENT_BINARY_DIR}/CHANGES.txt" MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/CHANGES") + add_custom_command(OUTPUT LICENSE.txt COMMAND ${UNIX2DOS} -n "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" "${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt" MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") add_custom_target(CHANGES ALL DEPENDS CHANGES.txt) add_custom_target(LICENSE ALL DEPENDS LICENSE.txt) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CHANGES.txt ${CMAKE_CURRENT_BINARY_DIR}/LICENSE.txt DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT ${BINARY_NAME}) + if(DISTBUILD AND WIN32) + if(INSTALLER_NAME) + set(INSTALLER_TARGET "${INSTALLER_NAME}.exe") + set(ISCC_FLAGS "/F${INSTALLER_NAME}") + else() + set(INSTALLER_TARGET "${PROJECT_NAME}-setup-${CLEAN_VERSION_STRING}-win${WIN_BITS}.exe") + endif() + if(CMAKE_CROSSCOMPILING) + find_program(WINE NAMES wine wine-stable wine-development) + find_file(ISCC ISCC.exe HINTS "$ENV{HOME}/.wine/drive_c/Program Files/" PATH_SUFFIXES "Inno Setup 5") + message(STATUS "${WINE}" "${ISCC}" setup.iss /Q ${ISCC_FLAGS}) + add_custom_command(OUTPUT ${INSTALLER_TARGET} + COMMAND "${WINE}" "${ISCC}" setup.iss /Q ${ISCC_FLAGS} + DEPENDS ${BINARY_NAME}-qt ${BINARY_NAME}-sdl CHANGES LICENSE) + else() + find_program(ISCC NAMES ISCC ISCC.exe PATH_SUFFIXES "Inno Setup 5") + add_custom_command(OUTPUT ${INSTALLER_TARGET} + COMMAND "${ISCC}" setup.iss /Q ${ISCC_FLAGS} + DEPENDS ${BINARY_NAME}-qt ${BINARY_NAME}-sdl CHANGES LICENSE) + endif() + if(ISCC) + add_custom_target(installer ALL DEPENDS ${INSTALLER_TARGET}) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${INSTALLER_TARGET}" DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT installer) + endif() + endif() endif() if(MARKDOWN)

@@ -1076,9 +1134,11 @@ set(CPACK_PACKAGE_CONTACT "Jeffrey Pfau <jeffrey@endrift.com>")

set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CPACK_DEBIAN_PACKAGE_SECTION "games") -SET(CPACK_DEB_COMPONENT_INSTALL ON) +set(CPACK_DEB_COMPONENT_INSTALL ON) -set(CPACK_STRIP_FILES ON) +if(CMAKE_BUILD_TYPE STREQUAL "Release") + set(CPACK_STRIP_FILES ON) +endif() if(DISTBUILD) set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)

@@ -1089,19 +1149,19 @@ add_custom_command(TARGET ${BINARY_NAME} POST_BUILD COMMAND "${STRIP}" -S "$<TARGET_FILE:${BINARY_NAME}>")

install(FILES "$<TARGET_FILE:${BINARY_NAME}>.dSYM" DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}-dbg) endif() endif() - if(WIN32 OR APPLE) + if(APPLE) set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-qt ${BINARY_NAME}-sdl ${BINARY_NAME}-qt-dbg ${BINARY_NAME}-sdl-dbg ${BINARY_NAME}-perf) - if(APPLE) - set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE) - endif() + set(CPACK_COMPONENTS_GROUPING ALL_COMPONENTS_IN_ONE) + elseif(WIN32) + set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-qt ${BINARY_NAME}-sdl ${BINARY_NAME}-qt-dbg ${BINARY_NAME}-sdl-dbg ${BINARY_NAME}-perf installer) elseif(3DS) - set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-3ds ${BINARY_NAME}-perf) + set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-dbg ${BINARY_NAME}-3ds ${BINARY_NAME}-perf) elseif(WII) - set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-wii) + set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-dbg ${BINARY_NAME}-wii) elseif(PSP2) - set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-psp2) + set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-dbg ${BINARY_NAME}-psp2) elseif(SWITCH) - set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-switch) + set(CPACK_COMPONENTS_ALL ${BINARY_NAME} ${BINARY_NAME}-dbg ${BINARY_NAME}-switch) endif() endif()

@@ -1140,16 +1200,22 @@ cpack_add_component_group(sdl PARENT_GROUP base)

cpack_add_component(${BINARY_NAME}-sdl GROUP sdl) endif() -if(DISTBUILD AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") +if(DISTBUILD) cpack_add_component_group(debug PARENT_GROUP dev) if(BUILD_SHARED AND NOT IS_EMBEDDED) cpack_add_component(lib${BINARY_NAME}-dbg GROUP debug) endif() + if(IS_EMBEDDED) + cpack_add_component(${BINARY_NAME}-dbg GROUP debug) + endif() if(BUILD_QT) cpack_add_component(${BINARY_NAME}-qt-dbg GROUP debug) endif() if(SDL_FOUND) cpack_add_component(${BINARY_NAME}-sdl-dbg GROUP debug) + endif() + if(WIN32) + cpack_add_component_group(installer PARENT_GROUP base) endif() endif()
M include/mgba-util/common.hinclude/mgba-util/common.h

@@ -178,7 +178,11 @@ #define LOAD_16LE(DEST, ADDR, ARR) DEST = *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR))

#define STORE_64LE(SRC, ADDR, ARR) *(uint64_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC #define STORE_32LE(SRC, ADDR, ARR) *(uint32_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC #define STORE_16LE(SRC, ADDR, ARR) *(uint16_t*) ((uintptr_t) (ARR) + (size_t) (ADDR)) = SRC +#ifdef _MSC_VER +#define LOAD_32BE(DEST, ADDR, ARR) DEST = _byteswap_ulong(((uint32_t*) ARR)[(ADDR) >> 2]) +#else #define LOAD_32BE(DEST, ADDR, ARR) DEST = __builtin_bswap32(((uint32_t*) ARR)[(ADDR) >> 2]) +#endif #endif #define MAKE_MASK(START, END) (((1 << ((END) - (START))) - 1) << (START))
M include/mgba-util/gui/menu.hinclude/mgba-util/gui/menu.h

@@ -12,12 +12,37 @@ CXX_GUARD_START

#include <mgba-util/vector.h> +#define GUI_V_V (struct GUIVariant) { .type = GUI_VARIANT_VOID } +#define GUI_V_U(U) (struct GUIVariant) { .type = GUI_VARIANT_UNSIGNED, .v.u = (U) } +#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) } + +enum GUIVariantType { + GUI_VARIANT_VOID = 0, + GUI_VARIANT_UNSIGNED, + GUI_VARIANT_INT, + GUI_VARIANT_FLOAT, + GUI_VARIANT_STRING +}; + +struct GUIVariant { + enum GUIVariantType type; + union { + unsigned u; + int i; + float f; + const char* s; + } v; +}; + struct GUIMenu; struct GUIMenuItem { const char* title; void* data; unsigned state; const char* const* validStates; + const struct GUIVariant* stateMappings; unsigned nStates; struct GUIMenu* submenu; };
M include/mgba/internal/gb/gb.hinclude/mgba/internal/gb/gb.h

@@ -117,6 +117,8 @@ bool cpuBlocked;

bool earlyExit; struct mTimingEvent eiPending; unsigned doubleSpeed; + + bool allowOpposingDirections; }; struct GBCartridge {
M include/mgba/internal/gba/gba.hinclude/mgba/internal/gba/gba.h

@@ -82,6 +82,8 @@

struct GBATimer timers[4]; int springIRQ; + struct mTimingEvent irqEvent; + uint32_t biosChecksum; int* keySource; struct mRotationSource* rotationSource;

@@ -141,8 +143,6 @@

void GBAReset(struct ARMCore* cpu); void GBASkipBIOS(struct GBA* gba); -void GBAWriteIE(struct GBA* gba, uint16_t value); -void GBAWriteIME(struct GBA* gba, uint16_t value); void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq); void GBATestIRQ(struct ARMCore* cpu); void GBAHalt(struct GBA* gba);
M include/mgba/internal/gba/serialize.hinclude/mgba/internal/gba/serialize.h

@@ -98,28 +98,28 @@ * | 0x00200 - 0x00201: Reload value

* | 0x00202 - 0x00203: Old reload value * | 0x00204 - 0x00207: Last event * | 0x00208 - 0x0020B: Next event - * | 0x0020C - 0x0020F: Next IRQ + * | 0x0020C - 0x0020F: Reserved * | 0x00210 - 0x00213: Miscellaneous flags * 0x00214 - 0x00227: Timer 1 * | 0x00214 - 0x00215: Reload value * | 0x00216 - 0x00217: Old reload value * | 0x00218 - 0x0021B: Last event * | 0x0021C - 0x0021F: Next event - * | 0x00220 - 0x00223: Next IRQ + * | 0x00220 - 0x00223: Reserved * | 0x00224 - 0x00227: Miscellaneous flags * 0x00228 - 0x0023B: Timer 2 * | 0x00228 - 0x00229: Reload value * | 0x0022A - 0x0022B: Old reload value * | 0x0022C - 0x0022F: Last event * | 0x00230 - 0x00233: Next event - * | 0x00234 - 0x00237: Next IRQ + * | 0x00234 - 0x00237: Reserved * | 0x00238 - 0x0023B: Miscellaneous flags * 0x0023C - 0x00250: Timer 3 * | 0x0023C - 0x0023D: Reload value * | 0x0023E - 0x0023F: Old reload value * | 0x00240 - 0x00243: Last event * | 0x00244 - 0x00247: Next event - * | 0x00248 - 0x0024B: Next IRQ + * | 0x00248 - 0x0024B: Reserved * | 0x0024C - 0x0024F: Miscellaneous flags * 0x00250 - 0x0025F: DMA 0 * | 0x00250 - 0x00253: DMA next source

@@ -196,7 +196,9 @@ * 0x00318 - 0x0031B: Last prefetched program counter

* 0x0031C - 0x0031F: Miscellaneous flags * | bit 0: Is CPU halted? * | bit 1: POSTFLG - * 0x00320 - 0x003FF: Reserved (leave zero) + * | bit 2: Is IRQ pending? + * 0x00320 - 0x00323: Next IRQ event + * 0x00324 - 0x003FF: Reserved (leave zero) * 0x00400 - 0x007FF: I/O memory * 0x00800 - 0x00BFF: Palette * 0x00C00 - 0x00FFF: OAM

@@ -227,6 +229,7 @@

DECL_BITFIELD(GBASerializedMiscFlags, uint32_t); DECL_BIT(GBASerializedMiscFlags, Halted, 0); DECL_BIT(GBASerializedMiscFlags, POSTFLG, 1); +DECL_BIT(GBASerializedMiscFlags, IrqPending, 2); struct GBASerializedState { uint32_t versionMagic;

@@ -267,10 +270,10 @@ } video;

struct { uint16_t reload; - uint16_t reserved; + uint16_t reserved0; uint32_t lastEvent; uint32_t nextEvent; - uint32_t nextIrq; + uint32_t reserved1; GBATimerFlags flags; } timers[4];

@@ -320,8 +323,9 @@ uint32_t reservedRr[5];

uint32_t lastPrefetchedPc; GBASerializedMiscFlags miscFlags; + uint32_t nextIrq; - uint32_t reserved[56]; + uint32_t reserved[55]; uint16_t io[SIZE_IO >> 1]; uint16_t pram[SIZE_PALETTE_RAM >> 1];
M include/mgba/internal/gba/timer.hinclude/mgba/internal/gba/timer.h

@@ -17,13 +17,11 @@ DECL_BITS(GBATimerFlags, PrescaleBits, 0, 4);

DECL_BIT(GBATimerFlags, CountUp, 4); DECL_BIT(GBATimerFlags, DoIrq, 5); DECL_BIT(GBATimerFlags, Enable, 6); -DECL_BIT(GBATimerFlags, IrqPending, 7); struct GBATimer { uint16_t reload; int32_t lastEvent; struct mTimingEvent event; - struct mTimingEvent irq; GBATimerFlags flags; int forcedPrescale; };

@@ -33,7 +31,7 @@ struct GBA;

void GBATimerInit(struct GBA* gba); void GBATimerUpdate(struct mTiming* timing, struct GBATimer* timer, uint16_t* io, uint32_t cyclesLate); -void GBATimerUpdateCountUp(struct mTiming* timing, struct GBATimer* nextTimer, uint16_t* io, uint32_t cyclesLate); +bool GBATimerUpdateCountUp(struct mTiming* timing, struct GBATimer* nextTimer, uint16_t* io, uint32_t cyclesLate); void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate); void GBATimerUpdateRegisterInternal(struct GBATimer* timer, struct mTiming* timing, uint16_t* io, int32_t skew); void GBATimerWriteTMCNT_LO(struct GBATimer* timer, uint16_t reload);
M src/arm/arm.csrc/arm/arm.c

@@ -175,6 +175,7 @@ _ARMSetMode(cpu, MODE_ARM);

cpu->spsr = cpsr; cpu->cpsr.i = 1; cpu->cycles += currentCycles; + cpu->halted = 0; } void ARMRaiseSWI(struct ARMCore* cpu) {
M src/debugger/cli-debugger.csrc/debugger/cli-debugger.c

@@ -66,8 +66,8 @@ { "b", _setBreakpoint, "Is", "Set a breakpoint" },

{ "break", _setBreakpoint, "Is", "Set a breakpoint" }, { "c", _continue, "", "Continue execution" }, { "continue", _continue, "", "Continue execution" }, - { "d", _clearBreakpoint, "I", "Delete a breakpoint" }, - { "delete", _clearBreakpoint, "I", "Delete a breakpoint" }, + { "d", _clearBreakpoint, "I", "Delete a breakpoint or watchpoint" }, + { "delete", _clearBreakpoint, "I", "Delete a breakpoint or watchpoint" }, { "dis", _disassemble, "Ii", "Disassemble instructions" }, { "disasm", _disassemble, "Ii", "Disassemble instructions" }, { "disassemble", _disassemble, "Ii", "Disassemble instructions" },

@@ -841,9 +841,9 @@ break;

case DEBUGGER_ENTER_WATCHPOINT: if (info) { if (info->type.wp.accessType & WATCHPOINT_WRITE) { - cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (new value = 0x%08x, old value = 0x%08X)\n", info->address, info->type.wp.newValue, info->type.wp.oldValue); + cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (new value = 0x%08X, old value = 0x%08X)\n", info->address, info->type.wp.newValue, info->type.wp.oldValue); } else { - cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (value = 0x%08x)\n", info->address, info->type.wp.oldValue); + cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint at 0x%08X: (value = 0x%08X)\n", info->address, info->type.wp.oldValue); } } else { cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint\n");
M src/ds/renderers/software.csrc/ds/renderers/software.c

@@ -489,6 +489,19 @@ }

} } + if (softwareRenderer->bg[0].enabled > 0 && softwareRenderer->bg[0].enabled < 4) { + ++softwareRenderer->bg[0].enabled; + } + if (softwareRenderer->bg[1].enabled > 0 && softwareRenderer->bg[1].enabled < 4) { + ++softwareRenderer->bg[1].enabled; + } + if (softwareRenderer->bg[2].enabled > 0 && softwareRenderer->bg[2].enabled < 4) { + ++softwareRenderer->bg[2].enabled; + } + if (softwareRenderer->bg[3].enabled > 0 && softwareRenderer->bg[3].enabled < 4) { + ++softwareRenderer->bg[3].enabled; + } + GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer); }
M src/ds/timer.csrc/ds/timer.c

@@ -10,57 +10,42 @@ #include <mgba/internal/ds/ds.h>

static void DSTimerIrq(struct DSCommon* dscore, int timerId) { struct GBATimer* timer = &dscore->timers[timerId]; - if (GBATimerFlagsIsIrqPending(timer->flags)) { - timer->flags = GBATimerFlagsClearIrqPending(timer->flags); + if (GBATimerFlagsIsDoIrq(timer->flags)) { DSRaiseIRQ(dscore->cpu, dscore->memory.io, DS_IRQ_TIMER0 + timerId); } } -static void DSTimerIrq0(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - DSTimerIrq(context, 0); -} - -static void DSTimerIrq1(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - DSTimerIrq(context, 1); -} - -static void DSTimerIrq2(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - DSTimerIrq(context, 2); -} - -static void DSTimerIrq3(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - DSTimerIrq(context, 3); -} - static void DSTimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct DSCommon* dscore = context; GBATimerUpdate(timing, &dscore->timers[0], &dscore->memory.io[DS_REG_TM0CNT_LO >> 1], cyclesLate); - GBATimerUpdateCountUp(timing, &dscore->timers[1], &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], cyclesLate); + DSTimerIrq(dscore, 0); + if (GBATimerUpdateCountUp(timing, &dscore->timers[1], &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], cyclesLate)) { + DSTimerIrq(dscore, 1); + } } static void DSTimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct DSCommon* dscore = context; GBATimerUpdate(timing, &dscore->timers[1], &dscore->memory.io[DS_REG_TM1CNT_LO >> 1], cyclesLate); - GBATimerUpdateCountUp(timing, &dscore->timers[2], &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], cyclesLate); + DSTimerIrq(dscore, 1); + if (GBATimerUpdateCountUp(timing, &dscore->timers[2], &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], cyclesLate)) { + DSTimerIrq(dscore, 2); + } } static void DSTimerUpdate2(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct DSCommon* dscore = context; GBATimerUpdate(timing, &dscore->timers[2], &dscore->memory.io[DS_REG_TM2CNT_LO >> 1], cyclesLate); - GBATimerUpdateCountUp(timing, &dscore->timers[3], &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], cyclesLate); + DSTimerIrq(dscore, 2); + if (GBATimerUpdateCountUp(timing, &dscore->timers[3], &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], cyclesLate)) { + DSTimerIrq(dscore, 3); + } } static void DSTimerUpdate3(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct DSCommon* dscore = context; GBATimerUpdate(timing, &dscore->timers[3], &dscore->memory.io[DS_REG_TM3CNT_LO >> 1], cyclesLate); + DSTimerIrq(dscore, 3); } void DSTimerInit(struct DS* ds) {

@@ -81,22 +66,6 @@ ds->ds7.timers[3].event.name = "DS7 Timer 3";

ds->ds7.timers[3].event.callback = DSTimerUpdate3; ds->ds7.timers[3].event.context = &ds->ds7; ds->ds7.timers[3].event.priority = 0x23; - ds->ds7.timers[0].irq.name = "DS7 Timer 0 IRQ"; - ds->ds7.timers[0].irq.callback = DSTimerIrq0; - ds->ds7.timers[0].irq.context = &ds->ds7; - ds->ds7.timers[0].irq.priority = 0x28; - ds->ds7.timers[1].irq.name = "DS7 Timer 1 IRQ"; - ds->ds7.timers[1].irq.callback = DSTimerIrq1; - ds->ds7.timers[1].irq.context = &ds->ds7; - ds->ds7.timers[1].irq.priority = 0x29; - ds->ds7.timers[2].irq.name = "DS7 Timer 2 IRQ"; - ds->ds7.timers[2].irq.callback = DSTimerIrq2; - ds->ds7.timers[2].irq.context = &ds->ds7; - ds->ds7.timers[2].irq.priority = 0x2A; - ds->ds7.timers[3].irq.name = "DS7 Timer 3 IRQ"; - ds->ds7.timers[3].irq.callback = DSTimerIrq3; - ds->ds7.timers[3].irq.context = &ds->ds7; - ds->ds7.timers[3].irq.priority = 0x2B; memset(ds->ds9.timers, 0, sizeof(ds->ds9.timers)); ds->ds9.timers[0].event.name = "DS9 Timer 0";

@@ -119,22 +88,6 @@ ds->ds9.timers[3].event.callback = DSTimerUpdate3;

ds->ds9.timers[3].event.context = &ds->ds9; ds->ds9.timers[3].event.priority = 0x23; ds->ds9.timers[3].forcedPrescale = 1; - ds->ds9.timers[0].irq.name = "DS9 Timer 0 IRQ"; - ds->ds9.timers[0].irq.callback = DSTimerIrq0; - ds->ds9.timers[0].irq.context = &ds->ds9; - ds->ds9.timers[0].irq.priority = 0x28; - ds->ds9.timers[1].irq.name = "DS9 Timer 1 IRQ"; - ds->ds9.timers[1].irq.callback = DSTimerIrq1; - ds->ds9.timers[1].irq.context = &ds->ds9; - ds->ds9.timers[1].irq.priority = 0x29; - ds->ds9.timers[2].irq.name = "DS9 Timer 2 IRQ"; - ds->ds9.timers[2].irq.callback = DSTimerIrq2; - ds->ds9.timers[2].irq.context = &ds->ds9; - ds->ds9.timers[2].irq.priority = 0x2A; - ds->ds9.timers[3].irq.name = "DS9 Timer 3 IRQ"; - ds->ds9.timers[3].irq.callback = DSTimerIrq3; - ds->ds9.timers[3].irq.context = &ds->ds9; - ds->ds9.timers[3].irq.priority = 0x2B; } void DSTimerWriteTMCNT_HI(struct GBATimer* timer, struct mTiming* timing, uint16_t* io, uint16_t value) {
M src/feature/gui/gui-config.csrc/feature/gui/gui-config.c

@@ -162,7 +162,50 @@ item = GUIMenuItemListGetPointer(&menu.items, i);

if (!item->validStates || !item->data) { continue; } - mCoreConfigGetUIntValue(&runner->config, item->data, &item->state); + if (item->stateMappings) { + item->state = 0; + + 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; + 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, &item->state); + } } while (true) {

@@ -185,10 +228,31 @@ mCoreConfigSetValue(&runner->config, "sgb.bios", sgbBiosPath);

} for (i = 0; i < GUIMenuItemListSize(&menu.items); ++i) { item = GUIMenuItemListGetPointer(&menu.items, i); - if (!item->validStates || !item->data) { + if (!item->validStates || !item->data || ((const char*) item->data)[0] == '*') { continue; } - mCoreConfigSetUIntValue(&runner->config, item->data, item->state); + if (item->stateMappings) { + const struct GUIVariant* v = &item->stateMappings[item->state]; + switch (v->type) { + case GUI_VARIANT_VOID: + mCoreConfigSetValue(&runner->config, item->data, NULL); + break; + case GUI_VARIANT_UNSIGNED: + mCoreConfigSetUIntValue(&runner->config, item->data, v->v.u); + break; + case GUI_VARIANT_INT: + mCoreConfigSetUIntValue(&runner->config, item->data, v->v.i); + break; + case GUI_VARIANT_FLOAT: + mCoreConfigSetFloatValue(&runner->config, item->data, v->v.f); + break; + case GUI_VARIANT_STRING: + mCoreConfigSetValue(&runner->config, item->data, v->v.s); + break; + } + } else { + mCoreConfigSetUIntValue(&runner->config, item->data, item->state); + } } if (runner->keySources) { size_t i;
M src/gb/audio.csrc/gb/audio.c

@@ -150,7 +150,7 @@ audio->playingCh1 = false;

audio->playingCh2 = false; audio->playingCh3 = false; audio->playingCh4 = false; - if (audio->p && audio->p->model != GB_MODEL_SGB) { + if (audio->p && !(audio->p->model & GB_MODEL_SGB)) { audio->playingCh1 = true; audio->enable = true; *audio->nr52 |= 0x01;
M src/gb/core.csrc/gb/core.c

@@ -219,8 +219,12 @@ mCoreConfigCopyValue(&core->config, config, "gbc.bios");

mCoreConfigCopyValue(&core->config, config, "gb.model"); mCoreConfigCopyValue(&core->config, config, "sgb.model"); mCoreConfigCopyValue(&core->config, config, "cgb.model"); + mCoreConfigCopyValue(&core->config, config, "allowOpposingDirections"); - int fakeBool; + int fakeBool = 0; + mCoreConfigGetIntValue(config, "allowOpposingDirections", &fakeBool); + gb->allowOpposingDirections = fakeBool; + if (mCoreConfigGetIntValue(config, "sgb.borders", &fakeBool)) { gb->video.sgbBorders = fakeBool; gb->video.renderer->enableSGBBorder(gb->video.renderer, fakeBool);

@@ -234,7 +238,7 @@ }

static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { struct GB* gb = core->board; - if (gb && (gb->model != GB_MODEL_SGB || !gb->video.sgbBorders)) { + if (gb && (!(gb->model & GB_MODEL_SGB) || !gb->video.sgbBorders)) { *width = GB_VIDEO_HORIZONTAL_PIXELS; *height = GB_VIDEO_VERTICAL_PIXELS; } else {

@@ -381,9 +385,9 @@ if (modelGB || modelCGB || modelSGB) {

GBDetectModel(gb); if (gb->model == GB_MODEL_DMG && modelGB) { gb->model = GBNameToModel(modelGB); - } else if (gb->model == GB_MODEL_CGB && modelCGB) { + } else if ((gb->model & GB_MODEL_CGB) && modelCGB) { gb->model = GBNameToModel(modelCGB); - } else if (gb->model == GB_MODEL_SGB && modelSGB) { + } else if ((gb->model & GB_MODEL_SGB) && modelSGB) { gb->model = GBNameToModel(modelSGB); } }

@@ -1069,6 +1073,7 @@

gb->cpu->pc = GB_BASE_HRAM; gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); + GBVideoReset(&gb->video); GBVideoDeserialize(&gb->video, state); GBIODeserialize(gb, state); GBAudioReset(&gb->audio);
M src/gb/gb.csrc/gb/gb.c

@@ -30,6 +30,7 @@ #define DMG_BIOS_CHECKSUM 0xC2F5CC97

#define DMG_2_BIOS_CHECKSUM 0x59C8598E #define MGB_BIOS_CHECKSUM 0xE6920754 #define SGB_BIOS_CHECKSUM 0xEC8A83B9 +#define SGB2_BIOS_CHECKSUM 0X53D0DD63 #define CGB_BIOS_CHECKSUM 0x41884E46 mLOG_DEFINE_CATEGORY(GB, "GB", "gb");

@@ -249,7 +250,11 @@ }

} void GBSavedataMask(struct GB* gb, struct VFile* vf, bool writeback) { + struct VFile* oldVf = gb->sramVf; GBSramDeinit(gb); + if (oldVf && oldVf != gb->sramRealVf) { + oldVf->close(oldVf); + } gb->sramVf = vf; gb->sramMaskWriteback = writeback; gb->memory.sram = vf->map(vf, gb->sramSize, MAP_READ);

@@ -396,6 +401,7 @@ case DMG_BIOS_CHECKSUM:

case DMG_2_BIOS_CHECKSUM: case MGB_BIOS_CHECKSUM: case SGB_BIOS_CHECKSUM: + case SGB2_BIOS_CHECKSUM: case CGB_BIOS_CHECKSUM: return true; default:

@@ -583,6 +589,9 @@ gb->model = GB_MODEL_MGB;

break; case SGB_BIOS_CHECKSUM: gb->model = GB_MODEL_SGB; + break; + case SGB2_BIOS_CHECKSUM: + gb->model = GB_MODEL_SGB2; break; case CGB_BIOS_CHECKSUM: gb->model = GB_MODEL_CGB;
M src/gb/io.csrc/gb/io.c

@@ -105,6 +105,7 @@ [REG_IE] = 0xE0,

}; static uint8_t _readKeys(struct GB* gb); +static uint8_t _readKeysFiltered(struct GB* gb); static void _writeSGBBits(struct GB* gb, int bits) { if (!bits) {

@@ -198,7 +199,7 @@ GBIOWrite(gb, REG_OBP1, 0xFF);

} GBIOWrite(gb, REG_WY, 0x00); GBIOWrite(gb, REG_WX, 0x00); - if (gb->model >= GB_MODEL_CGB) { + if (gb->model & GB_MODEL_CGB) { GBIOWrite(gb, REG_UNK4C, 0); GBIOWrite(gb, REG_JOYP, 0xFF); GBIOWrite(gb, REG_VBK, 0);

@@ -210,7 +211,7 @@ GBIOWrite(gb, REG_HDMA2, 0xFF);

GBIOWrite(gb, REG_HDMA3, 0xFF); GBIOWrite(gb, REG_HDMA4, 0xFF); gb->memory.io[REG_HDMA5] = 0xFF; - } else if (gb->model == GB_MODEL_SGB) { + } else if (gb->model & GB_MODEL_SGB) { GBIOWrite(gb, REG_JOYP, 0xFF); } GBIOWrite(gb, REG_IE, 0x00);

@@ -403,7 +404,7 @@ break;

case REG_JOYP: gb->memory.io[REG_JOYP] = value | 0x0F; _readKeys(gb); - if (gb->model == GB_MODEL_SGB) { + if (gb->model & GB_MODEL_SGB) { _writeSGBBits(gb, (value >> 4) & 3); } return;

@@ -557,10 +558,25 @@ }

return gb->memory.io[REG_JOYP]; } +static uint8_t _readKeysFiltered(struct GB* gb) { + uint8_t keys = _readKeys(gb); + if (!gb->allowOpposingDirections && (keys & 0x30) == 0x20) { + unsigned rl = keys & 0x03; + unsigned ud = keys & 0x0C; + if (!rl) { + keys |= 0x03; + } + if (!ud) { + keys |= 0x0C; + } + } + return keys; +} + uint8_t GBIORead(struct GB* gb, unsigned address) { switch (address) { case REG_JOYP: - return _readKeys(gb); + return _readKeysFiltered(gb); case REG_IE: return gb->memory.ie; case REG_WAVE_0:

@@ -703,7 +719,7 @@ gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCY, state->io[REG_SCY]);

gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCX, state->io[REG_SCX]); gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WY, state->io[REG_WY]); gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WX, state->io[REG_WX]); - if (gb->model == GB_MODEL_SGB) { + if (gb->model & GB_MODEL_SGB) { gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_BGP, state->io[REG_BGP]); gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_OBP0, state->io[REG_OBP0]); gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_OBP1, state->io[REG_OBP1]);
M src/gb/renderers/software.csrc/gb/renderers/software.c

@@ -30,7 +30,7 @@ static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y);

static void _clearScreen(struct GBVideoSoftwareRenderer* renderer) { size_t sgbOffset = 0; - if (renderer->model == GB_MODEL_SGB) { + if (renderer->model & GB_MODEL_SGB) { return; } int y;

@@ -56,7 +56,7 @@ }

int x, y; for (y = 0; y < 224; ++y) { for (x = 0; x < 256; x += 8) { - if (x >= 48 && x < 208 && y >= 40 && y < 104) { + if (x >= 48 && x < 208 && y >= 40 && y < 184) { continue; } uint16_t mapData;

@@ -79,16 +79,13 @@ size_t base = y * renderer->outputBufferStride + x;

int paletteBase = SGBBgAttributesGetPalette(mapData) * 0x10; int colorSelector; + int flip = 0; if (SGBBgAttributesIsXFlip(mapData)) { - for (i = 0; i < 8; ++i) { - colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3; - renderer->outputBuffer[base + i] = renderer->palette[paletteBase | colorSelector]; - } - } else { - for (i = 7; i >= 0; --i) { - colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3; - renderer->outputBuffer[base + 7 - i] = renderer->palette[paletteBase | colorSelector]; - } + flip = 7; + } + for (i = 7; i >= 0; --i) { + colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3; + renderer->outputBuffer[(base + 7 - i) ^ flip] = renderer->palette[paletteBase | colorSelector]; } } }

@@ -432,7 +429,7 @@

static void GBVideoSoftwareRendererWritePalette(struct GBVideoRenderer* renderer, int index, uint16_t value) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; color_t color = mColorFrom555(value); - if (softwareRenderer->model == GB_MODEL_SGB) { + if (softwareRenderer->model & GB_MODEL_SGB) { if (index < 0x10 && index && !(index & 3)) { color = softwareRenderer->palette[0]; } else if (index >= 0x40 && !(index & 0xF)) {

@@ -463,7 +460,7 @@ #endif

} softwareRenderer->palette[index] = color; - if (softwareRenderer->model == GB_MODEL_SGB && !index && GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) { + if (softwareRenderer->model & GB_MODEL_SGB && !index && GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) { renderer->writePalette(renderer, 0x04, value); renderer->writePalette(renderer, 0x08, value); renderer->writePalette(renderer, 0x0C, value);

@@ -528,7 +525,7 @@ }

} size_t sgbOffset = 0; - if (softwareRenderer->model == GB_MODEL_SGB && softwareRenderer->sgbBorders) { + if (softwareRenderer->model & GB_MODEL_SGB && softwareRenderer->sgbBorders) { sgbOffset = softwareRenderer->outputBufferStride * 40 + 48; } color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y + sgbOffset];

@@ -536,7 +533,7 @@ int x = startX;

int p = 0; switch (softwareRenderer->d.sgbRenderMode) { case 0: - if (softwareRenderer->model == GB_MODEL_SGB) { + if (softwareRenderer->model & GB_MODEL_SGB) { p = softwareRenderer->d.sgbAttributes[(startX >> 5) + 5 * (y >> 3)]; p >>= 6 - ((x / 4) & 0x6); p &= 3;

@@ -546,7 +543,7 @@ for (; x < ((startX + 7) & ~7) && x < endX; ++x) {

row[x] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x] & 0x7F]]; } for (; x + 7 < (endX & ~7); x += 8) { - if (softwareRenderer->model == GB_MODEL_SGB) { + if (softwareRenderer->model & GB_MODEL_SGB) { p = softwareRenderer->d.sgbAttributes[(x >> 5) + 5 * (y >> 3)]; p >>= 6 - ((x / 4) & 0x6); p &= 3;

@@ -561,7 +558,7 @@ row[x + 5] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 5] & 0x7F]];

row[x + 6] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 6] & 0x7F]]; row[x + 7] = softwareRenderer->palette[p | softwareRenderer->lookup[softwareRenderer->row[x + 7] & 0x7F]]; } - if (softwareRenderer->model == GB_MODEL_SGB) { + if (softwareRenderer->model & GB_MODEL_SGB) { p = softwareRenderer->d.sgbAttributes[(x >> 5) + 5 * (y >> 3)]; p >>= 6 - ((x / 4) & 0x6); p &= 3;

@@ -678,7 +675,7 @@ }

if (!GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) { _clearScreen(softwareRenderer); } - if (softwareRenderer->model == GB_MODEL_SGB) { + if (softwareRenderer->model & GB_MODEL_SGB) { switch (softwareRenderer->sgbCommandHeader >> 3) { case SGB_PAL_SET: case SGB_ATTR_SET:

@@ -711,7 +708,10 @@ }

static void GBVideoSoftwareRendererEnableSGBBorder(struct GBVideoRenderer* renderer, bool enable) { struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; - if (softwareRenderer->model == GB_MODEL_SGB) { + if (softwareRenderer->model & GB_MODEL_SGB) { + if (enable == softwareRenderer->sgbBorders) { + return; + } softwareRenderer->sgbBorders = enable; if (softwareRenderer->sgbBorders && !renderer->sgbRenderMode) { _regenerateSGBBorder(softwareRenderer);
M src/gb/serialize.csrc/gb/serialize.c

@@ -64,7 +64,7 @@ GBVideoSerialize(&gb->video, state);

GBTimerSerialize(&gb->timer, state); GBAudioSerialize(&gb->audio, state); - if (gb->model == GB_MODEL_SGB) { + if (gb->model & GB_MODEL_SGB) { GBSGBSerialize(gb, state); } }

@@ -187,7 +187,7 @@ GBIODeserialize(gb, state);

GBTimerDeserialize(&gb->timer, state); GBAudioDeserialize(&gb->audio, state); - if (gb->model == GB_MODEL_SGB && canSgb) { + if (gb->model & GB_MODEL_SGB && canSgb) { GBSGBDeserialize(gb, state); }
M src/gb/video.csrc/gb/video.c

@@ -107,7 +107,7 @@ memset(&video->oam, 0, sizeof(video->oam));

video->renderer->oam = &video->oam; memset(&video->palette, 0, sizeof(video->palette)); - if (video->p->model == GB_MODEL_SGB) { + if (video->p->model & GB_MODEL_SGB) { video->renderer->sgbCharRam = anonymousMemoryMap(SGB_SIZE_CHAR_RAM); video->renderer->sgbMapRam = anonymousMemoryMap(SGB_SIZE_MAP_RAM); video->renderer->sgbPalRam = anonymousMemoryMap(SGB_SIZE_PAL_RAM);

@@ -491,7 +491,7 @@ video->renderer->writePalette(video->renderer, 9 * 4 + 2, video->palette[9 * 4 + 2]);

video->renderer->writePalette(video->renderer, 9 * 4 + 3, video->palette[9 * 4 + 3]); break; } - } else if (video->p->model == GB_MODEL_SGB) { + } else if (video->p->model & GB_MODEL_SGB) { video->renderer->writeVideoRegister(video->renderer, address, value); } else { switch (address) {
M src/gba/core.csrc/gba/core.c

@@ -247,6 +247,11 @@ }

} } + int fakeBool = 0; + mCoreConfigGetIntValue(config, "allowOpposingDirections", &fakeBool); + gba->allowOpposingDirections = fakeBool; + + mCoreConfigCopyValue(&core->config, config, "allowOpposingDirections"); mCoreConfigCopyValue(&core->config, config, "gba.bios"); #ifndef DISABLE_THREADING
M src/gba/gba.csrc/gba/gba.c

@@ -25,6 +25,8 @@ #ifdef USE_ELF

#include <mgba-util/elf-read.h> #endif +#define GBA_IRQ_DELAY 7 + mLOG_DEFINE_CATEGORY(GBA, "GBA", "gba"); mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug");

@@ -44,6 +46,8 @@ static void GBAProcessEvents(struct ARMCore* cpu);

static void GBAHitStub(struct ARMCore* cpu, uint32_t opcode); static void GBAIllegal(struct ARMCore* cpu, uint32_t opcode); static void GBABreakpoint(struct ARMCore* cpu, int immediate); + +static void _triggerIRQ(struct mTiming*, void* user, uint32_t cyclesLate); #ifdef USE_DEBUGGERS static bool _setSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);

@@ -86,7 +90,6 @@ GBASIOInit(&gba->sio);

GBAHardwareInit(&gba->memory.hw, NULL); - gba->springIRQ = 0; gba->keySource = 0; gba->rotationSource = 0; gba->luminanceSource = 0;

@@ -116,6 +119,11 @@ gba->pristineRomSize = 0;

gba->yankedRomSize = 0; mTimingInit(&gba->timing, &gba->cpu->cycles, &gba->cpu->nextEvent); + + gba->irqEvent.name = "GBA IRQ Event"; + gba->irqEvent.callback = _triggerIRQ; + gba->irqEvent.context = gba; + gba->irqEvent.priority = 0; } void GBAUnloadROM(struct GBA* gba) {

@@ -138,6 +146,8 @@ }

gba->memory.rom = NULL; gba->isPristine = false; + gba->memory.savedata.maskWriteback = false; + GBASavedataUnmask(&gba->memory.savedata); GBASavedataDeinit(&gba->memory.savedata); if (gba->memory.savedata.realVf) { gba->memory.savedata.realVf->close(gba->memory.savedata.realVf);

@@ -245,11 +255,6 @@ if (cpu->executionMode == MODE_THUMB) {

gba->bus |= cpu->prefetch[1] << 16; } - if (gba->springIRQ && !cpu->cpsr.i) { - ARMRaiseIRQ(cpu); - gba->springIRQ = 0; - } - int32_t nextEvent = cpu->nextEvent; while (cpu->cycles >= nextEvent) { cpu->nextEvent = INT_MAX;

@@ -470,36 +475,19 @@ gba->memory.hw.gpioBase = &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1];

gba->memory.romSize = patchedSize; gba->memory.romMask = SIZE_CART0 - 1; gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); -} - -void GBAWriteIE(struct GBA* gba, uint16_t value) { - if (gba->memory.io[REG_IME >> 1] && value & gba->memory.io[REG_IF >> 1]) { - ARMRaiseIRQ(gba->cpu); - } -} - -void GBAWriteIME(struct GBA* gba, uint16_t value) { - if (value && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) { - ARMRaiseIRQ(gba->cpu); - } } void GBARaiseIRQ(struct GBA* gba, enum GBAIRQ irq) { gba->memory.io[REG_IF >> 1] |= 1 << irq; - - if (gba->memory.io[REG_IE >> 1] & 1 << irq) { - gba->cpu->halted = 0; - if (gba->memory.io[REG_IME >> 1]) { - ARMRaiseIRQ(gba->cpu); - } - } + GBATestIRQ(gba->cpu); } void GBATestIRQ(struct ARMCore* cpu) { struct GBA* gba = (struct GBA*) cpu->master; - if (gba->memory.io[REG_IME >> 1] && gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) { - gba->springIRQ = gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]; - gba->cpu->nextEvent = gba->cpu->cycles; + if (gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1]) { + if (!mTimingIsScheduled(&gba->timing, &gba->irqEvent)) { + mTimingSchedule(&gba->timing, &gba->irqEvent, GBA_IRQ_DELAY); + } } }

@@ -851,6 +839,20 @@ if (isAnd && keycnt == keyInput) {

GBARaiseIRQ(gba, IRQ_KEYPAD); } else if (!isAnd && keyInput) { GBARaiseIRQ(gba, IRQ_KEYPAD); + } +} + +static void _triggerIRQ(struct mTiming* timing, void* user, uint32_t cyclesLate) { + UNUSED(timing); + UNUSED(cyclesLate); + struct GBA* gba = user; + gba->cpu->halted = 0; + if (!(gba->memory.io[REG_IE >> 1] & gba->memory.io[REG_IF >> 1])) { + return; + } + + if (gba->memory.io[REG_IME >> 1] && !gba->cpu->cpsr.i) { + ARMRaiseIRQ(gba->cpu); } }
M src/gba/io.csrc/gba/io.c

@@ -547,15 +547,18 @@ value &= 0x5FFF;

GBAAdjustWaitstates(gba, value); break; case REG_IE: - GBAWriteIE(gba, value); - break; + gba->memory.io[REG_IE >> 1] = value; + GBATestIRQ(gba->cpu); + return; case REG_IF: - gba->springIRQ &= ~value; value = gba->memory.io[REG_IF >> 1] & ~value; - break; + gba->memory.io[REG_IF >> 1] = value; + GBATestIRQ(gba->cpu); + return; case REG_IME: - GBAWriteIME(gba, value); - break; + gba->memory.io[REG_IME >> 1] = value; + GBATestIRQ(gba->cpu); + return; case REG_MAX: // Some bad interrupt libraries will write to this break;

@@ -931,7 +934,6 @@ STORE_16(gba->memory.io[(REG_DMA0CNT_LO + i * 12) >> 1], (REG_DMA0CNT_LO + i * 12), state->io);

STORE_16(gba->timers[i].reload, 0, &state->timers[i].reload); STORE_32(gba->timers[i].lastEvent - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].lastEvent); STORE_32(gba->timers[i].event.when - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].nextEvent); - STORE_32(gba->timers[i].irq.when - mTimingCurrentTime(&gba->timing), 0, &state->timers[i].nextIrq); STORE_32(gba->timers[i].flags, 0, &state->timers[i].flags); STORE_32(gba->memory.dma[i].nextSource, 0, &state->dma[i].nextSource); STORE_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest);

@@ -970,10 +972,6 @@ }

LOAD_32(when, 0, &state->timers[i].nextEvent); if (GBATimerFlagsIsEnable(gba->timers[i].flags)) { mTimingSchedule(&gba->timing, &gba->timers[i].event, when); - } - LOAD_32(when, 0, &state->timers[i].nextIrq); - if (GBATimerFlagsIsIrqPending(gba->timers[i].flags)) { - mTimingSchedule(&gba->timing, &gba->timers[i].irq, when); } LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io);
M src/gba/memory.csrc/gba/memory.c

@@ -99,13 +99,6 @@ mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM + SIZE_WORKING_IRAM);

if (gba->memory.rom) { mappedMemoryFree(gba->memory.rom, gba->memory.romSize); } - gba->memory.savedata.maskWriteback = false; - GBASavedataUnmask(&gba->memory.savedata); - GBASavedataDeinit(&gba->memory.savedata); - if (gba->memory.savedata.realVf) { - gba->memory.savedata.realVf->close(gba->memory.savedata.realVf); - } - if (gba->memory.agbPrintBuffer) { mappedMemoryFree(gba->memory.agbPrintBuffer, SIZE_AGB_PRINT); }
M src/gba/renderers/video-software.csrc/gba/renderers/video-software.c

@@ -582,6 +582,8 @@ }

return; } + CLEAN_SCANLINE(softwareRenderer, y); + color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y]; if (GBARegisterDISPCNTIsForcedBlank(softwareRenderer->dispcnt)) { int x;

@@ -694,15 +696,19 @@ }

if (softwareRenderer->bg[0].enabled > 0 && softwareRenderer->bg[0].enabled < 4) { ++softwareRenderer->bg[0].enabled; + DIRTY_SCANLINE(softwareRenderer, y); } if (softwareRenderer->bg[1].enabled > 0 && softwareRenderer->bg[1].enabled < 4) { ++softwareRenderer->bg[1].enabled; + DIRTY_SCANLINE(softwareRenderer, y); } if (softwareRenderer->bg[2].enabled > 0 && softwareRenderer->bg[2].enabled < 4) { ++softwareRenderer->bg[2].enabled; + DIRTY_SCANLINE(softwareRenderer, y); } if (softwareRenderer->bg[3].enabled > 0 && softwareRenderer->bg[3].enabled < 4) { ++softwareRenderer->bg[3].enabled; + DIRTY_SCANLINE(softwareRenderer, y); } GBAVideoSoftwareRendererPostprocessBuffer(softwareRenderer);

@@ -718,7 +724,6 @@ }

#else memcpy(row, softwareRenderer->row, softwareRenderer->masterEnd * sizeof(*row)); #endif - CLEAN_SCANLINE(softwareRenderer, y); } static void GBAVideoSoftwareRendererFinishFrame(struct GBAVideoRenderer* renderer) {

@@ -765,9 +770,10 @@ }

} static void _enableBg(struct GBAVideoSoftwareRenderer* renderer, int bg, bool active) { + int wasActive = renderer->bg[bg].enabled; if (!active) { renderer->bg[bg].enabled = 0; - } else if (!renderer->bg[bg].enabled && active) { + } else if (!wasActive && active) { if (renderer->nextY == 0) { renderer->bg[bg].enabled = 4; } else {
M src/gba/savedata.csrc/gba/savedata.c

@@ -88,7 +88,11 @@ }

void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf, bool writeback) { enum SavedataType type = savedata->type; + struct VFile* oldVf = savedata->vf; GBASavedataDeinit(savedata); + if (oldVf && oldVf != savedata->realVf) { + oldVf->close(oldVf); + } savedata->vf = vf; savedata->mapMode = MAP_READ; savedata->maskWriteback = writeback;
M src/gba/serialize.csrc/gba/serialize.c

@@ -15,7 +15,7 @@

#include <fcntl.h> const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000; -const uint32_t GBA_SAVESTATE_VERSION = 0x00000002; +const uint32_t GBA_SAVESTATE_VERSION = 0x00000003; mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate", "gba.serialize");

@@ -62,6 +62,10 @@

GBASerializedMiscFlags miscFlags = 0; miscFlags = GBASerializedMiscFlagsSetHalted(miscFlags, gba->cpu->halted); miscFlags = GBASerializedMiscFlagsSetPOSTFLG(miscFlags, gba->memory.io[REG_POSTFLG >> 1] & 1); + if (mTimingIsScheduled(&gba->timing, &gba->irqEvent)) { + miscFlags = GBASerializedMiscFlagsFillIrqPending(miscFlags); + STORE_32(gba->irqEvent.when - mTimingCurrentTime(&gba->timing), 0, &state->nextIrq); + } STORE_32(miscFlags, 0, &state->miscFlags); GBAMemorySerialize(&gba->memory, state);

@@ -179,6 +183,11 @@ GBASerializedMiscFlags miscFlags = 0;

LOAD_32(miscFlags, 0, &state->miscFlags); gba->cpu->halted = GBASerializedMiscFlagsGetHalted(miscFlags); gba->memory.io[REG_POSTFLG >> 1] = GBASerializedMiscFlagsGetPOSTFLG(miscFlags); + if (GBASerializedMiscFlagsIsIrqPending(miscFlags)) { + int32_t when; + LOAD_32(when, 0, &state->nextIrq); + mTimingSchedule(&gba->timing, &gba->irqEvent, when); + } GBAVideoDeserialize(&gba->video, state); GBAMemoryDeserialize(&gba->memory, state);
M src/gba/timer.csrc/gba/timer.c

@@ -8,7 +8,6 @@

#include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/io.h> -#define TIMER_IRQ_DELAY 7 #define TIMER_RELOAD_DELAY 0 #define TIMER_STARTUP_DELAY 2

@@ -16,48 +15,16 @@ #define REG_TMCNT_LO(X) (REG_TM0CNT_LO + ((X) << 2))

static void GBATimerIrq(struct GBA* gba, int timerId) { struct GBATimer* timer = &gba->timers[timerId]; - if (GBATimerFlagsIsIrqPending(timer->flags)) { - timer->flags = GBATimerFlagsClearIrqPending(timer->flags); + if (GBATimerFlagsIsDoIrq(timer->flags)) { GBARaiseIRQ(gba, IRQ_TIMER0 + timerId); } } -static void GBATimerIrq0(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - GBATimerIrq(context, 0); -} - -static void GBATimerIrq1(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - GBATimerIrq(context, 1); -} - -static void GBATimerIrq2(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - GBATimerIrq(context, 2); -} - -static void GBATimerIrq3(struct mTiming* timing, void* context, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - GBATimerIrq(context, 3); -} - void GBATimerUpdate(struct mTiming* timing, struct GBATimer* timer, uint16_t* io, uint32_t cyclesLate) { if (GBATimerFlagsIsCountUp(timer->flags)) { *io = timer->reload; } else { GBATimerUpdateRegisterInternal(timer, timing, io, TIMER_RELOAD_DELAY + cyclesLate); - } - - if (GBATimerFlagsIsDoIrq(timer->flags)) { - timer->flags = GBATimerFlagsFillIrqPending(timer->flags); - if (!mTimingIsScheduled(timing, &timer->irq)) { - mTimingSchedule(timing, &timer->irq, TIMER_IRQ_DELAY - cyclesLate); - } } }

@@ -74,38 +41,50 @@ GBAAudioSampleFIFO(&gba->audio, 1, cyclesLate);

} } -void GBATimerUpdateCountUp(struct mTiming* timing, struct GBATimer* nextTimer, uint16_t* io, uint32_t cyclesLate) { +bool GBATimerUpdateCountUp(struct mTiming* timing, struct GBATimer* nextTimer, uint16_t* io, uint32_t cyclesLate) { if (GBATimerFlagsIsCountUp(nextTimer->flags)) { // TODO: Does this increment while disabled? ++*io; if (!*io && GBATimerFlagsIsEnable(nextTimer->flags)) { GBATimerUpdate(timing, nextTimer, io, cyclesLate); + return true; } } + return false; } static void GBATimerUpdate0(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GBA* gba = context; GBATimerUpdateAudio(gba, 0, cyclesLate); GBATimerUpdate(timing, &gba->timers[0], &gba->memory.io[REG_TM0CNT_LO >> 1], cyclesLate); - GBATimerUpdateCountUp(timing, &gba->timers[1], &gba->memory.io[REG_TM1CNT_LO >> 1], cyclesLate); + GBATimerIrq(gba, 0); + if (GBATimerUpdateCountUp(timing, &gba->timers[1], &gba->memory.io[REG_TM1CNT_LO >> 1], cyclesLate)) { + GBATimerIrq(gba, 1); + } } static void GBATimerUpdate1(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GBA* gba = context; GBATimerUpdateAudio(gba, 1, cyclesLate); GBATimerUpdate(timing, &gba->timers[1], &gba->memory.io[REG_TM1CNT_LO >> 1], cyclesLate); - GBATimerUpdateCountUp(timing, &gba->timers[2], &gba->memory.io[REG_TM2CNT_LO >> 1], cyclesLate); + GBATimerIrq(gba, 1); + if (GBATimerUpdateCountUp(timing, &gba->timers[2], &gba->memory.io[REG_TM2CNT_LO >> 1], cyclesLate)) { + GBATimerIrq(gba, 2); + } } static void GBATimerUpdate2(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GBA* gba = context; GBATimerUpdate(timing, &gba->timers[2], &gba->memory.io[REG_TM2CNT_LO >> 1], cyclesLate); - GBATimerUpdateCountUp(timing, &gba->timers[3], &gba->memory.io[REG_TM3CNT_LO >> 1], cyclesLate); + GBATimerIrq(gba, 2); + if (GBATimerUpdateCountUp(timing, &gba->timers[3], &gba->memory.io[REG_TM3CNT_LO >> 1], cyclesLate)) { + GBATimerIrq(gba, 3); + } } static void GBATimerUpdate3(struct mTiming* timing, void* context, uint32_t cyclesLate) { struct GBA* gba = context; GBATimerUpdate(timing, &gba->timers[3], &gba->memory.io[REG_TM3CNT_LO >> 1], cyclesLate); + GBATimerIrq(gba, 3); } void GBATimerInit(struct GBA* gba) {

@@ -126,22 +105,6 @@ gba->timers[3].event.name = "GBA Timer 3";

gba->timers[3].event.callback = GBATimerUpdate3; gba->timers[3].event.context = gba; gba->timers[3].event.priority = 0x23; - gba->timers[0].irq.name = "GBA Timer 0 IRQ"; - gba->timers[0].irq.callback = GBATimerIrq0; - gba->timers[0].irq.context = gba; - gba->timers[0].irq.priority = 0x28; - gba->timers[1].irq.name = "GBA Timer 1 IRQ"; - gba->timers[1].irq.callback = GBATimerIrq1; - gba->timers[1].irq.context = gba; - gba->timers[1].irq.priority = 0x29; - gba->timers[2].irq.name = "GBA Timer 2 IRQ"; - gba->timers[2].irq.callback = GBATimerIrq2; - gba->timers[2].irq.context = gba; - gba->timers[2].irq.priority = 0x2A; - gba->timers[3].irq.name = "GBA Timer 3 IRQ"; - gba->timers[3].irq.callback = GBATimerIrq3; - gba->timers[3].irq.context = gba; - gba->timers[3].irq.priority = 0x2B; } void GBATimerUpdateRegister(struct GBA* gba, int timer, int32_t cyclesLate) {
M src/platform/3ds/CMakeLists.txtsrc/platform/3ds/CMakeLists.txt

@@ -113,6 +113,8 @@ DESTINATION . COMPONENT ${BINARY_NAME}-perf)

endif() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cia.rsf.in ${CMAKE_CURRENT_BINARY_DIR}/cia.rsf) + +install(TARGETS ${BINARY_NAME}.elf DESTINATION . COMPONENT ${BINARY_NAME}-dbg) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.3dsx ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.smdh
M src/platform/libretro/libretro.csrc/platform/libretro/libretro.c

@@ -23,7 +23,6 @@ #include <mgba/gba/core.h>

#include <mgba/gba/interface.h> #include <mgba/internal/gba/gba.h> #endif -#include <mgba-util/circle-buffer.h> #include <mgba-util/memory.h> #include <mgba-util/vfs.h>

@@ -55,8 +54,8 @@ static void* data;

static size_t dataSize; static void* savedata; static struct mAVStream stream; -static int rumbleLevel; -static struct CircleBuffer rumbleHistory; +static int rumbleUp; +static int rumbleDown; static struct mRumble rumble; static struct GBALuminanceSource lux; static int luxLevel;

@@ -254,7 +253,6 @@

struct retro_rumble_interface rumbleInterface; if (environCallback(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumbleInterface)) { rumbleCallback = rumbleInterface.set_rumble_state; - CircleBufferInit(&rumbleHistory, RUMBLE_PWM); rumble.setRumble = _setRumble; } else { rumbleCallback = 0;

@@ -348,6 +346,18 @@ core->runFrame(core);

unsigned width, height; core->desiredVideoDimensions(core, &width, &height); videoCallback(outputBuffer, width, height, BYTES_PER_PIXEL * 256); + + if (rumbleCallback) { + if (rumbleUp) { + rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleUp * 0xFFFF / (rumbleUp + rumbleDown)); + rumbleCallback(0, RETRO_RUMBLE_WEAK, rumbleUp * 0xFFFF / (rumbleUp + rumbleDown)); + } else { + rumbleCallback(0, RETRO_RUMBLE_STRONG, 0); + rumbleCallback(0, RETRO_RUMBLE_WEAK, 0); + } + rumbleUp = 0; + rumbleDown = 0; + } } static void _setupMaps(struct mCore* core) {

@@ -438,9 +448,8 @@ void retro_reset(void) {

core->reset(core); _setupMaps(core); - if (rumbleCallback) { - CircleBufferClear(&rumbleHistory); - } + rumbleUp = 0; + rumbleDown = 0; } bool retro_load_game(const struct retro_game_info* game) {

@@ -558,7 +567,6 @@ mappedMemoryFree(data, dataSize);

data = 0; mappedMemoryFree(savedata, SIZE_CART_FLASH1M); savedata = 0; - CircleBufferDeinit(&rumbleHistory); } size_t retro_serialize_size(void) {

@@ -755,15 +763,11 @@ UNUSED(rumble);

if (!rumbleCallback) { return; } - rumbleLevel += enable; - if (CircleBufferSize(&rumbleHistory) == RUMBLE_PWM) { - int8_t oldLevel; - CircleBufferRead8(&rumbleHistory, &oldLevel); - rumbleLevel -= oldLevel; + if (enable) { + ++rumbleUp; + } else { + ++rumbleDown; } - CircleBufferWrite8(&rumbleHistory, enable); - rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleLevel * 0xFFFF / RUMBLE_PWM); - rumbleCallback(0, RETRO_RUMBLE_WEAK, rumbleLevel * 0xFFFF / RUMBLE_PWM); } static void _updateLux(struct GBALuminanceSource* lux) {
M src/platform/psp2/CMakeLists.txtsrc/platform/psp2/CMakeLists.txt

@@ -61,4 +61,5 @@ FILE ${CMAKE_CURRENT_SOURCE_DIR}/bg.png sce_sys/livearea/contents/bg.png

FILE ${CMAKE_CURRENT_SOURCE_DIR}/startup.png sce_sys/livearea/contents/startup.png FILE ${CMAKE_CURRENT_BINARY_DIR}/template.xml sce_sys/livearea/contents/template.xml) +install(TARGETS ${BINARY_NAME}.elf DESTINATION . COMPONENT ${BINARY_NAME}-dbg) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.vpk DESTINATION . COMPONENT ${BINARY_NAME}-psp2)
M src/platform/qt/CMakeLists.txtsrc/platform/qt/CMakeLists.txt

@@ -349,6 +349,10 @@ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")

find_program(BASH bash) install(CODE "execute_process(COMMAND \"${BASH}\" \"${CMAKE_SOURCE_DIR}/tools/deploy-win.sh\" \"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.exe\" \"\${CMAKE_INSTALL_PREFIX}\" \"\$ENV{PWD}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")" COMPONENT ${BINARY_NAME}-qt) endif() + if(DISTBUILD) + file(WRITE "${CMAKE_BINARY_DIR}/portable.ini" "") + install(FILES "${CMAKE_BINARY_DIR}/portable.ini" DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT ${BINARY_NAME}-qt) + endif() endif() if(DISTBUILD AND CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
M src/platform/qt/CoreController.cppsrc/platform/qt/CoreController.cpp

@@ -249,6 +249,10 @@ m_fpsTarget = config->getOption("fpsTarget").toFloat();

m_autosave = config->getOption("autosave", false).toInt(); m_autoload = config->getOption("autoload", true).toInt(); m_autofireThreshold = config->getOption("autofireThreshold", m_autofireThreshold).toInt(); + m_fastForwardVolume = config->getOption("fastForwardVolume", -1).toInt(); + m_fastForwardMute = config->getOption("fastForwardMute", -1).toInt(); + mCoreConfigCopyValue(&m_threadContext.core->config, config->config(), "volume"); + mCoreConfigCopyValue(&m_threadContext.core->config, config->config(), "mute"); mCoreLoadForeignConfig(m_threadContext.core, config->config()); if (hasStarted()) { updateFastForward();

@@ -782,15 +786,29 @@ }

void CoreController::updateFastForward() { if (m_fastForward || m_fastForwardForced) { + if (m_fastForwardVolume >= 0) { + m_threadContext.core->opts.volume = m_fastForwardVolume; + } + if (m_fastForwardMute >= 0) { + m_threadContext.core->opts.mute = m_fastForwardMute; + } if (m_fastForwardRatio > 0) { m_threadContext.impl->sync.fpsTarget = m_fpsTarget * m_fastForwardRatio; } else { setSync(false); } } else { + if (!mCoreConfigGetIntValue(&m_threadContext.core->config, "volume", &m_threadContext.core->opts.volume)) { + m_threadContext.core->opts.volume = 0x100; + } + int fakeBool = 0; + mCoreConfigGetIntValue(&m_threadContext.core->config, "mute", &fakeBool); + m_threadContext.core->opts.mute = fakeBool; m_threadContext.impl->sync.fpsTarget = m_fpsTarget; setSync(true); } + // XXX: Have a way of just updating opts + m_threadContext.core->loadConfig(m_threadContext.core, &m_threadContext.core->config); } CoreController::Interrupter::Interrupter(CoreController* parent, bool fromThread)
M src/platform/qt/CoreController.hsrc/platform/qt/CoreController.h

@@ -200,6 +200,8 @@ int m_autosaveCounter;

int m_fastForward = false; int m_fastForwardForced = false; + int m_fastForwardVolume = -1; + int m_fastForwardMute = -1; float m_fastForwardRatio = -1.f; float m_fpsTarget;
M src/platform/qt/DebuggerConsole.cppsrc/platform/qt/DebuggerConsole.cpp

@@ -17,6 +17,8 @@ , m_consoleController(controller)

{ m_ui.setupUi(this); + m_ui.prompt->installEventFilter(this); + connect(m_ui.prompt, &QLineEdit::returnPressed, this, &DebuggerConsole::postLine); connect(controller, &DebuggerConsoleController::log, this, &DebuggerConsole::log); connect(m_ui.breakpoint, &QAbstractButton::clicked, controller, &DebuggerController::attach);

@@ -36,7 +38,47 @@ m_ui.prompt->clear();

if (line.isEmpty()) { m_consoleController->enterLine(QString("\n")); } else { + m_history.append(line); + m_historyOffset = 0; log(QString("> %1\n").arg(line)); m_consoleController->enterLine(line); } } + +bool DebuggerConsole::eventFilter(QObject*, QEvent* event) { + if (event->type() != QEvent::KeyPress) { + return false; + } + if (m_history.isEmpty()) { + return false; + } + QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); + switch (keyEvent->key()) { + case Qt::Key_Down: + if (m_historyOffset <= 0) { + return false; + } + --m_historyOffset; + break; + case Qt::Key_Up: + if (m_historyOffset >= m_history.size()) { + return false; + } + ++m_historyOffset; + break; + case Qt::Key_End: + m_historyOffset = 0; + break; + case Qt::Key_Home: + m_historyOffset = m_history.size(); + break; + default: + return false; + } + if (m_historyOffset == 0) { + m_ui.prompt->clear(); + } else { + m_ui.prompt->setText(m_history[m_history.size() - m_historyOffset]); + } + return true; +}
M src/platform/qt/DebuggerConsole.hsrc/platform/qt/DebuggerConsole.h

@@ -21,8 +21,13 @@ private slots:

void log(const QString&); void postLine(); +protected: + bool eventFilter(QObject*, QEvent*) override; + private: Ui::DebuggerConsole m_ui; + QStringList m_history; + int m_historyOffset; DebuggerConsoleController* m_consoleController; };
M src/platform/qt/DisplayGL.cppsrc/platform/qt/DisplayGL.cpp

@@ -40,6 +40,7 @@ m_gl->setAttribute(Qt::WA_TransparentForMouseEvents); // This doesn't seem to work?

} DisplayGL::~DisplayGL() { + stopDrawing(); delete m_painter; }

@@ -196,8 +197,15 @@ #if !defined(_WIN32) || defined(USE_EPOXY)

mGLES2Context* gl2Backend; #endif + m_gl->makeCurrent(); +#if defined(_WIN32) && defined(USE_EPOXY) + epoxy_handle_external_wglMakeCurrent(); +#endif + + QStringList extensions = QString(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))).split(' '); + #if !defined(_WIN32) || defined(USE_EPOXY) - if (majorVersion >= 2) { + if (extensions.contains("GL_ARB_framebuffer_object") && majorVersion >= 2) { gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context))); mGLES2ContextCreate(gl2Backend); m_backend = &gl2Backend->d;

@@ -218,10 +226,6 @@ PainterGL* painter = static_cast<PainterGL*>(v->user);

painter->m_gl->swapBuffers(); }; - m_gl->makeCurrent(); -#if defined(_WIN32) && defined(USE_EPOXY) - epoxy_handle_external_wglMakeCurrent(); -#endif m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId())); #if !defined(_WIN32) || defined(USE_EPOXY) if (m_supportsShaders) {
M src/platform/qt/LoadSaveState.cppsrc/platform/qt/LoadSaveState.cpp

@@ -27,8 +27,9 @@ , m_controller(controller)

, m_mode(LoadSave::LOAD) , m_currentFocus(controller->stateSlot() - 1) { - setAttribute(Qt::WA_TranslucentBackground); m_ui.setupUi(this); + m_ui.lsLabel->setFocusProxy(this); + setFocusPolicy(Qt::ClickFocus); m_slots[0] = m_ui.state1; m_slots[1] = m_ui.state2;

@@ -56,6 +57,7 @@ }

if (m_currentFocus < 0) { m_currentFocus = 0; } + m_slots[m_currentFocus]->setFocus(); QAction* escape = new QAction(this); connect(escape, &QAction::triggered, this, &QWidget::close);

@@ -240,6 +242,10 @@

void LoadSaveState::showEvent(QShowEvent* event) { m_slots[m_currentFocus]->setFocus(); QWidget::showEvent(event); +} + +void LoadSaveState::focusInEvent(QFocusEvent*) { + m_slots[m_currentFocus]->setFocus(); } void LoadSaveState::paintEvent(QPaintEvent*) {
M src/platform/qt/LoadSaveState.hsrc/platform/qt/LoadSaveState.h

@@ -41,6 +41,7 @@ virtual bool eventFilter(QObject*, QEvent*) override;

virtual void closeEvent(QCloseEvent*) override; virtual void showEvent(QShowEvent*) override; virtual void paintEvent(QPaintEvent*) override; + virtual void focusInEvent(QFocusEvent*) override; private: void loadState(int slot);
M src/platform/qt/SensorView.cppsrc/platform/qt/SensorView.cpp

@@ -32,7 +32,7 @@ connect(m_ui.timeNow, &QPushButton::clicked, [this] () {

m_ui.time->setDateTime(QDateTime::currentDateTime()); }); - m_timer.setInterval(2); + m_timer.setInterval(15); connect(&m_timer, &QTimer::timeout, this, &SensorView::updateSensors); if (!m_rotation || !m_rotation->readTiltX || !m_rotation->readTiltY) { m_ui.tilt->hide();
M src/platform/qt/SettingsView.cppsrc/platform/qt/SettingsView.cpp

@@ -43,6 +43,18 @@ #endif

reloadConfig(); + connect(m_ui.volume, static_cast<void (QSlider::*)(int)>(&QSlider::valueChanged), [this](int v) { + if (v < m_ui.volumeFf->value()) { + m_ui.volumeFf->setValue(v); + } + }); + + connect(m_ui.mute, &QAbstractButton::toggled, [this](bool e) { + if (e) { + m_ui.muteFf->setChecked(e); + } + }); + if (m_ui.savegamePath->text().isEmpty()) { m_ui.savegameSameDir->setChecked(true); }

@@ -344,6 +356,8 @@ saveSetting("lockAspectRatio", m_ui.lockAspectRatio);

saveSetting("lockIntegerScaling", m_ui.lockIntegerScaling); saveSetting("volume", m_ui.volume); saveSetting("mute", m_ui.mute); + saveSetting("fastForwardVolume", m_ui.volumeFf); + saveSetting("fastForwardMute", m_ui.muteFf); saveSetting("rewindEnable", m_ui.rewind); saveSetting("rewindBufferCapacity", m_ui.rewindCapacity); saveSetting("resampleVideo", m_ui.resampleVideo);

@@ -472,8 +486,10 @@ loadSetting("fpsTarget", m_ui.fpsTarget);

loadSetting("autofireThreshold", m_ui.autofireThreshold); loadSetting("lockAspectRatio", m_ui.lockAspectRatio); loadSetting("lockIntegerScaling", m_ui.lockIntegerScaling); - loadSetting("volume", m_ui.volume); - loadSetting("mute", m_ui.mute); + loadSetting("volume", m_ui.volume, 0x100); + loadSetting("mute", m_ui.mute, false); + loadSetting("fastForwardVolume", m_ui.volumeFf, m_ui.volume->value()); + loadSetting("fastForwardMute", m_ui.muteFf, m_ui.mute->isChecked()); loadSetting("rewindEnable", m_ui.rewind); loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); loadSetting("resampleVideo", m_ui.resampleVideo);

@@ -604,9 +620,9 @@ QString option = loadSetting(key);

field->setText(option); } -void SettingsView::loadSetting(const char* key, QSlider* field) { +void SettingsView::loadSetting(const char* key, QSlider* field, int defaultVal) { QString option = loadSetting(key); - field->setValue(option.toInt()); + field->setValue(option.isNull() ? defaultVal : option.toInt()); } void SettingsView::loadSetting(const char* key, QSpinBox* field) {
M src/platform/qt/SettingsView.hsrc/platform/qt/SettingsView.h

@@ -75,7 +75,7 @@ void loadSetting(const char* key, QAbstractButton*, bool defaultVal = false);

void loadSetting(const char* key, QComboBox*); void loadSetting(const char* key, QDoubleSpinBox*); void loadSetting(const char* key, QLineEdit*); - void loadSetting(const char* key, QSlider*); + void loadSetting(const char* key, QSlider*, int defaultVal = 0); void loadSetting(const char* key, QSpinBox*); QString loadSetting(const char* key); };
M src/platform/qt/SettingsView.uisrc/platform/qt/SettingsView.ui

@@ -263,21 +263,61 @@ </widget>

</item> </layout> </item> - <item row="4" column="0" colspan="2"> + <item row="4" column="0"> + <widget class="QLabel" name="label_34"> + <property name="text"> + <string>Fast forward volume:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_17"> + <item> + <widget class="QSlider" name="volumeFf"> + <property name="minimumSize"> + <size> + <width>128</width> + <height>0</height> + </size> + </property> + <property name="maximum"> + <number>256</number> + </property> + <property name="pageStep"> + <number>16</number> + </property> + <property name="value"> + <number>256</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="muteFf"> + <property name="text"> + <string>Mute</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="5" column="0" colspan="2"> <widget class="Line" name="line_4"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="5" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="label_10"> <property name="text"> <string>Display driver:</string> </property> </widget> </item> - <item row="5" column="1"> + <item row="6" column="1"> <widget class="QComboBox" name="displayDriver"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">

@@ -287,14 +327,14 @@ </sizepolicy>

</property> </widget> </item> - <item row="6" column="0"> + <item row="7" column="0"> <widget class="QLabel" name="label_9"> <property name="text"> <string>Frameskip:</string> </property> </widget> </item> - <item row="6" column="1"> + <item row="7" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_16"> <item> <widget class="QLabel" name="label_12">

@@ -315,14 +355,14 @@ </widget>

</item> </layout> </item> - <item row="7" column="0"> + <item row="8" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>FPS target:</string> </property> </widget> </item> - <item row="7" column="1"> + <item row="8" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> <widget class="QDoubleSpinBox" name="fpsTarget">

@@ -349,21 +389,21 @@ </widget>

</item> </layout> </item> - <item row="8" column="0" colspan="2"> + <item row="9" column="0" colspan="2"> <widget class="Line" name="line_5"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="9" column="0"> + <item row="10" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Sync:</string> </property> </widget> </item> - <item row="9" column="1"> + <item row="10" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_10"> <item> <widget class="QCheckBox" name="videoSync">

@@ -381,7 +421,7 @@ </widget>

</item> </layout> </item> - <item row="10" column="1"> + <item row="11" column="1"> <widget class="QCheckBox" name="lockAspectRatio"> <property name="text"> <string>Lock aspect ratio</string>

@@ -389,16 +429,16 @@ </property>

</widget> </item> <item row="12" column="1"> - <widget class="QCheckBox" name="resampleVideo"> + <widget class="QCheckBox" name="lockIntegerScaling"> <property name="text"> - <string>Bilinear filtering</string> + <string>Force integer scaling</string> </property> </widget> </item> - <item row="11" column="1"> - <widget class="QCheckBox" name="lockIntegerScaling"> + <item row="13" column="1"> + <widget class="QCheckBox" name="resampleVideo"> <property name="text"> - <string>Force integer scaling</string> + <string>Bilinear filtering</string> </property> </widget> </item>
M src/platform/qt/TilePainter.cppsrc/platform/qt/TilePainter.cpp

@@ -59,8 +59,12 @@ // Only manage the size ourselves if we don't appear to have something else managing it

int w = width() / m_size; int h = (tiles + w - 1) * m_size / w; setMinimumSize(m_size, h - (h % m_size)); - resizeEvent(nullptr); + } else { + int w = minimumSize().width() / m_size; + int h = (tiles + w - 1) * m_size / w; + setMinimumSize(minimumSize().width(), h - (h % m_size)); } + resizeEvent(nullptr); } void TilePainter::setTileMagnification(int mag) {
M src/platform/qt/TileView.cppsrc/platform/qt/TileView.cpp

@@ -65,6 +65,21 @@ });

connect(m_ui.magnification, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this]() { updateTiles(true); }); + + connect(m_ui.tilesPerRow, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), [this](int count) { + m_ui.tiles->setMinimumSize(m_ui.magnification->value() * 8 * count, m_ui.tiles->minimumSize().height()); + updateTiles(true); + }); + + connect(m_ui.tileFit, &QAbstractButton::toggled, [this](bool selected) { + if (!selected) { + m_ui.tiles->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_ui.tiles->setMinimumSize(m_ui.magnification->value() * 8 * m_ui.tilesPerRow->value(), m_ui.tiles->minimumSize().height()); + } else { + m_ui.tiles->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + } + updateTiles(true); + }); } #ifdef M_CORE_GBA
M src/platform/qt/TileView.uisrc/platform/qt/TileView.ui

@@ -6,48 +6,15 @@ <property name="geometry">

<rect> <x>0</x> <y>0</y> - <width>501</width> - <height>335</height> + <width>693</width> + <height>467</height> </rect> </property> <property name="windowTitle"> <string>Tiles</string> </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0"> - <widget class="QGBA::AssetTile" name="tile"/> - </item> - <item row="1" column="0"> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QSpinBox" name="magnification"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="suffix"> - <string>×</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>4</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Magnification</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="0" column="1" rowspan="5"> + <layout class="QGridLayout" name="gridLayout" columnstretch="0,1"> + <item row="0" column="1" rowspan="4"> <widget class="QScrollArea" name="scrollArea"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Expanding">

@@ -66,7 +33,7 @@ <property name="geometry">

<rect> <x>0</x> <y>0</y> - <width>256</width> + <width>405</width> <height>768</height> </rect> </property>

@@ -112,7 +79,7 @@ </layout>

</widget> </widget> </item> - <item row="4" column="0"> + <item row="3" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum>

@@ -125,22 +92,84 @@ </size>

</property> </spacer> </item> + <item row="1" column="0"> + <widget class="QGBA::AssetTile" name="tile"/> + </item> <item row="0" column="0"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> <widget class="QSpinBox" name="paletteId"> <property name="maximum"> <number>15</number> </property> </widget> </item> - <item> + <item row="0" column="1"> <widget class="QCheckBox" name="palette256"> <property name="text"> <string>256 colors</string> </property> </widget> </item> + <item row="1" column="0"> + <widget class="QSpinBox" name="magnification"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="suffix"> + <string>×</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>4</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Magnification</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QSpinBox" name="tilesPerRow"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>64</number> + </property> + <property name="value"> + <number>32</number> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Tiles per row</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QCheckBox" name="tileFit"> + <property name="text"> + <string>Fit to window</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> </layout> </item> </layout>

@@ -165,18 +194,34 @@ </customwidgets>

<resources/> <connections> <connection> + <sender>tileFit</sender> + <signal>toggled(bool)</signal> + <receiver>tilesPerRow</receiver> + <slot>setDisabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>162</x> + <y>180</y> + </hint> + <hint type="destinationlabel"> + <x>39</x> + <y>133</y> + </hint> + </hints> + </connection> + <connection> <sender>magnification</sender> <signal>valueChanged(int)</signal> <receiver>tiles</receiver> <slot>setTileMagnification(int)</slot> <hints> <hint type="sourcelabel"> - <x>36</x> - <y>83</y> + <x>39</x> + <y>81</y> </hint> <hint type="destinationlabel"> - <x>339</x> - <y>396</y> + <x>462</x> + <y>391</y> </hint> </hints> </connection>

@@ -187,11 +232,11 @@ <receiver>paletteId</receiver>

<slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>158</x> - <y>29</y> + <x>148</x> + <y>24</y> </hint> <hint type="destinationlabel"> - <x>44</x> + <x>39</x> <y>29</y> </hint> </hints>
M src/platform/qt/Window.cppsrc/platform/qt/Window.cpp

@@ -103,7 +103,6 @@ setFocusPolicy(Qt::StrongFocus);

setAcceptDrops(true); setAttribute(Qt::WA_DeleteOnClose); updateTitle(); - reloadDisplayDriver(); m_logo.setDevicePixelRatio(m_screenWidget->devicePixelRatio()); m_logo = m_logo; // Free memory left over in old pixmap

@@ -160,12 +159,10 @@ setCentralWidget(m_screenWidget);

connect(this, &Window::shutdown, m_logView, &QWidget::hide); connect(&m_fpsTimer, &QTimer::timeout, this, &Window::showFPS); - connect(&m_frameTimer, &QTimer::timeout, this, &Window::delimitFrames); connect(&m_focusCheck, &QTimer::timeout, this, &Window::focusCheck); m_log.setLevels(mLOG_WARN | mLOG_ERROR | mLOG_FATAL); m_fpsTimer.setInterval(FPS_TIMER_INTERVAL); - m_frameTimer.setInterval(FRAME_LIST_INTERVAL); m_focusCheck.setInterval(200); setupMenu(menuBar());

@@ -270,8 +267,10 @@ m_audioProcessor->requestSampleRate(opts->sampleRate);

} m_display->resizeContext(); } - m_display->lockAspectRatio(opts->lockAspectRatio); - m_display->filter(opts->resampleVideo); + if (m_display) { + m_display->lockAspectRatio(opts->lockAspectRatio); + m_display->filter(opts->resampleVideo); + } m_inputController.setScreensaverSuspendable(opts->suspendScreensaver); }

@@ -410,6 +409,22 @@ m_controller->loadSave(filename, temporary);

} } +void Window::selectState(bool load) { + QStringList formats{"*.ss0", "*.ss1", "*.ss2", "*.ss3", "*.ss4", "*.ss5", "*.ss6", "*.ss7", "*.ss8", "*.ss9"}; + QString filter = tr("mGBA savestate files (%1)").arg(formats.join(QChar(' '))); + if (load) { + QString filename = GBAApp::app()->getOpenFileName(this, tr("Select savestate"), filter); + if (!filename.isEmpty()) { + m_controller->loadState(filename); + } + } else { + QString filename = GBAApp::app()->getSaveFileName(this, tr("Select savestate"), filter); + if (!filename.isEmpty()) { + m_controller->saveState(filename); + } + } +} + void Window::multiplayerChanged() { if (!m_controller) { return;

@@ -600,9 +615,7 @@ if (m_fullscreenOnStart) {

enterFullScreen(); m_fullscreenOnStart = false; } - if (m_display) { - reloadDisplayDriver(); - } + reloadDisplayDriver(); } void Window::closeEvent(QCloseEvent* event) {

@@ -614,6 +627,7 @@ m_config->setOption("height", VIDEO_VERTICAL_PIXELS * m_savedScale);

m_config->setOption("width", VIDEO_HORIZONTAL_PIXELS * m_savedScale); } saveConfig(); + m_display.reset(); QMainWindow::closeEvent(event); }

@@ -745,6 +759,9 @@ m_config->updateOption("lockAspectRatio");

if (m_savedScale > 0) { resizeFrame(size * m_savedScale); } + if (!m_display) { + reloadDisplayDriver(); + } attachWidget(m_display.get()); setMouseTracking(true); m_display->setMinimumSize(size);

@@ -830,7 +847,6 @@ m_videoLayers->clear();

m_audioChannels->clear(); m_fpsTimer.stop(); - m_frameTimer.stop(); m_focusCheck.stop(); emit paused(false);

@@ -960,19 +976,8 @@ dialog->show();

} void Window::recordFrame() { - if (m_frameList.isEmpty()) { - m_frameList.append(1); - } else { - ++m_frameList.back(); - } -} - -void Window::delimitFrames() { - if (m_frameList.size() >= FRAME_LIST_SIZE) { - m_frameCounter -= m_frameList.takeAt(0); - } - m_frameCounter += m_frameList.back(); - m_frameList.append(0); + m_frameList.append(m_frameTimer.nsecsElapsed()); + m_frameTimer.restart(); } void Window::showFPS() {

@@ -980,7 +985,12 @@ if (m_frameList.isEmpty()) {

updateTitle(); return; } - float fps = m_frameCounter * 10000.f / (FRAME_LIST_INTERVAL * (m_frameList.size() - 1)); + qint64 total = 0; + for (qint64 t : m_frameList) { + total += t; + } + double fps = (m_frameList.size() * 1e10) / total; + m_frameList.clear(); fps = round(fps) / 10.f; updateTitle(fps); }

@@ -1113,6 +1123,12 @@ m_nonMpActions.append(loadState);

m_platformActions.append(qMakePair(loadState, SUPPORT_GB | SUPPORT_GBA)); addControlledAction(fileMenu, loadState, "loadState"); + QAction* loadStateFile = new QAction(tr("Load state file..."), fileMenu); + connect(loadStateFile, &QAction::triggered, [this]() { this->selectState(true); }); + m_gameActions.append(loadStateFile); + m_nonMpActions.append(loadStateFile); + addControlledAction(fileMenu, loadStateFile, "loadStateFile"); + QAction* saveState = new QAction(tr("&Save state"), fileMenu); saveState->setShortcut(tr("Shift+F10")); connect(saveState, &QAction::triggered, [this]() { this->openStateWindow(LoadSave::SAVE); });

@@ -1120,6 +1136,12 @@ m_gameActions.append(saveState);

m_nonMpActions.append(saveState); m_platformActions.append(qMakePair(saveState, SUPPORT_GB | SUPPORT_GBA)); addControlledAction(fileMenu, saveState, "saveState"); + + QAction* saveStateFile = new QAction(tr("Save state file..."), fileMenu); + connect(saveStateFile, &QAction::triggered, [this]() { this->selectState(false); }); + m_gameActions.append(saveStateFile); + m_nonMpActions.append(saveStateFile); + addControlledAction(fileMenu, saveStateFile, "saveStateFile"); QMenu* quickLoadMenu = fileMenu->addMenu(tr("Quick load")); QMenu* quickSaveMenu = fileMenu->addMenu(tr("Quick save"));

@@ -1424,7 +1446,9 @@

ConfigOption* lockAspectRatio = m_config->addOption("lockAspectRatio"); lockAspectRatio->addBoolean(tr("Lock aspect ratio"), avMenu); lockAspectRatio->connect([this](const QVariant& value) { - m_display->lockAspectRatio(value.toBool()); + if (m_display) { + m_display->lockAspectRatio(value.toBool()); + } if (m_controller) { m_screenWidget->setLockAspectRatio(value.toBool()); }

@@ -1434,7 +1458,9 @@

ConfigOption* lockIntegerScaling = m_config->addOption("lockIntegerScaling"); lockIntegerScaling->addBoolean(tr("Force integer scaling"), avMenu); lockIntegerScaling->connect([this](const QVariant& value) { - m_display->lockIntegerScaling(value.toBool()); + if (m_display) { + m_display->lockIntegerScaling(value.toBool()); + } if (m_controller) { m_screenWidget->setLockIntegerScaling(value.toBool()); }

@@ -1444,7 +1470,9 @@

ConfigOption* resampleVideo = m_config->addOption("resampleVideo"); resampleVideo->addBoolean(tr("Bilinear filtering"), avMenu); resampleVideo->connect([this](const QVariant& value) { - m_display->filter(value.toBool()); + if (m_display) { + m_display->filter(value.toBool()); + } }, this); m_config->updateOption("resampleVideo");

@@ -1671,6 +1699,16 @@ volume->connect([this](const QVariant& value) {

reloadConfig(); }, this); + ConfigOption* volumeFf = m_config->addOption("fastForwardVolume"); + volumeFf->connect([this](const QVariant& value) { + reloadConfig(); + }, this); + + ConfigOption* muteFf = m_config->addOption("fastForwardMute"); + muteFf->connect([this](const QVariant& value) { + reloadConfig(); + }, this); + ConfigOption* rewindEnable = m_config->addOption("rewindEnable"); rewindEnable->connect([this](const QVariant& value) { reloadConfig();

@@ -1706,7 +1744,6 @@ ConfigOption* showFps = m_config->addOption("showFps");

showFps->connect([this](const QVariant& value) { if (!value.toInt()) { m_fpsTimer.stop(); - m_frameTimer.stop(); updateTitle(); } else if (m_controller) { m_fpsTimer.start();

@@ -1810,7 +1847,7 @@

void Window::updateFrame() { QSize size = m_controller->screenDimensions(); QImage currentImage(reinterpret_cast<const uchar*>(m_controller->drawContext()), size.width(), size.height(), - 256 * BYTES_PER_PIXEL, QImage::Format_RGBX8888); + size.width() * BYTES_PER_PIXEL, QImage::Format_RGBX8888); QPixmap pixmap; pixmap.convertFromImage(currentImage); m_screenWidget->setPixmap(pixmap);
M src/platform/qt/Window.hsrc/platform/qt/Window.h

@@ -7,6 +7,7 @@ #pragma once

#include <QAction> #include <QDateTime> +#include <QElapsedTimer> #include <QList> #include <QMainWindow> #include <QTimer>

@@ -68,6 +69,7 @@ void selectROMInArchive();

void addDirToLibrary(); #endif void selectSave(bool temporary); + void selectState(bool load); void selectPatch(); void enterFullScreen(); void exitFullScreen();

@@ -131,7 +133,6 @@ void tryMakePortable();

void mustRestart(); void recordFrame(); - void delimitFrames(); void showFPS(); void focusCheck();

@@ -139,8 +140,6 @@ void updateFrame();

private: static const int FPS_TIMER_INTERVAL = 2000; - static const int FRAME_LIST_INTERVAL = 100; - static const int FRAME_LIST_SIZE = 40; void setupMenu(QMenuBar*); void openStateWindow(LoadSave);

@@ -186,10 +185,9 @@ WindowBackground* m_screenWidget;

QPixmap m_logo{":/res/medusa-bg.jpg"}; ConfigController* m_config; InputController m_inputController; - QList<int> m_frameList; - int m_frameCounter = 0; + QList<qint64> m_frameList; + QElapsedTimer m_frameTimer; QTimer m_fpsTimer; - QTimer m_frameTimer; QList<QString> m_mruFiles; QMenu* m_mruMenu = nullptr; QMenu* m_videoLayers;
M src/platform/qt/input/InputController.cppsrc/platform/qt/input/InputController.cpp

@@ -947,13 +947,13 @@ #endif

} void InputController::loadCamImage(const QString& path) { - QMutexLocker locker(&m_image.mutex); - m_image.image.load(path); - m_image.resizedImage = QImage(); - m_image.outOfDate = true; + setCamImage(QImage(path)); } void InputController::setCamImage(const QImage& image) { + if (image.isNull()) { + return; + } QMutexLocker locker(&m_image.mutex); m_image.image = image; m_image.resizedImage = QImage();
M src/platform/qt/ts/medusa-emu-de.tssrc/platform/qt/ts/medusa-emu-de.ts

@@ -1166,40 +1166,6 @@ <translation>0x%0 (%1)</translation>

</message> </context> <context> - <name>QGBA::AudioDevice</name> - <message> - <location filename="../AudioDevice.cpp" line="26"/> - <source>Can&apos;t set format of context-less audio device</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../AudioDevice.cpp" line="48"/> - <source>Audio device is missing its core</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../AudioDevice.cpp" line="64"/> - <source>Writing data to read-only audio device</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> - <name>QGBA::AudioProcessorQt</name> - <message> - <location filename="../AudioProcessorQt.cpp" line="43"/> - <source>Can&apos;t start an audio processor without input</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> - <name>QGBA::AudioProcessorSDL</name> - <message> - <location filename="../AudioProcessorSDL.cpp" line="34"/> - <source>Can&apos;t start an audio processor without input</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> <name>QGBA::CheatsModel</name> <message> <location filename="../CheatsModel.cpp" line="54"/>

@@ -1245,22 +1211,22 @@ </context>

<context> <name>QGBA::CoreController</name> <message> - <location filename="../CoreController.cpp" line="561"/> + <location filename="../CoreController.cpp" line="557"/> <source>Failed to open save file: %1</source> <translation>Fehler beim Öffnen der Speicherdatei: %1</translation> </message> <message> - <location filename="../CoreController.cpp" line="590"/> + <location filename="../CoreController.cpp" line="586"/> <source>Failed to open game file: %1</source> <translation>Fehler beim Öffnen der Spieldatei: %1</translation> </message> <message> - <location filename="../CoreController.cpp" line="655"/> + <location filename="../CoreController.cpp" line="651"/> <source>Failed to open snapshot file for reading: %1</source> <translation>Konnte Snapshot-Datei %1 nicht zum Lesen öffnen</translation> </message> <message> - <location filename="../CoreController.cpp" line="671"/> + <location filename="../CoreController.cpp" line="667"/> <source>Failed to open snapshot file for writing: %1</source> <translation>Konnte Snapshot-Datei %1 nicht zum Schreiben öffnen</translation> </message>

@@ -2768,27 +2734,27 @@ </context>

<context> <name>QGBA::LoadSaveState</name> <message> - <location filename="../LoadSaveState.cpp" line="71"/> + <location filename="../LoadSaveState.cpp" line="73"/> <source>Load State</source> <translation>Savestate laden</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="71"/> + <location filename="../LoadSaveState.cpp" line="73"/> <source>Save State</source> <translation>Savestate speichern</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="180"/> + <location filename="../LoadSaveState.cpp" line="182"/> <source>Empty</source> <translation>Leer</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="189"/> + <location filename="../LoadSaveState.cpp" line="191"/> <source>Corrupted</source> <translation>Defekt</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="218"/> + <location filename="../LoadSaveState.cpp" line="220"/> <source>Slot %1</source> <translation>Speicherplatz %1</translation> </message>

@@ -2903,7 +2869,6 @@ <translation>Laden</translation>

</message> <message> <location filename="../MemoryModel.cpp" line="91"/> - <location filename="../MemoryModel.cpp" line="156"/> <source>All</source> <translation>Alle</translation> </message>

@@ -2913,32 +2878,32 @@ <source>Load TBL</source>

<translation>TBL laden</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="196"/> + <location filename="../MemoryModel.cpp" line="190"/> <source>Save selected memory</source> <translation>Ausgewählten Speicher abspeichern</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="202"/> + <location filename="../MemoryModel.cpp" line="196"/> <source>Failed to open output file: %1</source> <translation>Fehler beim Öffnen der Ausgabedatei: %1</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="210"/> + <location filename="../MemoryModel.cpp" line="204"/> <source>Load memory</source> <translation>Lade Speicher</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="216"/> + <location filename="../MemoryModel.cpp" line="210"/> <source>Failed to open input file: %1</source> <translation>Fehler beim Laden der Eingabedatei: %1</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="332"/> + <location filename="../MemoryModel.cpp" line="326"/> <source>TBL</source> <translation>TBL</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="332"/> + <location filename="../MemoryModel.cpp" line="326"/> <source>ISO-8859-1</source> <translation>ISO-8859-1</translation> </message>

@@ -3100,59 +3065,59 @@ </context>

<context> <name>QGBA::SettingsView</name> <message> - <location filename="../SettingsView.cpp" line="130"/> - <location filename="../SettingsView.cpp" line="172"/> + <location filename="../SettingsView.cpp" line="142"/> + <location filename="../SettingsView.cpp" line="184"/> <source>Qt Multimedia</source> <translation>Qt Multimedia</translation> </message> <message> - <location filename="../SettingsView.cpp" line="137"/> + <location filename="../SettingsView.cpp" line="149"/> <source>SDL</source> <translation>SDL</translation> </message> <message> - <location filename="../SettingsView.cpp" line="145"/> + <location filename="../SettingsView.cpp" line="157"/> <source>Software (Qt)</source> <translation>Software (Qt)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="151"/> + <location filename="../SettingsView.cpp" line="163"/> <source>OpenGL</source> <translation>OpenGL</translation> </message> <message> - <location filename="../SettingsView.cpp" line="158"/> + <location filename="../SettingsView.cpp" line="170"/> <source>OpenGL (force version 1.x)</source> <translation>OpenGL (erzwinge Version 1.x)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="166"/> + <location filename="../SettingsView.cpp" line="178"/> <source>None (Still Image)</source> <translation>Keiner (Standbild)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="247"/> + <location filename="../SettingsView.cpp" line="259"/> <source>Keyboard</source> <translation>Tastatur</translation> </message> <message> - <location filename="../SettingsView.cpp" line="256"/> + <location filename="../SettingsView.cpp" line="268"/> <source>Controllers</source> <translation>Gamepads</translation> </message> <message> - <location filename="../SettingsView.cpp" line="288"/> + <location filename="../SettingsView.cpp" line="300"/> <source>Shortcuts</source> <translation>Tastenkürzel</translation> </message> <message> - <location filename="../SettingsView.cpp" line="300"/> - <location filename="../SettingsView.cpp" line="310"/> + <location filename="../SettingsView.cpp" line="312"/> + <location filename="../SettingsView.cpp" line="322"/> <source>Shaders</source> <translation>Shader</translation> </message> <message> - <location filename="../SettingsView.cpp" line="317"/> + <location filename="../SettingsView.cpp" line="329"/> <source>Select BIOS</source> <translation>BIOS auswählen</translation> </message>

@@ -3193,12 +3158,12 @@ </context>

<context> <name>QGBA::VideoView</name> <message> - <location filename="../VideoView.cpp" line="211"/> + <location filename="../VideoView.cpp" line="212"/> <source>Failed to open output video file: %1</source> <translation>Fehler beim Öffnen der Ausgabe-Videodatei: %1</translation> </message> <message> - <location filename="../VideoView.cpp" line="229"/> + <location filename="../VideoView.cpp" line="230"/> <source>Native (%0x%1)</source> <translation>Nativ (%0x%1)</translation> </message>

@@ -3254,34 +3219,45 @@ <translation>Game Boy Advance-Speicherdateien (%1)</translation>

</message> <message> <location filename="../Window.cpp" line="360"/> - <location filename="../Window.cpp" line="405"/> - <location filename="../Window.cpp" line="412"/> + <location filename="../Window.cpp" line="421"/> + <location filename="../Window.cpp" line="428"/> <source>Select save</source> <translation>Speicherdatei wählen</translation> </message> <message> - <location filename="../Window.cpp" line="381"/> + <location filename="../Window.cpp" line="368"/> + <source>mGBA savestate files (%1)</source> + <translation>mGBA Savestate-Dateien (%1)</translation> + </message> + <message> + <location filename="../Window.cpp" line="370"/> + <location filename="../Window.cpp" line="375"/> + <source>Select savestate</source> + <translation>Savestate auswählen</translation> + </message> + <message> + <location filename="../Window.cpp" line="397"/> <source>Select patch</source> <translation>Patch wählen</translation> </message> <message> - <location filename="../Window.cpp" line="381"/> + <location filename="../Window.cpp" line="397"/> <source>Patches (*.ips *.ups *.bps)</source> <translation>Patches (*.ips *.ups *.bps)</translation> </message> <message> - <location filename="../Window.cpp" line="398"/> + <location filename="../Window.cpp" line="414"/> <source>Select image</source> <translation>Bild auswählen</translation> </message> <message> - <location filename="../Window.cpp" line="398"/> + <location filename="../Window.cpp" line="414"/> <source>Image file (*.png *.gif *.jpg *.jpeg);;All files (*)</source> <translation>Bild-Datei (*.png *.gif *.jpg *.jpeg);;Alle Dateien (*)</translation> </message> <message> - <location filename="../Window.cpp" line="405"/> - <location filename="../Window.cpp" line="412"/> + <location filename="../Window.cpp" line="421"/> + <location filename="../Window.cpp" line="428"/> <source>GameShark saves (*.sps *.xps)</source> <translation>GameShark-Speicherdaten (*.sps *.xps)</translation> </message>

@@ -3301,17 +3277,17 @@ <source>Select video log</source>

<translation>Video-Log auswählen</translation> </message> <message> - <location filename="../Window.cpp" line="437"/> + <location filename="../Window.cpp" line="453"/> <source>Video logs (*.mvl)</source> <translation>Video-Logs (*.mvl)</translation> </message> <message> - <location filename="../Window.cpp" line="782"/> + <location filename="../Window.cpp" line="799"/> <source>Crash</source> <translation>Absturz</translation> </message> <message> - <location filename="../Window.cpp" line="783"/> + <location filename="../Window.cpp" line="800"/> <source>The game has crashed with the following error: %1</source>

@@ -3320,538 +3296,508 @@

%1</translation> </message> <message> - <location filename="../Window.cpp" line="791"/> + <location filename="../Window.cpp" line="808"/> <source>Couldn&apos;t Load</source> <translation>Konnte nicht geladen werden</translation> </message> <message> - <location filename="../Window.cpp" line="792"/> + <location filename="../Window.cpp" line="809"/> <source>Could not load game. Are you sure it&apos;s in the correct format?</source> <translation>Konnte das Spiel nicht laden. Sind Sie sicher, dass es im korrekten Format vorliegt?</translation> </message> <message> - <location filename="../Window.cpp" line="805"/> + <location filename="../Window.cpp" line="822"/> <source>Unimplemented BIOS call</source> <translation>Nicht implementierter BIOS-Aufruf</translation> </message> <message> - <location filename="../Window.cpp" line="806"/> + <location filename="../Window.cpp" line="823"/> <source>This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience.</source> <translation>Dieses Spiel verwendet einen BIOS-Aufruf, der nicht implementiert ist. Bitte verwenden Sie für die beste Spielerfahrung das offizielle BIOS.</translation> </message> <message> - <location filename="../Window.cpp" line="887"/> + <location filename="../Window.cpp" line="905"/> <source>Really make portable?</source> <translation>Portablen Modus wirklich aktivieren?</translation> </message> <message> - <location filename="../Window.cpp" line="888"/> + <location filename="../Window.cpp" line="906"/> <source>This will make the emulator load its configuration from the same directory as the executable. Do you want to continue?</source> <translation>Diese Einstellung wird den Emulator so konfigurieren, dass er seine Konfiguration aus dem gleichen Verzeichnis wie die Programmdatei lädt. Möchten Sie fortfahren?</translation> </message> <message> - <location filename="../Window.cpp" line="896"/> + <location filename="../Window.cpp" line="914"/> <source>Restart needed</source> <translation>Neustart benötigt</translation> </message> <message> - <location filename="../Window.cpp" line="897"/> + <location filename="../Window.cpp" line="915"/> <source>Some changes will not take effect until the emulator is restarted.</source> <translation>Einige Änderungen werden erst übernommen, wenn der Emulator neu gestartet wurde.</translation> </message> <message> - <location filename="../Window.cpp" line="951"/> + <location filename="../Window.cpp" line="963"/> <source> - Player %1 of %2</source> <translation> - Spieler %1 von %2</translation> </message> <message> - <location filename="../Window.cpp" line="962"/> + <location filename="../Window.cpp" line="974"/> <source>%1 - %2</source> <translation>%1 - %2</translation> </message> <message> - <location filename="../Window.cpp" line="964"/> + <location filename="../Window.cpp" line="976"/> <source>%1 - %2 - %3</source> <translation>%1 - %2 - %3</translation> </message> <message> - <location filename="../Window.cpp" line="966"/> + <location filename="../Window.cpp" line="978"/> <source>%1 - %2 (%3 fps) - %4</source> <translation>%1 - %2 (%3 Bilder/Sekunde) - %4</translation> </message> <message> - <location filename="../Window.cpp" line="1002"/> + <location filename="../Window.cpp" line="1014"/> <source>&amp;File</source> <translation>&amp;Datei</translation> </message> <message> - <location filename="../Window.cpp" line="1005"/> + <location filename="../Window.cpp" line="1017"/> <source>Load &amp;ROM...</source> <translation>&amp;ROM laden...</translation> </message> <message> - <location filename="../Window.cpp" line="1008"/> + <location filename="../Window.cpp" line="1020"/> <source>Load ROM in archive...</source> <translation>ROM aus Archiv laden...</translation> </message> <message> - <location filename="../Window.cpp" line="1014"/> + <location filename="../Window.cpp" line="1026"/> <source>Load alternate save...</source> <translation>Alternative Speicherdatei laden...</translation> </message> <message> - <location filename="../Window.cpp" line="1019"/> + <location filename="../Window.cpp" line="1031"/> <source>Load temporary save...</source> <translation>Temporäre Speicherdatei laden...</translation> </message> <message> - <location filename="../Window.cpp" line="1024"/> + <location filename="../Window.cpp" line="1036"/> <source>Load &amp;patch...</source> <translation>&amp;Patch laden...</translation> </message> <message> - <location filename="../Window.cpp" line="1027"/> + <location filename="../Window.cpp" line="1039"/> <source>Boot BIOS</source> <translation>BIOS booten</translation> </message> <message> - <location filename="../Window.cpp" line="1034"/> + <location filename="../Window.cpp" line="1046"/> <source>Replace ROM...</source> <translation>ROM ersetzen...</translation> </message> <message> - <location filename="../Window.cpp" line="1036"/> + <location filename="../Window.cpp" line="1048"/> <source>ROM &amp;info...</source> <translation>ROM-&amp;Informationen...</translation> </message> <message> - <location filename="../Window.cpp" line="1041"/> + <location filename="../Window.cpp" line="1053"/> <source>Recent</source> <translation>Zuletzt verwendet</translation> </message> <message> - <location filename="../Window.cpp" line="1045"/> + <location filename="../Window.cpp" line="1057"/> <source>Make portable</source> <translation>Portablen Modus aktivieren</translation> </message> <message> - <location filename="../Window.cpp" line="1049"/> + <location filename="../Window.cpp" line="1061"/> <source>&amp;Load state</source> <translation>Savestate (aktueller Zustand) &amp;laden</translation> </message> <message> - <location filename="../Window.cpp" line="1050"/> + <location filename="../Window.cpp" line="1062"/> <source>F10</source> <translation>F10</translation> </message> <message> - <location filename="../Window.cpp" line="1056"/> + <location filename="../Window.cpp" line="1068"/> + <source>Load state file...</source> + <translation>Ssavestate-Datei laden...</translation> + </message> + <message> + <location filename="../Window.cpp" line="1074"/> <source>&amp;Save state</source> <translation>Savestate (aktueller Zustand) &amp;speichern</translation> </message> <message> - <location filename="../Window.cpp" line="1057"/> + <location filename="../Window.cpp" line="1075"/> <source>Shift+F10</source> <translation>Umschalt+F10</translation> </message> <message> - <location filename="../Window.cpp" line="1063"/> + <location filename="../Window.cpp" line="1081"/> + <source>Save state file...</source> + <translation>Savestate-Datei speichern...</translation> + </message> + <message> + <location filename="../Window.cpp" line="1087"/> <source>Quick load</source> <translation>Schnell laden</translation> </message> <message> - <location filename="../Window.cpp" line="1064"/> + <location filename="../Window.cpp" line="1088"/> <source>Quick save</source> <translation>Schnell speichern</translation> </message> <message> - <location filename="../Window.cpp" line="1068"/> + <location filename="../Window.cpp" line="1092"/> <source>Load recent</source> <translation>Lade zuletzt gespeicherten Savestate</translation> </message> <message> - <location filename="../Window.cpp" line="1076"/> + <location filename="../Window.cpp" line="1100"/> <source>Save recent</source> <translation>Speichere aktuellen Zustand</translation> </message> <message> - <location filename="../Window.cpp" line="1087"/> + <location filename="../Window.cpp" line="1111"/> <source>Undo load state</source> <translation>Laden des Savestate rückgängig machen</translation> </message> <message> - <location filename="../Window.cpp" line="1088"/> + <location filename="../Window.cpp" line="1112"/> <source>F11</source> <translation>F11</translation> </message> <message> - <location filename="../Window.cpp" line="1096"/> + <location filename="../Window.cpp" line="1120"/> <source>Undo save state</source> <translation>Speichern des Savestate rückgängig machen</translation> </message> <message> - <location filename="../Window.cpp" line="1097"/> + <location filename="../Window.cpp" line="1121"/> <source>Shift+F11</source> <translation>Umschalt+F11</translation> </message> <message> - <location filename="../Window.cpp" line="1110"/> - <location filename="../Window.cpp" line="1119"/> + <location filename="../Window.cpp" line="1134"/> + <location filename="../Window.cpp" line="1143"/> <source>State &amp;%1</source> <translation>Savestate &amp;%1</translation> </message> <message> - <location filename="../Window.cpp" line="1111"/> + <location filename="../Window.cpp" line="1135"/> <source>F%1</source> <translation>F%1</translation> </message> <message> - <location filename="../Window.cpp" line="1120"/> + <location filename="../Window.cpp" line="1144"/> <source>Shift+F%1</source> <translation>Umschalt+F%1</translation> </message> <message> - <location filename="../Window.cpp" line="1130"/> + <location filename="../Window.cpp" line="1154"/> <source>Load camera image...</source> <translation>Lade Kamerabild...</translation> </message> <message> - <location filename="../Window.cpp" line="1136"/> + <location filename="../Window.cpp" line="1160"/> <source>Import GameShark Save</source> <translation>Importiere GameShark-Speicherstand</translation> </message> <message> - <location filename="../Window.cpp" line="1142"/> + <location filename="../Window.cpp" line="1166"/> <source>Export GameShark Save</source> <translation>Exportiere GameShark-Speicherstand</translation> </message> <message> - <location filename="../Window.cpp" line="1150"/> + <location filename="../Window.cpp" line="1174"/> <source>New multiplayer window</source> <translation>Neues Multiplayer-Fenster</translation> </message> <message> - <location filename="../Window.cpp" line="1160"/> + <location filename="../Window.cpp" line="1184"/> <source>About</source> <translation>Über</translation> </message> <message> - <location filename="../Window.cpp" line="1165"/> + <location filename="../Window.cpp" line="1189"/> <source>E&amp;xit</source> <translation>&amp;Beenden</translation> </message> <message> - <location filename="../Window.cpp" line="1168"/> + <location filename="../Window.cpp" line="1192"/> <source>&amp;Emulation</source> <translation>&amp;Emulation</translation> </message> <message> - <location filename="../Window.cpp" line="1170"/> + <location filename="../Window.cpp" line="1194"/> <source>&amp;Reset</source> <translation>Zu&amp;rücksetzen</translation> </message> <message> - <location filename="../Window.cpp" line="1171"/> + <location filename="../Window.cpp" line="1195"/> <source>Ctrl+R</source> <translation>Strg+R</translation> </message> <message> - <location filename="../Window.cpp" line="1178"/> + <location filename="../Window.cpp" line="1202"/> <source>Sh&amp;utdown</source> <translation>Schli&amp;eßen</translation> </message> <message> - <location filename="../Window.cpp" line="1186"/> + <location filename="../Window.cpp" line="1210"/> <source>Yank game pak</source> <translation>Spielmodul herausziehen</translation> </message> <message> - <location filename="../Window.cpp" line="1196"/> + <location filename="../Window.cpp" line="1220"/> <source>&amp;Pause</source> <translation>&amp;Pause</translation> </message> <message> - <location filename="../Window.cpp" line="1199"/> + <location filename="../Window.cpp" line="1223"/> <source>Ctrl+P</source> <translation>Strg+P</translation> </message> <message> - <location filename="../Window.cpp" line="1212"/> + <location filename="../Window.cpp" line="1236"/> <source>&amp;Next frame</source> <translation>&amp;Nächstes Bild</translation> </message> <message> - <location filename="../Window.cpp" line="1213"/> + <location filename="../Window.cpp" line="1237"/> <source>Ctrl+N</source> <translation>Strg+N</translation> </message> <message> - <location filename="../Window.cpp" line="1230"/> + <location filename="../Window.cpp" line="1254"/> <source>Fast forward (held)</source> <translation>Schneller Vorlauf (gehalten)</translation> </message> <message> - <location filename="../Window.cpp" line="1232"/> + <location filename="../Window.cpp" line="1256"/> <source>&amp;Fast forward</source> <translation>Schneller &amp;Vorlauf</translation> </message> <message> - <location filename="../Window.cpp" line="1235"/> + <location filename="../Window.cpp" line="1259"/> <source>Shift+Tab</source> <translation>Umschalt+Tab</translation> </message> <message> - <location filename="../Window.cpp" line="1242"/> + <location filename="../Window.cpp" line="1266"/> <source>Fast forward speed</source> <translation>Vorlauf-Geschwindigkeit</translation> </message> <message> - <location filename="../Window.cpp" line="1247"/> + <location filename="../Window.cpp" line="1271"/> <source>Unbounded</source> <translation>Unbegrenzt</translation> </message> <message> - <location filename="../Window.cpp" line="1251"/> + <location filename="../Window.cpp" line="1275"/> <source>%0x</source> <translation>%0x</translation> </message> <message> - <location filename="../Window.cpp" line="1263"/> + <location filename="../Window.cpp" line="1287"/> <source>Rewind (held)</source> <translation>Zurückspulen (gehalten)</translation> </message> <message> - <location filename="../Window.cpp" line="1265"/> + <location filename="../Window.cpp" line="1289"/> <source>Re&amp;wind</source> <translation>Zur&amp;ückspulen</translation> </message> <message> - <location filename="../Window.cpp" line="1266"/> + <location filename="../Window.cpp" line="1290"/> <source>~</source> <translation>~</translation> </message> <message> - <location filename="../Window.cpp" line="1274"/> + <location filename="../Window.cpp" line="1298"/> <source>Step backwards</source> <translation>Schrittweiser Rücklauf</translation> </message> <message> - <location filename="../Window.cpp" line="1275"/> + <location filename="../Window.cpp" line="1299"/> <source>Ctrl+B</source> <translation>Strg+B</translation> </message> <message> - <location filename="../Window.cpp" line="1284"/> + <location filename="../Window.cpp" line="1308"/> <source>Sync to &amp;video</source> <translation>Mit &amp;Video synchronisieren</translation> </message> <message> - <location filename="../Window.cpp" line="1291"/> + <location filename="../Window.cpp" line="1315"/> <source>Sync to &amp;audio</source> <translation>Mit &amp;Audio synchronisieren</translation> </message> <message> - <location filename="../Window.cpp" line="1299"/> + <location filename="../Window.cpp" line="1323"/> <source>Solar sensor</source> <translation>Solar-Sensor</translation> </message> <message> - <location filename="../Window.cpp" line="1301"/> + <location filename="../Window.cpp" line="1325"/> <source>Increase solar level</source> <translation>Sonnen-Level erhöhen</translation> </message> <message> - <location filename="../Window.cpp" line="1305"/> + <location filename="../Window.cpp" line="1329"/> <source>Decrease solar level</source> <translation>Sonnen-Level verringern</translation> </message> <message> - <location filename="../Window.cpp" line="1309"/> + <location filename="../Window.cpp" line="1333"/> <source>Brightest solar level</source> <translation>Hellster Sonnen-Level</translation> </message> <message> - <location filename="../Window.cpp" line="1313"/> + <location filename="../Window.cpp" line="1337"/> <source>Darkest solar level</source> <translation>Dunkelster Sonnen-Level</translation> </message> <message> - <location filename="../Window.cpp" line="1319"/> + <location filename="../Window.cpp" line="1343"/> <source>Brightness %1</source> <translation>Helligkeit %1</translation> </message> <message> - <location filename="../Window.cpp" line="1326"/> + <location filename="../Window.cpp" line="1350"/> <source>Audio/&amp;Video</source> <translation>Audio/&amp;Video</translation> </message> <message> - <location filename="../Window.cpp" line="1328"/> + <location filename="../Window.cpp" line="1352"/> <source>Frame size</source> <translation>Bildgröße</translation> </message> <message> - <location filename="../Window.cpp" line="1331"/> + <location filename="../Window.cpp" line="1355"/> <source>%1x</source> <translation>%1x</translation> </message> <message> - <location filename="../Window.cpp" line="1359"/> + <location filename="../Window.cpp" line="1383"/> <source>Toggle fullscreen</source> <translation>Vollbildmodus umschalten</translation> </message> <message> - <location filename="../Window.cpp" line="1362"/> + <location filename="../Window.cpp" line="1386"/> <source>Lock aspect ratio</source> <translation>Seitenverhältnis korrigieren</translation> </message> <message> - <location filename="../Window.cpp" line="1372"/> + <location filename="../Window.cpp" line="1398"/> <source>Force integer scaling</source> <translation>Pixelgenaue Skalierung (Integer scaling)</translation> </message> <message> - <location filename="../Window.cpp" line="1388"/> + <location filename="../Window.cpp" line="1418"/> <source>Frame&amp;skip</source> <translation>Frame&amp;skip</translation> </message> <message> - <location filename="../Window.cpp" line="1401"/> + <location filename="../Window.cpp" line="1431"/> <source>Mute</source> <translation>Stummschalten</translation> </message> <message> - <location filename="../Window.cpp" line="1408"/> + <location filename="../Window.cpp" line="1438"/> <source>FPS target</source> <translation>Bildwiederholrate</translation> </message> <message> - <location filename="../Window.cpp" line="1413"/> - <source>15</source> - <translation>15</translation> - </message> - <message> - <location filename="../Window.cpp" line="1414"/> - <source>30</source> - <translation>30</translation> - </message> - <message> - <location filename="../Window.cpp" line="1415"/> - <source>45</source> - <translation>45</translation> - </message> - <message> - <location filename="../Window.cpp" line="1416"/> - <source>Native (59.7)</source> - <translation>Nativ (59.7)</translation> - </message> - <message> - <location filename="../Window.cpp" line="1417"/> - <source>60</source> - <translation>60</translation> - </message> - <message> - <location filename="../Window.cpp" line="1418"/> - <source>90</source> - <translation>90</translation> - </message> - <message> - <location filename="../Window.cpp" line="1419"/> - <source>120</source> - <translation>120</translation> - </message> - <message> - <location filename="../Window.cpp" line="1420"/> - <source>240</source> - <translation>240</translation> - </message> - <message> - <location filename="../Window.cpp" line="1426"/> + <location filename="../Window.cpp" line="1461"/> <source>Take &amp;screenshot</source> <translation>&amp;Screenshot erstellen</translation> </message> <message> - <location filename="../Window.cpp" line="1427"/> + <location filename="../Window.cpp" line="1462"/> <source>F12</source> <translation>F12</translation> </message> <message> - <location filename="../Window.cpp" line="1436"/> + <location filename="../Window.cpp" line="1471"/> <source>Record output...</source> <translation>Ausgabe aufzeichen...</translation> </message> <message> - <location filename="../Window.cpp" line="1443"/> + <location filename="../Window.cpp" line="1478"/> <source>Record GIF...</source> <translation>GIF aufzeichen...</translation> </message> <message> - <location filename="../Window.cpp" line="1448"/> + <location filename="../Window.cpp" line="1483"/> <source>Record video log...</source> <translation>Video-Log aufzeichnen...</translation> </message> <message> - <location filename="../Window.cpp" line="1453"/> + <location filename="../Window.cpp" line="1488"/> <source>Stop video log</source> <translation>Video-Log beenden</translation> </message> <message> - <location filename="../Window.cpp" line="1461"/> + <location filename="../Window.cpp" line="1496"/> <source>Game Boy Printer...</source> <translation>Game Boy Printer...</translation> </message> <message> - <location filename="../Window.cpp" line="1473"/> + <location filename="../Window.cpp" line="1508"/> <source>Video layers</source> <translation>Video-Ebenen</translation> </message> <message> - <location filename="../Window.cpp" line="1476"/> + <location filename="../Window.cpp" line="1511"/> <source>Audio channels</source> <translation>Audio-Kanäle</translation> </message> <message> - <location filename="../Window.cpp" line="1479"/> + <location filename="../Window.cpp" line="1514"/> <source>Adjust layer placement...</source> <translation>Lage der Bildebenen anpassen...</translation> </message> <message> - <location filename="../Window.cpp" line="1484"/> + <location filename="../Window.cpp" line="1519"/> <source>&amp;Tools</source> <translation>&amp;Werkzeuge</translation> </message> <message> - <location filename="../Window.cpp" line="1486"/> + <location filename="../Window.cpp" line="1521"/> <source>View &amp;logs...</source> <translation>&amp;Logs ansehen...</translation> </message> <message> - <location filename="../Window.cpp" line="1490"/> + <location filename="../Window.cpp" line="1525"/> <source>Game &amp;overrides...</source> <translation>Spiel-&amp;Überschreibungen...</translation> </message> <message> - <location filename="../Window.cpp" line="1504"/> + <location filename="../Window.cpp" line="1539"/> <source>Game &amp;Pak sensors...</source> <translation>Game &amp;Pak-Sensoren...</translation> </message> <message> - <location filename="../Window.cpp" line="1517"/> + <location filename="../Window.cpp" line="1552"/> <source>&amp;Cheats...</source> <translation>&amp;Cheats...</translation> </message> <message> - <location filename="../Window.cpp" line="1529"/> + <location filename="../Window.cpp" line="1564"/> <source>Open debugger console...</source> <translation>Debugger-Konsole öffnen...</translation> </message> <message> - <location filename="../Window.cpp" line="1535"/> + <location filename="../Window.cpp" line="1570"/> <source>Start &amp;GDB server...</source> <translation>&amp;GDB-Server starten...</translation> </message> <message> - <location filename="../Window.cpp" line="1523"/> + <location filename="../Window.cpp" line="1558"/> <source>Settings...</source> <translation>Einstellungen...</translation> </message>

@@ -3876,37 +3822,42 @@ <source>Select folder</source>

<translation>Ordner auswählen</translation> </message> <message> - <location filename="../Window.cpp" line="1010"/> + <location filename="../Window.cpp" line="1022"/> <source>Add folder to library...</source> <translation>Ordner zur Bibliothek hinzufügen...</translation> </message> <message> - <location filename="../Window.cpp" line="1382"/> + <location filename="../Window.cpp" line="1410"/> <source>Bilinear filtering</source> <translation>Bilineare Filterung</translation> </message> <message> - <location filename="../Window.cpp" line="1543"/> + <location filename="../Window.cpp" line="1446"/> + <source>Native (59.7275)</source> + <translation>Nativ (59.7275)</translation> + </message> + <message> + <location filename="../Window.cpp" line="1578"/> <source>View &amp;palette...</source> <translation>&amp;Palette betrachten...</translation> </message> <message> - <location filename="../Window.cpp" line="1548"/> + <location filename="../Window.cpp" line="1583"/> <source>View &amp;sprites...</source> <translation>&amp;Sprites betrachten...</translation> </message> <message> - <location filename="../Window.cpp" line="1553"/> + <location filename="../Window.cpp" line="1588"/> <source>View &amp;tiles...</source> <translation>&amp;Tiles betrachten...</translation> </message> <message> - <location filename="../Window.cpp" line="1558"/> + <location filename="../Window.cpp" line="1593"/> <source>View &amp;map...</source> <translation>&amp;Map betrachten...</translation> </message> <message> - <location filename="../Window.cpp" line="1563"/> + <location filename="../Window.cpp" line="1598"/> <source>View memory...</source> <translation>Speicher betrachten...</translation> </message>

@@ -3921,72 +3872,72 @@ <source>Search memory...</source>

<translation>Speicher durchsuchen...</translation> </message> <message> - <location filename="../Window.cpp" line="1574"/> + <location filename="../Window.cpp" line="1609"/> <source>View &amp;I/O registers...</source> <translation>&amp;I/O-Register betrachten...</translation> </message> <message> - <location filename="../Window.cpp" line="1654"/> + <location filename="../Window.cpp" line="1693"/> <source>Exit fullscreen</source> <translation>Vollbildmodus beenden</translation> </message> <message> - <location filename="../Window.cpp" line="1667"/> + <location filename="../Window.cpp" line="1706"/> <source>GameShark Button (held)</source> <translation>GameShark-Taste (gehalten)</translation> </message> <message> - <location filename="../Window.cpp" line="1669"/> + <location filename="../Window.cpp" line="1708"/> <source>Autofire</source> <translation>Autofeuer</translation> </message> <message> - <location filename="../Window.cpp" line="1676"/> + <location filename="../Window.cpp" line="1715"/> <source>Autofire A</source> <translation>Autofeuer A</translation> </message> <message> - <location filename="../Window.cpp" line="1682"/> + <location filename="../Window.cpp" line="1721"/> <source>Autofire B</source> <translation>Autofeuer B</translation> </message> <message> - <location filename="../Window.cpp" line="1688"/> + <location filename="../Window.cpp" line="1727"/> <source>Autofire L</source> <translation>Autofeuer L</translation> </message> <message> - <location filename="../Window.cpp" line="1694"/> + <location filename="../Window.cpp" line="1733"/> <source>Autofire R</source> <translation>Autofeuer R</translation> </message> <message> - <location filename="../Window.cpp" line="1700"/> + <location filename="../Window.cpp" line="1739"/> <source>Autofire Start</source> <translation>Autofeuer Start</translation> </message> <message> - <location filename="../Window.cpp" line="1706"/> + <location filename="../Window.cpp" line="1745"/> <source>Autofire Select</source> <translation>Autofeuer Select</translation> </message> <message> - <location filename="../Window.cpp" line="1712"/> + <location filename="../Window.cpp" line="1751"/> <source>Autofire Up</source> <translation>Autofeuer nach oben</translation> </message> <message> - <location filename="../Window.cpp" line="1718"/> + <location filename="../Window.cpp" line="1757"/> <source>Autofire Right</source> <translation>Autofeuer rechts</translation> </message> <message> - <location filename="../Window.cpp" line="1724"/> + <location filename="../Window.cpp" line="1763"/> <source>Autofire Down</source> <translation>Autofeuer nach unten</translation> </message> <message> - <location filename="../Window.cpp" line="1730"/> + <location filename="../Window.cpp" line="1769"/> <source>Autofire Left</source> <translation>Autofeuer links</translation> </message>

@@ -4263,233 +4214,233 @@ <translation>Lautstärke:</translation>

</message> <message> <location filename="../SettingsView.ui" line="260"/> + <location filename="../SettingsView.ui" line="300"/> <source>Mute</source> <translation>Stummschalten</translation> </message> <message> - <location filename="../SettingsView.ui" line="276"/> + <location filename="../SettingsView.ui" line="269"/> + <source>Fast forward volume:</source> + <translation>Vorspul-Lautstärke:</translation> + </message> + <message> + <location filename="../SettingsView.ui" line="316"/> <source>Display driver:</source> <translation>Anzeige-Treiber:</translation> </message> <message> - <location filename="../SettingsView.ui" line="293"/> + <location filename="../SettingsView.ui" line="333"/> <source>Frameskip:</source> <translation>Frameskip:</translation> </message> <message> - <location filename="../SettingsView.ui" line="302"/> + <location filename="../SettingsView.ui" line="342"/> <source>Skip every</source> <translation>Überspringe</translation> </message> <message> - <location filename="../SettingsView.ui" line="312"/> - <location filename="../SettingsView.ui" line="645"/> + <location filename="../SettingsView.ui" line="352"/> + <location filename="../SettingsView.ui" line="705"/> <source>frames</source> <translation>Bild(er)</translation> </message> <message> - <location filename="../SettingsView.ui" line="321"/> + <location filename="../SettingsView.ui" line="361"/> <source>FPS target:</source> <translation>Bildwiederholrate:</translation> </message> <message> - <location filename="../SettingsView.ui" line="343"/> + <location filename="../SettingsView.ui" line="386"/> <source>frames per second</source> <translation>Bilder pro Sekunde</translation> </message> <message> - <location filename="../SettingsView.ui" line="359"/> + <location filename="../SettingsView.ui" line="402"/> <source>Sync:</source> <translation>Synchronisierung:</translation> </message> <message> - <location filename="../SettingsView.ui" line="368"/> + <location filename="../SettingsView.ui" line="411"/> <source>Video</source> <translation>Video</translation> </message> <message> - <location filename="../SettingsView.ui" line="375"/> + <location filename="../SettingsView.ui" line="418"/> <source>Audio</source> <translation>Audio</translation> </message> <message> - <location filename="../SettingsView.ui" line="384"/> + <location filename="../SettingsView.ui" line="427"/> <source>Lock aspect ratio</source> <translation>Seitenverhältnis korrigieren</translation> </message> <message> - <location filename="../SettingsView.ui" line="398"/> + <location filename="../SettingsView.ui" line="434"/> <source>Force integer scaling</source> <translation>Erzwinge pixelgenaue Skalierung (Integer scaling)</translation> </message> <message> - <location filename="../SettingsView.ui" line="409"/> + <location filename="../SettingsView.ui" line="452"/> <source>Language</source> <translation>Sprache</translation> </message> <message> - <location filename="../SettingsView.ui" line="417"/> + <location filename="../SettingsView.ui" line="460"/> <source>English</source> <translation>Englisch</translation> </message> <message> - <location filename="../SettingsView.ui" line="440"/> + <location filename="../SettingsView.ui" line="483"/> <source>List view</source> <translation>Listenansicht</translation> </message> <message> - <location filename="../SettingsView.ui" line="445"/> + <location filename="../SettingsView.ui" line="488"/> <source>Tree view</source> <translation>Baumansicht</translation> </message> <message> - <location filename="../SettingsView.ui" line="501"/> + <location filename="../SettingsView.ui" line="544"/> <source>Show FPS in title bar</source> <translation>Bildwiederholrate in der Titelleiste anzeigen</translation> </message> <message> - <location filename="../SettingsView.ui" line="525"/> + <location filename="../SettingsView.ui" line="568"/> <source>Automatically save cheats</source> <translation>Cheats automatisch speichern</translation> </message> <message> - <location filename="../SettingsView.ui" line="535"/> + <location filename="../SettingsView.ui" line="578"/> <source>Automatically load cheats</source> <translation>Cheats automatisch laden</translation> </message> <message> - <location filename="../SettingsView.ui" line="545"/> + <location filename="../SettingsView.ui" line="588"/> <source>Automatically save state</source> <translation>Zustand (Savestate) automatisch speichern</translation> </message> <message> - <location filename="../SettingsView.ui" line="555"/> + <location filename="../SettingsView.ui" line="598"/> <source>Automatically load state</source> <translation>Zustand (Savestate) automatisch laden</translation> </message> <message> - <location filename="../SettingsView.ui" line="1135"/> + <location filename="../SettingsView.ui" line="1168"/> <source>Cheats</source> <translation>Cheats</translation> </message> <message> - <location filename="../SettingsView.ui" line="1180"/> + <location filename="../SettingsView.ui" line="1213"/> <source>Game Boy model</source> <translation>Game Boy-Modell</translation> </message> <message> - <location filename="../SettingsView.ui" line="1188"/> - <location filename="../SettingsView.ui" line="1224"/> - <location filename="../SettingsView.ui" line="1260"/> + <location filename="../SettingsView.ui" line="1221"/> + <location filename="../SettingsView.ui" line="1257"/> + <location filename="../SettingsView.ui" line="1293"/> <source>Autodetect</source> <translation>Automatisch erkennen</translation> </message> <message> - <location filename="../SettingsView.ui" line="1193"/> - <location filename="../SettingsView.ui" line="1229"/> - <location filename="../SettingsView.ui" line="1265"/> + <location filename="../SettingsView.ui" line="1226"/> + <location filename="../SettingsView.ui" line="1262"/> + <location filename="../SettingsView.ui" line="1298"/> <source>Game Boy (DMG)</source> <translation>Game Boy (DMG)</translation> </message> <message> - <location filename="../SettingsView.ui" line="1198"/> - <location filename="../SettingsView.ui" line="1234"/> - <location filename="../SettingsView.ui" line="1270"/> + <location filename="../SettingsView.ui" line="1231"/> + <location filename="../SettingsView.ui" line="1267"/> + <location filename="../SettingsView.ui" line="1303"/> <source>Super Game Boy (SGB)</source> <translation>Super Game Boy (SGB)</translation> </message> <message> - <location filename="../SettingsView.ui" line="1203"/> - <location filename="../SettingsView.ui" line="1239"/> - <location filename="../SettingsView.ui" line="1275"/> + <location filename="../SettingsView.ui" line="1236"/> + <location filename="../SettingsView.ui" line="1272"/> + <location filename="../SettingsView.ui" line="1308"/> <source>Game Boy Color (CGB)</source> <translation>Game Boy Color (CGB)</translation> </message> <message> - <location filename="../SettingsView.ui" line="1208"/> - <location filename="../SettingsView.ui" line="1244"/> - <location filename="../SettingsView.ui" line="1280"/> + <location filename="../SettingsView.ui" line="1241"/> + <location filename="../SettingsView.ui" line="1277"/> + <location filename="../SettingsView.ui" line="1313"/> <source>Game Boy Advance (AGB)</source> <translation>Game Boy Advance (AGB)</translation> </message> <message> - <location filename="../SettingsView.ui" line="1216"/> + <location filename="../SettingsView.ui" line="1249"/> <source>Super Game Boy model</source> <translation>Super Game Boy-Modell</translation> </message> <message> - <location filename="../SettingsView.ui" line="1252"/> + <location filename="../SettingsView.ui" line="1285"/> <source>Game Boy Color model</source> <translation>Game Boy Color-Modell</translation> </message> <message> - <location filename="../SettingsView.ui" line="1295"/> + <location filename="../SettingsView.ui" line="1328"/> <source>Default BG colors:</source> <translation>Standard-Hintergrundfarben:</translation> </message> <message> - <location filename="../SettingsView.ui" line="1573"/> + <location filename="../SettingsView.ui" line="1606"/> <source>Default sprite colors 1:</source> <translation>Standard-Sprite-Farben 1:</translation> </message> <message> - <location filename="../SettingsView.ui" line="1580"/> + <location filename="../SettingsView.ui" line="1613"/> <source>Default sprite colors 2:</source> <translation>Standard-Sprite-Farben 2:</translation> </message> <message> - <location filename="../SettingsView.ui" line="1462"/> + <location filename="../SettingsView.ui" line="1495"/> <source>Super Game Boy borders</source> <translation>Super Game Boy-Rahmen</translation> </message> <message> - <location filename="../SettingsView.ui" line="1476"/> + <location filename="../SettingsView.ui" line="1509"/> <source>Camera driver:</source> <translation>Kamera-Treiber:</translation> </message> <message> - <location filename="../SettingsView.ui" line="432"/> + <location filename="../SettingsView.ui" line="475"/> <source>Library:</source> <translation>Bibliothek:</translation> </message> <message> - <location filename="../SettingsView.ui" line="453"/> + <location filename="../SettingsView.ui" line="496"/> <source>Show when no game open</source> <translation>Anzeigen, wenn kein Spiel geöffnet ist</translation> </message> <message> - <location filename="../SettingsView.ui" line="463"/> + <location filename="../SettingsView.ui" line="506"/> <source>Clear cache</source> <translation>Cache leeren</translation> </message> <message> - <location filename="../SettingsView.ui" line="572"/> + <location filename="../SettingsView.ui" line="615"/> <source>Fast forward speed:</source> <translation>Vorlauf-Geschwindigkeit:</translation> </message> <message> - <location filename="../SettingsView.ui" line="769"/> - <source>Rewind affects save data</source> - <translation>Rücklauf beeinflusst -Speicherdaten</translation> - </message> - <message> - <location filename="../SettingsView.ui" line="779"/> + <location filename="../SettingsView.ui" line="747"/> <source>Preload entire ROM into memory</source> <translation>ROM-Datei vollständig in Arbeitsspeicher vorladen</translation> </message> <message> - <location filename="../SettingsView.ui" line="826"/> - <location filename="../SettingsView.ui" line="864"/> - <location filename="../SettingsView.ui" line="899"/> - <location filename="../SettingsView.ui" line="927"/> - <location filename="../SettingsView.ui" line="968"/> - <location filename="../SettingsView.ui" line="1016"/> - <location filename="../SettingsView.ui" line="1064"/> - <location filename="../SettingsView.ui" line="1112"/> - <location filename="../SettingsView.ui" line="1160"/> + <location filename="../SettingsView.ui" line="859"/> + <location filename="../SettingsView.ui" line="897"/> + <location filename="../SettingsView.ui" line="932"/> + <location filename="../SettingsView.ui" line="960"/> + <location filename="../SettingsView.ui" line="1001"/> + <location filename="../SettingsView.ui" line="1049"/> + <location filename="../SettingsView.ui" line="1097"/> + <location filename="../SettingsView.ui" line="1145"/> + <location filename="../SettingsView.ui" line="1193"/> <source>Browse</source> <translation>Durchsuchen</translation> </message>

@@ -4510,22 +4461,22 @@ <translation>BIOS-Datei verwenden,

wenn vorhanden</translation> </message> <message> - <location filename="../SettingsView.ui" line="845"/> + <location filename="../SettingsView.ui" line="878"/> <source>Skip BIOS intro</source> <translation>BIOS-Intro überspringen</translation> </message> <message> - <location filename="../SettingsView.ui" line="584"/> + <location filename="../SettingsView.ui" line="627"/> <source>×</source> <translation>×</translation> </message> <message> - <location filename="../SettingsView.ui" line="603"/> + <location filename="../SettingsView.ui" line="646"/> <source>Unbounded</source> <translation>unbegrenzt</translation> </message> <message> - <location filename="../SettingsView.ui" line="484"/> + <location filename="../SettingsView.ui" line="527"/> <source>Suspend screensaver</source> <translation>Bildschirmschoner deaktivieren</translation> </message>

@@ -4535,95 +4486,95 @@ <source>BIOS</source>

<translation>BIOS</translation> </message> <message> - <location filename="../SettingsView.ui" line="494"/> + <location filename="../SettingsView.ui" line="537"/> <source>Pause when inactive</source> <translation>Pause, wenn inaktiv</translation> </message> <message> - <location filename="../SettingsView.ui" line="669"/> + <location filename="../SettingsView.ui" line="729"/> <source>Run all</source> <translation>Alle ausführen</translation> </message> <message> - <location filename="../SettingsView.ui" line="674"/> + <location filename="../SettingsView.ui" line="734"/> <source>Remove known</source> <translation>Bekannte entfernen</translation> </message> <message> - <location filename="../SettingsView.ui" line="679"/> + <location filename="../SettingsView.ui" line="739"/> <source>Detect and remove</source> <translation>Erkennen und entfernen</translation> </message> <message> - <location filename="../SettingsView.ui" line="477"/> + <location filename="../SettingsView.ui" line="520"/> <source>Allow opposing input directions</source> <translation>Gegensätzliche Eingaberichtungen erlauben</translation> </message> <message> - <location filename="../SettingsView.ui" line="701"/> - <location filename="../SettingsView.ui" line="738"/> + <location filename="../SettingsView.ui" line="768"/> + <location filename="../SettingsView.ui" line="812"/> <source>Screenshot</source> <translation>Screenshot</translation> </message> <message> - <location filename="../SettingsView.ui" line="711"/> - <location filename="../SettingsView.ui" line="748"/> + <location filename="../SettingsView.ui" line="778"/> + <location filename="../SettingsView.ui" line="822"/> <source>Save data</source> <translation>Speicherdaten</translation> </message> <message> - <location filename="../SettingsView.ui" line="721"/> - <location filename="../SettingsView.ui" line="755"/> + <location filename="../SettingsView.ui" line="788"/> + <location filename="../SettingsView.ui" line="829"/> <source>Cheat codes</source> <translation>Cheat-Codes</translation> </message> <message> - <location filename="../SettingsView.ui" line="622"/> + <location filename="../SettingsView.ui" line="682"/> <source>Enable rewind</source> <translation>Rücklauf aktivieren</translation> </message> <message> - <location filename="../SettingsView.ui" line="391"/> + <location filename="../SettingsView.ui" line="441"/> <source>Bilinear filtering</source> <translation>Bilineare Filterung</translation> </message> <message> - <location filename="../SettingsView.ui" line="629"/> + <location filename="../SettingsView.ui" line="689"/> <source>Rewind history:</source> <translation>Rücklauf-Verlauf:</translation> </message> <message> - <location filename="../SettingsView.ui" line="661"/> + <location filename="../SettingsView.ui" line="721"/> <source>Idle loops:</source> <translation>Leerlaufprozesse:</translation> </message> <message> - <location filename="../SettingsView.ui" line="694"/> + <location filename="../SettingsView.ui" line="761"/> <source>Savestate extra data:</source> <translation>Zusätzliche Savestate-Daten:</translation> </message> <message> - <location filename="../SettingsView.ui" line="731"/> + <location filename="../SettingsView.ui" line="805"/> <source>Load extra data:</source> <translation>Lade zusätzliche Daten:</translation> </message> <message> - <location filename="../SettingsView.ui" line="786"/> + <location filename="../SettingsView.ui" line="658"/> <source>Autofire interval:</source> <translation>Autofeuer-Intervall:</translation> </message> <message> - <location filename="../SettingsView.ui" line="807"/> + <location filename="../SettingsView.ui" line="840"/> <source>GB BIOS file:</source> <translation>Datei mit GB-BIOS:</translation> </message> <message> - <location filename="../SettingsView.ui" line="873"/> + <location filename="../SettingsView.ui" line="906"/> <source>GBA BIOS file:</source> <translation>Datei mit GBA-BIOS:</translation> </message> <message> - <location filename="../SettingsView.ui" line="880"/> + <location filename="../SettingsView.ui" line="913"/> <source>GBC BIOS file:</source> <translation>Datei mit GBC-BIOS:</translation> </message>

@@ -4638,31 +4589,31 @@ <source>SGB BIOS file:</source>

<translation>Datei mit SGB-BIOS:</translation> </message> <message> - <location filename="../SettingsView.ui" line="943"/> + <location filename="../SettingsView.ui" line="976"/> <source>Save games</source> <translation>Spielstände</translation> </message> <message> - <location filename="../SettingsView.ui" line="977"/> - <location filename="../SettingsView.ui" line="1025"/> - <location filename="../SettingsView.ui" line="1073"/> - <location filename="../SettingsView.ui" line="1121"/> - <location filename="../SettingsView.ui" line="1169"/> + <location filename="../SettingsView.ui" line="1010"/> + <location filename="../SettingsView.ui" line="1058"/> + <location filename="../SettingsView.ui" line="1106"/> + <location filename="../SettingsView.ui" line="1154"/> + <location filename="../SettingsView.ui" line="1202"/> <source>Same directory as the ROM</source> <translation>Verzeichnis der ROM-Datei</translation> </message> <message> - <location filename="../SettingsView.ui" line="991"/> + <location filename="../SettingsView.ui" line="1024"/> <source>Save states</source> <translation>Savestates</translation> </message> <message> - <location filename="../SettingsView.ui" line="1039"/> + <location filename="../SettingsView.ui" line="1072"/> <source>Screenshots</source> <translation>Screenshots</translation> </message> <message> - <location filename="../SettingsView.ui" line="1087"/> + <location filename="../SettingsView.ui" line="1120"/> <source>Patches</source> <translation>Patches</translation> </message>

@@ -4779,47 +4730,12 @@ <source>Presets</source>

<translation>Vorgaben</translation> </message> <message> - <location filename="../VideoView.ui" line="109"/> - <source>High Quality</source> - <translation>Hohe Qualität</translation> - </message> - <message> - <location filename="../VideoView.ui" line="119"/> - <source>YouTube</source> - <translation>YouTube</translation> - </message> - <message> <location filename="../VideoView.ui" line="129"/> <location filename="../VideoView.ui" line="237"/> <source>WebM</source> <translation>WebM</translation> </message> <message> - <location filename="../VideoView.ui" line="139"/> - <source>Lossless</source> - <translation>Verlustfrei</translation> - </message> - <message> - <location filename="../VideoView.ui" line="156"/> - <source>1080p</source> - <translation>1080p</translation> - </message> - <message> - <location filename="../VideoView.ui" line="166"/> - <source>720p</source> - <translation>720p</translation> - </message> - <message> - <location filename="../VideoView.ui" line="176"/> - <source>480p</source> - <translation>480p</translation> - </message> - <message> - <location filename="../VideoView.ui" line="189"/> - <source>Native</source> - <translation>Nativ</translation> - </message> - <message> <location filename="../VideoView.ui" line="222"/> <source>Format</source> <translation>Format</translation>

@@ -4840,8 +4756,39 @@ <source>MP4</source>

<translation>MP4</translation> </message> <message> - <source>PNG</source> - <translation type="vanished">PNG</translation> + <location filename="../VideoView.ui" line="109"/> + <source>High &amp;Quality</source> + <translation>Hohe &amp;Qualität</translation> + </message> + <message> + <location filename="../VideoView.ui" line="119"/> + <source>&amp;YouTube</source> + <translation>&amp;YouTube</translation> + </message> + <message> + <location filename="../VideoView.ui" line="139"/> + <source>&amp;Lossless</source> + <translation>Ver&amp;lustfrei</translation> + </message> + <message> + <location filename="../VideoView.ui" line="156"/> + <source>&amp;1080p</source> + <translation>&amp;1080p</translation> + </message> + <message> + <location filename="../VideoView.ui" line="166"/> + <source>&amp;720p</source> + <translation>&amp;720p</translation> + </message> + <message> + <location filename="../VideoView.ui" line="176"/> + <source>&amp;480p</source> + <translation>&amp;480p</translation> + </message> + <message> + <location filename="../VideoView.ui" line="189"/> + <source>&amp;Native</source> + <translation>&amp;Nativ</translation> </message> <message> <location filename="../VideoView.ui" line="259"/>

@@ -4865,76 +4812,81 @@ <translation>VP8</translation>

</message> <message> <location filename="../VideoView.ui" line="279"/> + <source>VP9</source> + <translation>VP9</translation> + </message> + <message> + <location filename="../VideoView.ui" line="284"/> <source>FFV1</source> <translation>FFV1</translation> </message> <message> - <location filename="../VideoView.ui" line="291"/> + <location filename="../VideoView.ui" line="296"/> <source>FLAC</source> <translation>FLAC</translation> </message> <message> - <location filename="../VideoView.ui" line="296"/> + <location filename="../VideoView.ui" line="301"/> <source>Opus</source> <translation>Opus</translation> </message> <message> - <location filename="../VideoView.ui" line="301"/> + <location filename="../VideoView.ui" line="306"/> <source>Vorbis</source> <translation>Vorbis</translation> </message> <message> - <location filename="../VideoView.ui" line="306"/> + <location filename="../VideoView.ui" line="311"/> <source>MP3</source> <translation>MP3</translation> </message> <message> - <location filename="../VideoView.ui" line="311"/> + <location filename="../VideoView.ui" line="316"/> <source>AAC</source> <translation>AAC</translation> </message> <message> - <location filename="../VideoView.ui" line="316"/> + <location filename="../VideoView.ui" line="321"/> <source>Uncompressed</source> <translation>Unkomprimiert</translation> </message> <message> - <location filename="../VideoView.ui" line="327"/> + <location filename="../VideoView.ui" line="332"/> <source> Bitrate (kbps)</source> <translation> Bitrate (kbps)</translation> </message> <message> - <location filename="../VideoView.ui" line="333"/> + <location filename="../VideoView.ui" line="338"/> <source>VBR </source> <translation>VBR </translation> </message> <message> - <location filename="../VideoView.ui" line="378"/> + <location filename="../VideoView.ui" line="383"/> <source>ABR</source> <translation>ABR</translation> </message> <message> - <location filename="../VideoView.ui" line="394"/> + <location filename="../VideoView.ui" line="399"/> <source>Dimensions</source> <translation>Abmessungen</translation> </message> <message> - <location filename="../VideoView.ui" line="400"/> + <location filename="../VideoView.ui" line="405"/> <source>:</source> <translation>:</translation> </message> <message> - <location filename="../VideoView.ui" line="410"/> + <location filename="../VideoView.ui" line="415"/> <source>×</source> <translation>×</translation> </message> <message> - <location filename="../VideoView.ui" line="460"/> + <location filename="../VideoView.ui" line="465"/> <source>Lock aspect ratio</source> <translation>Seitenverhältnis sperren</translation> </message> <message> - <location filename="../VideoView.ui" line="475"/> + <location filename="../VideoView.ui" line="480"/> <source>Show advanced</source> <translation>Erweiterte Optionen anzeigen</translation> </message>
M src/platform/qt/ts/medusa-emu-es.tssrc/platform/qt/ts/medusa-emu-es.ts

@@ -168,7 +168,7 @@ </message>

<message> <location filename="../DebuggerConsole.ui" line="25"/> <source>Enter command (try `help` for more info)</source> - <translation>Ingresa un comando (intenta `help` para más información)</translation> + <translation>Ingresa un comando (prueba con `help` para más información)</translation> </message> <message> <location filename="../DebuggerConsole.ui" line="32"/>

@@ -1249,22 +1249,22 @@ </context>

<context> <name>QGBA::CoreController</name> <message> - <location filename="../CoreController.cpp" line="561"/> + <location filename="../CoreController.cpp" line="557"/> <source>Failed to open save file: %1</source> <translation>Error al abrir el archivo de guardado: %1</translation> </message> <message> - <location filename="../CoreController.cpp" line="590"/> + <location filename="../CoreController.cpp" line="586"/> <source>Failed to open game file: %1</source> <translation>Error al abrir el archivo del juego: %1</translation> </message> <message> - <location filename="../CoreController.cpp" line="655"/> + <location filename="../CoreController.cpp" line="651"/> <source>Failed to open snapshot file for reading: %1</source> <translation>Error al leer del archivo de captura: %1</translation> </message> <message> - <location filename="../CoreController.cpp" line="671"/> + <location filename="../CoreController.cpp" line="667"/> <source>Failed to open snapshot file for writing: %1</source> <translation>Error al escribir al archivo de captura: %1</translation> </message>

@@ -2764,27 +2764,27 @@ </context>

<context> <name>QGBA::LoadSaveState</name> <message> - <location filename="../LoadSaveState.cpp" line="71"/> + <location filename="../LoadSaveState.cpp" line="73"/> <source>Load State</source> <translation>Cargar estado</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="71"/> + <location filename="../LoadSaveState.cpp" line="73"/> <source>Save State</source> <translation>Guardar estado</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="180"/> + <location filename="../LoadSaveState.cpp" line="182"/> <source>Empty</source> <translation>Vacío</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="189"/> + <location filename="../LoadSaveState.cpp" line="191"/> <source>Corrupted</source> <translation>Dañado</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="218"/> + <location filename="../LoadSaveState.cpp" line="220"/> <source>Slot %1</source> <translation>Espacio %1</translation> </message>

@@ -2832,7 +2832,7 @@ <name>QGBA::MapView</name>

<message> <location filename="../MapView.cpp" line="84"/> <source>Map Addr.</source> - <translation>Dirección de mapa</translation> + <translation>Dir de mapa</translation> </message> <message> <location filename="../MapView.cpp" line="85"/>

@@ -2899,7 +2899,6 @@ <translation>Cargar</translation>

</message> <message> <location filename="../MemoryModel.cpp" line="91"/> - <location filename="../MemoryModel.cpp" line="156"/> <source>All</source> <translation>Todo</translation> </message>

@@ -2909,32 +2908,32 @@ <source>Load TBL</source>

<translation>Cargar TBL</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="196"/> + <location filename="../MemoryModel.cpp" line="190"/> <source>Save selected memory</source> <translation>Guardar memoria seleccionada</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="202"/> + <location filename="../MemoryModel.cpp" line="196"/> <source>Failed to open output file: %1</source> <translation>Error al abrir el archivo de salida: %1</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="210"/> + <location filename="../MemoryModel.cpp" line="204"/> <source>Load memory</source> <translation>Cargar memoria</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="216"/> + <location filename="../MemoryModel.cpp" line="210"/> <source>Failed to open input file: %1</source> <translation>Error al abrir el archivo de entrada: %1</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="332"/> + <location filename="../MemoryModel.cpp" line="326"/> <source>TBL</source> <translation>TBL</translation> </message> <message> - <location filename="../MemoryModel.cpp" line="332"/> + <location filename="../MemoryModel.cpp" line="326"/> <source>ISO-8859-1</source> <translation>ISO-8859-1</translation> </message>

@@ -3108,59 +3107,59 @@ </context>

<context> <name>QGBA::SettingsView</name> <message> - <location filename="../SettingsView.cpp" line="130"/> - <location filename="../SettingsView.cpp" line="172"/> + <location filename="../SettingsView.cpp" line="142"/> + <location filename="../SettingsView.cpp" line="184"/> <source>Qt Multimedia</source> <translation>Qt Multimedia</translation> </message> <message> - <location filename="../SettingsView.cpp" line="137"/> + <location filename="../SettingsView.cpp" line="149"/> <source>SDL</source> <translation>SDL</translation> </message> <message> - <location filename="../SettingsView.cpp" line="145"/> + <location filename="../SettingsView.cpp" line="157"/> <source>Software (Qt)</source> <translation>Software (Qt)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="151"/> + <location filename="../SettingsView.cpp" line="163"/> <source>OpenGL</source> <translation>OpenGL</translation> </message> <message> - <location filename="../SettingsView.cpp" line="158"/> + <location filename="../SettingsView.cpp" line="170"/> <source>OpenGL (force version 1.x)</source> <translation>OpenGL (forzar versión 1.x)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="166"/> + <location filename="../SettingsView.cpp" line="178"/> <source>None (Still Image)</source> <translation>Nada (imagen estática)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="247"/> + <location filename="../SettingsView.cpp" line="259"/> <source>Keyboard</source> <translation>Teclado</translation> </message> <message> - <location filename="../SettingsView.cpp" line="256"/> + <location filename="../SettingsView.cpp" line="268"/> <source>Controllers</source> <translation>Controladores</translation> </message> <message> - <location filename="../SettingsView.cpp" line="288"/> + <location filename="../SettingsView.cpp" line="300"/> <source>Shortcuts</source> <translation>Atajos de teclado</translation> </message> <message> - <location filename="../SettingsView.cpp" line="300"/> - <location filename="../SettingsView.cpp" line="310"/> + <location filename="../SettingsView.cpp" line="312"/> + <location filename="../SettingsView.cpp" line="322"/> <source>Shaders</source> <translation>Shaders</translation> </message> <message> - <location filename="../SettingsView.cpp" line="317"/> + <location filename="../SettingsView.cpp" line="329"/> <source>Select BIOS</source> <translation>Seleccionar BIOS</translation> </message>

@@ -3219,17 +3218,17 @@ </context>

<context> <name>QGBA::VideoView</name> <message> - <location filename="../VideoView.cpp" line="211"/> + <location filename="../VideoView.cpp" line="212"/> <source>Failed to open output video file: %1</source> <translation>Error al abrir el archivo de video de salida: %1</translation> </message> <message> - <location filename="../VideoView.cpp" line="229"/> + <location filename="../VideoView.cpp" line="230"/> <source>Native (%0x%1)</source> <translation>Native (%0x%1)</translation> </message> <message> - <location filename="../VideoView.cpp" line="244"/> + <location filename="../VideoView.cpp" line="245"/> <source>Select output file</source> <translation>Seleccionar archivo de salida</translation> </message>

@@ -3280,54 +3279,65 @@ <translation>Archivos de guardado de Game Boy Advance (%1)</translation>

</message> <message> <location filename="../Window.cpp" line="360"/> - <location filename="../Window.cpp" line="405"/> - <location filename="../Window.cpp" line="412"/> + <location filename="../Window.cpp" line="421"/> + <location filename="../Window.cpp" line="428"/> <source>Select save</source> <translation>Seleccionar guardado</translation> </message> <message> - <location filename="../Window.cpp" line="381"/> + <location filename="../Window.cpp" line="368"/> + <source>mGBA savestate files (%1)</source> + <translation>Archivos de estado de guardado de mGBA (%1)</translation> + </message> + <message> + <location filename="../Window.cpp" line="370"/> + <location filename="../Window.cpp" line="375"/> + <source>Select savestate</source> + <translation>Elegir estado de guardado</translation> + </message> + <message> + <location filename="../Window.cpp" line="397"/> <source>Select patch</source> <translation>Seleccionar parche</translation> </message> <message> - <location filename="../Window.cpp" line="381"/> + <location filename="../Window.cpp" line="397"/> <source>Patches (*.ips *.ups *.bps)</source> <translation>Parches (*.ips *.ups *.bps)</translation> </message> <message> - <location filename="../Window.cpp" line="398"/> + <location filename="../Window.cpp" line="414"/> <source>Select image</source> <translation>Seleccionar imagen</translation> </message> <message> - <location filename="../Window.cpp" line="398"/> + <location filename="../Window.cpp" line="414"/> <source>Image file (*.png *.gif *.jpg *.jpeg);;All files (*)</source> <translation>Archivo de imagen (*.png *.gif *.jpg *.jpeg);;Todos los archivos (*)</translation> </message> <message> - <location filename="../Window.cpp" line="405"/> - <location filename="../Window.cpp" line="412"/> + <location filename="../Window.cpp" line="421"/> + <location filename="../Window.cpp" line="428"/> <source>GameShark saves (*.sps *.xps)</source> <translation>Guardados de GameShark (*.sps *.xps)</translation> </message> <message> - <location filename="../Window.cpp" line="437"/> + <location filename="../Window.cpp" line="453"/> <source>Select video log</source> <translation>Seleccionar video-registro</translation> </message> <message> - <location filename="../Window.cpp" line="437"/> + <location filename="../Window.cpp" line="453"/> <source>Video logs (*.mvl)</source> <translation>Video-registros (*.mvl)</translation> </message> <message> - <location filename="../Window.cpp" line="782"/> + <location filename="../Window.cpp" line="799"/> <source>Crash</source> <translation>Error fatal</translation> </message> <message> - <location filename="../Window.cpp" line="783"/> + <location filename="../Window.cpp" line="800"/> <source>The game has crashed with the following error: %1</source>

@@ -3336,648 +3346,655 @@

%1</translation> </message> <message> - <location filename="../Window.cpp" line="791"/> + <location filename="../Window.cpp" line="808"/> <source>Couldn&apos;t Load</source> <translation>No se pudo cargar</translation> </message> <message> - <location filename="../Window.cpp" line="792"/> + <location filename="../Window.cpp" line="809"/> <source>Could not load game. Are you sure it&apos;s in the correct format?</source> <translation>No se pudo cargar el juego. ¿Estás seguro de que está en el formato correcto?</translation> </message> <message> - <location filename="../Window.cpp" line="805"/> + <location filename="../Window.cpp" line="822"/> <source>Unimplemented BIOS call</source> <translation>Llamada a BIOS no implementada</translation> </message> <message> - <location filename="../Window.cpp" line="806"/> + <location filename="../Window.cpp" line="823"/> <source>This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience.</source> <translation>Este juego utiliza una llamada al BIOS que no se ha implementado. Utiliza el BIOS oficial para obtener la mejor experiencia.</translation> </message> <message> - <location filename="../Window.cpp" line="887"/> + <location filename="../Window.cpp" line="905"/> <source>Really make portable?</source> <translation>¿Hacer &quot;portable&quot;?</translation> </message> <message> - <location filename="../Window.cpp" line="888"/> + <location filename="../Window.cpp" line="906"/> <source>This will make the emulator load its configuration from the same directory as the executable. Do you want to continue?</source> <translation>Esto hará que el emulador cargue su configuración desde el mismo directorio que el ejecutable. ¿Quieres continuar?</translation> </message> <message> - <location filename="../Window.cpp" line="896"/> + <location filename="../Window.cpp" line="914"/> <source>Restart needed</source> <translation>Reinicio necesario</translation> </message> <message> - <location filename="../Window.cpp" line="897"/> + <location filename="../Window.cpp" line="915"/> <source>Some changes will not take effect until the emulator is restarted.</source> <translation>Algunos cambios no surtirán efecto hasta que se reinicie el emulador.</translation> </message> <message> - <location filename="../Window.cpp" line="951"/> + <location filename="../Window.cpp" line="963"/> <source> - Player %1 of %2</source> <translation> - Jugador %1 de %2</translation> </message> <message> - <location filename="../Window.cpp" line="962"/> + <location filename="../Window.cpp" line="974"/> <source>%1 - %2</source> <translation>%1 - %2</translation> </message> <message> - <location filename="../Window.cpp" line="964"/> + <location filename="../Window.cpp" line="976"/> <source>%1 - %2 - %3</source> <translation>%1 - %2 - %3</translation> </message> <message> - <location filename="../Window.cpp" line="966"/> + <location filename="../Window.cpp" line="978"/> <source>%1 - %2 (%3 fps) - %4</source> <translation>%1 - %2 (%3 fps) - %4</translation> </message> <message> - <location filename="../Window.cpp" line="1002"/> + <location filename="../Window.cpp" line="1014"/> <source>&amp;File</source> <translation>&amp;Archivo</translation> </message> <message> - <location filename="../Window.cpp" line="1005"/> + <location filename="../Window.cpp" line="1017"/> <source>Load &amp;ROM...</source> <translation>Cargar &amp;ROM...</translation> </message> <message> - <location filename="../Window.cpp" line="1008"/> + <location filename="../Window.cpp" line="1020"/> <source>Load ROM in archive...</source> <translation>Cargar ROM desde contenedor...</translation> </message> <message> - <location filename="../Window.cpp" line="1010"/> + <location filename="../Window.cpp" line="1022"/> <source>Add folder to library...</source> <translation>Agregar carpeta a la biblioteca...</translation> </message> <message> - <location filename="../Window.cpp" line="1014"/> + <location filename="../Window.cpp" line="1026"/> <source>Load alternate save...</source> <translation>Cargar guardado alternativo...</translation> </message> <message> - <location filename="../Window.cpp" line="1019"/> + <location filename="../Window.cpp" line="1031"/> <source>Load temporary save...</source> <translation>Cargar guardado temporal...</translation> </message> <message> - <location filename="../Window.cpp" line="1024"/> + <location filename="../Window.cpp" line="1036"/> <source>Load &amp;patch...</source> <translation>Cargar &amp;parche...</translation> </message> <message> - <location filename="../Window.cpp" line="1027"/> + <location filename="../Window.cpp" line="1039"/> <source>Boot BIOS</source> <translation>Arrancar BIOS</translation> </message> <message> - <location filename="../Window.cpp" line="1034"/> + <location filename="../Window.cpp" line="1046"/> <source>Replace ROM...</source> <translation>Reemplazar ROM...</translation> </message> <message> - <location filename="../Window.cpp" line="1036"/> + <location filename="../Window.cpp" line="1048"/> <source>ROM &amp;info...</source> <translation>&amp;Información de la ROM...</translation> </message> <message> - <location filename="../Window.cpp" line="1041"/> + <location filename="../Window.cpp" line="1053"/> <source>Recent</source> <translation>Recientes</translation> </message> <message> - <location filename="../Window.cpp" line="1045"/> + <location filename="../Window.cpp" line="1057"/> <source>Make portable</source> <translation>Hacer &quot;portable&quot;</translation> </message> <message> - <location filename="../Window.cpp" line="1049"/> + <location filename="../Window.cpp" line="1061"/> <source>&amp;Load state</source> <translation>Ca&amp;rgar estado</translation> </message> <message> - <location filename="../Window.cpp" line="1050"/> + <location filename="../Window.cpp" line="1062"/> <source>F10</source> <translation>F10</translation> </message> <message> - <location filename="../Window.cpp" line="1056"/> + <location filename="../Window.cpp" line="1068"/> + <source>Load state file...</source> + <translation>Cargar archivo de estado...</translation> + </message> + <message> + <location filename="../Window.cpp" line="1074"/> <source>&amp;Save state</source> <translation>Guardar e&amp;stado</translation> </message> <message> - <location filename="../Window.cpp" line="1057"/> + <location filename="../Window.cpp" line="1075"/> <source>Shift+F10</source> <translation>Shift+F10</translation> </message> <message> - <location filename="../Window.cpp" line="1063"/> + <location filename="../Window.cpp" line="1081"/> + <source>Save state file...</source> + <translation>Guardar archivo de estado...</translation> + </message> + <message> + <location filename="../Window.cpp" line="1087"/> <source>Quick load</source> <translation>Cargado rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1064"/> + <location filename="../Window.cpp" line="1088"/> <source>Quick save</source> <translation>Guardado rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1068"/> + <location filename="../Window.cpp" line="1092"/> <source>Load recent</source> <translation>Cargar reciente</translation> </message> <message> - <location filename="../Window.cpp" line="1076"/> + <location filename="../Window.cpp" line="1100"/> <source>Save recent</source> <translation>Guardar reciente</translation> </message> <message> - <location filename="../Window.cpp" line="1087"/> + <location filename="../Window.cpp" line="1111"/> <source>Undo load state</source> <translation>Deshacer cargar estado</translation> </message> <message> - <location filename="../Window.cpp" line="1088"/> + <location filename="../Window.cpp" line="1112"/> <source>F11</source> <translation>F11</translation> </message> <message> - <location filename="../Window.cpp" line="1096"/> + <location filename="../Window.cpp" line="1120"/> <source>Undo save state</source> <translation>Deshacer guardar estado</translation> </message> <message> - <location filename="../Window.cpp" line="1097"/> + <location filename="../Window.cpp" line="1121"/> <source>Shift+F11</source> <translation>Shift+F11</translation> </message> <message> - <location filename="../Window.cpp" line="1110"/> - <location filename="../Window.cpp" line="1119"/> + <location filename="../Window.cpp" line="1134"/> + <location filename="../Window.cpp" line="1143"/> <source>State &amp;%1</source> <translation>Estado &amp;%1</translation> </message> <message> - <location filename="../Window.cpp" line="1111"/> + <location filename="../Window.cpp" line="1135"/> <source>F%1</source> <translation>F%1</translation> </message> <message> - <location filename="../Window.cpp" line="1120"/> + <location filename="../Window.cpp" line="1144"/> <source>Shift+F%1</source> <translation>Shift+F%1</translation> </message> <message> - <location filename="../Window.cpp" line="1130"/> + <location filename="../Window.cpp" line="1154"/> <source>Load camera image...</source> <translation>Cargar imagen para la cámara...</translation> </message> <message> - <location filename="../Window.cpp" line="1136"/> + <location filename="../Window.cpp" line="1160"/> <source>Import GameShark Save</source> <translation>Importar guardado de GameShark</translation> </message> <message> - <location filename="../Window.cpp" line="1142"/> + <location filename="../Window.cpp" line="1166"/> <source>Export GameShark Save</source> <translation>Exportar guardado de GameShark</translation> </message> <message> - <location filename="../Window.cpp" line="1150"/> + <location filename="../Window.cpp" line="1174"/> <source>New multiplayer window</source> <translation>Nueva ventana multijugador</translation> </message> <message> - <location filename="../Window.cpp" line="1160"/> + <location filename="../Window.cpp" line="1184"/> <source>About</source> <translation>Acerca de</translation> </message> <message> - <location filename="../Window.cpp" line="1165"/> + <location filename="../Window.cpp" line="1189"/> <source>E&amp;xit</source> <translation>Salir (&amp;X)</translation> </message> <message> - <location filename="../Window.cpp" line="1168"/> + <location filename="../Window.cpp" line="1192"/> <source>&amp;Emulation</source> <translation>&amp;Emulación</translation> </message> <message> - <location filename="../Window.cpp" line="1170"/> + <location filename="../Window.cpp" line="1194"/> <source>&amp;Reset</source> <translation>&amp;Reinicializar</translation> </message> <message> - <location filename="../Window.cpp" line="1171"/> + <location filename="../Window.cpp" line="1195"/> <source>Ctrl+R</source> <translation>Ctrl+R</translation> </message> <message> - <location filename="../Window.cpp" line="1178"/> + <location filename="../Window.cpp" line="1202"/> <source>Sh&amp;utdown</source> <translation>Apagar (&amp;U)</translation> </message> <message> - <location filename="../Window.cpp" line="1186"/> + <location filename="../Window.cpp" line="1210"/> <source>Yank game pak</source> <translation>Tirar del cartucho</translation> </message> <message> - <location filename="../Window.cpp" line="1196"/> + <location filename="../Window.cpp" line="1220"/> <source>&amp;Pause</source> <translation>&amp;Pausar</translation> </message> <message> - <location filename="../Window.cpp" line="1199"/> + <location filename="../Window.cpp" line="1223"/> <source>Ctrl+P</source> <translation>Ctrl+P</translation> </message> <message> - <location filename="../Window.cpp" line="1212"/> + <location filename="../Window.cpp" line="1236"/> <source>&amp;Next frame</source> <translation>Cuadro siguie&amp;nte</translation> </message> <message> - <location filename="../Window.cpp" line="1213"/> + <location filename="../Window.cpp" line="1237"/> <source>Ctrl+N</source> <translation>Ctrl+N</translation> </message> <message> - <location filename="../Window.cpp" line="1230"/> + <location filename="../Window.cpp" line="1254"/> <source>Fast forward (held)</source> <translation>Avance rápido (mantener)</translation> </message> <message> - <location filename="../Window.cpp" line="1232"/> + <location filename="../Window.cpp" line="1256"/> <source>&amp;Fast forward</source> <translation>&amp;Avance rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1235"/> + <location filename="../Window.cpp" line="1259"/> <source>Shift+Tab</source> <translation>Shift+Tab</translation> </message> <message> - <location filename="../Window.cpp" line="1242"/> + <location filename="../Window.cpp" line="1266"/> <source>Fast forward speed</source> <translation>Velocidad de avance rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1247"/> + <location filename="../Window.cpp" line="1271"/> <source>Unbounded</source> <translation>Sin límite</translation> </message> <message> - <location filename="../Window.cpp" line="1251"/> + <location filename="../Window.cpp" line="1275"/> <source>%0x</source> <translation>%0x</translation> </message> <message> - <location filename="../Window.cpp" line="1263"/> + <location filename="../Window.cpp" line="1287"/> <source>Rewind (held)</source> <translation>Rebobinar (mantener)</translation> </message> <message> - <location filename="../Window.cpp" line="1265"/> + <location filename="../Window.cpp" line="1289"/> <source>Re&amp;wind</source> <translation>Re&amp;bobinar</translation> </message> <message> - <location filename="../Window.cpp" line="1266"/> + <location filename="../Window.cpp" line="1290"/> <source>~</source> <translation>~</translation> </message> <message> - <location filename="../Window.cpp" line="1274"/> + <location filename="../Window.cpp" line="1298"/> <source>Step backwards</source> <translation>Paso hacia atrás</translation> </message> <message> - <location filename="../Window.cpp" line="1275"/> + <location filename="../Window.cpp" line="1299"/> <source>Ctrl+B</source> <translation>Ctrl+B</translation> </message> <message> - <location filename="../Window.cpp" line="1284"/> + <location filename="../Window.cpp" line="1308"/> <source>Sync to &amp;video</source> <translation>Sincronizar a &amp;video</translation> </message> <message> - <location filename="../Window.cpp" line="1291"/> + <location filename="../Window.cpp" line="1315"/> <source>Sync to &amp;audio</source> <translation>Sincronizar a au&amp;dio</translation> </message> <message> - <location filename="../Window.cpp" line="1299"/> + <location filename="../Window.cpp" line="1323"/> <source>Solar sensor</source> <translation>Sensor solar</translation> </message> <message> - <location filename="../Window.cpp" line="1301"/> + <location filename="../Window.cpp" line="1325"/> <source>Increase solar level</source> <translation>Subir nivel</translation> </message> <message> - <location filename="../Window.cpp" line="1305"/> + <location filename="../Window.cpp" line="1329"/> <source>Decrease solar level</source> <translation>Bajar nivel</translation> </message> <message> - <location filename="../Window.cpp" line="1309"/> + <location filename="../Window.cpp" line="1333"/> <source>Brightest solar level</source> <translation>Más claro</translation> </message> <message> - <location filename="../Window.cpp" line="1313"/> + <location filename="../Window.cpp" line="1337"/> <source>Darkest solar level</source> <translation>Más oscuro</translation> </message> <message> - <location filename="../Window.cpp" line="1319"/> + <location filename="../Window.cpp" line="1343"/> <source>Brightness %1</source> <translation>Brillo %1</translation> </message> <message> - <location filename="../Window.cpp" line="1326"/> + <location filename="../Window.cpp" line="1350"/> <source>Audio/&amp;Video</source> <translation>Audio/&amp;video</translation> </message> <message> - <location filename="../Window.cpp" line="1328"/> + <location filename="../Window.cpp" line="1352"/> <source>Frame size</source> <translation>Tamaño del cuadro</translation> </message> <message> - <location filename="../Window.cpp" line="1331"/> + <location filename="../Window.cpp" line="1355"/> <source>%1x</source> <translation>%1x</translation> </message> <message> - <location filename="../Window.cpp" line="1359"/> + <location filename="../Window.cpp" line="1383"/> <source>Toggle fullscreen</source> <translation>Pantalla completa</translation> </message> <message> - <location filename="../Window.cpp" line="1362"/> + <location filename="../Window.cpp" line="1386"/> <source>Lock aspect ratio</source> <translation>Bloquear proporción de aspecto</translation> </message> <message> - <location filename="../Window.cpp" line="1372"/> + <location filename="../Window.cpp" line="1398"/> <source>Force integer scaling</source> <translation>Forzar escala a enteros</translation> </message> <message> - <location filename="../Window.cpp" line="1382"/> + <location filename="../Window.cpp" line="1410"/> <source>Bilinear filtering</source> <translation>Filtro bilineal</translation> </message> <message> - <location filename="../Window.cpp" line="1388"/> + <location filename="../Window.cpp" line="1418"/> <source>Frame&amp;skip</source> <translation>&amp;Salto de cuadros</translation> </message> <message> - <location filename="../Window.cpp" line="1401"/> + <location filename="../Window.cpp" line="1431"/> <source>Mute</source> <translation>Silenciar</translation> </message> <message> - <location filename="../Window.cpp" line="1408"/> + <location filename="../Window.cpp" line="1438"/> <source>FPS target</source> <translation>Objetivo de FPS</translation> </message> <message> - <location filename="../Window.cpp" line="1413"/> + <location filename="../Window.cpp" line="1446"/> + <source>Native (59.7275)</source> + <translation>Nativo (59,7275)</translation> + </message> + <message> <source>15</source> - <translation>15</translation> + <translation type="vanished">15</translation> </message> <message> - <location filename="../Window.cpp" line="1414"/> <source>30</source> - <translation>30</translation> + <translation type="vanished">30</translation> </message> <message> - <location filename="../Window.cpp" line="1415"/> <source>45</source> - <translation>45</translation> + <translation type="vanished">45</translation> </message> <message> - <location filename="../Window.cpp" line="1416"/> <source>Native (59.7)</source> - <translation>Nativo (59.7)</translation> + <translation type="vanished">Nativo (59.7)</translation> </message> <message> - <location filename="../Window.cpp" line="1417"/> <source>60</source> - <translation>60</translation> + <translation type="vanished">60</translation> </message> <message> - <location filename="../Window.cpp" line="1418"/> <source>90</source> - <translation>90</translation> + <translation type="vanished">90</translation> </message> <message> - <location filename="../Window.cpp" line="1419"/> <source>120</source> - <translation>Bilineal120</translation> + <translation type="vanished">Bilineal120</translation> </message> <message> - <location filename="../Window.cpp" line="1420"/> <source>240</source> - <translation>240</translation> + <translation type="vanished">240</translation> </message> <message> - <location filename="../Window.cpp" line="1426"/> + <location filename="../Window.cpp" line="1461"/> <source>Take &amp;screenshot</source> <translation>Tomar pan&amp;tallazo</translation> </message> <message> - <location filename="../Window.cpp" line="1427"/> + <location filename="../Window.cpp" line="1462"/> <source>F12</source> <translation>F12</translation> </message> <message> - <location filename="../Window.cpp" line="1436"/> + <location filename="../Window.cpp" line="1471"/> <source>Record output...</source> <translation>Grabar salida...</translation> </message> <message> - <location filename="../Window.cpp" line="1443"/> + <location filename="../Window.cpp" line="1478"/> <source>Record GIF...</source> <translation>Grabar GIF...</translation> </message> <message> - <location filename="../Window.cpp" line="1448"/> + <location filename="../Window.cpp" line="1483"/> <source>Record video log...</source> <translation>Grabar video-registro...</translation> </message> <message> - <location filename="../Window.cpp" line="1453"/> + <location filename="../Window.cpp" line="1488"/> <source>Stop video log</source> <translation>Detener video-registro</translation> </message> <message> - <location filename="../Window.cpp" line="1461"/> + <location filename="../Window.cpp" line="1496"/> <source>Game Boy Printer...</source> <translation>Game Boy Printer...</translation> </message> <message> - <location filename="../Window.cpp" line="1473"/> + <location filename="../Window.cpp" line="1508"/> <source>Video layers</source> <translation>Capas de video</translation> </message> <message> - <location filename="../Window.cpp" line="1476"/> + <location filename="../Window.cpp" line="1511"/> <source>Audio channels</source> <translation>Canales de audio</translation> </message> <message> - <location filename="../Window.cpp" line="1479"/> + <location filename="../Window.cpp" line="1514"/> <source>Adjust layer placement...</source> <translation>Ajustar ubicación de capas...</translation> </message> <message> - <location filename="../Window.cpp" line="1484"/> + <location filename="../Window.cpp" line="1519"/> <source>&amp;Tools</source> <translation>Herramien&amp;tas</translation> </message> <message> - <location filename="../Window.cpp" line="1486"/> + <location filename="../Window.cpp" line="1521"/> <source>View &amp;logs...</source> <translation>Ver re&amp;gistros...</translation> </message> <message> - <location filename="../Window.cpp" line="1490"/> + <location filename="../Window.cpp" line="1525"/> <source>Game &amp;overrides...</source> <translation>Ajustes específic&amp;os por juego...</translation> </message> <message> - <location filename="../Window.cpp" line="1504"/> + <location filename="../Window.cpp" line="1539"/> <source>Game &amp;Pak sensors...</source> <translation>Sensores del Game &amp;Pak...</translation> </message> <message> - <location filename="../Window.cpp" line="1517"/> + <location filename="../Window.cpp" line="1552"/> <source>&amp;Cheats...</source> <translation>Tru&amp;cos...</translation> </message> <message> - <location filename="../Window.cpp" line="1523"/> + <location filename="../Window.cpp" line="1558"/> <source>Settings...</source> <translation>Ajustes...</translation> </message> <message> - <location filename="../Window.cpp" line="1529"/> + <location filename="../Window.cpp" line="1564"/> <source>Open debugger console...</source> <translation>Abrir consola de depuración...</translation> </message> <message> - <location filename="../Window.cpp" line="1535"/> + <location filename="../Window.cpp" line="1570"/> <source>Start &amp;GDB server...</source> <translation>Iniciar servidor &amp;GDB...</translation> </message> <message> - <location filename="../Window.cpp" line="1543"/> + <location filename="../Window.cpp" line="1578"/> <source>View &amp;palette...</source> <translation>Ver &amp;paleta...</translation> </message> <message> - <location filename="../Window.cpp" line="1548"/> + <location filename="../Window.cpp" line="1583"/> <source>View &amp;sprites...</source> <translation>Ver &amp;sprites...</translation> </message> <message> - <location filename="../Window.cpp" line="1553"/> + <location filename="../Window.cpp" line="1588"/> <source>View &amp;tiles...</source> <translation>Ver &amp;tiles...</translation> </message> <message> - <location filename="../Window.cpp" line="1558"/> + <location filename="../Window.cpp" line="1593"/> <source>View &amp;map...</source> <translation>Ver &amp;mapa...</translation> </message> <message> - <location filename="../Window.cpp" line="1563"/> + <location filename="../Window.cpp" line="1598"/> <source>View memory...</source> <translation>Ver memoria...</translation> </message> <message> - <location filename="../Window.cpp" line="1568"/> + <location filename="../Window.cpp" line="1603"/> <source>Search memory...</source> <translation>Buscar memoria...</translation> </message> <message> - <location filename="../Window.cpp" line="1574"/> + <location filename="../Window.cpp" line="1609"/> <source>View &amp;I/O registers...</source> <translation>Ver registros &amp;I/O...</translation> </message> <message> - <location filename="../Window.cpp" line="1654"/> + <location filename="../Window.cpp" line="1693"/> <source>Exit fullscreen</source> <translation>Salir de pantalla completa</translation> </message> <message> - <location filename="../Window.cpp" line="1667"/> + <location filename="../Window.cpp" line="1706"/> <source>GameShark Button (held)</source> <translation>Botón GameShark (mantener)</translation> </message> <message> - <location filename="../Window.cpp" line="1669"/> + <location filename="../Window.cpp" line="1708"/> <source>Autofire</source> <translation>Disparo automático</translation> </message> <message> - <location filename="../Window.cpp" line="1676"/> + <location filename="../Window.cpp" line="1715"/> <source>Autofire A</source> <translation>Disparo automático A</translation> </message> <message> - <location filename="../Window.cpp" line="1682"/> + <location filename="../Window.cpp" line="1721"/> <source>Autofire B</source> <translation>Disparo automático B</translation> </message> <message> - <location filename="../Window.cpp" line="1688"/> + <location filename="../Window.cpp" line="1727"/> <source>Autofire L</source> <translation>Disparo automático L</translation> </message> <message> - <location filename="../Window.cpp" line="1694"/> + <location filename="../Window.cpp" line="1733"/> <source>Autofire R</source> <translation>Disparo automático R</translation> </message> <message> - <location filename="../Window.cpp" line="1700"/> + <location filename="../Window.cpp" line="1739"/> <source>Autofire Start</source> <translation>Disparo automático Start</translation> </message> <message> - <location filename="../Window.cpp" line="1706"/> + <location filename="../Window.cpp" line="1745"/> <source>Autofire Select</source> <translation>Disparo automático Select</translation> </message> <message> - <location filename="../Window.cpp" line="1712"/> + <location filename="../Window.cpp" line="1751"/> <source>Autofire Up</source> <translation>Disparo automático Arriba</translation> </message> <message> - <location filename="../Window.cpp" line="1718"/> + <location filename="../Window.cpp" line="1757"/> <source>Autofire Right</source> <translation>Disparo automático Derecha</translation> </message> <message> - <location filename="../Window.cpp" line="1724"/> + <location filename="../Window.cpp" line="1763"/> <source>Autofire Down</source> <translation>Disparo automático Abajo</translation> </message> <message> - <location filename="../Window.cpp" line="1730"/> + <location filename="../Window.cpp" line="1769"/> <source>Autofire Left</source> <translation>Disparo automático Izquierda</translation> </message>

@@ -4259,382 +4276,387 @@ <translation>Volumen:</translation>

</message> <message> <location filename="../SettingsView.ui" line="260"/> + <location filename="../SettingsView.ui" line="300"/> <source>Mute</source> <translation>Silenciar</translation> </message> <message> - <location filename="../SettingsView.ui" line="276"/> + <location filename="../SettingsView.ui" line="269"/> + <source>Fast forward volume:</source> + <translation>Vol. durante av. rápido:</translation> + </message> + <message> + <location filename="../SettingsView.ui" line="316"/> <source>Display driver:</source> <translation>Sistema de video:</translation> </message> <message> - <location filename="../SettingsView.ui" line="293"/> + <location filename="../SettingsView.ui" line="333"/> <source>Frameskip:</source> <translation>Salto de cuadros:</translation> </message> <message> - <location filename="../SettingsView.ui" line="302"/> + <location filename="../SettingsView.ui" line="342"/> <source>Skip every</source> <translation>Saltar cada</translation> </message> <message> - <location filename="../SettingsView.ui" line="312"/> - <location filename="../SettingsView.ui" line="645"/> + <location filename="../SettingsView.ui" line="352"/> + <location filename="../SettingsView.ui" line="705"/> <source>frames</source> <translation>cuadros</translation> </message> <message> - <location filename="../SettingsView.ui" line="321"/> + <location filename="../SettingsView.ui" line="361"/> <source>FPS target:</source> <translation>Objetivo de FPS:</translation> </message> <message> - <location filename="../SettingsView.ui" line="343"/> + <location filename="../SettingsView.ui" line="386"/> <source>frames per second</source> <translation>cuadros por segundo</translation> </message> <message> - <location filename="../SettingsView.ui" line="359"/> + <location filename="../SettingsView.ui" line="402"/> <source>Sync:</source> <translation>Sincronizar con:</translation> </message> <message> - <location filename="../SettingsView.ui" line="368"/> + <location filename="../SettingsView.ui" line="411"/> <source>Video</source> <translation>Video</translation> </message> <message> - <location filename="../SettingsView.ui" line="375"/> + <location filename="../SettingsView.ui" line="418"/> <source>Audio</source> <translation>Audio</translation> </message> <message> - <location filename="../SettingsView.ui" line="384"/> + <location filename="../SettingsView.ui" line="427"/> <source>Lock aspect ratio</source> <translation>Bloquear proporción de aspecto</translation> </message> <message> - <location filename="../SettingsView.ui" line="391"/> + <location filename="../SettingsView.ui" line="441"/> <source>Bilinear filtering</source> <translation>Filtro bilineal</translation> </message> <message> - <location filename="../SettingsView.ui" line="398"/> + <location filename="../SettingsView.ui" line="434"/> <source>Force integer scaling</source> - <translation>Forzar escala a enteros</translation> + <translation>Forzar escalado de enteros</translation> </message> <message> - <location filename="../SettingsView.ui" line="409"/> + <location filename="../SettingsView.ui" line="452"/> <source>Language</source> <translation>Idioma</translation> </message> <message> - <location filename="../SettingsView.ui" line="417"/> + <location filename="../SettingsView.ui" line="460"/> <source>English</source> <translation>English</translation> </message> <message> - <location filename="../SettingsView.ui" line="432"/> + <location filename="../SettingsView.ui" line="475"/> <source>Library:</source> <translation>Biblioteca:</translation> </message> <message> - <location filename="../SettingsView.ui" line="440"/> + <location filename="../SettingsView.ui" line="483"/> <source>List view</source> <translation>Lista</translation> </message> <message> - <location filename="../SettingsView.ui" line="445"/> + <location filename="../SettingsView.ui" line="488"/> <source>Tree view</source> <translation>Árbol</translation> </message> <message> - <location filename="../SettingsView.ui" line="453"/> + <location filename="../SettingsView.ui" line="496"/> <source>Show when no game open</source> <translation>Mostrar cuando no haya un juego abierto</translation> </message> <message> - <location filename="../SettingsView.ui" line="463"/> + <location filename="../SettingsView.ui" line="506"/> <source>Clear cache</source> <translation>Limpiar caché</translation> </message> <message> - <location filename="../SettingsView.ui" line="477"/> + <location filename="../SettingsView.ui" line="520"/> <source>Allow opposing input directions</source> <translation>Permitir direcciones opuestas al mismo tiempo</translation> </message> <message> - <location filename="../SettingsView.ui" line="484"/> + <location filename="../SettingsView.ui" line="527"/> <source>Suspend screensaver</source> <translation>Suspender protector de pantalla</translation> </message> <message> - <location filename="../SettingsView.ui" line="494"/> + <location filename="../SettingsView.ui" line="537"/> <source>Pause when inactive</source> <translation>Pausar al no estar activo</translation> </message> <message> - <location filename="../SettingsView.ui" line="501"/> + <location filename="../SettingsView.ui" line="544"/> <source>Show FPS in title bar</source> <translation>Mostrar FPS en la barra de título</translation> </message> <message> - <location filename="../SettingsView.ui" line="525"/> + <location filename="../SettingsView.ui" line="568"/> <source>Automatically save cheats</source> <translation>Guardar trucos automáticamente</translation> </message> <message> - <location filename="../SettingsView.ui" line="535"/> + <location filename="../SettingsView.ui" line="578"/> <source>Automatically load cheats</source> <translation>Cargar trucos automáticamente</translation> </message> <message> - <location filename="../SettingsView.ui" line="545"/> + <location filename="../SettingsView.ui" line="588"/> <source>Automatically save state</source> <translation>Guardar estado automáticamente</translation> </message> <message> - <location filename="../SettingsView.ui" line="555"/> + <location filename="../SettingsView.ui" line="598"/> <source>Automatically load state</source> <translation>Cargar estado automáticamente</translation> </message> <message> - <location filename="../SettingsView.ui" line="572"/> + <location filename="../SettingsView.ui" line="615"/> <source>Fast forward speed:</source> <translation>Velocidad de avance rápido:</translation> </message> <message> - <location filename="../SettingsView.ui" line="584"/> + <location filename="../SettingsView.ui" line="627"/> <source>×</source> <translation>×</translation> </message> <message> - <location filename="../SettingsView.ui" line="603"/> + <location filename="../SettingsView.ui" line="646"/> <source>Unbounded</source> <translation>Sin límite</translation> </message> <message> - <location filename="../SettingsView.ui" line="622"/> + <location filename="../SettingsView.ui" line="682"/> <source>Enable rewind</source> <translation>Habilitar el rebobinar</translation> </message> <message> - <location filename="../SettingsView.ui" line="629"/> + <location filename="../SettingsView.ui" line="689"/> <source>Rewind history:</source> <translation>Historial de rebobinado:</translation> </message> <message> - <location filename="../SettingsView.ui" line="661"/> + <location filename="../SettingsView.ui" line="721"/> <source>Idle loops:</source> <translation>Bucles inactivos:</translation> </message> <message> - <location filename="../SettingsView.ui" line="669"/> + <location filename="../SettingsView.ui" line="729"/> <source>Run all</source> <translation>Ejecutarlos todos</translation> </message> <message> - <location filename="../SettingsView.ui" line="674"/> + <location filename="../SettingsView.ui" line="734"/> <source>Remove known</source> <translation>Eliminar los conocidos</translation> </message> <message> - <location filename="../SettingsView.ui" line="679"/> + <location filename="../SettingsView.ui" line="739"/> <source>Detect and remove</source> <translation>Detectar y eliminar</translation> </message> <message> - <location filename="../SettingsView.ui" line="694"/> + <location filename="../SettingsView.ui" line="761"/> <source>Savestate extra data:</source> <translation>Guardar datos extra con el estado:</translation> </message> <message> - <location filename="../SettingsView.ui" line="701"/> - <location filename="../SettingsView.ui" line="738"/> + <location filename="../SettingsView.ui" line="768"/> + <location filename="../SettingsView.ui" line="812"/> <source>Screenshot</source> <translation>Pantallazo</translation> </message> <message> - <location filename="../SettingsView.ui" line="711"/> - <location filename="../SettingsView.ui" line="748"/> + <location filename="../SettingsView.ui" line="778"/> + <location filename="../SettingsView.ui" line="822"/> <source>Save data</source> <translation>Datos de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="721"/> - <location filename="../SettingsView.ui" line="755"/> + <location filename="../SettingsView.ui" line="788"/> + <location filename="../SettingsView.ui" line="829"/> <source>Cheat codes</source> <translation>Trucos</translation> </message> <message> - <location filename="../SettingsView.ui" line="731"/> + <location filename="../SettingsView.ui" line="805"/> <source>Load extra data:</source> <translation>Cargar datos extra con el estado:</translation> </message> <message> - <location filename="../SettingsView.ui" line="769"/> <source>Rewind affects save data</source> - <translation>El rebobinar afecta los datos de guardado</translation> + <translation type="vanished">El rebobinar afecta los datos de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="779"/> + <location filename="../SettingsView.ui" line="747"/> <source>Preload entire ROM into memory</source> <translation>Cargar ROM completa a la memoria</translation> </message> <message> - <location filename="../SettingsView.ui" line="786"/> + <location filename="../SettingsView.ui" line="658"/> <source>Autofire interval:</source> <translation>Intervalo de disparo automático:</translation> </message> <message> - <location filename="../SettingsView.ui" line="807"/> + <location filename="../SettingsView.ui" line="840"/> <source>GB BIOS file:</source> <translation>Archivo BIOS GB:</translation> </message> <message> - <location filename="../SettingsView.ui" line="826"/> - <location filename="../SettingsView.ui" line="864"/> - <location filename="../SettingsView.ui" line="899"/> - <location filename="../SettingsView.ui" line="927"/> - <location filename="../SettingsView.ui" line="968"/> - <location filename="../SettingsView.ui" line="1016"/> - <location filename="../SettingsView.ui" line="1064"/> - <location filename="../SettingsView.ui" line="1112"/> - <location filename="../SettingsView.ui" line="1160"/> + <location filename="../SettingsView.ui" line="859"/> + <location filename="../SettingsView.ui" line="897"/> + <location filename="../SettingsView.ui" line="932"/> + <location filename="../SettingsView.ui" line="960"/> + <location filename="../SettingsView.ui" line="1001"/> + <location filename="../SettingsView.ui" line="1049"/> + <location filename="../SettingsView.ui" line="1097"/> + <location filename="../SettingsView.ui" line="1145"/> + <location filename="../SettingsView.ui" line="1193"/> <source>Browse</source> <translation>Examinar</translation> </message> <message> - <location filename="../SettingsView.ui" line="835"/> + <location filename="../SettingsView.ui" line="868"/> <source>Use BIOS file if found</source> <translation>Usar archivo BIOS si fue encontrado</translation> </message> <message> - <location filename="../SettingsView.ui" line="845"/> + <location filename="../SettingsView.ui" line="878"/> <source>Skip BIOS intro</source> <translation>Saltar animación de entrada del BIOS</translation> </message> <message> - <location filename="../SettingsView.ui" line="873"/> + <location filename="../SettingsView.ui" line="906"/> <source>GBA BIOS file:</source> <translation>Archivo BIOS GBA:</translation> </message> <message> - <location filename="../SettingsView.ui" line="880"/> + <location filename="../SettingsView.ui" line="913"/> <source>GBC BIOS file:</source> <translation>Archivo BIOS GBC:</translation> </message> <message> - <location filename="../SettingsView.ui" line="908"/> + <location filename="../SettingsView.ui" line="941"/> <source>SGB BIOS file:</source> <translation>SGB BIOS file:</translation> </message> <message> - <location filename="../SettingsView.ui" line="943"/> + <location filename="../SettingsView.ui" line="976"/> <source>Save games</source> <translation>Datos de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="977"/> - <location filename="../SettingsView.ui" line="1025"/> - <location filename="../SettingsView.ui" line="1073"/> - <location filename="../SettingsView.ui" line="1121"/> - <location filename="../SettingsView.ui" line="1169"/> + <location filename="../SettingsView.ui" line="1010"/> + <location filename="../SettingsView.ui" line="1058"/> + <location filename="../SettingsView.ui" line="1106"/> + <location filename="../SettingsView.ui" line="1154"/> + <location filename="../SettingsView.ui" line="1202"/> <source>Same directory as the ROM</source> <translation>Al mismo directorio que la ROM</translation> </message> <message> - <location filename="../SettingsView.ui" line="991"/> + <location filename="../SettingsView.ui" line="1024"/> <source>Save states</source> <translation>Estados de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="1039"/> + <location filename="../SettingsView.ui" line="1072"/> <source>Screenshots</source> <translation>Pantallazos</translation> </message> <message> - <location filename="../SettingsView.ui" line="1087"/> + <location filename="../SettingsView.ui" line="1120"/> <source>Patches</source> <translation>Parches</translation> </message> <message> - <location filename="../SettingsView.ui" line="1135"/> + <location filename="../SettingsView.ui" line="1168"/> <source>Cheats</source> <translation>Trucos</translation> </message> <message> - <location filename="../SettingsView.ui" line="1180"/> + <location filename="../SettingsView.ui" line="1213"/> <source>Game Boy model</source> <translation>Modelo de Game Boy</translation> </message> <message> - <location filename="../SettingsView.ui" line="1188"/> - <location filename="../SettingsView.ui" line="1224"/> - <location filename="../SettingsView.ui" line="1260"/> + <location filename="../SettingsView.ui" line="1221"/> + <location filename="../SettingsView.ui" line="1257"/> + <location filename="../SettingsView.ui" line="1293"/> <source>Autodetect</source> <translation>Detección automática</translation> </message> <message> - <location filename="../SettingsView.ui" line="1193"/> - <location filename="../SettingsView.ui" line="1229"/> - <location filename="../SettingsView.ui" line="1265"/> + <location filename="../SettingsView.ui" line="1226"/> + <location filename="../SettingsView.ui" line="1262"/> + <location filename="../SettingsView.ui" line="1298"/> <source>Game Boy (DMG)</source> <translation>Game Boy (DMG)</translation> </message> <message> - <location filename="../SettingsView.ui" line="1198"/> - <location filename="../SettingsView.ui" line="1234"/> - <location filename="../SettingsView.ui" line="1270"/> + <location filename="../SettingsView.ui" line="1231"/> + <location filename="../SettingsView.ui" line="1267"/> + <location filename="../SettingsView.ui" line="1303"/> <source>Super Game Boy (SGB)</source> <translation></translation> </message> <message> - <location filename="../SettingsView.ui" line="1203"/> - <location filename="../SettingsView.ui" line="1239"/> - <location filename="../SettingsView.ui" line="1275"/> + <location filename="../SettingsView.ui" line="1236"/> + <location filename="../SettingsView.ui" line="1272"/> + <location filename="../SettingsView.ui" line="1308"/> <source>Game Boy Color (CGB)</source> <translation>Game Boy Color (CGB)</translation> </message> <message> - <location filename="../SettingsView.ui" line="1208"/> - <location filename="../SettingsView.ui" line="1244"/> - <location filename="../SettingsView.ui" line="1280"/> + <location filename="../SettingsView.ui" line="1241"/> + <location filename="../SettingsView.ui" line="1277"/> + <location filename="../SettingsView.ui" line="1313"/> <source>Game Boy Advance (AGB)</source> <translation>Game Boy Advance (AGB)</translation> </message> <message> - <location filename="../SettingsView.ui" line="1216"/> + <location filename="../SettingsView.ui" line="1249"/> <source>Super Game Boy model</source> <translation>Modelo de Super Game Boy</translation> </message> <message> - <location filename="../SettingsView.ui" line="1252"/> + <location filename="../SettingsView.ui" line="1285"/> <source>Game Boy Color model</source> <translation>Modelo de Game Boy Color</translation> </message> <message> - <location filename="../SettingsView.ui" line="1295"/> + <location filename="../SettingsView.ui" line="1328"/> <source>Default BG colors:</source> <translation>Colores de fondo por defecto:</translation> </message> <message> - <location filename="../SettingsView.ui" line="1462"/> + <location filename="../SettingsView.ui" line="1495"/> <source>Super Game Boy borders</source> <translation>Bordes de Super Game Boy</translation> </message> <message> - <location filename="../SettingsView.ui" line="1476"/> + <location filename="../SettingsView.ui" line="1509"/> <source>Camera driver:</source> <translation>Controlador de cámara:</translation> </message> <message> - <location filename="../SettingsView.ui" line="1573"/> + <location filename="../SettingsView.ui" line="1606"/> <source>Default sprite colors 1:</source> <translation>Colores de sprite 1 por defecto:</translation> </message> <message> - <location filename="../SettingsView.ui" line="1580"/> + <location filename="../SettingsView.ui" line="1613"/> <source>Default sprite colors 2:</source> <translation>Colores de sprite 2 por defecto:</translation> </message>

@@ -4751,14 +4773,12 @@ <source>Presets</source>

<translation>Ajustes predefinidos</translation> </message> <message> - <location filename="../VideoView.ui" line="109"/> <source>High Quality</source> - <translation>Alta calidad</translation> + <translation type="vanished">Alta calidad</translation> </message> <message> - <location filename="../VideoView.ui" line="119"/> <source>YouTube</source> - <translation>YouTube</translation> + <translation type="vanished">YouTube</translation> </message> <message> <location filename="../VideoView.ui" line="129"/>

@@ -4767,29 +4787,24 @@ <source>WebM</source>

<translation>WebM</translation> </message> <message> - <location filename="../VideoView.ui" line="139"/> <source>Lossless</source> - <translation>Sin pérdidas</translation> + <translation type="vanished">Sin pérdidas</translation> </message> <message> - <location filename="../VideoView.ui" line="156"/> <source>1080p</source> - <translation>1080p</translation> + <translation type="vanished">1080p</translation> </message> <message> - <location filename="../VideoView.ui" line="166"/> <source>720p</source> - <translation>720p</translation> + <translation type="vanished">720p</translation> </message> <message> - <location filename="../VideoView.ui" line="176"/> <source>480p</source> - <translation>480p</translation> + <translation type="vanished">480p</translation> </message> <message> - <location filename="../VideoView.ui" line="189"/> <source>Native</source> - <translation>Nativa</translation> + <translation type="vanished">Nativa</translation> </message> <message> <location filename="../VideoView.ui" line="222"/>

@@ -4816,6 +4831,41 @@ <source>PNG</source>

<translation type="vanished">PNG</translation> </message> <message> + <location filename="../VideoView.ui" line="109"/> + <source>High &amp;Quality</source> + <translation>Alta &amp;calidad</translation> + </message> + <message> + <location filename="../VideoView.ui" line="119"/> + <source>&amp;YouTube</source> + <translation>&amp;YouTube</translation> + </message> + <message> + <location filename="../VideoView.ui" line="139"/> + <source>&amp;Lossless</source> + <translation>Sin pér&amp;didas</translation> + </message> + <message> + <location filename="../VideoView.ui" line="156"/> + <source>&amp;1080p</source> + <translation>&amp;1080p</translation> + </message> + <message> + <location filename="../VideoView.ui" line="166"/> + <source>&amp;720p</source> + <translation>&amp;720p</translation> + </message> + <message> + <location filename="../VideoView.ui" line="176"/> + <source>&amp;480p</source> + <translation>&amp;480p</translation> + </message> + <message> + <location filename="../VideoView.ui" line="189"/> + <source>&amp;Native</source> + <translation>&amp;NAtivo</translation> + </message> + <message> <location filename="../VideoView.ui" line="259"/> <source>h.264</source> <translation>h.264</translation>

@@ -4837,76 +4887,81 @@ <translation>VP8</translation>

</message> <message> <location filename="../VideoView.ui" line="279"/> + <source>VP9</source> + <translation>VP9</translation> + </message> + <message> + <location filename="../VideoView.ui" line="284"/> <source>FFV1</source> <translation>FFV1</translation> </message> <message> - <location filename="../VideoView.ui" line="291"/> + <location filename="../VideoView.ui" line="296"/> <source>FLAC</source> <translation>FLAC</translation> </message> <message> - <location filename="../VideoView.ui" line="296"/> + <location filename="../VideoView.ui" line="301"/> <source>Opus</source> <translation>Opus</translation> </message> <message> - <location filename="../VideoView.ui" line="301"/> + <location filename="../VideoView.ui" line="306"/> <source>Vorbis</source> <translation>Vorbis</translation> </message> <message> - <location filename="../VideoView.ui" line="306"/> + <location filename="../VideoView.ui" line="311"/> <source>MP3</source> <translation>MP3</translation> </message> <message> - <location filename="../VideoView.ui" line="311"/> + <location filename="../VideoView.ui" line="316"/> <source>AAC</source> <translation>AAC</translation> </message> <message> - <location filename="../VideoView.ui" line="316"/> + <location filename="../VideoView.ui" line="321"/> <source>Uncompressed</source> <translation>Sin comprimir</translation> </message> <message> - <location filename="../VideoView.ui" line="327"/> + <location filename="../VideoView.ui" line="332"/> <source> Bitrate (kbps)</source> <translation> Tasa de bits (kbps)</translation> </message> <message> - <location filename="../VideoView.ui" line="333"/> + <location filename="../VideoView.ui" line="338"/> <source>VBR </source> <translation>VBR </translation> </message> <message> - <location filename="../VideoView.ui" line="378"/> + <location filename="../VideoView.ui" line="383"/> <source>ABR</source> <translation>ABR</translation> </message> <message> - <location filename="../VideoView.ui" line="394"/> + <location filename="../VideoView.ui" line="399"/> <source>Dimensions</source> <translation>Dimensiones</translation> </message> <message> - <location filename="../VideoView.ui" line="400"/> + <location filename="../VideoView.ui" line="405"/> <source>:</source> <translation>:</translation> </message> <message> - <location filename="../VideoView.ui" line="410"/> + <location filename="../VideoView.ui" line="415"/> <source>×</source> <translation>×</translation> </message> <message> - <location filename="../VideoView.ui" line="460"/> + <location filename="../VideoView.ui" line="465"/> <source>Lock aspect ratio</source> <translation>Bloquear proporción de aspecto</translation> </message> <message> - <location filename="../VideoView.ui" line="475"/> + <location filename="../VideoView.ui" line="480"/> <source>Show advanced</source> <translation>Mostrar ajustes avanzados</translation> </message>
M src/platform/switch/CMakeLists.txtsrc/platform/switch/CMakeLists.txt

@@ -50,4 +50,5 @@ add_custom_target(${BINARY_NAME}.nro ALL

${ELF2NRO} ${BINARY_NAME}.elf ${BINARY_NAME}.nro --romfs=romfs.bin --nacp=control.nacp --icon="${CMAKE_CURRENT_SOURCE_DIR}/icon.jpg" DEPENDS ${BINARY_NAME}.elf control.nacp ${CMAKE_CURRENT_SOURCE_DIR}/icon.jpg romfs.bin) +install(TARGETS ${BINARY_NAME}.elf DESTINATION . COMPONENT ${BINARY_NAME}-dbg) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.nro DESTINATION . COMPONENT ${BINARY_NAME}-switch)
M src/platform/switch/main.csrc/platform/switch/main.c

@@ -75,6 +75,13 @@ static GLuint tex;

static color_t* frameBuffer; static struct mAVStream stream; +static struct mSwitchRumble { + struct mRumble d; + int up; + int down; + HidVibrationValue value; +} rumble; +static struct mRotationSource rotation = {0}; static int audioBufferActive; static struct GBAStereoSample audioBuffer[N_BUFFERS][SAMPLES] __attribute__((__aligned__(0x1000))); static AudioOutBuffer audoutBuffer[N_BUFFERS];

@@ -82,6 +89,8 @@ static int enqueuedBuffers;

static bool frameLimiter = true; static unsigned framecount = 0; static unsigned framecap = 10; +static u32 vibrationDeviceHandles[4]; +static HidVibrationValue vibrationStop = { .freq_low = 160.f, .freq_high = 320.f }; static bool initEgl() { s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

@@ -226,6 +235,8 @@ _mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_L, GBA_KEY_L);

_mapKey(&runner->core->inputMap, AUTO_INPUT, KEY_R, GBA_KEY_R); runner->core->setVideoBuffer(runner->core, frameBuffer, 256); + runner->core->setPeripheral(runner->core, mPERIPH_RUMBLE, &rumble.d); + runner->core->setPeripheral(runner->core, mPERIPH_ROTATION, &rotation); runner->core->setAVStream(runner->core, &stream); }

@@ -237,6 +248,18 @@ blip_set_rates(runner->core->getAudioChannel(runner->core, 0), runner->core->frequency(runner->core), samplerate * ratio);

blip_set_rates(runner->core->getAudioChannel(runner->core, 1), runner->core->frequency(runner->core), samplerate * ratio); mCoreConfigGetUIntValue(&runner->config, "fastForwardCap", &framecap); + + rumble.up = 0; + rumble.down = 0; +} + +static void _gameUnloaded(struct mGUIRunner* runner) { + HidVibrationValue values[4]; + memcpy(&values[0], &vibrationStop, sizeof(rumble.value)); + memcpy(&values[1], &vibrationStop, sizeof(rumble.value)); + memcpy(&values[2], &vibrationStop, sizeof(rumble.value)); + memcpy(&values[3], &vibrationStop, sizeof(rumble.value)); + hidSendVibrationValues(vibrationDeviceHandles, values, 4); } static void _drawTex(struct mGUIRunner* runner, unsigned width, unsigned height, bool faded) {

@@ -299,6 +322,24 @@ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, height, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); _drawTex(runner, width, height, faded); + + HidVibrationValue values[4]; + if (rumble.up) { + rumble.value.amp_low = rumble.up / (float) (rumble.up + rumble.down); + rumble.value.amp_high = rumble.up / (float) (rumble.up + rumble.down); + memcpy(&values[0], &rumble.value, sizeof(rumble.value)); + memcpy(&values[1], &rumble.value, sizeof(rumble.value)); + memcpy(&values[2], &rumble.value, sizeof(rumble.value)); + memcpy(&values[3], &rumble.value, sizeof(rumble.value)); + } else { + memcpy(&values[0], &vibrationStop, sizeof(rumble.value)); + memcpy(&values[1], &vibrationStop, sizeof(rumble.value)); + memcpy(&values[2], &vibrationStop, sizeof(rumble.value)); + memcpy(&values[3], &vibrationStop, sizeof(rumble.value)); + } + hidSendVibrationValues(vibrationDeviceHandles, values, 4); + rumble.up = 0; + rumble.down = 0; } static void _drawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded) {

@@ -355,6 +396,36 @@ audioBufferActive %= N_BUFFERS;

++enqueuedBuffers; } +void _setRumble(struct mRumble* rumble, int enable) { + struct mSwitchRumble* sr = (struct mSwitchRumble*) rumble; + if (enable) { + ++sr->up; + } else { + ++sr->down; + } +} + +int32_t _readTiltX(struct mRotationSource* source) { + UNUSED(source); + SixAxisSensorValues sixaxis; + hidSixAxisSensorValuesRead(&sixaxis, CONTROLLER_P1_AUTO, 1); + return sixaxis.accelerometer.x * 3e8f; +} + +int32_t _readTiltY(struct mRotationSource* source) { + UNUSED(source); + SixAxisSensorValues sixaxis; + hidSixAxisSensorValuesRead(&sixaxis, CONTROLLER_P1_AUTO, 1); + return sixaxis.accelerometer.y * -3e8f; +} + +int32_t _readGyroZ(struct mRotationSource* source) { + UNUSED(source); + SixAxisSensorValues sixaxis; + hidSixAxisSensorValuesRead(&sixaxis, CONTROLLER_P1_AUTO, 1); + return sixaxis.gyroscope.z * 1.1e9f; +} + static int _batteryState(void) { u32 charge; int state = 0;

@@ -455,6 +526,24 @@ glVertexAttribPointer(offsetLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);

glEnableVertexAttribArray(offsetLocation); glBindVertexArray(0); + rumble.d.setRumble = _setRumble; + rumble.value.freq_low = 120.0; + rumble.value.freq_high = 180.0; + hidInitializeVibrationDevices(&vibrationDeviceHandles[0], 2, CONTROLLER_HANDHELD, TYPE_HANDHELD | TYPE_JOYCON_PAIR); + hidInitializeVibrationDevices(&vibrationDeviceHandles[2], 2, CONTROLLER_PLAYER_1, TYPE_HANDHELD | TYPE_JOYCON_PAIR); + + u32 handles[4]; + hidGetSixAxisSensorHandles(&handles[0], 2, CONTROLLER_PLAYER_1, TYPE_JOYCON_PAIR); + hidGetSixAxisSensorHandles(&handles[2], 1, CONTROLLER_PLAYER_1, TYPE_PROCONTROLLER); + hidGetSixAxisSensorHandles(&handles[3], 1, CONTROLLER_HANDHELD, TYPE_HANDHELD); + hidStartSixAxisSensor(handles[0]); + hidStartSixAxisSensor(handles[1]); + hidStartSixAxisSensor(handles[2]); + hidStartSixAxisSensor(handles[3]); + rotation.readTiltX = _readTiltX; + rotation.readTiltY = _readTiltY; + rotation.readGyroZ = _readGyroZ; + stream.videoDimensionsChanged = NULL; stream.postVideoFrame = NULL; stream.postAudioFrame = NULL;

@@ -528,6 +617,23 @@ "3", "4", "5", "6", "7", "8", "9",

"10", "11", "12", "13", "14", "15", "20", "30" }, + .stateMappings = (const struct GUIVariant[]) { + GUI_V_U(3), + GUI_V_U(4), + GUI_V_U(5), + GUI_V_U(6), + GUI_V_U(7), + GUI_V_U(8), + GUI_V_U(9), + GUI_V_U(10), + GUI_V_U(11), + GUI_V_U(12), + GUI_V_U(13), + GUI_V_U(14), + GUI_V_U(15), + GUI_V_U(20), + GUI_V_U(30), + }, .nStates = 15 }, },

@@ -535,11 +641,11 @@ .nConfigExtra = 1,

.setup = _setup, .teardown = NULL, .gameLoaded = _gameLoaded, - .gameUnloaded = NULL, + .gameUnloaded = _gameUnloaded, .prepareForFrame = _prepareForFrame, .drawFrame = _drawFrame, .drawScreenshot = _drawScreenshot, - .paused = NULL, + .paused = _gameUnloaded, .unpaused = _gameLoaded, .incrementScreenMode = NULL, .setFrameLimiter = _setFrameLimiter,

@@ -576,6 +682,11 @@ glDeleteTextures(1, &tex);

glDeleteBuffers(1, &vbo); glDeleteProgram(program); glDeleteVertexArrays(1, &vao); + + hidStopSixAxisSensor(handles[0]); + hidStopSixAxisSensor(handles[1]); + hidStopSixAxisSensor(handles[2]); + hidStopSixAxisSensor(handles[3]); psmExit(); audoutExit();
M src/platform/wii/CMakeLists.txtsrc/platform/wii/CMakeLists.txt

@@ -40,5 +40,7 @@ add_custom_target(run ${WIILOAD} ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.dol

DEPENDS ${BINARY_NAME}.dol) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/meta.xml.in ${CMAKE_CURRENT_BINARY_DIR}/meta.xml) + +install(TARGETS ${BINARY_NAME}.elf DESTINATION . COMPONENT ${BINARY_NAME}-dbg) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/icon.png ${CMAKE_CURRENT_BINARY_DIR}/meta.xml DESTINATION . COMPONENT ${BINARY_NAME}-wii) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${BINARY_NAME}.dol DESTINATION . RENAME boot.dol COMPONENT ${BINARY_NAME}-wii)
M src/platform/wii/main.csrc/platform/wii/main.c

@@ -195,18 +195,18 @@ guiScale = GUI_SCALE_240p;

break; } - free(framebuffer[0]); - free(framebuffer[1]); - VIDEO_SetBlack(true); VIDEO_Configure(vmode); + + free(framebuffer[0]); + free(framebuffer[1]); framebuffer[0] = SYS_AllocateFramebuffer(vmode); framebuffer[1] = SYS_AllocateFramebuffer(vmode); - VIDEO_ClearFrameBuffer(vmode, framebuffer[0], COLOR_BLACK); - VIDEO_ClearFrameBuffer(vmode, framebuffer[1], COLOR_BLACK); + VIDEO_ClearFrameBuffer(vmode, MEM_K0_TO_K1(framebuffer[0]), COLOR_BLACK); + VIDEO_ClearFrameBuffer(vmode, MEM_K0_TO_K1(framebuffer[1]), COLOR_BLACK); - VIDEO_SetNextFramebuffer(framebuffer[whichFb]); + VIDEO_SetNextFramebuffer(MEM_K0_TO_K1(framebuffer[whichFb])); VIDEO_Flush(); VIDEO_WaitVSync(); if (vmode->viTVMode & VI_NON_INTERLACE) {

@@ -469,9 +469,49 @@ "Bilinear (smoother)",

"Bilinear (pixelated)", }, .nStates = 3 - } + }, + { + .title = "Horizontal stretch", + .data = "stretchWidth", + .submenu = 0, + .state = 7, + .validStates = (const char*[]) { + "1/2x", "0.6x", "1/3x", "0.7x", "1/4x", "0.8x", "0.9x", "1.0x" + }, + .stateMappings = (const struct GUIVariant[]) { + GUI_V_F(0.5f), + GUI_V_F(0.6f), + GUI_V_F(1.f / 3.f), + GUI_V_F(0.7f), + GUI_V_F(0.75f), + GUI_V_F(0.8f), + GUI_V_F(0.9f), + GUI_V_F(1.0f), + }, + .nStates = 8 + }, + { + .title = "Vertical stretch", + .data = "stretchHeight", + .submenu = 0, + .state = 6, + .validStates = (const char*[]) { + "1/2x", "0.6x", "1/3x", "0.7x", "1/4x", "0.8x", "0.9x", "1.0x" + }, + .stateMappings = (const struct GUIVariant[]) { + GUI_V_F(0.5f), + GUI_V_F(0.6f), + GUI_V_F(1.f / 3.f), + GUI_V_F(0.7f), + GUI_V_F(0.75f), + GUI_V_F(0.8f), + GUI_V_F(0.9f), + GUI_V_F(1.0f), + }, + .nStates = 8 + }, }, - .nConfigExtra = 3, + .nConfigExtra = 5, .setup = _setup, .teardown = 0, .gameLoaded = _gameLoaded,

@@ -516,6 +556,15 @@ _mapKey(&runner.params.keyMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_UP, GUI_INPUT_UP);

_mapKey(&runner.params.keyMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_DOWN, GUI_INPUT_DOWN); _mapKey(&runner.params.keyMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_LEFT, GUI_INPUT_LEFT); _mapKey(&runner.params.keyMap, CLASSIC_INPUT, WPAD_CLASSIC_BUTTON_RIGHT, GUI_INPUT_RIGHT); + + + float stretch = 0; + if (mCoreConfigGetFloatValue(&runner.config, "stretchWidth", &stretch)) { + wStretch = fminf(1.0f, fmaxf(0.5f, stretch)); + } + if (mCoreConfigGetFloatValue(&runner.config, "stretchHeight", &stretch)) { + hStretch = fminf(1.0f, fmaxf(0.5f, stretch)); + } if (argc > 1) { size_t i;

@@ -595,7 +644,7 @@

static void _drawEnd(void) { GX_CopyDisp(framebuffer[whichFb], GX_TRUE); GX_DrawDone(); - VIDEO_SetNextFramebuffer(framebuffer[whichFb]); + VIDEO_SetNextFramebuffer(MEM_K0_TO_K1(framebuffer[whichFb])); VIDEO_Flush(); whichFb = !whichFb;

@@ -862,8 +911,8 @@ GX_CopyTex(rescaleTexmem, GX_TRUE);

GX_LoadTexObj(&rescaleTex, GX_TEXMAP0); } - int hfactor = vmode->fbWidth / (corew * wAdjust); - int vfactor = vmode->efbHeight / (coreh * hAdjust); + int hfactor = (vmode->fbWidth * wStretch) / (corew * wAdjust); + int vfactor = (vmode->efbHeight * hStretch) / (coreh * hAdjust); if (hfactor > vfactor) { scaleFactor = vfactor; } else {
A src/platform/windows/setup/setup.iss.in

@@ -0,0 +1,140 @@

+#define AppName "${PROJECT_NAME}" +#define AppName2 "${BINARY_NAME}" +#define VerMajor ${LIB_VERSION_MAJOR} +#define VerMinor ${LIB_VERSION_MINOR} +#define VerRev ${LIB_VERSION_PATCH} +#define VerBuild ${GIT_REV} +#define Release ${IS_RELEASE} +#define WinBits "${WIN_BITS}" +#define VersionString "${VERSION_STRING}" +#define CleanVersionString "${CLEAN_VERSION_STRING}" +#define SetupDir "${SETUP_DIR}" +#define BinDir "${BIN_DIR}" +#define ResDir "${RES_DIR}" + +#define FullVersion ParseVersion('{#AppName}.exe', VerMajor, VerMinor, VerRev, VerBuild) +#define AppVer Str(VerMajor) + "." + Str(VerMinor) + "." + Str(VerRev) + +[Setup] +SourceDir={#BinDir} +SetupIconFile={#SetupDir}\setup.ico +WizardImageFile={#SetupDir}\wizard-image.bmp + +AppName={#AppName} +AppVersion={#AppVer} +AppPublisher=Jeffrey Pfau +AppPublisherURL=https://mgba.io +AppSupportURL=https://mgba.io +AppUpdatesURL=https://mgba.io +AppReadmeFile={#BinDir}\README.html +OutputDir=.\ +DefaultDirName={pf}\{#AppName} +DefaultGroupName={#AppName} +AllowNoIcons=yes +DirExistsWarning=no +ChangesAssociations=True +AppendDefaultDirName=False +UninstallDisplayIcon={app}\{#AppName}.exe +MinVersion=0,6.0 +AlwaysShowDirOnReadyPage=True +UsePreviousSetupType=True +UsePreviousTasks=True +AlwaysShowGroupOnReadyPage=True +LicenseFile={#BinDir}\LICENSE.txt +#if Release + #define IsRelease = 'yes' + AppVerName={#AppName} {#AppVer} +#else + #define IsRelease = 'no' + AppVerName={#AppName} {#VersionString} (Development build) +#endif +#if '{#WinBits}' == '64' + ArchitecturesInstallIn64BitMode=x64 + ArchitecturesAllows=x64 +#endif +OutputBaseFilename={#AppName}-setup-{#CleanVersionString}-win{#WinBits} +UsePreviousLanguage=False +DisableWelcomePage=False +VersionInfoDescription={#AppName} is an open-source Game Boy Advance emulator +VersionInfoCopyright= 20132018 Jeffrey Pfau +VersionInfoProductName={#AppName} +VersionInfoVersion={#AppVer} +Compression=lzma2/ultra64 +SolidCompression=True +VersionInfoTextVersion={#AppVer} +VersionInfoProductVersion={#AppVer} +VersionInfoProductTextVersion={#AppVer} + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" +Name: "french"; MessagesFile: "compiler:Languages\French.isl" +Name: "german"; MessagesFile: "compiler:Languages\German.isl" +Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl" +Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}" +Name: "gbfileassoc"; Description: "{cm:AssocFileExtension,{#AppName},Game Boy}"; GroupDescription: "{cm:FileAssoc}" +Name: "gbcfileassoc"; Description: "{cm:AssocFileExtension,{#AppName},Game Boy Color}"; GroupDescription: "{cm:FileAssoc}" +Name: "sgbfileassoc"; Description: "{cm:AssocFileExtension,{#AppName},Super Game Boy}"; GroupDescription: "{cm:FileAssoc}" +Name: "gbafileassoc"; Description: "{cm:AssocFileExtension,{#AppName},Game Boy Advance}"; GroupDescription: "{cm:FileAssoc}" + +[Files] +Source: "{#BinDir}\qt\{#AppName}.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "{#BinDir}\sdl\{#AppName2}-sdl.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "{#BinDir}\CHANGES.txt"; DestDir: "{app}\"; Flags: ignoreversion isreadme +Source: "{#BinDir}\LICENSE.txt"; DestDir: "{app}\"; Flags: ignoreversion +Source: "{#ResDir}\nointro.dat"; DestDir: "{app}\"; Flags: ignoreversion +Source: "{#BinDir}\README.html"; DestDir: "{app}\"; Flags: ignoreversion isreadme; Languages: english italian spanish +Source: "{#BinDir}\README_DE.html"; DestDir: "{app}\"; DestName: "LIESMICH.html"; Flags: ignoreversion isreadme; Languages: german +Source: "{#ResDir}\shaders\*"; DestDir: "{app}\shaders\"; Flags: ignoreversion recursesubdirs +Source: "{#ResDir}\licenses\*"; DestDir: "{app}\licenses\"; Flags: ignoreversion recursesubdirs + +[Icons] +Name: "{commonstartmenu}\{#AppName}"; Filename: "{app}\{#AppName}.exe" +Name: "{commondesktop}\{#AppName}"; Filename: "{app}\{#AppName}.exe"; Tasks: desktopicon + +[Run] +Filename: "{app}\{#AppName}.exe"; Description: "{cm:LaunchProgram,{#AppName}}"; Flags: nowait postinstall skipifsilent + +[Dirs] +Name: "{app}" + +[CustomMessages] +english.FileAssoc=Register file associations +french.FileAssoc=Register file associations +italian.FileAssoc=Register file associations +spanish.FileAssoc=Register file associations +german.FileAssoc=Dateierweiterungen registrieren + +[Registry] +Root: HKCR; Subkey: ".gb"; ValueType: string; ValueName: ""; ValueData: "Game Boy ROM"; Flags: uninsdeletevalue; Tasks: gbfileassoc +Root: HKCR; Subkey: ".gb\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#AppName}.exe,0"; Tasks: gbfileassoc +Root: HKCR; Subkey: ".gb\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#AppName}.exe"" ""%1"""; Tasks: gbfileassoc +Root: HKCR; Subkey: ".gbc"; ValueType: string; ValueName: ""; ValueData: "Game Boy Color ROM"; Flags: uninsdeletevalue; Tasks: gbcfileassoc +Root: HKCR; Subkey: ".gbc\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#AppName}.exe,0"; Tasks: gbcfileassoc +Root: HKCR; Subkey: ".gbc\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#AppName}.exe"" ""%1"""; Tasks: gbcfileassoc +Root: HKCR; Subkey: ".sgb"; ValueType: string; ValueName: ""; ValueData: "Super Game Boy ROM"; Flags: uninsdeletevalue; Tasks: sgbfileassoc +Root: HKCR; Subkey: ".sgb\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#AppName}.exe,0"; Tasks: sgbfileassoc +Root: HKCR; Subkey: ".sgb\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#AppName}.exe"" ""%1"""; Tasks: sgbfileassoc +Root: HKCR; Subkey: ".gba"; ValueType: string; ValueName: ""; ValueData: "Game Boy Advance ROM"; Flags: uninsdeletevalue; Tasks: gbafileassoc +Root: HKCR; Subkey: ".gba\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#AppName}.exe,0"; Tasks: gbafileassoc +Root: HKCR; Subkey: ".gba\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#AppName}.exe"" ""%1"""; Tasks: gbafileassoc + +[Code] +var + noReleaseWarning: String; + +procedure InitializeWizard(); + begin + if ExpandConstant('{#IsRelease}') = 'no' then + begin + if ExpandConstant('{language}') = 'english' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.'; + if ExpandConstant('{language}') = 'french' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.'; + if ExpandConstant('{language}') = 'italian' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.'; + if ExpandConstant('{language}') = 'spanish' then noReleaseWarning := 'You are about to install a development build of {#AppName}.' + #13#10#13#10 + 'Development builds may contain bugs that are not yet discovered. Please report any issues you can find to the GitHub project page.'; + if ExpandConstant('{language}') = 'german' then noReleaseWarning := 'Sie mchten eine Entwicklerversion von {#AppName} installieren.' + #13#10#13#10 + 'Entwicklerversionen knnen bislang noch nicht endeckte Fehler beinhalten. Bitte melden Sie alle Fehler, die Sie finden knnen, auf der GitHub-Projektseite.'; + MsgBox(noReleaseWarning, mbInformation, MB_OK); + end; + end; +end.