Merge branch 'feature/input-revamp' into medusa
jump to
@@ -8,179 +8,199 @@ Misc:
- DS GX: Clean up and unify texture mapping 0.7.0: (Future) +Bugfixes: + - GB Audio: Make audio unsigned with bias (fixes mgba.io/i/749) Misc: - GBA Timer: Use global cycles for timers + - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722) + - All: Make FIXED_ROM_BUFFER an option instead of 3DS-only 0.6.0: (Future) Features: - - GBA: Support printing debug strings from inside a game - - GBA: Better cheat type autodetection - - GB: Tile viewer + - Library view - Sprite viewer - Debugging console - Improved memory viewer - - GB: LR35902/GB-Z80 disassembler - - Configuration of gamepad hats - - Qt: Spanish translation (by Kevin López) - - Add option for whether rewinding restores save games - - Qt: German translation (by Lothar Serra Mari) - - Savestates now contain any RTC override data + - Memory search - Command line ability to override configuration values - Add option to allow preloading the entire ROM before running - - GB: Video/audio channel enabling/disabling + - Add option for whether rewinding restores save games + - Savestates now contain any RTC override data - Add option to lock video to integer scaling - - Video log recording for testing and bug reporting - - Library view - - Debugger: Segment/bank support + - LR35902: Watchpoints + - LR35902/GB-Z80 disassembler + - GB: Tile viewer + - GB: Video/audio channel enabling/disabling - GB: Symbol table support - GB MBC: Add MBC1 multicart support + - GBA: Support printing debug strings from inside a game + - GBA: Better cheat type autodetection - Implement keypad interrupts - - LR35902: Watchpoints - - Memory search + - Configuration of gamepad hats + - Video log recording for testing and bug reporting + - Debugger: Segment/bank support - Debugger: Execution tracing + - Qt: German translation (by Lothar Serra Mari) + - Qt: Spanish translation (by Kevin López) - Qt: Italian translation (by theheroGAC) Bugfixes: - - LR35902: Fix core never exiting with certain event patterns + - ARM7: Fix MLA/*MULL/*MLAL timing + - Core: Fix crash with rewind if savestates shrink + - Core: Fix interrupting a thread while on the thread (fixes mgba.io/i/692) + - Core: Fix directory sets crashing on close if base isn't properly detached + - FFmpeg: Fix overflow and general issues with audio encoding + - GB: Fix flickering when screen is strobed quickly + - GB: Fix STAT blocking + - GB MBC: Fix ROM bank overflows getting set to bank 0 + - GB MBC: Fix swapping carts not detect new MBC - GB Timer: Improve DIV reset behavior - - GBA Memory: Improve initial skipped BIOS state + - GB Timer: Fix DIV batching if TAC changes + - GB Video: Reset renderer when loading state + - GBA: Fix multiboot ROM loading + - GBA: Fix multiboot loading resulting in too small WRAM - GBA BIOS: Implement BitUnPack - - ARM7: Fix MLA/*MULL/*MLAL timing - - GBA: Fix multiboot ROM loading + - GBA BIOS: Fix ArcTan sign in HLE BIOS + - GBA BIOS: Fix ArcTan2 sign in HLE BIOS (fixes mgba.io/i/689) + - GBA BIOS: Fix INT_MIN/-1 crash + - GBA Hardware: Fix crash if a savestate lies about game hardware + - GBA I/O: Handle audio registers specially when deserializing + - GBA Memory: Improve initial skipped BIOS state + - GBA Savedata: Fix savedata unmasking (fixes mgba.io/i/441) + - GBA Savedata: Update and fix Sharkport importing (fixes mgba.io/i/658) + - GBA Video: Fix wrong palette on 256-color sprites in OBJWIN + - GBA Video: Don't update background scanline params in mode 0 (fixes mgba.io/i/377) - Libretro: Fix saving in GB games (fixes mgba.io/i/486) + - LR35902: Fix core never exiting with certain event patterns - LR35902: Fix pc overflowing current region off-by-one - - GB MBC: Fix ROM bank overflows getting set to bank 0 + - LR35902: Fix decoding LD r, $imm and 0-valued immediates (fixes mgba.io/i/735) + - OpenGL: Fix some shaders causing offset graphics + - GB Timer: Fix sub-M-cycle DIV reset timing and edge triggering + - Qt: Fix window icon being stretched + - Qt: Fix data directory path - Qt: Fix timing issues on high refresh rate monitors - - GBA Savedata: Fix savedata unmasking (fixes mgba.io/i/441) - - Util: Fix overflow when loading invalid UPS patches - - Tools: Fix recurring multiple times over the same library - - GBA I/O: Handle audio registers specially when deserializing - - Util: Fix highest-fd socket not being returned by SocketAccept - Qt: Fix linking after some windows have been closed - - GBA Video: Fix wrong palette on 256-color sprites in OBJWIN - - Windows: Fix VDir.rewind + - Qt: Fix crash when changing audio settings after a game is closed + - Qt: Ensure CLI backend is attached when submitting commands (fixes mgba.io/i/662) + - Qt: Disable "New multiplayer window" when MAX_GBAS is reached (fixes mgba.io/i/107) + - Qt: Fix game unpausing after frame advancing and refocusing - SDL: Fix game crash check - SDL: Fix race condition with audio thread when starting - - GB: Fix flickering when screen is strobed quickly - - FFmpeg: Fix overflow and general issues with audio encoding - - Qt: Fix crash when changing audio settings after a game is closed - - GBA BIOS: Fix ArcTan sign in HLE BIOS - - GBA BIOS: Fix ArcTan2 sign in HLE BIOS (fixes mgba.io/i/689) - - GBA Video: Don't update background scanline params in mode 0 (fixes mgba.io/i/377) - - Qt: Ensure CLI backend is attached when submitting commands (fixes mgba.io/i/662) - - Core: Fix crash with rewind if savestates shrink + - SDL: Fix showing version number - Test: Fix crash when loading invalid file - - GBA Hardware: Fix crash if a savestate lies about game hardware - Test: Fix crash when fuzzing fails to load a file - - GBA: Fix multiboot loading resulting in too small WRAM - Test: Don't rely on core for frames elapsed - Test: Fix crash when loading invalid file - - GBA Hardware: Fix crash if a savestate lies about game hardware - Test: Fix crash when fuzzing fails to load a file - - Qt: Disable "New multiplayer window" when MAX_GBAS is reached (fixes mgba.io/i/107) - - LR35902: Fix decoding LD r, $imm and 0-valued immediates (fixes mgba.io/i/735) - - GB: Fix STAT blocking - - GB MBC: Fix swapping carts not detect new MBC - - GB Timer: Fix DIV batching if TAC changes - - GB Video: Reset renderer when loading state - - GBA BIOS: Fix INT_MIN/-1 crash - - GBA Savedata: Update and fix Sharkport importing (fixes mgba.io/i/658) - - OpenGL: Fix some shaders causing offset graphics - - Qt: Fix game unpausing after frame advancing and refocusing - - GB Timer: Fix sub-M-cycle DIV reset timing and edge triggering - - Core: Fix interrupting a thread while on the thread (fixes mgba.io/i/692) - - Core: Fix directory sets crashing on close if base isn't properly detached - - Qt: Fix window icon being stretched - - Qt: Fix data directory path + - Tools: Fix recurring multiple times over the same library + - Util: Fix overflow when loading invalid UPS patches + - Util: Fix highest-fd socket not being returned by SocketAccept + - Windows: Fix VDir.rewind Misc: - - SDL: Remove scancode key input - - GBA Video: Clean up unused timers - - Test: Add a basic test suite - - GBA Video: Allow multiple handles into the same tile cache - - VFS: Call msync when syncing mapped data - - GBA Video, GB Video: Colors are now fully scaled - - VFS: Allow truncating memory chunk VFiles - - Debugger: Modularize CLI debugger + - All: Add C++ header guards + - All: Move time.h include to common.h + - 3DS, PSP2, Wii: Last directory loaded is saved + - CMake: Add ability to just print version string + - Core: New, faster event timing subsystem - Core: Clean up some thread state checks + - Core: Add generic checksum function + - Core: Cores can now have multiple sets of callbacks + - Core: Restore sleep callback + - Core: Move rewind diffing to its own thread + - Core: Ability to enumerate and modify video and audio channels + - Core: List memory segments in the core + - Core: Move savestate creation time to extdata + - Core: Config values can now be hexadecimal + - Core: Improved threading interrupted detection + - Debugger: Modularize CLI debugger - Debugger: Make building with debugging aspects optional - - GBA Memory: Support for Mo Jie Qi Bing by Vast Fame (taizou) - - GBA Memory: Support reading/writing POSTFLG - - Util: Add size counting to Table - - Qt: Move last directory setting from qt.ini to config.ini - - 3DS, PSP2, Wii: Last directory loaded is saved + - Debugger: Add functions for read- or write-only watchpoints + - Debugger: Make attaching a backend idempotent + - Debugger: Add mDebuggerRunFrame convenience function + - Feature: Move game database from flatfile to SQLite3 + - Feature: Support ImageMagick 7 + - Feature: Make -l option explicit + - FFmpeg: Return false if a file fails to open + - FFmpeg: Force MP4 files to YUV420P + - GB: Trust ROM header for number of SRAM banks (fixes mgba.io/i/726) + - GB: Reset with initial state of DIV register + - GB MBC: New MBC7 implementation - GB Audio: Simplify envelope code - GB Audio: Improve initial envelope samples - - Debugger: Add functions for read- or write-only watchpoints + - GB Audio: Start implementing "zombie" audio (fixes mgba.io/i/389) + - GB Video: Improved video timings + - GBA: Ignore invalid opcodes used by the Wii U VC emulator + - GBA, GB: ROM is now unloaded if a patch is applied - GBA DMA: Refactor DMA out of memory.c - GBA DMA: Move DMAs to using absolute timing - - All: Add C++ header guards - GBA I/O: Clear JOYSTAT RECV flag when reading JOY_RECV registers - GBA I/O: Set JOYSTAT TRANS flag when writing JOY_TRANS registers + - GBA Memory: Support for Mo Jie Qi Bing by Vast Fame (taizou) + - GBA Memory: Support reading/writing POSTFLG + - GBA Memory: Remove unused prefetch cruft + - GBA Timer: Improve accuracy of timers + - GBA Video: Clean up unused timers + - GBA Video: Allow multiple handles into the same tile cache + - GBA Video, GB Video: Colors are now fully scaled + - GBA Video: Optimize when BLD* registers are written frequently + - OpenGL: Add xBR-lv2 shader + - Qt: Move last directory setting from qt.ini to config.ini - Qt: Improved HiDPI support - Qt: Expose configuration directory - - Feature: Move game database from flatfile to SQLite3 - - GB Audio: Start implementing "zombie" audio (fixes mgba.io/i/389) - - VFS: Fix some minor VFile issues with FILEs - - Core: Add generic checksum function - - Feature: Support ImageMagick 7 - - All: Move time.h include to common.h - - CMake: Add ability to just print version string - Qt: Merge "Save" and "OK" buttons in shader options - - SDL: Automatically map controllers when plugged in - Qt: Automatically load controller profile when plugged in - - OpenGL: Add xBR-lv2 shader - - GBA, GB: ROM is now unloaded if a patch is applied - - Util: Add 8-bit PNG write support - Qt: Rename "Resample video" option to "Bilinear filtering" - - GBA Video: Optimize when BLD* registers are written frequently - - Core: Cores can now have multiple sets of callbacks - - GBA: Ignore invalid opcodes used by the Wii U VC emulator - Qt: Remove audio thread - Qt: Remove audio buffer sizing in AudioProcessorQt - Qt: Re-enable QtMultimedia on Windows - - FFmpeg: Return false if a file fails to open - - FFmpeg: Force MP4 files to YUV420P - Qt: Make "Mute" able to be bound to a key - - Core: Restore sleep callback - Qt: Add .gb/.gbc files to the extension list in Info.plist - - Feature: Make -l option explicit - - Core: Ability to enumerate and modify video and audio channels - - Debugger: Make attaching a backend idempotent + - Qt: Relax hard dependency on OpenGL + - Qt: Better highlight active key in control binding + - SDL: Remove scancode key input + - SDL: Automatically map controllers when plugged in + - Test: Add a basic test suite + - Util: Add size counting to Table + - Util: Add 8-bit PNG write support + - Util: Tune patch-fast extent sizes + - VFS: Call msync when syncing mapped data + - VFS: Allow truncating memory chunk VFiles + - VFS: Fix some minor VFile issues with FILEs - VFS: Optimize expanding in-memory files - VFS: Add VFileFIFO for operating on circle buffers - - Core: Move rewind diffing to its own thread - - Util: Tune patch-fast extent sizes - - Qt: Relax hard dependency on OpenGL - - GB Video: Improved video timings - - Core: List memory segments in the core - - Core: Move savestate creation time to extdata - - Debugger: Add mDebuggerRunFrame convenience function - - GBA Memory: Remove unused prefetch cruft - - GB: Trust ROM header for number of SRAM banks (fixes mgba.io/i/726) - - Core: Config values can now be hexadecimal - - GB: Reset with initial state of DIV register - - GB MBC: New MBC7 implementation - - Qt: Better highlight active key in control binding - - Core: Improved threading interrupted detection - - GBA Timer: Improve accuracy of timers - -0.6 beta 2: (Future) +Changes from beta 1: Features: - Qt: Italian translation (by theheroGAC) - Qt: Updated German translation Bugfixes: + - GB Audio: Fix incorrect channel 4 iteration + - GB Audio: Fix zombie mode bit masking + - GB Serialize: Fix timer serialization + - GB Video: Fix LYC regression + - GBA SIO: Improve SIO Normal dummy driver (fixes mgba.io/i/520) + - GBA Timer: Fix count-up timing overflowing timer 3 + - PSP2: Use custom localtime_r since newlib version is broken (fixes mgba.io/i/560) - Qt: Fix memory search close button (fixes mgba.io/i/769) - Qt: Fix window icon being stretched - Qt: Fix initial window size (fixes mgba.io/i/766) - Qt: Fix data directory path - Qt: Fix controls not saving on non-SDL builds - - GB Video: Fix LYC regression - Qt: Fix translation initialization (fixes mgba.io/i/776) - - PSP2: Use custom localtime_r since newlib version is broken (fixes mgba.io/i/560) + - Qt: Fix patch loading while a game is running + - Qt: Fix shader selector on Ubuntu (fixes mgba.io/i/767) + - Core: Fix rewinding getting out of sync (fixes mgba.io/i/791) + - Qt: Fix GL-less build + - Qt: Fix Software renderer not handling alpha bits properly Misc: - - Qt: Add language selector + - GB Serialize: Add MBC state serialization + - GBA Memory: Call crash callbacks regardless of if hard crash is enabled - GBA Timer: Improve accuracy of timers + - PSP2: Update toolchain to use vita.cmake + - Qt: Add language selector - Qt: Minor test fixes - - PSP2: Update toolchain to use vita.cmake + - Qt: Move shader settings into main settings window + - Qt: Dismiss game crashing/failing dialogs when a new game loads + - Qt: Properly ship Qt translations + - SDL: Remove writing back obtained samples (fixes mgba.io/i/768) 0.6 beta 1: (2017-06-29) - Initial beta for 0.6
@@ -20,6 +20,7 @@ set(M_CORE_GBA ON CACHE BOOL "Build Game Boy Advance core")
set(M_CORE_GB ON CACHE BOOL "Build Game Boy core") set(M_CORE_DS ON CACHE BOOL "Build DS core") set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support") +set(ENABLE_SCRIPTING ON CACHE BOOL "Whether or not to enable scripting support") set(BUILD_QT ON CACHE BOOL "Build Qt frontend") set(BUILD_SDL ON CACHE BOOL "Build SDL frontend") set(BUILD_LIBRETRO OFF CACHE BOOL "Build libretro core")@@ -258,6 +259,10 @@
if(DEFINED 3DS OR DEFINED PSP2 OR DEFINED WII) set(USE_DEBUGGERS OFF) set(USE_SQLITE3 OFF) +endif() + +if(DEFINED 3DS OR DEFINED WII) + add_definitions(-DFIXED_ROM_BUFFER) endif() if(NOT M_CORE_GBA)@@ -354,6 +359,7 @@
# Feature dependencies set(FEATURE_DEFINES) set(FEATURES) +set(ENABLES) if(CMAKE_SYSTEM_NAME MATCHES .*BSD) set(LIBEDIT_LIBRARIES -ledit) if (CMAKE_SYSTEM_NAME STREQUAL OpenBSD)@@ -396,6 +402,7 @@ find_feature(USE_MAGICK "MagickWand")
find_feature(USE_EPOXY "epoxy") find_feature(USE_CMOCKA "cmocka") find_feature(USE_SQLITE3 "sqlite3") +find_feature(ENABLE_PYTHON "PythonLibs") # Features set(DEBUGGER_SRC@@ -611,6 +618,18 @@ include_directories(AFTER ${SQLITE3_INCLUDE_DIRS})
list(APPEND DEPENDENCY_LIB ${SQLITE3_LIBRARIES}) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libsqlite3-0") list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/sqlite3/no-intro.c") +endif() + +if(ENABLE_SCRIPTING) + list(APPEND ENABLES SCRIPTING) + + if(BUILD_PYTHON) + find_program(PYTHON python) + include(FindPythonLibs) + list(APPEND DEPENDENCY_LIB ${PYTHON_LIBRARIES}) + include_directories(AFTER ${PYTHON_INCLUDE_DIRS}) + list(APPEND ENABLES PYTHON) + endif() endif() set(TEST_SRC ${CORE_TEST_SRC})@@ -673,6 +692,10 @@ foreach(FEATURE IN LISTS FEATURES)
list(APPEND FEATURE_DEFINES "USE_${FEATURE}") endforeach() +foreach(ENABLE IN LISTS ENABLES) + list(APPEND FEATURE_DEFINES "ENABLE_${ENABLE}") +endforeach() + source_group("Virtual files" FILES ${CORE_VFS_SRC} ${VFS_SRC}) source_group("Extra features" FILES ${FEATURE_SRC}) source_group("Third-party code" FILES ${THIRD_PARTY_SRC})@@ -749,7 +772,7 @@ set_target_properties(${BINARY_NAME} PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_ABI} COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
target_link_libraries(${BINARY_NAME} ${DEBUGGER_LIB} ${DEPENDENCY_LIB} ${OS_LIB}) install(TARGETS ${BINARY_NAME} LIBRARY DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME} NAMELINK_SKIP ARCHIVE DESTINATION ${LIBDIR} RUNTIME DESTINATION ${LIBDIR} COMPONENT lib${BINARY_NAME}) - if(UNIX AND NOT APPLE) + if(UNIX AND NOT APPLE AND NOT HAIKU) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/${BINARY_NAME}-16.png DESTINATION share/icons/hicolor/16x16/apps RENAME ${BINARY_NAME}.png COMPONENT lib${BINARY_NAME}) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/${BINARY_NAME}-24.png DESTINATION share/icons/hicolor/24x24/apps RENAME ${BINARY_NAME}.png COMPONENT lib${BINARY_NAME}) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/res/${BINARY_NAME}-32.png DESTINATION share/icons/hicolor/32x32/apps RENAME ${BINARY_NAME}.png COMPONENT lib${BINARY_NAME})@@ -785,6 +808,11 @@ set(BUILD_SDL OFF)
set(BUILD_QT OFF) endif() +if(BUILD_PYTHON) + enable_testing() + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/python ${CMAKE_CURRENT_BINARY_DIR}/python) +endif() + if(BUILD_LIBRETRO) file(GLOB RETRO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/libretro/*.c) add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC})@@ -857,11 +885,6 @@ set_target_properties(${BINARY_NAME}-suite PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}")
add_test(${BINARY_NAME}-suite ${BINARY_NAME}-suite) endif() -if(BUILD_PYTHON) - enable_testing() - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/platform/python ${CMAKE_CURRENT_BINARY_DIR}/python) -endif() - if(BUILD_EXAMPLE) add_executable(${BINARY_NAME}-example-server ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/example/client-server/server.c) target_link_libraries(${BINARY_NAME}-example-server ${BINARY_NAME})@@ -877,7 +900,7 @@ endif()
endif() 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 include/mgba COMPONENT lib${BINARY_NAME}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/flags.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mgba COMPONENT lib${BINARY_NAME}) # Packaging set(CPACK_PACKAGE_VERSION ${VERSION_STRING})
@@ -31,6 +31,7 @@ bool onThread;
Thread thread; Condition cond; Mutex mutex; + bool ready; #endif };
@@ -0,0 +1,49 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_SCRIPTING_H +#define M_SCRIPTING_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +#ifdef USE_DEBUGGERS +#include <mgba/debugger/debugger.h> +#endif + +struct mScriptBridge; +struct VFile; +struct mScriptEngine { + const char* (*name)(struct mScriptEngine*); + + bool (*init)(struct mScriptEngine*, struct mScriptBridge*); + void (*deinit)(struct mScriptEngine*); + bool (*isScript)(struct mScriptEngine*, const char* name, struct VFile* vf); + bool (*loadScript)(struct mScriptEngine*, const char* name, struct VFile* vf); + void (*run)(struct mScriptEngine*); + +#ifdef USE_DEBUGGERS + void (*debuggerEntered)(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); +#endif +}; + +struct mScriptBridge* mScriptBridgeCreate(void); +void mScriptBridgeDestroy(struct mScriptBridge*); + +void mScriptBridgeInstallEngine(struct mScriptBridge*, struct mScriptEngine*); + +#ifdef USE_DEBUGGERS +void mScriptBridgeSetDebugger(struct mScriptBridge*, struct mDebugger*); +struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge*); +void mScriptBridgeDebuggerEntered(struct mScriptBridge*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); +#endif + +void mScriptBridgeRun(struct mScriptBridge*); +bool mScriptBridgeLoadScript(struct mScriptBridge*, const char* name); + +CXX_GUARD_END + +#endif
@@ -11,15 +11,40 @@
CXX_GUARD_START #include <mgba/core/log.h> -#include <mgba/core/rewind.h> -#include <mgba/core/sync.h> -#include <mgba-util/threading.h> struct mCoreThread; struct mCore; typedef void (*ThreadCallback)(struct mCoreThread* threadContext); +struct mCoreThread; +struct mThreadLogger { + struct mLogger d; + struct mCoreThread* p; +}; + +struct mCoreThreadInternal; +struct mCoreThread { + // Input + struct mCore* core; + + struct mThreadLogger logger; + ThreadCallback startCallback; + ThreadCallback resetCallback; + ThreadCallback cleanCallback; + ThreadCallback frameCallback; + ThreadCallback sleepCallback; + void* userData; + void (*run)(struct mCoreThread*); + + struct mCoreThreadInternal* impl; +}; + +#ifndef OPAQUE_THREADING +#include <mgba/core/rewind.h> +#include <mgba/core/sync.h> +#include <mgba-util/threading.h> + enum mCoreThreadState { THREAD_INITIALIZED = -1, THREAD_RUNNING = 0,@@ -37,17 +62,7 @@ THREAD_SHUTDOWN,
THREAD_CRASHED }; -struct mCoreThread; -struct mThreadLogger { - struct mLogger d; - struct mCoreThread* p; -}; - -struct mCoreThread { - // Input - struct mCore* core; - - // Threading state +struct mCoreThreadInternal { Thread thread; enum mCoreThreadState state;@@ -57,18 +72,11 @@ enum mCoreThreadState savedState;
int interruptDepth; bool frameWasOn; - struct mThreadLogger logger; - ThreadCallback startCallback; - ThreadCallback resetCallback; - ThreadCallback cleanCallback; - ThreadCallback frameCallback; - ThreadCallback sleepCallback; - void* userData; - void (*run)(struct mCoreThread*); - struct mCoreSync sync; struct mCoreRewindContext rewind; }; + +#endif bool mCoreThreadStart(struct mCoreThread* threadContext); bool mCoreThreadHasStarted(struct mCoreThread* threadContext);
@@ -92,6 +92,7 @@ struct mCPUComponent d;
struct mDebuggerPlatform* platform; enum mDebuggerState state; struct mCore* core; + struct mScriptBridge* bridge; void (*init)(struct mDebugger*); void (*deinit)(struct mDebugger*);
@@ -18,6 +18,7 @@ struct GB;
struct GBMemory; void GBMBCInit(struct GB* gb); void GBMBCSwitchBank(struct GB* gb, int bank); +void GBMBCSwitchBank0(struct GB* gb, int bank); void GBMBCSwitchSramBank(struct GB* gb, int bank); struct GBMBCRTCSaveBuffer {
@@ -145,7 +145,7 @@ * | 0x0017A - 0x0017B: Next HDMA destination
* | 0x0017C - 0x0017D: HDMA remaining * | 0x0017E: DMA remaining * | 0x0017F - 0x00183: RTC registers - * | 0x00184 - 0x00193: MBC state (TODO) + * | 0x00184 - 0x00193: MBC state * | 0x00194 - 0x00195: Flags * | bit 0: SRAM accessable * | bit 1: RTC accessible@@ -331,18 +331,21 @@ uint8_t rtcRegs[5];
union { struct { - uint32_t mode; + uint8_t mode; + uint8_t multicartStride; } mbc1; struct { uint64_t lastLatch; } rtc; struct { - int8_t machineState; - GBMBC7Field field; - int8_t address; + uint8_t state; + GBMBC7Field eeprom; + uint8_t address; + uint8_t access; + uint8_t latch; uint8_t srBits; - uint32_t sr; - GBSerializedMBC7Flags flags; + uint16_t sr; + uint32_t writable; } mbc7; struct { uint8_t reserved[16];
@@ -30,6 +30,7 @@ context->size = 0;
context->stateFlags = SAVESTATE_SAVEDATA; #ifndef DISABLE_THREADING context->onThread = onThread; + context->ready = false; if (onThread) { MutexInit(&context->mutex); ConditionInit(&context->cond);@@ -73,6 +74,7 @@ context->previousState = context->currentState;
context->currentState = nextState; #ifndef DISABLE_THREADING if (context->onThread) { + context->ready = true; ConditionWake(&context->cond); MutexUnlock(&context->mutex); return;@@ -121,6 +123,12 @@ return false;
} --context->size; + mCoreLoadStateNamed(core, context->previousState, context->stateFlags); + if (context->current == 0) { + context->current = mCoreRewindPatchesSize(&context->patchMemory); + } + --context->current; + struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current); size_t size2 = context->previousState->size(context->previousState); size_t size = context->currentState->size(context->currentState);@@ -129,18 +137,12 @@ size = size2;
} void* current = context->currentState->map(context->currentState, size, MAP_READ); void* previous = context->previousState->map(context->previousState, size, MAP_WRITE); - patch->d.applyPatch(&patch->d, current, size, previous, size); + patch->d.applyPatch(&patch->d, previous, size, current, size); context->currentState->unmap(context->currentState, current, size); context->previousState->unmap(context->previousState, previous, size); - mCoreLoadStateNamed(core, context->previousState, context->stateFlags); struct VFile* nextState = context->previousState; context->previousState = context->currentState; context->currentState = nextState; - - if (context->current == 0) { - context->current = mCoreRewindPatchesSize(&context->patchMemory); - } - --context->current; #ifndef DISABLE_THREADING if (context->onThread) { MutexUnlock(&context->mutex);@@ -154,13 +156,14 @@ THREAD_ENTRY _rewindThread(void* context) {
struct mCoreRewindContext* rewindContext = context; ThreadSetName("Rewind Diff Thread"); MutexLock(&rewindContext->mutex); - struct VFile* state = rewindContext->currentState; while (rewindContext->onThread) { - if (rewindContext->currentState != state) { + while (!rewindContext->ready && rewindContext->onThread) { + ConditionWait(&rewindContext->cond, &rewindContext->mutex); + } + if (rewindContext->ready) { _rewindDiff(rewindContext); - state = rewindContext->currentState; } - ConditionWait(&rewindContext->cond, &rewindContext->mutex); + rewindContext->ready = false; } MutexUnlock(&rewindContext->mutex); return 0;
@@ -0,0 +1,113 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <mgba/core/scripting.h> + +#include <mgba-util/table.h> +#include <mgba-util/vfs.h> + +struct mScriptBridge { + struct Table engines; + struct mDebugger* debugger; +}; + +struct mScriptInfo { + const char* name; + struct VFile* vf; + bool success; +}; + +static void _seDeinit(void* value) { + struct mScriptEngine* se = value; + se->deinit(se); +} + +static void _seTryLoad(const char* key, void* value, void* user) { + UNUSED(key); + struct mScriptEngine* se = value; + struct mScriptInfo* si = user; + if (!si->success && se->isScript(se, si->name, si->vf)) { + si->success = se->loadScript(se, si->name, si->vf); + } +} + +static void _seRun(const char* key, void* value, void* user) { + UNUSED(key); + UNUSED(user); + struct mScriptEngine* se = value; + se->run(se); +} + +#ifdef USE_DEBUGGERS +struct mScriptDebuggerEntry { + enum mDebuggerEntryReason reason; + struct mDebuggerEntryInfo* info; +}; + +static void _seDebuggerEnter(const char* key, void* value, void* user) { + UNUSED(key); + struct mScriptEngine* se = value; + struct mScriptDebuggerEntry* entry = user; + se->debuggerEntered(se, entry->reason, entry->info); +} +#endif + +struct mScriptBridge* mScriptBridgeCreate(void) { + struct mScriptBridge* sb = malloc(sizeof(*sb)); + HashTableInit(&sb->engines, 0, _seDeinit); + sb->debugger = NULL; + return sb; +} + +void mScriptBridgeDestroy(struct mScriptBridge* sb) { + HashTableDeinit(&sb->engines); + free(sb); +} + +void mScriptBridgeInstallEngine(struct mScriptBridge* sb, struct mScriptEngine* se) { + if (!se->init(se, sb)) { + return; + } + const char* name = se->name(se); + HashTableInsert(&sb->engines, name, se); +} + +#ifdef USE_DEBUGGERS +void mScriptBridgeSetDebugger(struct mScriptBridge* sb, struct mDebugger* debugger) { + sb->debugger = debugger; + debugger->bridge = sb; +} + +struct mDebugger* mScriptBridgeGetDebugger(struct mScriptBridge* sb) { + return sb->debugger; +} + +void mScriptBridgeDebuggerEntered(struct mScriptBridge* sb, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { + struct mScriptDebuggerEntry entry = { + .reason = reason, + .info = info + }; + HashTableEnumerate(&sb->engines, _seDebuggerEnter, &entry); +} +#endif + +void mScriptBridgeRun(struct mScriptBridge* sb) { + HashTableEnumerate(&sb->engines, _seRun, NULL); +} + +bool mScriptBridgeLoadScript(struct mScriptBridge* sb, const char* name) { + struct VFile* vf = VFileOpen(name, O_RDONLY); + if (!vf) { + return false; + } + struct mScriptInfo info = { + .name = name, + .vf = vf, + .success = false + }; + HashTableEnumerate(&sb->engines, _seTryLoad, &info); + vf->close(vf); + return info.success; +}
@@ -38,7 +38,7 @@ #endif
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args); -static void _changeState(struct mCoreThread* threadContext, enum mCoreThreadState newState, bool broadcast) { +static void _changeState(struct mCoreThreadInternal* threadContext, enum mCoreThreadState newState, bool broadcast) { MutexLock(&threadContext->stateMutex); threadContext->state = newState; if (broadcast) {@@ -47,13 +47,13 @@ }
MutexUnlock(&threadContext->stateMutex); } -static void _waitOnInterrupt(struct mCoreThread* threadContext) { +static void _waitOnInterrupt(struct mCoreThreadInternal* threadContext) { while (threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) { ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); } } -static void _waitUntilNotState(struct mCoreThread* threadContext, enum mCoreThreadState oldState) { +static void _waitUntilNotState(struct mCoreThreadInternal* threadContext, enum mCoreThreadState oldState) { MutexLock(&threadContext->sync.videoFrameMutex); bool videoFrameWait = threadContext->sync.videoFrameWait; threadContext->sync.videoFrameWait = false;@@ -81,7 +81,7 @@ threadContext->sync.videoFrameWait = videoFrameWait;
MutexUnlock(&threadContext->sync.videoFrameMutex); } -static void _pauseThread(struct mCoreThread* threadContext) { +static void _pauseThread(struct mCoreThreadInternal* threadContext) { threadContext->state = THREAD_PAUSING; _waitUntilNotState(threadContext, THREAD_PAUSING); }@@ -92,11 +92,11 @@ if (!thread) {
return; } if (thread->core->opts.rewindEnable && thread->core->opts.rewindBufferCapacity > 0) { - if (thread->state != THREAD_REWINDING) { - mCoreRewindAppend(&thread->rewind, thread->core); - } else if (thread->state == THREAD_REWINDING) { - if (!mCoreRewindRestore(&thread->rewind, thread->core)) { - mCoreRewindAppend(&thread->rewind, thread->core); + if (thread->impl->state != THREAD_REWINDING) { + mCoreRewindAppend(&thread->impl->rewind, thread->core); + } else if (thread->impl->state == THREAD_REWINDING) { + if (!mCoreRewindRestore(&thread->impl->rewind, thread->core)) { + mCoreRewindAppend(&thread->impl->rewind, thread->core); } } }@@ -117,7 +117,7 @@ struct mCoreThread* thread = context;
if (!thread) { return; } - _changeState(thread, THREAD_CRASHED, true); + _changeState(thread->impl, THREAD_CRASHED, true); } void _coreSleep(void* context) {@@ -157,7 +157,7 @@ .sleep = _coreSleep,
.context = threadContext }; core->addCoreCallbacks(core, &callbacks); - core->setSync(core, &threadContext->sync); + core->setSync(core, &threadContext->impl->sync); core->reset(core); struct mLogFilter filter;@@ -168,11 +168,11 @@ mLogFilterLoad(threadContext->logger.d.filter, &core->config);
} if (core->opts.rewindEnable && core->opts.rewindBufferCapacity > 0) { - mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity, true); - threadContext->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0; + mCoreRewindContextInit(&threadContext->impl->rewind, core->opts.rewindBufferCapacity, true); + threadContext->impl->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0; } - _changeState(threadContext, THREAD_RUNNING, true); + _changeState(threadContext->impl, THREAD_RUNNING, true); if (threadContext->startCallback) { threadContext->startCallback(threadContext);@@ -181,49 +181,50 @@ if (threadContext->resetCallback) {
threadContext->resetCallback(threadContext); } - while (threadContext->state < THREAD_EXITING) { + struct mCoreThreadInternal* impl = threadContext->impl; + while (impl->state < THREAD_EXITING) { #ifdef USE_DEBUGGERS struct mDebugger* debugger = core->debugger; if (debugger) { mDebuggerRun(debugger); if (debugger->state == DEBUGGER_SHUTDOWN) { - _changeState(threadContext, THREAD_EXITING, false); + _changeState(impl, THREAD_EXITING, false); } } else #endif { - while (threadContext->state <= THREAD_MAX_RUNNING) { + while (impl->state <= THREAD_MAX_RUNNING) { core->runLoop(core); } } int resetScheduled = 0; - MutexLock(&threadContext->stateMutex); - while (threadContext->state > THREAD_MAX_RUNNING && threadContext->state < THREAD_EXITING) { - if (threadContext->state == THREAD_PAUSING) { - threadContext->state = THREAD_PAUSED; - ConditionWake(&threadContext->stateCond); + MutexLock(&impl->stateMutex); + while (impl->state > THREAD_MAX_RUNNING && impl->state < THREAD_EXITING) { + if (impl->state == THREAD_PAUSING) { + impl->state = THREAD_PAUSED; + ConditionWake(&impl->stateCond); } - if (threadContext->state == THREAD_INTERRUPTING) { - threadContext->state = THREAD_INTERRUPTED; - ConditionWake(&threadContext->stateCond); + if (impl->state == THREAD_INTERRUPTING) { + impl->state = THREAD_INTERRUPTED; + ConditionWake(&impl->stateCond); } - if (threadContext->state == THREAD_RUN_ON) { + if (impl->state == THREAD_RUN_ON) { if (threadContext->run) { threadContext->run(threadContext); } - threadContext->state = threadContext->savedState; - ConditionWake(&threadContext->stateCond); + impl->state = impl->savedState; + ConditionWake(&impl->stateCond); } - if (threadContext->state == THREAD_RESETING) { - threadContext->state = THREAD_RUNNING; + if (impl->state == THREAD_RESETING) { + impl->state = THREAD_RUNNING; resetScheduled = 1; } - while (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_WAITING) { - ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); + while (impl->state == THREAD_PAUSED || impl->state == THREAD_INTERRUPTED || impl->state == THREAD_WAITING) { + ConditionWait(&impl->stateCond, &impl->stateMutex); } } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&impl->stateMutex); if (resetScheduled) { core->reset(core); if (threadContext->resetCallback) {@@ -232,12 +233,12 @@ }
} } - while (threadContext->state < THREAD_SHUTDOWN) { - _changeState(threadContext, THREAD_SHUTDOWN, false); + while (impl->state < THREAD_SHUTDOWN) { + _changeState(impl, THREAD_SHUTDOWN, false); } if (core->opts.rewindEnable) { - mCoreRewindContextDeinit(&threadContext->rewind); + mCoreRewindContextDeinit(&impl->rewind); } if (threadContext->cleanCallback) {@@ -251,27 +252,28 @@ return 0;
} bool mCoreThreadStart(struct mCoreThread* threadContext) { - threadContext->state = THREAD_INITIALIZED; + threadContext->impl = malloc(sizeof(*threadContext->impl)); + threadContext->impl->state = THREAD_INITIALIZED; threadContext->logger.p = threadContext; if (!threadContext->logger.d.log) { threadContext->logger.d.log = _mCoreLog; threadContext->logger.d.filter = NULL; } - if (!threadContext->sync.fpsTarget) { - threadContext->sync.fpsTarget = _defaultFPSTarget; + if (!threadContext->impl->sync.fpsTarget) { + threadContext->impl->sync.fpsTarget = _defaultFPSTarget; } - MutexInit(&threadContext->stateMutex); - ConditionInit(&threadContext->stateCond); + MutexInit(&threadContext->impl->stateMutex); + ConditionInit(&threadContext->impl->stateCond); - MutexInit(&threadContext->sync.videoFrameMutex); - ConditionInit(&threadContext->sync.videoFrameAvailableCond); - ConditionInit(&threadContext->sync.videoFrameRequiredCond); - MutexInit(&threadContext->sync.audioBufferMutex); - ConditionInit(&threadContext->sync.audioRequiredCond); + MutexInit(&threadContext->impl->sync.videoFrameMutex); + ConditionInit(&threadContext->impl->sync.videoFrameAvailableCond); + ConditionInit(&threadContext->impl->sync.videoFrameRequiredCond); + MutexInit(&threadContext->impl->sync.audioBufferMutex); + ConditionInit(&threadContext->impl->sync.audioRequiredCond); - threadContext->interruptDepth = 0; + threadContext->impl->interruptDepth = 0; #ifdef USE_PTHREADS sigset_t signals;@@ -281,271 +283,289 @@ sigaddset(&signals, SIGTRAP);
pthread_sigmask(SIG_BLOCK, &signals, 0); #endif - threadContext->sync.audioWait = threadContext->core->opts.audioSync; - threadContext->sync.videoFrameWait = threadContext->core->opts.videoSync; - threadContext->sync.fpsTarget = threadContext->core->opts.fpsTarget; + threadContext->impl->sync.audioWait = threadContext->core->opts.audioSync; + threadContext->impl->sync.videoFrameWait = threadContext->core->opts.videoSync; + threadContext->impl->sync.fpsTarget = threadContext->core->opts.fpsTarget; - MutexLock(&threadContext->stateMutex); - ThreadCreate(&threadContext->thread, _mCoreThreadRun, threadContext); - while (threadContext->state < THREAD_RUNNING) { - ConditionWait(&threadContext->stateCond, &threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); + ThreadCreate(&threadContext->impl->thread, _mCoreThreadRun, threadContext); + while (threadContext->impl->state < THREAD_RUNNING) { + ConditionWait(&threadContext->impl->stateCond, &threadContext->impl->stateMutex); } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); return true; } bool mCoreThreadHasStarted(struct mCoreThread* threadContext) { + if (!threadContext->impl) { + return false; + } bool hasStarted; - MutexLock(&threadContext->stateMutex); - hasStarted = threadContext->state > THREAD_INITIALIZED; - MutexUnlock(&threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); + hasStarted = threadContext->impl->state > THREAD_INITIALIZED; + MutexUnlock(&threadContext->impl->stateMutex); return hasStarted; } bool mCoreThreadHasExited(struct mCoreThread* threadContext) { + if (!threadContext->impl) { + return false; + } bool hasExited; - MutexLock(&threadContext->stateMutex); - hasExited = threadContext->state > THREAD_EXITING; - MutexUnlock(&threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); + hasExited = threadContext->impl->state > THREAD_EXITING; + MutexUnlock(&threadContext->impl->stateMutex); return hasExited; } bool mCoreThreadHasCrashed(struct mCoreThread* threadContext) { + if (!threadContext->impl) { + return false; + } bool hasExited; - MutexLock(&threadContext->stateMutex); - hasExited = threadContext->state == THREAD_CRASHED; - MutexUnlock(&threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); + hasExited = threadContext->impl->state == THREAD_CRASHED; + MutexUnlock(&threadContext->impl->stateMutex); return hasExited; } void mCoreThreadMarkCrashed(struct mCoreThread* threadContext) { - MutexLock(&threadContext->stateMutex); - threadContext->state = THREAD_CRASHED; - MutexUnlock(&threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); + threadContext->impl->state = THREAD_CRASHED; + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadEnd(struct mCoreThread* threadContext) { - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - threadContext->state = THREAD_EXITING; - ConditionWake(&threadContext->stateCond); - MutexUnlock(&threadContext->stateMutex); - MutexLock(&threadContext->sync.audioBufferMutex); - threadContext->sync.audioWait = 0; - ConditionWake(&threadContext->sync.audioRequiredCond); - MutexUnlock(&threadContext->sync.audioBufferMutex); + MutexLock(&threadContext->impl->stateMutex); + _waitOnInterrupt(threadContext->impl); + threadContext->impl->state = THREAD_EXITING; + ConditionWake(&threadContext->impl->stateCond); + MutexUnlock(&threadContext->impl->stateMutex); + MutexLock(&threadContext->impl->sync.audioBufferMutex); + threadContext->impl->sync.audioWait = 0; + ConditionWake(&threadContext->impl->sync.audioRequiredCond); + MutexUnlock(&threadContext->impl->sync.audioBufferMutex); - MutexLock(&threadContext->sync.videoFrameMutex); - threadContext->sync.videoFrameWait = false; - threadContext->sync.videoFrameOn = false; - ConditionWake(&threadContext->sync.videoFrameRequiredCond); - ConditionWake(&threadContext->sync.videoFrameAvailableCond); - MutexUnlock(&threadContext->sync.videoFrameMutex); + MutexLock(&threadContext->impl->sync.videoFrameMutex); + threadContext->impl->sync.videoFrameWait = false; + threadContext->impl->sync.videoFrameOn = false; + ConditionWake(&threadContext->impl->sync.videoFrameRequiredCond); + ConditionWake(&threadContext->impl->sync.videoFrameAvailableCond); + MutexUnlock(&threadContext->impl->sync.videoFrameMutex); } void mCoreThreadReset(struct mCoreThread* threadContext) { - MutexLock(&threadContext->stateMutex); - if (threadContext->state == THREAD_INTERRUPTED || threadContext->state == THREAD_INTERRUPTING) { - threadContext->savedState = THREAD_RESETING; + MutexLock(&threadContext->impl->stateMutex); + if (threadContext->impl->state == THREAD_INTERRUPTED || threadContext->impl->state == THREAD_INTERRUPTING) { + threadContext->impl->savedState = THREAD_RESETING; } else { - threadContext->state = THREAD_RESETING; + threadContext->impl->state = THREAD_RESETING; } - ConditionWake(&threadContext->stateCond); - MutexUnlock(&threadContext->stateMutex); + ConditionWake(&threadContext->impl->stateCond); + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadJoin(struct mCoreThread* threadContext) { - ThreadJoin(threadContext->thread); + if (!threadContext->impl) { + return; + } + ThreadJoin(threadContext->impl->thread); - MutexDeinit(&threadContext->stateMutex); - ConditionDeinit(&threadContext->stateCond); + MutexDeinit(&threadContext->impl->stateMutex); + ConditionDeinit(&threadContext->impl->stateCond); - MutexDeinit(&threadContext->sync.videoFrameMutex); - ConditionWake(&threadContext->sync.videoFrameAvailableCond); - ConditionDeinit(&threadContext->sync.videoFrameAvailableCond); - ConditionWake(&threadContext->sync.videoFrameRequiredCond); - ConditionDeinit(&threadContext->sync.videoFrameRequiredCond); + MutexDeinit(&threadContext->impl->sync.videoFrameMutex); + ConditionWake(&threadContext->impl->sync.videoFrameAvailableCond); + ConditionDeinit(&threadContext->impl->sync.videoFrameAvailableCond); + ConditionWake(&threadContext->impl->sync.videoFrameRequiredCond); + ConditionDeinit(&threadContext->impl->sync.videoFrameRequiredCond); - ConditionWake(&threadContext->sync.audioRequiredCond); - ConditionDeinit(&threadContext->sync.audioRequiredCond); - MutexDeinit(&threadContext->sync.audioBufferMutex); + ConditionWake(&threadContext->impl->sync.audioRequiredCond); + ConditionDeinit(&threadContext->impl->sync.audioRequiredCond); + MutexDeinit(&threadContext->impl->sync.audioBufferMutex); + + free(threadContext->impl); + threadContext->impl = NULL; } bool mCoreThreadIsActive(struct mCoreThread* threadContext) { - return threadContext->state >= THREAD_RUNNING && threadContext->state < THREAD_EXITING; + if (!threadContext->impl) { + return false; + } + return threadContext->impl->state >= THREAD_RUNNING && threadContext->impl->state < THREAD_EXITING; } void mCoreThreadInterrupt(struct mCoreThread* threadContext) { if (!threadContext) { return; } - MutexLock(&threadContext->stateMutex); - ++threadContext->interruptDepth; - if (threadContext->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { - MutexUnlock(&threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); + ++threadContext->impl->interruptDepth; + if (threadContext->impl->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { + MutexUnlock(&threadContext->impl->stateMutex); return; } - threadContext->savedState = threadContext->state; - _waitOnInterrupt(threadContext); - threadContext->state = THREAD_INTERRUPTING; - ConditionWake(&threadContext->stateCond); - _waitUntilNotState(threadContext, THREAD_INTERRUPTING); - MutexUnlock(&threadContext->stateMutex); + threadContext->impl->savedState = threadContext->impl->state; + _waitOnInterrupt(threadContext->impl); + threadContext->impl->state = THREAD_INTERRUPTING; + ConditionWake(&threadContext->impl->stateCond); + _waitUntilNotState(threadContext->impl, THREAD_INTERRUPTING); + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadInterruptFromThread(struct mCoreThread* threadContext) { if (!threadContext) { return; } - MutexLock(&threadContext->stateMutex); - ++threadContext->interruptDepth; - if (threadContext->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { - if (threadContext->state == THREAD_INTERRUPTING) { - threadContext->state = THREAD_INTERRUPTED; + MutexLock(&threadContext->impl->stateMutex); + ++threadContext->impl->interruptDepth; + if (threadContext->impl->interruptDepth > 1 || !mCoreThreadIsActive(threadContext)) { + if (threadContext->impl->state == THREAD_INTERRUPTING) { + threadContext->impl->state = THREAD_INTERRUPTED; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); return; } - threadContext->savedState = threadContext->state; - threadContext->state = THREAD_INTERRUPTED; - ConditionWake(&threadContext->stateCond); - MutexUnlock(&threadContext->stateMutex); + threadContext->impl->savedState = threadContext->impl->state; + threadContext->impl->state = THREAD_INTERRUPTING; + ConditionWake(&threadContext->impl->stateCond); + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadContinue(struct mCoreThread* threadContext) { if (!threadContext) { return; } - MutexLock(&threadContext->stateMutex); - --threadContext->interruptDepth; - if (threadContext->interruptDepth < 1 && mCoreThreadIsActive(threadContext)) { - threadContext->state = threadContext->savedState; - ConditionWake(&threadContext->stateCond); + MutexLock(&threadContext->impl->stateMutex); + --threadContext->impl->interruptDepth; + if (threadContext->impl->interruptDepth < 1 && mCoreThreadIsActive(threadContext)) { + threadContext->impl->state = threadContext->impl->savedState; + ConditionWake(&threadContext->impl->stateCond); } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadRunFunction(struct mCoreThread* threadContext, void (*run)(struct mCoreThread*)) { - MutexLock(&threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); threadContext->run = run; - _waitOnInterrupt(threadContext); - threadContext->savedState = threadContext->state; - threadContext->state = THREAD_RUN_ON; - ConditionWake(&threadContext->stateCond); - _waitUntilNotState(threadContext, THREAD_RUN_ON); - MutexUnlock(&threadContext->stateMutex); + _waitOnInterrupt(threadContext->impl); + threadContext->impl->savedState = threadContext->impl->state; + threadContext->impl->state = THREAD_RUN_ON; + ConditionWake(&threadContext->impl->stateCond); + _waitUntilNotState(threadContext->impl, THREAD_RUN_ON); + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadPause(struct mCoreThread* threadContext) { - bool frameOn = threadContext->sync.videoFrameOn; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - if (threadContext->state == THREAD_RUNNING) { - _pauseThread(threadContext); - threadContext->frameWasOn = frameOn; + bool frameOn = threadContext->impl->sync.videoFrameOn; + MutexLock(&threadContext->impl->stateMutex); + _waitOnInterrupt(threadContext->impl); + if (threadContext->impl->state == THREAD_RUNNING) { + _pauseThread(threadContext->impl); + threadContext->impl->frameWasOn = frameOn; frameOn = false; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); - mCoreSyncSetVideoSync(&threadContext->sync, frameOn); + mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } void mCoreThreadUnpause(struct mCoreThread* threadContext) { - bool frameOn = threadContext->sync.videoFrameOn; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { - threadContext->state = THREAD_RUNNING; - ConditionWake(&threadContext->stateCond); - frameOn = threadContext->frameWasOn; + bool frameOn = threadContext->impl->sync.videoFrameOn; + MutexLock(&threadContext->impl->stateMutex); + _waitOnInterrupt(threadContext->impl); + if (threadContext->impl->state == THREAD_PAUSED || threadContext->impl->state == THREAD_PAUSING) { + threadContext->impl->state = THREAD_RUNNING; + ConditionWake(&threadContext->impl->stateCond); + frameOn = threadContext->impl->frameWasOn; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); - mCoreSyncSetVideoSync(&threadContext->sync, frameOn); + mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } bool mCoreThreadIsPaused(struct mCoreThread* threadContext) { bool isPaused; - MutexLock(&threadContext->stateMutex); - if (threadContext->interruptDepth) { - isPaused = threadContext->savedState == THREAD_PAUSED; + MutexLock(&threadContext->impl->stateMutex); + if (threadContext->impl->interruptDepth) { + isPaused = threadContext->impl->savedState == THREAD_PAUSED; } else { - isPaused = threadContext->state == THREAD_PAUSED; + isPaused = threadContext->impl->state == THREAD_PAUSED; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); return isPaused; } void mCoreThreadTogglePause(struct mCoreThread* threadContext) { - bool frameOn = threadContext->sync.videoFrameOn; - MutexLock(&threadContext->stateMutex); - _waitOnInterrupt(threadContext); - if (threadContext->state == THREAD_PAUSED || threadContext->state == THREAD_PAUSING) { - threadContext->state = THREAD_RUNNING; - ConditionWake(&threadContext->stateCond); - frameOn = threadContext->frameWasOn; - } else if (threadContext->state == THREAD_RUNNING) { - _pauseThread(threadContext); - threadContext->frameWasOn = frameOn; + bool frameOn = threadContext->impl->sync.videoFrameOn; + MutexLock(&threadContext->impl->stateMutex); + _waitOnInterrupt(threadContext->impl); + if (threadContext->impl->state == THREAD_PAUSED || threadContext->impl->state == THREAD_PAUSING) { + threadContext->impl->state = THREAD_RUNNING; + ConditionWake(&threadContext->impl->stateCond); + frameOn = threadContext->impl->frameWasOn; + } else if (threadContext->impl->state == THREAD_RUNNING) { + _pauseThread(threadContext->impl); + threadContext->impl->frameWasOn = frameOn; frameOn = false; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); - mCoreSyncSetVideoSync(&threadContext->sync, frameOn); + mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } void mCoreThreadPauseFromThread(struct mCoreThread* threadContext) { bool frameOn = true; - MutexLock(&threadContext->stateMutex); - if (threadContext->state == THREAD_RUNNING || (threadContext->interruptDepth && threadContext->savedState == THREAD_RUNNING)) { - threadContext->state = THREAD_PAUSING; + MutexLock(&threadContext->impl->stateMutex); + if (threadContext->impl->state == THREAD_RUNNING || (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_RUNNING)) { + threadContext->impl->state = THREAD_PAUSING; frameOn = false; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); - mCoreSyncSetVideoSync(&threadContext->sync, frameOn); + mCoreSyncSetVideoSync(&threadContext->impl->sync, frameOn); } void mCoreThreadSetRewinding(struct mCoreThread* threadContext, bool rewinding) { - MutexLock(&threadContext->stateMutex); - if (rewinding && (threadContext->state == THREAD_REWINDING || (threadContext->interruptDepth && threadContext->savedState == THREAD_REWINDING))) { - MutexUnlock(&threadContext->stateMutex); + MutexLock(&threadContext->impl->stateMutex); + if (rewinding && (threadContext->impl->state == THREAD_REWINDING || (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_REWINDING))) { + MutexUnlock(&threadContext->impl->stateMutex); return; } - if (!rewinding && ((!threadContext->interruptDepth && threadContext->state != THREAD_REWINDING) || (threadContext->interruptDepth && threadContext->savedState != THREAD_REWINDING))) { - MutexUnlock(&threadContext->stateMutex); + if (!rewinding && ((!threadContext->impl->interruptDepth && threadContext->impl->state != THREAD_REWINDING) || (threadContext->impl->interruptDepth && threadContext->impl->savedState != THREAD_REWINDING))) { + MutexUnlock(&threadContext->impl->stateMutex); return; } - _waitOnInterrupt(threadContext); - if (rewinding && threadContext->state == THREAD_RUNNING) { - threadContext->state = THREAD_REWINDING; + _waitOnInterrupt(threadContext->impl); + if (rewinding && threadContext->impl->state == THREAD_RUNNING) { + threadContext->impl->state = THREAD_REWINDING; } - if (!rewinding && threadContext->state == THREAD_REWINDING) { - threadContext->state = THREAD_RUNNING; + if (!rewinding && threadContext->impl->state == THREAD_REWINDING) { + threadContext->impl->state = THREAD_RUNNING; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadWaitFromThread(struct mCoreThread* threadContext) { - MutexLock(&threadContext->stateMutex); - if (threadContext->interruptDepth && threadContext->savedState == THREAD_RUNNING) { - threadContext->savedState = THREAD_WAITING; - } else if (threadContext->state == THREAD_RUNNING) { - threadContext->state = THREAD_WAITING; + MutexLock(&threadContext->impl->stateMutex); + if (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_RUNNING) { + threadContext->impl->savedState = THREAD_WAITING; + } else if (threadContext->impl->state == THREAD_RUNNING) { + threadContext->impl->state = THREAD_WAITING; } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); } void mCoreThreadStopWaiting(struct mCoreThread* threadContext) { - MutexLock(&threadContext->stateMutex); - if (threadContext->interruptDepth && threadContext->savedState == THREAD_WAITING) { - threadContext->savedState = THREAD_RUNNING; - } else if (threadContext->state == THREAD_WAITING) { - threadContext->state = THREAD_RUNNING; - ConditionWake(&threadContext->stateCond); + MutexLock(&threadContext->impl->stateMutex); + if (threadContext->impl->interruptDepth && threadContext->impl->savedState == THREAD_WAITING) { + threadContext->impl->savedState = THREAD_RUNNING; + } else if (threadContext->impl->state == THREAD_WAITING) { + threadContext->impl->state = THREAD_RUNNING; + ConditionWake(&threadContext->impl->stateCond); } - MutexUnlock(&threadContext->stateMutex); + MutexUnlock(&threadContext->impl->stateMutex); } #ifdef USE_PTHREADS
@@ -12,6 +12,10 @@ #include <mgba/core/version.h>
#include <mgba/internal/debugger/parser.h> #include <mgba-util/string.h> +#if ENABLE_SCRIPTING +#include <mgba/core/scripting.h> +#endif + #if !defined(NDEBUG) && !defined(_WIN32) #include <signal.h> #endif@@ -51,6 +55,9 @@ static void _writeWord(struct CLIDebugger*, struct CLIDebugVector*);
static void _dumpByte(struct CLIDebugger*, struct CLIDebugVector*); static void _dumpHalfword(struct CLIDebugger*, struct CLIDebugVector*); static void _dumpWord(struct CLIDebugger*, struct CLIDebugVector*); +#ifdef ENABLE_SCRIPTING +static void _source(struct CLIDebugger*, struct CLIDebugVector*); +#endif static struct CLIDebuggerCommandSummary _debuggerCommands[] = { { "b", _setBreakpoint, CLIDVParse, "Set a breakpoint" },@@ -92,6 +99,9 @@ { "watch/w", _setWriteWatchpoint, CLIDVParse, "Set a write watchpoint" },
{ "x/1", _dumpByte, CLIDVParse, "Examine bytes at a specified offset" }, { "x/2", _dumpHalfword, CLIDVParse, "Examine halfwords at a specified offset" }, { "x/4", _dumpWord, CLIDVParse, "Examine words at a specified offset" }, +#ifdef ENABLE_SCRIPTING + { "source", _source, CLIDVStringParse, "Load a script" }, +#endif #if !defined(NDEBUG) && !defined(_WIN32) { "!", _breakInto, 0, "Break into attached debugger (for developers)" }, #endif@@ -410,6 +420,20 @@ }
debugger->backend->printf(debugger->backend, "\n"); } } + +#ifdef ENABLE_SCRIPTING +static void _source(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { + if (!dv) { + debugger->backend->printf(debugger->backend, "Needs a filename\n"); + return; + } + if (debugger->d.bridge && mScriptBridgeLoadScript(debugger->d.bridge, dv->charValue)) { + mScriptBridgeRun(debugger->d.bridge); + } else { + debugger->backend->printf(debugger->backend, "Failed to load script\n"); + } +} +#endif static void _setBreakpoint(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { if (!dv || dv->type != CLIDV_INT_TYPE) {
@@ -13,6 +13,10 @@ #ifdef USE_GDB_STUB
#include <mgba/internal/debugger/gdb-stub.h> #endif +#if ENABLE_SCRIPTING +#include <mgba/core/scripting.h> +#endif + const uint32_t DEBUGGER_ID = 0xDEADBEEF; mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger", "core.debugger");@@ -34,6 +38,7 @@ #endif
}; union DebugUnion* debugger = malloc(sizeof(union DebugUnion)); + memset(debugger, 0, sizeof(*debugger)); switch (type) { case DEBUGGER_CLI:@@ -109,6 +114,11 @@ debugger->state = DEBUGGER_PAUSED;
if (debugger->platform->entered) { debugger->platform->entered(debugger->platform, reason, info); } +#ifdef ENABLE_SCRIPTING + if (debugger->bridge) { + mScriptBridgeDebuggerEntered(debugger->bridge, reason, info); + } +#endif } static void mDebuggerInit(void* cpu, struct mCPUComponent* component) {
@@ -620,8 +620,9 @@ sampleRight += audio->ch4.sample;
} } - *left = sampleLeft * (1 + audio->volumeLeft); - *right = sampleRight * (1 + audio->volumeRight); + int dcOffset = audio->style == GB_AUDIO_GBA ? 0 : 0x1FC; + *left = (sampleLeft - dcOffset) * (1 + audio->volumeLeft); + *right = (sampleRight - dcOffset) * (1 + audio->volumeRight); } static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {@@ -702,6 +703,7 @@ envelope->initialVolume = GBAudioRegisterSweepGetInitialVolume(value);
if (!envelope->stepTime) { // TODO: Improve "zombie" mode ++envelope->currentVolume; + envelope->currentVolume &= 0xF; } _updateEnvelopeDead(envelope); envelope->nextStep = envelope->stepTime;@@ -709,7 +711,7 @@ return (envelope->initialVolume || envelope->direction) && envelope->dead != 2;
} static void _updateSquareSample(struct GBAudioSquareChannel* ch) { - ch->sample = (ch->control.hi * 2 - 1) * ch->envelope.currentVolume * 0x8; + ch->sample = ch->control.hi * ch->envelope.currentVolume * 0x8; } static int32_t _updateSquareChannel(struct GBAudioSquareChannel* ch) {@@ -860,8 +862,7 @@ }
ch->sample = bitsCarry >> 4; break; } - ch->sample -= 8; - ch->sample *= volume * 4; + ch->sample *= volume * 2; audio->ch3.readable = true; if (audio->style == GB_AUDIO_DMG) { mTimingDeschedule(audio->timing, &audio->ch3Fade);@@ -888,12 +889,12 @@ int32_t cycles = 0;
do { int lsb = ch->lfsr & 1; - ch->sample = lsb * 0x10 - 0x8; + ch->sample = lsb * 0x8; ch->sample *= ch->envelope.currentVolume; ch->lfsr >>= 1; ch->lfsr ^= (lsb * 0x60) << (ch->power ? 0 : 8); cycles += baseCycles; - } while (cycles < audio->sampleInterval); + } while (cycles + baseCycles < audio->sampleInterval); mTimingSchedule(timing, &audio->ch4Event, cycles - cyclesLate); }
@@ -42,7 +42,7 @@ static void GBStop(struct LR35902Core* cpu);
static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate); -#ifdef _3DS +#ifdef FIXED_ROM_BUFFER extern uint32_t* romBuffer; extern size_t romBufferSize; #endif@@ -109,7 +109,7 @@ gb->romVf = vf;
gb->pristineRomSize = vf->size(vf); vf->seek(vf, 0, SEEK_SET); gb->isPristine = true; -#ifdef _3DS +#ifdef FIXED_ROM_BUFFER if (gb->pristineRomSize <= romBufferSize) { gb->memory.rom = romBuffer; vf->read(vf, romBuffer, gb->pristineRomSize);@@ -277,7 +277,7 @@ mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX);
} if (gb->romVf) { -#ifndef _3DS +#ifndef FIXED_ROM_BUFFER gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); #endif gb->romVf->close(gb->romVf);@@ -326,7 +326,7 @@ mappedMemoryFree(newRom, GB_SIZE_CART_MAX);
return; } if (gb->romVf) { -#ifndef _3DS +#ifndef FIXED_ROM_BUFFER gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); #endif gb->romVf->close(gb->romVf);
@@ -50,7 +50,7 @@ gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
} } -static void _switchBank0(struct GB* gb, int bank) { +void GBMBCSwitchBank0(struct GB* gb, int bank) { size_t bankStart = bank * GB_SIZE_CART_BANK0 << gb->memory.mbcState.mbc1.multicartStride; if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) { mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);@@ -320,7 +320,7 @@ break;
case 0x2: bank &= 3; if (memory->mbcState.mbc1.mode) { - _switchBank0(gb, bank); + GBMBCSwitchBank0(gb, bank); GBMBCSwitchSramBank(gb, bank); } GBMBCSwitchBank(gb, (bank << memory->mbcState.mbc1.multicartStride) | (memory->currentBank & (stride - 1)));@@ -328,9 +328,9 @@ break;
case 0x3: memory->mbcState.mbc1.mode = value & 1; if (memory->mbcState.mbc1.mode) { - _switchBank0(gb, memory->currentBank >> memory->mbcState.mbc1.multicartStride); + GBMBCSwitchBank0(gb, memory->currentBank >> memory->mbcState.mbc1.multicartStride); } else { - _switchBank0(gb, 0); + GBMBCSwitchBank0(gb, 0); GBMBCSwitchSramBank(gb, 0); } break;
@@ -629,6 +629,28 @@ flags = GBSerializedMemoryFlagsSetIme(flags, memory->ime);
flags = GBSerializedMemoryFlagsSetIsHdma(flags, memory->isHdma); flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg); STORE_16LE(flags, 0, &state->memory.flags); + + switch (memory->mbcType) { + case GB_MBC1: + state->memory.mbc1.mode = memory->mbcState.mbc1.mode; + state->memory.mbc1.multicartStride = memory->mbcState.mbc1.multicartStride; + break; + case GB_MBC3_RTC: + STORE_64LE(gb->memory.rtcLastLatch, 0, &state->memory.rtc.lastLatch); + break; + case GB_MBC7: + state->memory.mbc7.state = memory->mbcState.mbc7.state; + state->memory.mbc7.eeprom = memory->mbcState.mbc7.eeprom; + state->memory.mbc7.address = memory->mbcState.mbc7.address; + state->memory.mbc7.access = memory->mbcState.mbc7.access; + state->memory.mbc7.latch = memory->mbcState.mbc7.latch; + state->memory.mbc7.srBits = memory->mbcState.mbc7.srBits; + STORE_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr); + STORE_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable); + break; + default: + break; + } } void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {@@ -671,6 +693,32 @@ memory->rtcLatched = GBSerializedMemoryFlagsGetRtcLatched(flags);
memory->ime = GBSerializedMemoryFlagsGetIme(flags); memory->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags); memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags); + + switch (memory->mbcType) { + case GB_MBC1: + memory->mbcState.mbc1.mode = state->memory.mbc1.mode; + memory->mbcState.mbc1.multicartStride = state->memory.mbc1.multicartStride; + if (memory->mbcState.mbc1.mode) { + GBMBCSwitchBank0(gb, memory->currentBank >> memory->mbcState.mbc1.multicartStride); + } + break; + case GB_MBC3_RTC: + // TODO? + //LOAD_64LE(gb->memory.rtcLastLatch, 0, &state->memory.rtc.lastLatch); + break; + case GB_MBC7: + memory->mbcState.mbc7.state = state->memory.mbc7.state; + memory->mbcState.mbc7.eeprom = state->memory.mbc7.eeprom; + memory->mbcState.mbc7.address = state->memory.mbc7.address & 0x7F; + memory->mbcState.mbc7.access = state->memory.mbc7.access; + memory->mbcState.mbc7.latch = state->memory.mbc7.latch; + memory->mbcState.mbc7.srBits = state->memory.mbc7.srBits; + LOAD_16LE(memory->mbcState.mbc7.sr, 0, &state->memory.mbc7.sr); + LOAD_32LE(memory->mbcState.mbc7.writable, 0, &state->memory.mbc7.writable); + break; + default: + break; + } } void _pristineCow(struct GB* gb) {
@@ -118,7 +118,7 @@ STORE_32LE(timer->timaPeriod, 0, &state->timer.timaPeriod);
STORE_32LE(timer->event.when - mTimingCurrentTime(&timer->p->timing), 0, &state->timer.nextEvent); STORE_32LE(timer->irq.when - mTimingCurrentTime(&timer->p->timing), 0, &state->timer.nextIRQ); GBSerializedTimerFlags flags = GBSerializedTimerFlagsSetIrqPending(0, mTimingIsScheduled(&timer->p->timing, &timer->irq)); - STORE_32LE(flags, 0, &state->timer.flags); + state->timer.flags = flags; } void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* state) {@@ -130,8 +130,7 @@ uint32_t when;
LOAD_32LE(when, 0, &state->timer.nextEvent); mTimingSchedule(&timer->p->timing, &timer->event, when); - GBSerializedTimerFlags flags; - LOAD_32LE(flags, 0, &state->timer.flags); + GBSerializedTimerFlags flags = state->timer.flags; if (GBSerializedTimerFlagsIsIrqPending(flags)) { LOAD_32LE(when, 0, &state->timer.nextIRQ);
@@ -42,7 +42,7 @@ static bool _setSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
static bool _clearSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode); -#ifdef _3DS +#ifdef FIXED_ROM_BUFFER extern uint32_t* romBuffer; extern size_t romBufferSize; #endif@@ -120,7 +120,7 @@ mappedMemoryFree(gba->memory.rom, SIZE_CART0);
} if (gba->romVf) { -#ifndef _3DS +#ifndef FIXED_ROM_BUFFER gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize); #endif gba->romVf->close(gba->romVf);@@ -323,7 +323,7 @@ if (gba->pristineRomSize > SIZE_CART0) {
gba->pristineRomSize = SIZE_CART0; } gba->isPristine = true; -#ifdef _3DS +#ifdef FIXED_ROM_BUFFER if (gba->pristineRomSize <= romBufferSize) { gba->memory.rom = romBuffer; vf->read(vf, romBuffer, gba->pristineRomSize);@@ -342,6 +342,16 @@ gba->memory.mirroring = false;
gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); GBAVFameDetect(&gba->memory.vfame, gba->memory.rom, gba->memory.romSize); + if (popcount32(gba->memory.romSize) != 1) { + // This ROM is either a bad dump or homebrew. Emulate flash cart behavior. +#ifndef FIXED_ROM_BUFFER + void* newRom = anonymousMemoryMap(SIZE_CART0); + memcpy(newRom, gba->memory.rom, gba->pristineRomSize); + gba->memory.rom = newRom; +#endif + gba->memory.romSize = SIZE_CART0; + gba->isPristine = false; + } // TODO: error check return true; }@@ -394,7 +404,7 @@ mappedMemoryFree(newRom, SIZE_CART0);
return; } if (gba->romVf) { -#ifndef _3DS +#ifndef FIXED_ROM_BUFFER gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize); #endif gba->romVf->close(gba->romVf);
@@ -709,16 +709,16 @@
switch (address) { // Reading this takes two cycles (1N+1I), so let's remove them preemptively case REG_TM0CNT_LO: - GBATimerUpdateRegister(gba, 0, 2); + GBATimerUpdateRegister(gba, 0, 4); break; case REG_TM1CNT_LO: - GBATimerUpdateRegister(gba, 1, 2); + GBATimerUpdateRegister(gba, 1, 4); break; case REG_TM2CNT_LO: - GBATimerUpdateRegister(gba, 2, 2); + GBATimerUpdateRegister(gba, 2, 4); break; case REG_TM3CNT_LO: - GBATimerUpdateRegister(gba, 3, 2); + GBATimerUpdateRegister(gba, 3, 4); break; case REG_KEYINPUT:
@@ -297,10 +297,8 @@ default:
memory->activeRegion = -1; cpu->memory.activeRegion = _deadbeef; cpu->memory.activeMask = 0; - if (gba->yankedRomSize || !gba->hardCrash) { - mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); - } else if (mCoreCallbacksListSize(&gba->coreCallbacks)) { - mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); + + if (!gba->yankedRomSize && mCoreCallbacksListSize(&gba->coreCallbacks)) { size_t c; for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);@@ -308,6 +306,10 @@ if (callbacks->coreCrashed) {
callbacks->coreCrashed(callbacks->context); } } + } + + if (gba->yankedRomSize || !gba->hardCrash) { + mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); } else { mLOG(GBA_MEM, FATAL, "Jumped to invalid address: %08X", address); }@@ -1551,7 +1553,7 @@ if (gba->cpu->memory.activeRegion == gba->memory.rom) {
gba->cpu->memory.activeRegion = newRom; } if (gba->romVf) { -#ifndef _3DS +#ifndef FIXED_ROM_BUFFER gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->memory.romSize); #endif gba->romVf->close(gba->romVf);
@@ -155,11 +155,13 @@ switch (sio->mode) {
case SIO_NORMAL_8: case SIO_NORMAL_32: value |= 0x0004; - if ((value & 0x4080) == 0x4080) { - // TODO: Test this on hardware to see if this is correct - GBARaiseIRQ(sio->p, IRQ_SIO); + if ((value & 0x0081) == 0x0081) { + if (value & 0x4000) { + // TODO: Test this on hardware to see if this is correct + GBARaiseIRQ(sio->p, IRQ_SIO); + } + value &= ~0x0080; } - value &= ~0x0080; break; default: // TODO
@@ -6,12 +6,33 @@ foreach(DIR IN LISTS INCLUDE_DIRECTORIES)
list(APPEND INCLUDE_FLAGS "-I${DIR}") endforeach() +include(FindPythonLibs) +list(APPEND DEPENDENCY_LIB ${PYTHON_LIBRARIES}) +include_directories(AFTER ${PYTHON_INCLUDE_DIRS}) + +file(GLOB PYTHON_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.h) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/setup.py) add_custom_command(OUTPUT build/lib/${BINARY_NAME}/__init__.py COMMAND BINDIR=${CMAKE_CURRENT_BINARY_DIR}/.. CPPFLAGS="${INCLUDE_FLAGS}" ${PYTHON} ${CMAKE_CURRENT_BINARY_DIR}/setup.py build --build-base ${CMAKE_CURRENT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${BINARY_NAME} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/setup.py + DEPENDS ${PYTHON_HEADERS} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py) -add_custom_target(${BINARY_NAME}-py ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/build/lib/${BINARY_NAME}/__init__.py) +add_custom_command(OUTPUT lib.c + COMMAND BINDIR=${CMAKE_CURRENT_BINARY_DIR}/.. CPPFLAGS="${INCLUDE_FLAGS}" ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py + DEPENDS ${PYTHON_HEADERS} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py) + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/lib.c PROPERTIES GENERATED ON) + +file(GLOB PYTHON_SRC ${CMAKE_CURRENT_SOURCE_DIR}/*.c) +add_library(${BINARY_NAME}-pylib STATIC ${CMAKE_CURRENT_BINARY_DIR}/lib.c ${PYTHON_SRC}) +add_dependencies(${BINARY_NAME}-pylib ${CMAKE_CURRENT_SOURCE_DIR}/_builder.py) +set_target_properties(${BINARY_NAME}-pylib PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_BINARY_DIR};${INCLUDE_DIRECTORIES}") +set_target_properties(${BINARY_NAME}-pylib PROPERTIES COMPILE_DEFINITIONS "${OS_DEFINES};${FEATURE_DEFINES};${FUNCTION_DEFINES}") +set(PYTHON_LIBRARY ${BINARY_NAME}-pylib PARENT_SCOPE) + +add_custom_target(${BINARY_NAME}-py ALL DEPENDS ${BINARY_NAME}-pylib ${CMAKE_CURRENT_BINARY_DIR}/build/lib/${BINARY_NAME}/__init__.py)
@@ -1,5 +1,6 @@
#define COMMON_H #define PNG_H +#define OPAQUE_THREADING #define _SYS_TIME_H #define _SYS_TIME_H_ #define _TIME_H@@ -30,9 +31,11 @@
#include <mgba/core/core.h> #include <mgba/core/mem-search.h> #include <mgba/core/tile-cache.h> +#include <mgba/core/thread.h> #include <mgba/core/version.h> #define PYEXPORT extern "Python+C" +#include "platform/python/core.h" #include "platform/python/log.h" #include "platform/python/sio.h" #include "platform/python/vfs-py.h"@@ -53,3 +56,6 @@ #include <mgba/internal/gb/gb.h>
#include <mgba/internal/gba/input.h> #include <mgba/internal/gb/renderers/tile-cache.h> #endif +#ifdef USE_DEBUGGERS +#include <mgba/debugger/debugger.h> +#endif
@@ -18,12 +18,15 @@ cppflags.extend(["-I" + incdir, "-I" + srcdir, "-I" + bindir])
ffi.set_source("mgba._pylib", """ #include "flags.h" +#define OPAQUE_THREADING #include <mgba-util/common.h> #include <mgba/core/core.h> #include <mgba/core/log.h> #include <mgba/core/mem-search.h> +#include <mgba/core/thread.h> #include <mgba/core/tile-cache.h> #include <mgba/core/version.h> +#include <mgba/debugger/debugger.h> #include <mgba/internal/arm/arm.h> #include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/input.h>@@ -35,6 +38,7 @@ #include <mgba-util/png-io.h>
#include <mgba-util/vfs.h> #define PYEXPORT +#include "platform/python/core.h" #include "platform/python/log.h" #include "platform/python/sio.h" #include "platform/python/vfs-py.h"@@ -43,7 +47,7 @@ """, include_dirs=[incdir, srcdir],
extra_compile_args=cppflags, libraries=["medusa-emu"], library_dirs=[bindir], - sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "log.c", "sio.c"]]) + sources=[os.path.join(pydir, path) for path in ["vfs-py.c", "core.c", "log.c", "sio.c"]]) preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "_builder.h")], universal_newlines=True)@@ -55,5 +59,59 @@ continue
lines.append(line) ffi.cdef('\n'.join(lines)) +preprocessed = subprocess.check_output(cpp + ["-fno-inline", "-P"] + cppflags + [os.path.join(pydir, "lib.h")], universal_newlines=True) + +lines = [] +for line in preprocessed.splitlines(): + line = line.strip() + if line.startswith('#'): + continue + lines.append(line) +ffi.embedding_api('\n'.join(lines)) + +ffi.embedding_init_code(""" + from mgba._pylib import ffi + debugger = None + pendingCode = [] + + @ffi.def_extern() + def mPythonSetDebugger(_debugger): + from mgba.debugger import NativeDebugger + global debugger + if debugger and debugger._native == _debugger: + return + debugger = _debugger and NativeDebugger(_debugger) + + @ffi.def_extern() + def mPythonLoadScript(name, vf): + from mgba.vfs import VFile + vf = VFile(vf) + name = ffi.string(name) + source = vf.readAll().decode('utf-8') + try: + code = compile(source, name, 'exec') + pendingCode.append(code) + except: + return False + return True + + @ffi.def_extern() + def mPythonRunPending(): + global pendingCode + for code in pendingCode: + exec(code) + pendingCode = [] + + @ffi.def_extern() + def mPythonDebuggerEntered(reason, info): + global debugger + if not debugger: + return + if info == ffi.NULL: + info = None + for cb in debugger._cbs: + cb(reason, info) +""") + if __name__ == "__main__": - ffi.compile() + ffi.emit_c_code("lib.c")
@@ -0,0 +1,19 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "core.h" + +#include <mgba/core/core.h> + +struct mCoreCallbacks* mCorePythonCallbackCreate(void* pyobj) { + struct mCoreCallbacks* callbacks = malloc(sizeof(*callbacks)); + callbacks->videoFrameStarted = _mCorePythonCallbacksVideoFrameStarted; + callbacks->videoFrameEnded = _mCorePythonCallbacksVideoFrameEnded; + callbacks->coreCrashed = _mCorePythonCallbacksCoreCrashed; + callbacks->sleep = _mCorePythonCallbacksSleep; + + callbacks->context = pyobj; + return callbacks; +}
@@ -0,0 +1,15 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <mgba-util/common.h> + +#include "pycommon.h" + +struct mCoreCallbacks* mCorePythonCallbackCreate(void* pyobj); + +PYEXPORT void _mCorePythonCallbacksVideoFrameStarted(void* user); +PYEXPORT void _mCorePythonCallbacksVideoFrameEnded(void* user); +PYEXPORT void _mCorePythonCallbacksCoreCrashed(void* user); +PYEXPORT void _mCorePythonCallbacksSleep(void* user);
@@ -0,0 +1,103 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "engine.h" + +#include <mgba/core/scripting.h> +#include <mgba-util/string.h> +#include <mgba-util/vfs.h> + +#ifdef USE_DEBUGGERS +#include <mgba/debugger/debugger.h> +#endif + +#include "lib.h" + +static const char* mPythonScriptEngineName(struct mScriptEngine*); +static bool mPythonScriptEngineInit(struct mScriptEngine*, struct mScriptBridge*); +static void mPythonScriptEngineDeinit(struct mScriptEngine*); +static bool mPythonScriptEngineIsScript(struct mScriptEngine*, const char* name, struct VFile* vf); +static bool mPythonScriptEngineLoadScript(struct mScriptEngine*, const char* name, struct VFile* vf); +static void mPythonScriptEngineRun(struct mScriptEngine*); + +#ifdef USE_DEBUGGERS +static void mPythonScriptDebuggerEntered(struct mScriptEngine*, enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); +#endif + +struct mPythonScriptEngine { + struct mScriptEngine d; + struct mScriptBridge* sb; +}; + +struct mPythonScriptEngine* mPythonCreateScriptEngine(void) { + struct mPythonScriptEngine* engine = malloc(sizeof(*engine)); + engine->d.name = mPythonScriptEngineName; + engine->d.init = mPythonScriptEngineInit; + engine->d.deinit = mPythonScriptEngineDeinit; + engine->d.isScript = mPythonScriptEngineIsScript; + engine->d.loadScript = mPythonScriptEngineLoadScript; + engine->d.run = mPythonScriptEngineRun; +#ifdef USE_DEBUGGERS + engine->d.debuggerEntered = mPythonScriptDebuggerEntered; +#endif + engine->sb = NULL; + return engine; +} + +void mPythonSetup(struct mScriptBridge* sb) { + struct mPythonScriptEngine* se = mPythonCreateScriptEngine(); + mScriptBridgeInstallEngine(sb, &se->d); +} + +const char* mPythonScriptEngineName(struct mScriptEngine* se) { + UNUSED(se); + return "python"; +} + +bool mPythonScriptEngineInit(struct mScriptEngine* se, struct mScriptBridge* sb) { + struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se; + engine->sb = sb; + return true; +} + +void mPythonScriptEngineDeinit(struct mScriptEngine* se) { + struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se; + free(se); +} + +bool mPythonScriptEngineIsScript(struct mScriptEngine* se, const char* name, struct VFile* vf) { + UNUSED(se); + UNUSED(vf); + return endswith(name, ".py"); +} + +bool mPythonScriptEngineLoadScript(struct mScriptEngine* se, const char* name, struct VFile* vf) { + struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se; + return mPythonLoadScript(name, vf); +} + +void mPythonScriptEngineRun(struct mScriptEngine* se) { + struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se; + + struct mDebugger* debugger = mScriptBridgeGetDebugger(engine->sb); + if (debugger) { + mPythonSetDebugger(debugger); + } + + mPythonRunPending(); +} + +#ifdef USE_DEBUGGERS +void mPythonScriptDebuggerEntered(struct mScriptEngine* se, enum mDebuggerEntryReason reason, struct mDebuggerEntryInfo* info) { + struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se; + + struct mDebugger* debugger = mScriptBridgeGetDebugger(engine->sb); + if (!debugger) { + return; + } + + mPythonDebuggerEntered(reason, info); +} +#endif
@@ -0,0 +1,20 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PYTHON_ENGINE_H +#define PYTHON_ENGINE_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +struct mScriptBridge; +struct mPythonScriptEngine; +struct mPythonScriptEngine* mPythonCreateScriptEngine(void); +void mPythonSetup(struct mScriptBridge* sb); + +CXX_GUARD_END + +#endif
@@ -0,0 +1,11 @@
+#include "flags.h" + +struct VFile; + +extern bool mPythonLoadScript(const char*, struct VFile*); +extern void mPythonRunPending(); + +#ifdef USE_DEBUGGERS +extern void mPythonSetDebugger(struct mDebugger*); +extern void mPythonDebuggerEntered(enum mDebuggerEntryReason, struct mDebuggerEntryInfo*); +#endif
@@ -3,14 +3,7 @@ *
* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include <mgba/core/log.h> - -struct mLoggerPy { - struct mLogger d; - void* pyobj; -}; - -void _pyLog(void* logger, int category, enum mLogLevel level, const char* message); +#include "log.h" static void _pyLogShim(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { struct mLoggerPy* pylogger = (struct mLoggerPy*) logger;
@@ -5,6 +5,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <mgba/core/log.h> +#include "pycommon.h" + struct mLoggerPy { struct mLogger d; void* pyobj;
@@ -4,7 +4,7 @@ # This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. from ._pylib import ffi, lib -from . import tile +from . import tile, createCallback from cached_property import cached_property def find(path):@@ -38,10 +38,65 @@ raise RuntimeError("Core must be reset first")
return f(self, *args, **kwargs) return wrapper +def protected(f): + def wrapper(self, *args, **kwargs): + if self._protected: + raise RuntimeError("Core is protected") + return f(self, *args, **kwargs) + return wrapper + +@ffi.def_extern() +def _mCorePythonCallbacksVideoFrameStarted(user): + context = ffi.from_handle(user) + context._videoFrameStarted() + +@ffi.def_extern() +def _mCorePythonCallbacksVideoFrameEnded(user): + context = ffi.from_handle(user) + context._videoFrameEnded() + +@ffi.def_extern() +def _mCorePythonCallbacksCoreCrashed(user): + context = ffi.from_handle(user) + context._coreCrashed() + +@ffi.def_extern() +def _mCorePythonCallbacksSleep(user): + context = ffi.from_handle(user) + context._sleep() + +class CoreCallbacks(object): + def __init__(self): + self._handle = ffi.new_handle(self) + self.videoFrameStarted = [] + self.videoFrameEnded = [] + self.coreCrashed = [] + self.sleep = [] + self.context = lib.mCorePythonCallbackCreate(self._handle) + + def _videoFrameStarted(self): + for cb in self.videoFrameStarted: + cb() + + def _videoFrameEnded(self): + for cb in self.videoFrameEnded: + cb() + + def _coreCrashed(self): + for cb in self.coreCrashed: + cb() + + def _sleep(self): + for cb in self.sleep: + cb() + class Core(object): def __init__(self, native): self._core = native self._wasReset = False + self._protected = False + self._callbacks = CoreCallbacks() + self._core.addCoreCallbacks(self._core, self._callbacks.context) @cached_property def tiles(self):@@ -51,17 +106,22 @@ @classmethod
def _init(cls, native): core = ffi.gc(native, native.deinit) success = bool(core.init(core)) + lib.mCoreInitConfig(core, ffi.NULL) if not success: raise RuntimeError("Failed to initialize core") + return cls._detect(core) + + def _deinit(self): + self._core.deinit(self._core) + + @classmethod + def _detect(cls, core): if hasattr(cls, 'PLATFORM_GBA') and core.platform(core) == cls.PLATFORM_GBA: return GBA(core) if hasattr(cls, 'PLATFORM_GB') and core.platform(core) == cls.PLATFORM_GB: return GB(core) return Core(core) - def _deinit(self): - self._core.deinit(self._core) - def loadFile(self, path): return bool(lib.mCoreLoadFile(self._core, path.encode('UTF-8')))@@ -103,10 +163,12 @@ self._core.reset(self._core)
self._wasReset = True @needsReset + @protected def runFrame(self): self._core.runFrame(self._core) @needsReset + @protected def runLoop(self): self._core.runLoop(self._core)@@ -132,25 +194,65 @@
def clearKeys(self, *args, **kwargs): self._core.clearKeys(self._core, self._keysToInt(*args, **kwargs)) + @property @needsReset def frameCounter(self): return self._core.frameCounter(self._core) + @property def frameCycles(self): return self._core.frameCycles(self._core) + @property def frequency(self): return self._core.frequency(self._core) - def getGameTitle(self): + @property + def gameTitle(self): title = ffi.new("char[16]") self._core.getGameTitle(self._core, title) return ffi.string(title, 16).decode("ascii") - def getGameCode(self): + @property + def gameCode(self): code = ffi.new("char[12]") self._core.getGameCode(self._core, code) return ffi.string(code, 12).decode("ascii") + + def addFrameCallback(self, cb): + self._callbacks.videoFrameEnded.append(cb) + +class ICoreOwner(object): + def claim(self): + raise NotImplementedError + + def release(self): + raise NotImplementedError + + def __enter__(self): + self.core = self.claim() + self.core._protected = True + return self.core + + def __exit__(self, type, value, traceback): + self.core._protected = False + self.release() + +class IRunner(object): + def pause(self): + raise NotImplementedError + + def unpause(self): + raise NotImplementedError + + def useCore(self): + raise NotImplementedError + + def isRunning(self): + raise NotImplementedError + + def isPaused(self): + raise NotImplementedError if hasattr(lib, 'PLATFORM_GBA'): from .gba import GBA
@@ -0,0 +1,80 @@
+# Copyright (c) 2013-2017 Jeffrey Pfau +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +from ._pylib import ffi, lib +from .core import IRunner, ICoreOwner, Core + +class DebuggerCoreOwner(ICoreOwner): + def __init__(self, debugger): + self.debugger = debugger + self.wasPaused = False + + def claim(self): + if self.debugger.isRunning(): + self.wasPaused = True + self.debugger.pause() + return self.debugger._core + + def release(self): + if self.wasPaused: + self.debugger.unpause() + +class NativeDebugger(IRunner): + WATCHPOINT_WRITE = lib.WATCHPOINT_WRITE + WATCHPOINT_READ = lib.WATCHPOINT_READ + WATCHPOINT_RW = lib.WATCHPOINT_RW + + BREAKPOINT_HARDWARE = lib.BREAKPOINT_HARDWARE + BREAKPOINT_SOFTWARE = lib.BREAKPOINT_SOFTWARE + + ENTER_MANUAL = lib.DEBUGGER_ENTER_MANUAL + ENTER_ATTACHED = lib.DEBUGGER_ENTER_ATTACHED + ENTER_BREAKPOINT = lib.DEBUGGER_ENTER_BREAKPOINT + ENTER_WATCHPOINT = lib.DEBUGGER_ENTER_WATCHPOINT + ENTER_ILLEGAL_OP = lib.DEBUGGER_ENTER_ILLEGAL_OP + + def __init__(self, native): + self._native = native + self._cbs = [] + self._core = Core._detect(native.core) + self._core._wasReset = True + + def pause(self): + lib.mDebuggerEnter(self._native, lib.DEBUGGER_ENTER_MANUAL, ffi.NULL) + + def unpause(self): + self._native.state = lib.DEBUGGER_RUNNING + + def isRunning(self): + return self._native.state == lib.DEBUGGER_RUNNING + + def isPaused(self): + return self._native.state in (lib.DEBUGGER_PAUSED, lib.DEBUGGER_CUSTOM) + + def useCore(self): + return DebuggerCoreOwner(self) + + def setBreakpoint(self, address): + if not self._native.platform.setBreakpoint: + raise RuntimeError("Platform does not support breakpoints") + self._native.platform.setBreakpoint(self._native.platform, address) + + def clearBreakpoint(self, address): + if not self._native.platform.setBreakpoint: + raise RuntimeError("Platform does not support breakpoints") + self._native.platform.clearBreakpoint(self._native.platform, address) + + def setWatchpoint(self, address): + if not self._native.platform.setWatchpoint: + raise RuntimeError("Platform does not support watchpoints") + self._native.platform.setWatchpoint(self._native.platform, address) + + def clearWatchpoint(self, address): + if not self._native.platform.clearWatchpoint: + raise RuntimeError("Platform does not support watchpoints") + self._native.platform.clearWatchpoint(self._native.platform, address) + + def addCallback(self, cb): + self._cbs.append(cb)
@@ -0,0 +1,58 @@
+# Copyright (c) 2013-2017 Jeffrey Pfau +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +from ._pylib import ffi, lib +from .core import IRunner, ICoreOwner, Core + +class ThreadCoreOwner(ICoreOwner): + def __init__(self, thread): + self.thread = thread + + def claim(self): + if not self.thread.isRunning(): + raise ValueError + lib.mCoreThreadInterrupt(self.thread._native) + return self.thread._core + + def release(self): + lib.mCoreThreadContinue(self.thread._native) + +class Thread(IRunner): + def __init__(self, native=None): + if native: + self._native = native + self._core = Core(native.core) + self._core._wasReset = lib.mCoreThreadHasStarted(self._native) + else: + self._native = ffi.new("struct mCoreThread*") + + def start(self, core): + if lib.mCoreThreadHasStarted(self._native): + raise ValueError + self._core = core + self._native.core = core._core + lib.mCoreThreadStart(self._native) + self._core._wasReset = lib.mCoreThreadHasStarted(self._native) + + def end(self): + if not lib.mCoreThreadHasStarted(self._native): + raise ValueError + lib.mCoreThreadEnd(self._native) + lib.mCoreThreadJoin(self._native) + + def pause(self): + lib.mCoreThreadPause(self._native) + + def unpause(self): + lib.mCoreThreadUnpause(self._native) + + def isRunning(self): + return bool(lib.mCoreThreadIsActive(self._native)) + + def isPaused(self): + return bool(lib.mCoreThreadIsPaused(self._native)) + + def useCore(self): + return ThreadCoreOwner(self)
@@ -108,6 +108,13 @@
def read(self, buffer, size): return self.handle.read(self.handle, buffer, size) + def readAll(self, size=0): + if not size: + size = self.size() + buffer = ffi.new("char[%i]" % size) + size = self.handle.read(self.handle, buffer, size) + return ffi.unpack(buffer, size) + def readline(self, buffer, size): return self.handle.readline(self.handle, buffer, size)
@@ -0,0 +1,15 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef PYTHON_COMMON_H +#define PYTHON_COMMON_H + +#include <mgba-util/common.h> + +#ifndef PYEXPORT +#define PYEXPORT extern +#endif + +#endif
@@ -3,22 +3,7 @@ *
* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include <mgba-util/vfs.h> - -struct VFilePy { - struct VFile d; - void* fileobj; -}; - -bool _vfpClose(struct VFile* vf); -off_t _vfpSeek(struct VFile* vf, off_t offset, int whence); -ssize_t _vfpRead(struct VFile* vf, void* buffer, size_t size); -ssize_t _vfpWrite(struct VFile* vf, const void* buffer, size_t size); -void* _vfpMap(struct VFile* vf, size_t size, int flags); -void _vfpUnmap(struct VFile* vf, void* memory, size_t size); -void _vfpTruncate(struct VFile* vf, size_t size); -ssize_t _vfpSize(struct VFile* vf); -bool _vfpSync(struct VFile* vf, const void* buffer, size_t size); +#include "vfs-py.h" struct VFile* VFileFromPython(void* fileobj) { if (!fileobj) {
@@ -3,8 +3,9 @@ *
* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <mgba-util/vfs.h> -#include <mgba-util/vfs.h> +#include "pycommon.h" struct VFilePy { struct VFile d;
@@ -26,13 +26,13 @@ if (!m_context || !mCoreThreadIsActive(m_context)) {
LOG(QT, INFO) << tr("Can't set format of context-less audio device"); return; } - double fauxClock = GBAAudioCalculateRatio(1, m_context->sync.fpsTarget, 1); - mCoreSyncLockAudio(&m_context->sync); + double fauxClock = GBAAudioCalculateRatio(1, m_context->impl->sync.fpsTarget, 1); + mCoreSyncLockAudio(&m_context->impl->sync); blip_set_rates(m_context->core->getAudioChannel(m_context->core, 0), m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock); blip_set_rates(m_context->core->getAudioChannel(m_context->core, 1), m_context->core->frequency(m_context->core), format.sampleRate() * fauxClock); - mCoreSyncUnlockAudio(&m_context->sync); + mCoreSyncUnlockAudio(&m_context->impl->sync); } void AudioDevice::setInput(mCoreThread* input) {@@ -49,14 +49,14 @@ LOG(QT, WARN) << tr("Audio device is missing its core");
return 0; } - mCoreSyncLockAudio(&m_context->sync); + mCoreSyncLockAudio(&m_context->impl->sync); int available = blip_samples_avail(m_context->core->getAudioChannel(m_context->core, 0)); if (available > maxSize / sizeof(GBAStereoSample)) { available = maxSize / sizeof(GBAStereoSample); } blip_read_samples(m_context->core->getAudioChannel(m_context->core, 0), &reinterpret_cast<GBAStereoSample*>(data)->left, available, true); blip_read_samples(m_context->core->getAudioChannel(m_context->core, 1), &reinterpret_cast<GBAStereoSample*>(data)->right, available, true); - mCoreSyncConsumeAudio(&m_context->sync); + mCoreSyncConsumeAudio(&m_context->impl->sync); return available * sizeof(GBAStereoSample); }
@@ -214,7 +214,9 @@ else()
set(DATADIR ${CMAKE_INSTALL_DATADIR}/${BINARY_NAME}) endif() endif() -install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) +if(BUILD_GL OR BUILD_GLES2) + install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) +endif() install(FILES ${CMAKE_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt) if(NOT WIN32 AND NOT APPLE) list(APPEND QT_DEFINES DATADIR="${CMAKE_INSTALL_PREFIX}/${DATADIR}")@@ -230,8 +232,20 @@ qt5_create_translation(TRANSLATION_FILES ${SOURCE_FILES} ${UI_FILES} ${TS_FILES} OPTIONS -locations absolute -no-obsolete)
else() qt5_add_translation(TRANSLATION_FILES ${TS_FILES}) endif() + set(QT_QM_FILES) + if(QT_STATIC) + get_target_property(QT_CORE_LOCATION Qt5::Core LOCATION) + get_filename_component(QT_CORE_LOCATION ${QT_CORE_LOCATION} DIRECTORY) + get_filename_component(QT_QM_LOCATION "${QT_CORE_LOCATION}/../translations" ABSOLUTE) + foreach(TS ${TS_FILES}) + get_filename_component(TS ${TS} NAME) + string(REGEX REPLACE "${BINARY_NAME}-(.*).ts$" "qtbase_\\1.qm" QT_QM "${TS}") + list(APPEND QT_QM_FILES "${QT_QM_LOCATION}/${QT_QM}") + endforeach() + list(APPEND TRANSLATION_FILES ${QT_QM_FILES}) + endif() add_custom_command(OUTPUT ${TRANSLATION_QRC} - COMMAND ${CMAKE_COMMAND} -DTRANSLATION_QRC:FILEPATH="${TRANSLATION_QRC}" -DQM_BASE="${CMAKE_CURRENT_BINARY_DIR}" -P "${CMAKE_CURRENT_SOURCE_DIR}/ts.cmake" + COMMAND ${CMAKE_COMMAND} -DTRANSLATION_QRC:FILEPATH="${TRANSLATION_QRC}" -DQM_BASE="${CMAKE_CURRENT_BINARY_DIR}" "-DTRANSLATION_FILES='${TRANSLATION_FILES}'" -P "${CMAKE_CURRENT_SOURCE_DIR}/ts.cmake" DEPENDS ${TRANSLATION_FILES}) qt5_add_resources(TRANSLATION_RESOURCES ${TRANSLATION_QRC}) list(APPEND RESOURCES ${TRANSLATION_RESOURCES})@@ -250,7 +264,7 @@ target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES})
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE) install(TARGETS ${BINARY_NAME}-qt - RUNTIME DESTINATION bin COMPONENT ${BINARY_NAME}-qt + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-qt BUNDLE DESTINATION Applications COMPONENT ${BINARY_NAME}-qt) if(UNIX AND NOT APPLE) find_program(DESKTOP_FILE_INSTALL desktop-file-install)@@ -265,7 +279,6 @@ if(APPLE OR WIN32)
set_target_properties(${BINARY_NAME}-qt PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) endif() if(APPLE) - message(STATUS ${CMAKE_SYSTEM_NAME}) if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") get_target_property(QTCOCOA Qt5::QCocoaIntegrationPlugin LOCATION) get_target_property(COREAUDIO Qt5::CoreAudioPlugin LOCATION)
@@ -69,7 +69,7 @@ m_gl->context()->moveToThread(m_drawThread);
m_painter->moveToThread(m_drawThread); connect(m_drawThread, &QThread::started, m_painter, &PainterGL::start); m_drawThread->start(); - mCoreSyncSetVideoSync(&m_context->sync, false); + mCoreSyncSetVideoSync(&m_context->impl->sync, false); lockAspectRatio(isAspectRatioLocked()); lockIntegerScaling(isIntegerScalingLocked());@@ -338,9 +338,9 @@ if (m_queue.isEmpty() || !mCoreThreadIsActive(m_context)) {
return; } - if (mCoreSyncWaitFrameStart(&m_context->sync) || !m_queue.isEmpty()) { + if (mCoreSyncWaitFrameStart(&m_context->impl->sync) || !m_queue.isEmpty()) { dequeue(); - mCoreSyncWaitFrameEnd(&m_context->sync); + mCoreSyncWaitFrameEnd(&m_context->impl->sync); m_painter.begin(m_gl->context()->device()); performDraw(); m_painter.end();@@ -354,7 +354,7 @@ }
m_delayTimer.restart(); } } else { - mCoreSyncWaitFrameEnd(&m_context->sync); + mCoreSyncWaitFrameEnd(&m_context->impl->sync); } if (!m_queue.isEmpty()) { QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection);
@@ -51,7 +51,8 @@ #else
m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB555); #endif #else - m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_RGB32); + m_backing = QImage(reinterpret_cast<const uchar*>(buffer), m_width, m_height, QImage::Format_ARGB32); + m_backing = m_backing.convertToFormat(QImage::Format_RGB32); #endif }
@@ -79,7 +79,7 @@ #endif
default: break; } - controller->m_fpsTarget = context->sync.fpsTarget; + controller->m_fpsTarget = context->impl->sync.fpsTarget; if (controller->m_override) { controller->m_override->identify(context->core);@@ -126,7 +126,6 @@
if (controller->m_multiplayer) { controller->m_multiplayer->detachGame(controller); } - controller->m_patch = QString(); controller->clearOverride(); controller->endVideoLog();@@ -300,8 +299,8 @@ m_config = config;
if (isLoaded()) { Interrupter interrupter(this); mCoreLoadForeignConfig(m_threadContext.core, config); - m_audioSync = m_threadContext.sync.audioWait; - m_videoSync = m_threadContext.sync.videoFrameWait; + m_audioSync = m_threadContext.impl->sync.audioWait; + m_videoSync = m_threadContext.impl->sync.videoFrameWait; m_audioProcessor->setInput(&m_threadContext); } }@@ -411,13 +410,6 @@ }
m_pauseAfterFrame = false; - if (m_turbo) { - m_threadContext.sync.videoFrameWait = false; - m_threadContext.sync.audioWait = false; - } else { - m_threadContext.sync.videoFrameWait = m_videoSync; - m_threadContext.sync.audioWait = m_audioSync; - } m_threadContext.core->init(m_threadContext.core); mCoreInitConfig(m_threadContext.core, nullptr);@@ -474,6 +466,7 @@ if (patch) {
m_threadContext.core->loadPatch(m_threadContext.core, patch); } patch->close(patch); + m_patch = QString(); } else { mCoreAutoloadPatch(m_threadContext.core); }@@ -483,6 +476,13 @@
if (!mCoreThreadStart(&m_threadContext)) { emit gameFailed(); } + if (m_turbo) { + m_threadContext.impl->sync.videoFrameWait = false; + m_threadContext.impl->sync.audioWait = false; + } else { + m_threadContext.impl->sync.videoFrameWait = m_videoSync; + m_threadContext.impl->sync.audioWait = m_audioSync; + } } void GameController::loadBIOS(int platform, const QString& path) {@@ -543,12 +543,10 @@ mCoreLoadFile(m_threadContext.core, m_fname.toLocal8Bit().constData());
} void GameController::loadPatch(const QString& path) { + m_patch = path; if (m_gameOpen) { closeGame(); - m_patch = path; openGame(); - } else { - m_patch = path; } }@@ -713,14 +711,14 @@ void GameController::setRewind(bool enable, int capacity, bool rewindSave) {
if (m_gameOpen) { Interrupter interrupter(this); if (m_threadContext.core->opts.rewindEnable && m_threadContext.core->opts.rewindBufferCapacity > 0) { - mCoreRewindContextDeinit(&m_threadContext.rewind); + mCoreRewindContextDeinit(&m_threadContext.impl->rewind); } m_threadContext.core->opts.rewindEnable = enable; m_threadContext.core->opts.rewindBufferCapacity = capacity; m_threadContext.core->opts.rewindSave = rewindSave; if (enable && capacity > 0) { - mCoreRewindContextInit(&m_threadContext.rewind, capacity, true); - m_threadContext.rewind.stateFlags = rewindSave ? SAVESTATE_SAVEDATA : 0; + mCoreRewindContextInit(&m_threadContext.impl->rewind, capacity, true); + m_threadContext.impl->rewind.stateFlags = rewindSave ? SAVESTATE_SAVEDATA : 0; } } }@@ -731,7 +729,7 @@ if (!states) {
states = INT_MAX; } for (int i = 0; i < states; ++i) { - if (!mCoreRewindRestore(&m_threadContext.rewind, m_threadContext.core)) { + if (!mCoreRewindRestore(&m_threadContext.impl->rewind, m_threadContext.core)) { break; } }@@ -873,8 +871,10 @@ LOG(QT, ERROR) << tr("Failed to start audio processor");
// Don't freeze! m_audioSync = false; m_videoSync = true; - m_threadContext.sync.audioWait = false; - m_threadContext.sync.videoFrameWait = true; + if (isLoaded()) { + m_threadContext.impl->sync.audioWait = false; + m_threadContext.impl->sync.videoFrameWait = true; + } } }@@ -895,9 +895,11 @@
void GameController::setFPSTarget(float fps) { Interrupter interrupter(this); m_fpsTarget = fps; - m_threadContext.sync.fpsTarget = fps; - if (m_turbo && m_turboSpeed > 0) { - m_threadContext.sync.fpsTarget *= m_turboSpeed; + if (isLoaded()) { + m_threadContext.impl->sync.fpsTarget = fps; + if (m_turbo && m_turboSpeed > 0) { + m_threadContext.impl->sync.fpsTarget *= m_turboSpeed; + } } if (m_audioProcessor) { redoSamples(m_audioProcessor->getBufferSamples());@@ -1015,22 +1017,25 @@ }
void GameController::enableTurbo() { Interrupter interrupter(this); + if (!isLoaded()) { + return; + } bool shouldRedoSamples = false; if (!m_turbo) { - shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget; - m_threadContext.sync.fpsTarget = m_fpsTarget; - m_threadContext.sync.audioWait = m_audioSync; - m_threadContext.sync.videoFrameWait = m_videoSync; + shouldRedoSamples = m_threadContext.impl->sync.fpsTarget != m_fpsTarget; + m_threadContext.impl->sync.fpsTarget = m_fpsTarget; + m_threadContext.impl->sync.audioWait = m_audioSync; + m_threadContext.impl->sync.videoFrameWait = m_videoSync; } else if (m_turboSpeed <= 0) { - shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget; - m_threadContext.sync.fpsTarget = m_fpsTarget; - m_threadContext.sync.audioWait = false; - m_threadContext.sync.videoFrameWait = false; + shouldRedoSamples = m_threadContext.impl->sync.fpsTarget != m_fpsTarget; + m_threadContext.impl->sync.fpsTarget = m_fpsTarget; + m_threadContext.impl->sync.audioWait = false; + m_threadContext.impl->sync.videoFrameWait = false; } else { - shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget * m_turboSpeed; - m_threadContext.sync.fpsTarget = m_fpsTarget * m_turboSpeed; - m_threadContext.sync.audioWait = true; - m_threadContext.sync.videoFrameWait = false; + shouldRedoSamples = m_threadContext.impl->sync.fpsTarget != m_fpsTarget * m_turboSpeed; + m_threadContext.impl->sync.fpsTarget = m_fpsTarget * m_turboSpeed; + m_threadContext.impl->sync.audioWait = true; + m_threadContext.impl->sync.videoFrameWait = false; } if (m_audioProcessor && shouldRedoSamples) { redoSamples(m_audioProcessor->getBufferSamples());@@ -1040,24 +1045,30 @@
void GameController::setSync(bool enable) { m_turbo = false; m_turboForced = false; - if (!enable) { - m_threadContext.sync.audioWait = false; - m_threadContext.sync.videoFrameWait = false; - } else { - m_threadContext.sync.audioWait = m_audioSync; - m_threadContext.sync.videoFrameWait = m_videoSync; + if (isLoaded()) { + if (!enable) { + m_threadContext.impl->sync.audioWait = false; + m_threadContext.impl->sync.videoFrameWait = false; + } else { + m_threadContext.impl->sync.audioWait = m_audioSync; + m_threadContext.impl->sync.videoFrameWait = m_videoSync; + } } m_sync = enable; } void GameController::setAudioSync(bool enable) { m_audioSync = enable; - m_threadContext.sync.audioWait = enable; + if (isLoaded()) { + m_threadContext.impl->sync.audioWait = enable; + } } void GameController::setVideoSync(bool enable) { m_videoSync = enable; - m_threadContext.sync.videoFrameWait = enable; + if (isLoaded()) { + m_threadContext.impl->sync.videoFrameWait = enable; + } } void GameController::setAVStream(mAVStream* stream) {
@@ -20,7 +20,7 @@ , m_controller(controller)
, m_key(GBA_KEY_NONE) { ignore(); - if (controller) { + if (controller && controller->map()) { m_key = static_cast<GBAKey>(mInputMapAxis(controller->map(), type, axis, direction * INT_MAX)); } }
@@ -19,7 +19,7 @@ , m_controller(controller)
, m_key(GBA_KEY_NONE) { ignore(); - if (controller) { + if (controller && controller->map()) { m_key = static_cast<GBAKey>(mInputMapKey(controller->map(), type, button)); } }
@@ -20,7 +20,7 @@ , m_controller(controller)
, m_key(GBA_KEY_NONE) { ignore(); - if (controller) { + if (controller && controller->map()) { m_key = static_cast<GBAKey>(mInputMapHat(controller->map(), type, hatId, direction)); } }
@@ -10,6 +10,7 @@ #include "ConfigController.h"
#include "Display.h" #include "GBAApp.h" #include "InputController.h" +#include "ShaderSelector.h" #include "ShortcutView.h" #include <mgba/core/serialize.h>@@ -158,7 +159,7 @@
m_ui.languages->setItemData(0, QLocale("en")); QDir ts(":/translations/"); for (auto name : ts.entryList()) { - if (!name.endsWith(".qm")) { + if (!name.endsWith(".qm") || !name.startsWith(binaryName)) { continue; } QLocale locale(name.remove(QString("%0-").arg(binaryName)).remove(".qm"));@@ -180,6 +181,24 @@ m_ui.stackedWidget->addWidget(m_shortcutView);
m_ui.tabs->addItem(tr("Shortcuts")); } +SettingsView::~SettingsView() { +#if defined(BUILD_GL) || defined(BUILD_GLES) + if (m_shader) { + m_ui.stackedWidget->removeWidget(m_shader); + m_shader->setParent(nullptr); + } +#endif +} + +void SettingsView::setShaderSelector(ShaderSelector* shaderSelector) { +#if defined(BUILD_GL) || defined(BUILD_GLES) + m_shader = shaderSelector; + m_ui.stackedWidget->addWidget(m_shader); + m_ui.tabs->addItem(tr("Shaders")); + connect(m_ui.buttonBox, &QDialogButtonBox::accepted, m_shader, &ShaderSelector::saved); +#endif +} + void SettingsView::selectBios(QLineEdit* bios) { QString filename = GBAApp::app()->getOpenFileName(this, tr("Select BIOS")); if (!filename.isEmpty()) {@@ -314,6 +333,8 @@ loadSetting("screenshotPath", m_ui.screenshotPath);
loadSetting("patchPath", m_ui.patchPath); loadSetting("showLibrary", m_ui.showLibrary); loadSetting("preload", m_ui.preload); + + m_ui.libraryStyle->setCurrentIndex(loadSetting("libraryStyle").toInt()); double fastForwardRatio = loadSetting("fastForwardRatio").toDouble(); if (fastForwardRatio <= 0) {
@@ -18,12 +18,16 @@ class ConfigController;
class InputController; class InputIndex; class ShortcutView; +class ShaderSelector; class SettingsView : public QDialog { Q_OBJECT public: SettingsView(ConfigController* controller, InputController* inputController, QWidget* parent = nullptr); + ~SettingsView(); + + void setShaderSelector(ShaderSelector* shaderSelector); signals: void biosLoaded(int platform, const QString&);@@ -45,6 +49,7 @@ ConfigController* m_controller;
InputController* m_input; ShortcutView* m_shortcutView; ShortcutView* m_keyView; + ShaderSelector* m_shader = nullptr; void saveSetting(const char* key, const QAbstractButton*); void saveSetting(const char* key, const QComboBox*);
@@ -21,6 +21,8 @@ #include <mgba/core/version.h>
#include <mgba-util/vfs.h> #include "platform/video-backend.h" +#if defined(BUILD_GL) || defined(BUILD_GLES) + #if !defined(_WIN32) || defined(USE_EPOXY) #include "platform/opengl/gles2.h" #endif@@ -39,6 +41,9 @@
connect(m_ui.load, &QAbstractButton::clicked, this, &ShaderSelector::selectShader); connect(m_ui.unload, &QAbstractButton::clicked, this, &ShaderSelector::clearShader); connect(m_ui.buttonBox, &QDialogButtonBox::clicked, this, &ShaderSelector::buttonPressed); + connect(this, &ShaderSelector::saved, [this]() { + m_config->setOption("shader", m_shaderPath); + }); } ShaderSelector::~ShaderSelector() {@@ -59,7 +64,7 @@
void ShaderSelector::selectShader() { QString path(GBAApp::dataDir()); path += QLatin1String("/shaders"); - QFileDialog dialog(nullptr, tr("Load shader"), path, tr("%1 Shader (%.shader)").arg(projectName)); + QFileDialog dialog(nullptr, tr("Load shader"), path); dialog.setFileMode(QFileDialog::Directory); dialog.exec(); QStringList names = dialog.selectedFiles();@@ -86,7 +91,6 @@ void ShaderSelector::clearShader() {
m_display->clearShaders(); refreshShaders(); m_shaderPath = ""; - m_config->setOption("shader", nullptr); } void ShaderSelector::refreshShaders() {@@ -114,6 +118,10 @@
disconnect(this, &ShaderSelector::saved, 0, 0); disconnect(this, &ShaderSelector::reset, 0, 0); disconnect(this, &ShaderSelector::resetToDefault, 0, 0); + + connect(this, &ShaderSelector::saved, [this]() { + m_config->setOption("shader", m_shaderPath); + }); #if !defined(_WIN32) || defined(USE_EPOXY) if (m_shaders->preprocessShader) {@@ -264,7 +272,6 @@ case QDialogButtonBox::Reset:
emit reset(); break; case QDialogButtonBox::Ok: - m_config->setOption("shader", m_shaderPath); emit saved(); close(); break;@@ -275,3 +282,5 @@ default:
break; } } + +#endif
@@ -6,6 +6,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef QGBA_SHADER_SELECTOR_H #define QGBA_SHADER_SELECTOR_H +#if defined(BUILD_GL) || defined(BUILD_GLES) + #include <QDialog> #include "ui_ShaderSelector.h"@@ -56,3 +58,5 @@
} #endif + +#endif
@@ -81,32 +81,35 @@ </property>
</widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> <widget class="QPushButton" name="unload"> <property name="text"> <string>Unload Shader</string> </property> </widget> </item> - <item> + <item row="0" column="1"> <widget class="QPushButton" name="load"> <property name="text"> <string>Load New Shader</string> </property> </widget> </item> + <item row="1" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Reset|QDialogButtonBox::RestoreDefaults</set> + </property> + <property name="centerButtons"> + <bool>true</bool> + </property> + </widget> + </item> </layout> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Ok|QDialogButtonBox::Reset|QDialogButtonBox::RestoreDefaults</set> - </property> - </widget> </item> </layout> </widget>
@@ -100,7 +100,9 @@ m_controller->setInputController(&m_inputController);
updateTitle(); m_display = Display::create(this); +#if defined(BUILD_GL) || defined(BUILD_GLES) m_shaderView = new ShaderSelector(m_display, m_config); +#endif m_logo.setDevicePixelRatio(m_screenWidget->devicePixelRatio()); m_logo = m_logo; // Free memory left over in old pixmap@@ -199,7 +201,6 @@ connect(this, &Window::startDrawing, m_display, &Display::startDrawing, Qt::QueuedConnection);
connect(this, &Window::shutdown, m_display, &Display::stopDrawing); connect(this, &Window::shutdown, m_controller, &GameController::closeGame); connect(this, &Window::shutdown, m_logView, &QWidget::hide); - connect(this, &Window::shutdown, m_shaderView, &QWidget::hide); connect(this, &Window::audioBufferSamplesChanged, m_controller, &GameController::setAudioBufferSamples); connect(this, &Window::sampleRateChanged, m_controller, &GameController::setAudioSampleRate); connect(this, &Window::fpsTargetChanged, m_controller, &GameController::setFPSTarget);@@ -308,6 +309,7 @@ if (opts->fullscreen) {
enterFullScreen(); } +#if defined(BUILD_GL) || defined(BUILD_GLES) if (opts->shader) { struct VDir* shader = VDirOpen(opts->shader); if (shader) {@@ -316,6 +318,7 @@ m_shaderView->refreshShaders();
shader->close(shader); } } +#endif m_mruFiles = m_config->getMRU(); updateMRU();@@ -509,6 +512,11 @@ }
void Window::openSettingsWindow() { SettingsView* settingsWindow = new SettingsView(m_config, &m_inputController); +#if defined(BUILD_GL) || defined(BUILD_GLES) + if (m_display->supportsShaders()) { + settingsWindow->setShaderSelector(m_shaderView); + } +#endif connect(settingsWindow, &SettingsView::biosLoaded, m_controller, &GameController::loadBIOS); connect(settingsWindow, &SettingsView::audioDriverChanged, m_controller, &GameController::reloadAudioDriver); connect(settingsWindow, &SettingsView::displayDriverChanged, this, &Window::mustRestart);@@ -763,14 +771,9 @@ }
} void Window::gameStarted(mCoreThread* context, const QString& fname) { - MutexLock(&context->stateMutex); - if (context->state < THREAD_EXITING) { - emit startDrawing(context); - } else { - MutexUnlock(&context->stateMutex); + if (!mCoreThreadIsActive(context)) { return; } - MutexUnlock(&context->stateMutex); int platform = 1 << context->core->platform(context->core); #ifdef M_CORE_DS if ((platform & SUPPORT_DS) && (!m_config->getOption("useBios").toInt() || m_config->getOption("ds.bios7").isNull() || m_config->getOption("ds.bios9").isNull() || m_config->getOption("ds.firmware").isNull())) {@@ -783,6 +786,7 @@ m_controller->closeGame();
return; } #endif + emit startDrawing(context); for (QAction* action : m_gameActions) { action->setDisabled(false); }@@ -887,6 +891,7 @@ tr("The game has crashed with the following error:\n\n%1").arg(errorMessage),
QMessageBox::Ok, this, Qt::Sheet); crash->setAttribute(Qt::WA_DeleteOnClose); crash->show(); + connect(m_controller, &GameController::gameStarted, crash, &QWidget::close); } void Window::gameFailed() {@@ -895,6 +900,7 @@ tr("Could not load game. Are you sure it's in the correct format?"),
QMessageBox::Ok, this, Qt::Sheet); fail->setAttribute(Qt::WA_DeleteOnClose); fail->show(); + connect(m_controller, &GameController::gameStarted, fail, &QWidget::close); } void Window::unimplementedBiosCall(int call) {@@ -1364,13 +1370,6 @@ for (int i = 0; i <= 10; ++i) {
skip->addValue(QString::number(i), i, skipMenu); } m_config->updateOption("frameskip"); - - QAction* shaderView = new QAction(tr("Shader options..."), avMenu); - connect(shaderView, &QAction::triggered, m_shaderView, &QWidget::show); - if (!m_display->supportsShaders()) { - shaderView->setEnabled(false); - } - addControlledAction(avMenu, shaderView, "shaderSelector"); avMenu->addSeparator();
@@ -375,6 +375,9 @@ #endif
} const mInputMap* InputController::map() { + if (!m_activeKeyInfo) { + return nullptr; + } return &m_inputMap; }
@@ -120,7 +120,13 @@
QModelIndex InputModel::index(int row, int column, const QModelIndex& parent) const { if (parent.isValid()) { InputModelItem* p = static_cast<InputModelItem*>(parent.internalPointer()); + if (row >= m_tree[p->obj].count()) { + return QModelIndex(); + } return createIndex(row, column, const_cast<InputModelItem*>(&m_tree[p->obj][row])); + } + if (row >= m_topLevelMenus.count()) { + return QModelIndex(); } return createIndex(row, column, const_cast<InputModelItem*>(&m_topLevelMenus[row])); }
@@ -30,7 +30,7 @@
using namespace QGBA; int main(int argc, char* argv[]) { -#ifdef BUILD_SDL +#if defined(BUILD_SDL) && SDL_VERSION_ATLEAST(2, 0, 0) SDL_SetMainReady(); #endif@@ -57,6 +57,12 @@
QTranslator qtTranslator; qtTranslator.load(locale, "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath)); application.installTranslator(&qtTranslator); + +#ifdef QT_STATIC + QTranslator qtStaticTranslator; + qtStaticTranslator.load(locale, "qtbase", "_", ":/translations/"); + application.installTranslator(&qtStaticTranslator); +#endif QTranslator langTranslator; langTranslator.load(locale, binaryName, "-", ":/translations/");
@@ -1,7 +1,6 @@
-file(GLOB TRANSLATION_FILES "${QM_BASE}/*.qm") file(WRITE ${TRANSLATION_QRC} "<RCC>\n\t<qresource prefix=\"/translations/\">\n") foreach(TS ${TRANSLATION_FILES}) get_filename_component(TS_BASE "${TS}" NAME) - file(APPEND ${TRANSLATION_QRC} "\t\t<file>${TS_BASE}</file>\n") + file(APPEND ${TRANSLATION_QRC} "\t\t<file alias=\"${TS_BASE}\">${TS}</file>\n") endforeach() file(APPEND ${TRANSLATION_QRC} "\t</qresource>\n</RCC>")
@@ -40,9 +40,9 @@ <translation>{projectVersion}</translation>
</message> <message> <location filename="../AboutScreen.ui" line="86"/> - <source>© 2013 – 2016 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + <source>© 2013 – 2017 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy and Game Boy Advance are registered trademarks of Nintendo Co., Ltd.</source> - <translation>© 2013 – 2016 Jeffrey Pfau, lizenziert unter der Mozilla Public License, Version 2.0 + <translation>© 2013 – 2017 Jeffrey Pfau, lizenziert unter der Mozilla Public License, Version 2.0 Game Boy und Game Boy Advance sind eingetragene Warenzeichen von Nintendo Co., Ltd.</translation> </message> <message>@@ -458,8 +458,8 @@ <context>
<name>MemorySearch</name> <message> <location filename="../MemorySearch.ui" line="20"/> - <source>Form</source> - <translation>Eingabemaske</translation> + <source>Memory Search</source> + <translation>Speicher durchsuchen</translation> </message> <message> <location filename="../MemorySearch.ui" line="45"/>@@ -1146,28 +1146,28 @@ </context>
<context> <name>QGBA::GameController</name> <message> - <location filename="../GameController.cpp" line="351"/> - <location filename="../GameController.cpp" line="535"/> + <location filename="../GameController.cpp" line="352"/> + <location filename="../GameController.cpp" line="536"/> <source>Failed to open game file: %1</source> <translation>Fehler beim Öffnen der Spieldatei: %1</translation> </message> <message> - <location filename="../GameController.cpp" line="507"/> + <location filename="../GameController.cpp" line="508"/> <source>Failed to open save file: %1</source> <translation>Fehler beim Öffnen der Speicherdatei: %1</translation> </message> <message> - <location filename="../GameController.cpp" line="564"/> + <location filename="../GameController.cpp" line="565"/> <source>Failed to open snapshot file for reading: %1</source> <translation>Konnte Snapshot-Datei %1 nicht zum Lesen öffnen</translation> </message> <message> - <location filename="../GameController.cpp" line="584"/> + <location filename="../GameController.cpp" line="585"/> <source>Failed to open snapshot file for writing: %1</source> <translation>Konnte Snapshot-Datei %1 nicht zum Schreiben öffnen</translation> </message> <message> - <location filename="../GameController.cpp" line="850"/> + <location filename="../GameController.cpp" line="851"/> <source>Failed to start audio processor</source> <translation>Fehler beim Starten des Audio-Prozessors</translation> </message>@@ -3285,7 +3285,7 @@ </message>
<message> <location filename="../Window.cpp" line="1105"/> <source>Sh&utdown</source> - <translation>B&eenden</translation> + <translation>Schli&eßen</translation> </message> <message> <location filename="../Window.cpp" line="1111"/>@@ -3935,7 +3935,7 @@ </message>
<message> <location filename="../SettingsView.ui" line="173"/> <source>Sample rate:</source> - <translation>Sample-Rate:</translation> + <translation>Abtastrate:</translation> </message> <message> <location filename="../SettingsView.ui" line="185"/>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> -<TS version="2.1" language="es" sourcelanguage="en_US"> +<TS version="2.1" language="es_419" sourcelanguage="en_US"> <context> <name>AboutScreen</name> <message>@@ -11,7 +11,12 @@ </message>
<message> <location filename="../AboutScreen.ui" line="23"/> <source><a href="http://mgba.io/">Website</a> • <a href="https://forums.mgba.io/">Forums / Support</a> • <a href="https://patreon.com/mgba">Donate</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Source</a></source> - <translation><a href="http://mgba.io/">Sitio web</a> • <a href="https://forums.mgba.io/">Foros / Soporte</a> • <a href="https://patreon.com/mgba">Donar</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Código fuente</a></translation> + <translation><a href="http://mgba.io/">Sitio web</a> • <a href="https://forums.mgba.io/">Foros / soporte</a> • <a href="https://patreon.com/mgba">Donar</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Código fuente</a></translation> + </message> + <message> + <location filename="../AboutScreen.ui" line="41"/> + <source>Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt></source> + <translation>Rama: <tt>{gitBranch}</tt><br/>Revisión: <tt>{gitCommit}</tt></translation> </message> <message> <location filename="../AboutScreen.ui" line="58"/>@@ -21,17 +26,14 @@ </message>
<message> <location filename="../AboutScreen.ui" line="68"/> <source>{projectName} would like to thank the following patrons from Patreon:</source> - <translation>{projectName} desea agradecer a los siguientes mecenas de Patreon:</translation> + <translation>{projectName} desea agradecer a los siguientes patrocinadores desde Patreon:</translation> </message> <message> - <location filename="../AboutScreen.ui" line="177"/> - <source>{projectName} is an open-source Game Boy/Game Boy Advance/DS emulator</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../AboutScreen.ui" line="190"/> - <source>{patrons}</source> - <translation>{patrons}</translation> + <location filename="../AboutScreen.ui" line="86"/> + <source>© 2013 – 2017 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd.</source> + <translation>© 2013 – 2017 Jeffrey Pfau, licenciado bajo la Mozilla Public License, versión 2.0 +Game Boy Advance es una marca registrada de Nintendo Co., Ltd.</translation> </message> <message> <location filename="../AboutScreen.ui" line="106"/>@@ -39,20 +41,19 @@ <source>{projectVersion}</source>
<translation>{projectVersion}</translation> </message> <message> - <location filename="../AboutScreen.ui" line="86"/> - <source>© 2013 – 2016 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 -Game Boy and Game Boy Advance are registered trademarks of Nintendo Co., Ltd.</source> - <translation type="unfinished"></translation> - </message> - <message> <location filename="../AboutScreen.ui" line="155"/> <source>{logo}</source> <translation>{logo}</translation> </message> <message> - <location filename="../AboutScreen.ui" line="41"/> - <source>Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt></source> - <translation>Rama Git: <tt>{gitBranch}</tt><br/>Revisión: <tt>{gitCommit}</tt></translation> + <location filename="../AboutScreen.ui" line="177"/> + <source>{projectName} is an open-source Game Boy Advance emulator</source> + <translation>{projectName} es un emulador de código abierto de Game Boy Advance</translation> + </message> + <message> + <location filename="../AboutScreen.ui" line="190"/> + <source>{patrons}</source> + <translation>{patrons}</translation> </message> </context> <context>@@ -60,7 +61,7 @@ <name>ArchiveInspector</name>
<message> <location filename="../ArchiveInspector.ui" line="14"/> <source>Open in archive...</source> - <translation>Abrir dentro de archivo ...</translation> + <translation>Abrir desde contenedor...</translation> </message> <message> <location filename="../ArchiveInspector.ui" line="20"/>@@ -128,7 +129,7 @@ </message>
<message> <location filename="../CheatsView.ui" line="20"/> <source>Remove</source> - <translation>Eliminar</translation> + <translation>Quitar</translation> </message> <message> <location filename="../CheatsView.ui" line="34"/>@@ -161,12 +162,12 @@ </message>
<message> <location filename="../DebuggerConsole.ui" line="25"/> <source>Enter command (try `help` for more info)</source> - <translation>Ingresa un comando (prueba con 'help' para más información)</translation> + <translation>Ingresa un comando (intenta `help` para más información)</translation> </message> <message> <location filename="../DebuggerConsole.ui" line="32"/> <source>Break</source> - <translation>Entrar en depuración</translation> + <translation>Entrar a depuración</translation> </message> </context> <context>@@ -189,7 +190,7 @@ </message>
<message> <location filename="../GIFView.ui" line="63"/> <source>Select File</source> - <translation>Elegir archivo</translation> + <translation>Seleccionar archivo</translation> </message> <message> <location filename="../GIFView.ui" line="101"/>@@ -212,7 +213,7 @@ <name>IOViewer</name>
<message> <location filename="../IOViewer.ui" line="14"/> <source>I/O Viewer</source> - <translation>Visor de E/S</translation> + <translation>Visor de I/O</translation> </message> <message> <location filename="../IOViewer.ui" line="26"/>@@ -305,27 +306,27 @@ <name>LibraryTree</name>
<message> <location filename="../library/LibraryTree.cpp" line="46"/> <source>Name</source> - <translation type="unfinished">Nombre</translation> + <translation>Nombre</translation> </message> <message> <location filename="../library/LibraryTree.cpp" line="47"/> <source>Location</source> - <translation type="unfinished">Ubicación</translation> + <translation>Ubicación</translation> </message> <message> <location filename="../library/LibraryTree.cpp" line="48"/> <source>Platform</source> - <translation type="unfinished">Plataforma</translation> + <translation>Plataforma</translation> </message> <message> <location filename="../library/LibraryTree.cpp" line="49"/> <source>Size</source> - <translation type="unfinished">Tamaño</translation> + <translation>Tamaño</translation> </message> <message> <location filename="../library/LibraryTree.cpp" line="50"/> <source>CRC32</source> - <translation type="unfinished">CRC32</translation> + <translation>CRC32</translation> </message> </context> <context>@@ -334,7 +335,7 @@ <message>
<location filename="../LoadSaveState.ui" line="14"/> <location filename="../LoadSaveState.ui" line="88"/> <source>%1 State</source> - <translation>%1 captura de estado</translation> + <translation>%1 estado</translation> </message> <message> <location filename="../LoadSaveState.ui" line="41"/>@@ -347,7 +348,7 @@ <location filename="../LoadSaveState.ui" line="195"/>
<location filename="../LoadSaveState.ui" line="217"/> <location filename="../LoadSaveState.ui" line="239"/> <source>No Save</source> - <translation>Sin captura</translation> + <translation>Sin estado</translation> </message> <message> <location filename="../LoadSaveState.ui" line="50"/>@@ -410,22 +411,22 @@ </message>
<message> <location filename="../LogView.ui" line="28"/> <source>Debug</source> - <translation>Depuración</translation> + <translation>Depuración (Debug)</translation> </message> <message> <location filename="../LogView.ui" line="38"/> <source>Stub</source> - <translation>Auxiliar</translation> + <translation>Stub</translation> </message> <message> <location filename="../LogView.ui" line="48"/> <source>Info</source> - <translation>Información</translation> + <translation>Información (Info)</translation> </message> <message> <location filename="../LogView.ui" line="58"/> <source>Warning</source> - <translation>Advertencia</translation> + <translation>Advertencia (Warning)</translation> </message> <message> <location filename="../LogView.ui" line="68"/>@@ -440,7 +441,7 @@ </message>
<message> <location filename="../LogView.ui" line="95"/> <source>Game Error</source> - <translation>Error del juego</translation> + <translation>Error de juego</translation> </message> <message> <location filename="../LogView.ui" line="121"/>@@ -454,11 +455,110 @@ <translation>Máximo de líneas</translation>
</message> </context> <context> + <name>MemorySearch</name> + <message> + <location filename="../MemorySearch.ui" line="20"/> + <source>Memory Search</source> + <translation>Búsqueda en la memoria</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="45"/> + <source>Address</source> + <translation>Dirección</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="50"/> + <source>Current Value</source> + <translation>Valor actual</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="55"/> + <location filename="../MemorySearch.ui" line="75"/> + <source>Type</source> + <translation>Tipo</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="65"/> + <source>Value</source> + <translation>Valor</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="82"/> + <source>Numeric</source> + <translation>Numérico</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="95"/> + <source>Text</source> + <translation>Texto</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="105"/> + <source>Width</source> + <translation>Ancho</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="112"/> + <source>1 Byte (8-bit)</source> + <translation>1 byte (8 bits)</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="122"/> + <source>2 Bytes (16-bit)</source> + <translation>2 bytes (16 bits)</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="132"/> + <source>4 Bytes (32-bit)</source> + <translation>4 bytes (32 bits)</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="145"/> + <source>Number type</source> + <translation>Tipo de número</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="152"/> + <source>Hexadecimal</source> + <translation>Hexadecimal</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="162"/> + <source>Decimal</source> + <translation>Decimal</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="169"/> + <source>Guess</source> + <translation>Adivinar</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="187"/> + <source>Search</source> + <translation>Buscar</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="194"/> + <source>Search Within</source> + <translation>Buscar dentro</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="201"/> + <source>Open in Memory Viewer</source> + <translation>Abrir en el Visor de memoria</translation> + </message> + <message> + <location filename="../MemorySearch.ui" line="208"/> + <source>Refresh</source> + <translation>Actualizar</translation> + </message> +</context> +<context> <name>MemoryView</name> <message> <location filename="../MemoryView.ui" line="14"/> <source>Memory</source> - <translation>Memoría</translation> + <translation>Visor de memoria</translation> </message> <message> <location filename="../MemoryView.ui" line="38"/>@@ -473,7 +573,7 @@ </message>
<message> <location filename="../MemoryView.ui" line="81"/> <source>Set Alignment:</source> - <translation>Alinear en:</translation> + <translation>Alinear a:</translation> </message> <message> <location filename="../MemoryView.ui" line="101"/>@@ -491,6 +591,11 @@ <source>4 Bytes</source>
<translation>4 bytes</translation> </message> <message> + <location filename="../MemoryView.ui" line="181"/> + <source>Unsigned Integer:</source> + <translation>Entero sin signo:</translation> + </message> + <message> <location filename="../MemoryView.ui" line="199"/> <source>Signed Integer:</source> <translation>Entero con signo:</translation>@@ -525,11 +630,6 @@ <location filename="../MemoryView.ui" line="278"/>
<source>Load</source> <translation>Cargar</translation> </message> - <message> - <location filename="../MemoryView.ui" line="181"/> - <source>Unsigned Integer:</source> - <translation>Entero sin signo:</translation> - </message> </context> <context> <name>ObjView</name>@@ -542,17 +642,17 @@ <message>
<location filename="../ObjView.ui" line="56"/> <location filename="../ObjView.ui" line="506"/> <source>×</source> - <translation>×</translation> + <translation>x</translation> </message> <message> <location filename="../ObjView.ui" line="69"/> <source>Magnification</source> - <translation>Magnificación</translation> + <translation>Ampliación</translation> </message> <message> <location filename="../ObjView.ui" line="76"/> <source>Export</source> - <translation type="unfinished"></translation> + <translation>Esportar</translation> </message> <message> <location filename="../ObjView.ui" line="85"/>@@ -585,7 +685,7 @@ </message>
<message> <location filename="../ObjView.ui" line="158"/> <source>Double Size</source> - <translation>Doble tamaño</translation> + <translation>Tamaño doble</translation> </message> <message> <location filename="../ObjView.ui" line="184"/>@@ -682,7 +782,7 @@ <name>OverrideView</name>
<message> <location filename="../OverrideView.ui" line="20"/> <source>Game Overrides</source> - <translation>Valores específicos por juego</translation> + <translation>Ajustes específicos por juego</translation> </message> <message> <location filename="../OverrideView.ui" line="30"/>@@ -700,7 +800,7 @@ </message>
<message> <location filename="../OverrideView.ui" line="55"/> <source>Realtime clock</source> - <translation>Reloj de tiempo real</translation> + <translation>Reloj en tiempo real</translation> </message> <message> <location filename="../OverrideView.ui" line="65"/>@@ -710,7 +810,7 @@ </message>
<message> <location filename="../OverrideView.ui" line="75"/> <source>Tilt</source> - <translation>Inclinación</translation> + <translation>Sensor de inclinación</translation> </message> <message> <location filename="../OverrideView.ui" line="85"/>@@ -761,7 +861,7 @@ </message>
<message> <location filename="../OverrideView.ui" line="195"/> <source>Game Boy Player features</source> - <translation>Habilitar Game Boy Player</translation> + <translation>Características del Game Boy Player</translation> </message> <message> <location filename="../OverrideView.ui" line="234"/>@@ -791,7 +891,7 @@ </message>
<message> <location filename="../OverrideView.ui" line="271"/> <source>Memory bank controller</source> - <translation>Controlador de banco de memoria</translation> + <translation>Controlador de bancos de memoria</translation> </message> <message> <location filename="../OverrideView.ui" line="289"/>@@ -811,7 +911,7 @@ </message>
<message> <location filename="../OverrideView.ui" line="304"/> <source>MBC3 + RTC</source> - <translation>MBC3 + Reloj</translation> + <translation>MBC3 + RTC</translation> </message> <message> <location filename="../OverrideView.ui" line="309"/>@@ -821,7 +921,7 @@ </message>
<message> <location filename="../OverrideView.ui" line="314"/> <source>MBC5 + Rumble</source> - <translation>MBC5 + Vibración</translation> + <translation>MBC5 + Rumble</translation> </message> <message> <location filename="../OverrideView.ui" line="319"/>@@ -833,6 +933,11 @@ <location filename="../OverrideView.ui" line="324"/>
<source>HuC-3</source> <translation>HuC-3</translation> </message> + <message> + <location filename="../OverrideView.ui" line="332"/> + <source>Colors</source> + <translation>Colores</translation> + </message> </context> <context> <name>PaletteView</name>@@ -849,7 +954,7 @@ </message>
<message> <location filename="../PaletteView.ui" line="94"/> <source>Objects</source> - <translation>Objetos (OBJ)</translation> + <translation>Objetos</translation> </message> <message> <location filename="../PaletteView.ui" line="153"/>@@ -881,12 +986,12 @@ </message>
<message> <location filename="../PaletteView.ui" line="244"/> <source>16-bit value</source> - <translation>Valor en 16 bits</translation> + <translation>Valor de 16 bits</translation> </message> <message> <location filename="../PaletteView.ui" line="251"/> <source>Hex code</source> - <translation>Código hexadecimal</translation> + <translation>Código hex</translation> </message> <message> <location filename="../PaletteView.ui" line="258"/>@@ -935,6 +1040,40 @@ <translation>0x%0 (%1)</translation>
</message> </context> <context> + <name>QGBA::AudioDevice</name> + <message> + <location filename="../AudioDevice.cpp" line="26"/> + <source>Can't set format of context-less audio device</source> + <translation>No se puede establecer el formato de un dispositivo de audio sin contexto</translation> + </message> + <message> + <location filename="../AudioDevice.cpp" line="48"/> + <source>Audio device is missing its core</source> + <translation>El dispositivo de audio no tiene núcleo</translation> + </message> + <message> + <location filename="../AudioDevice.cpp" line="64"/> + <source>Writing data to read-only audio device</source> + <translation>Escribiendo datos a un dispositivo de audio de sólo lectura</translation> + </message> +</context> +<context> + <name>QGBA::AudioProcessorQt</name> + <message> + <location filename="../AudioProcessorQt.cpp" line="35"/> + <source>Can't start an audio processor without input</source> + <translation>No se puede iniciar un procesador de audio sin entrada</translation> + </message> +</context> +<context> + <name>QGBA::AudioProcessorSDL</name> + <message> + <location filename="../AudioProcessorSDL.cpp" line="33"/> + <source>Can't start an audio processor without input</source> + <translation>No se puede iniciar un procesador de audio sin entrada</translation> + </message> +</context> +<context> <name>QGBA::CheatsModel</name> <message> <location filename="../CheatsModel.cpp" line="54"/>@@ -944,7 +1083,7 @@ </message>
<message> <location filename="../CheatsModel.cpp" line="209"/> <source>Failed to open cheats file: %1</source> - <translation>Ocurrió un error al cargar el archivo de trucos: %1</translation> + <translation>Error al abrir el archivo de trucos: %1</translation> </message> </context> <context>@@ -974,7 +1113,30 @@ <message>
<location filename="../CheatsView.cpp" line="112"/> <location filename="../CheatsView.cpp" line="119"/> <source>Select cheats file</source> - <translation>Elegir archivo de trucos</translation> + <translation>Seleccionar archivo de trucos</translation> + </message> +</context> +<context> + <name>QGBA::GBAKeyEditor</name> + <message> + <location filename="../GBAKeyEditor.cpp" line="68"/> + <source>Clear Button</source> + <translation>Limpiar botón</translation> + </message> + <message> + <location filename="../GBAKeyEditor.cpp" line="80"/> + <source>Clear Analog</source> + <translation>Limpiar análogo</translation> + </message> + <message> + <location filename="../GBAKeyEditor.cpp" line="91"/> + <source>Refresh</source> + <translation>Actualizar</translation> + </message> + <message> + <location filename="../GBAKeyEditor.cpp" line="101"/> + <source>Set all</source> + <translation>Configurar todo</translation> </message> </context> <context>@@ -982,7 +1144,7 @@ <name>QGBA::GDBWindow</name>
<message> <location filename="../GDBWindow.cpp" line="28"/> <source>Server settings</source> - <translation>Ajustes del servidor</translation> + <translation>Configuración del servidor</translation> </message> <message> <location filename="../GDBWindow.cpp" line="34"/>@@ -997,7 +1159,7 @@ </message>
<message> <location filename="../GDBWindow.cpp" line="55"/> <source>Break</source> - <translation>Entrar en depuración</translation> + <translation>Entrar a depuración</translation> </message> <message> <location filename="../GDBWindow.cpp" line="104"/>@@ -1012,7 +1174,7 @@ </message>
<message> <location filename="../GDBWindow.cpp" line="122"/> <source>Crash</source> - <translation>Error</translation> + <translation>Error fatal</translation> </message> <message> <location filename="../GDBWindow.cpp" line="122"/>@@ -1025,36 +1187,36 @@ <name>QGBA::GIFView</name>
<message> <location filename="../GIFView.cpp" line="46"/> <source>Failed to open output GIF file: %1</source> - <translation>Error al abrir el archivo de salida GIF: %1</translation> + <translation>Error al abrir el archivo GIF de salida: %1</translation> </message> <message> <location filename="../GIFView.cpp" line="64"/> <source>Select output file</source> - <translation>Elegir archivo de salida</translation> + <translation>Seleccionar archivo de salida</translation> </message> <message> <location filename="../GIFView.cpp" line="64"/> <source>Graphics Interchange Format (*.gif)</source> - <translation>Formato de intercambio de gráficos (*.gif)</translation> + <translation>Graphics Interchange Format (*.gif)</translation> </message> </context> <context> <name>QGBA::GameController</name> <message> - <location filename="../GameController.cpp" line="350"/> - <location filename="../GameController.cpp" line="534"/> + <location filename="../GameController.cpp" line="351"/> + <location filename="../GameController.cpp" line="536"/> <source>Failed to open game file: %1</source> <translation>Error al abrir el archivo del juego: %1</translation> </message> <message> - <location filename="../GameController.cpp" line="506"/> + <location filename="../GameController.cpp" line="508"/> <source>Failed to open save file: %1</source> <translation>Error al abrir el archivo de guardado: %1</translation> </message> <message> <location filename="../GameController.cpp" line="563"/> <source>Failed to open snapshot file for reading: %1</source> - <translation>Error al leer el archivo de captura: %1</translation> + <translation>Error al leer del archivo de captura: %1</translation> </message> <message> <location filename="../GameController.cpp" line="583"/>@@ -1062,7 +1224,7 @@ <source>Failed to open snapshot file for writing: %1</source>
<translation>Error al escribir al archivo de captura: %1</translation> </message> <message> - <location filename="../GameController.cpp" line="869"/> + <location filename="../GameController.cpp" line="849"/> <source>Failed to start audio processor</source> <translation>Error al iniciar el procesador de audio</translation> </message>@@ -1082,27 +1244,27 @@ </message>
<message> <location filename="../IOViewer.cpp" line="32"/> <source>Mode 1: 2 tile layers + 1 rotated/scaled tile layer</source> - <translation>Modo 1: 2 capas de tiles + 1 capa de tiles rotados/escalados</translation> + <translation>Modo 1: 2 capas de tiles + 1 capa de tiles con rotación/escalado</translation> </message> <message> <location filename="../IOViewer.cpp" line="33"/> <source>Mode 2: 2 rotated/scaled tile layers</source> - <translation>Modo 2: 2 capas de tiles rotados/escalados</translation> + <translation>Modo 2: 2 capas de tiles con rotación/escalado</translation> </message> <message> <location filename="../IOViewer.cpp" line="34"/> <source>Mode 3: Full 15-bit bitmap</source> - <translation>Modo 3: mapa de bits de 15 bits</translation> + <translation>Modo 3: Mapa de bits de 15 bits de tamaño completo</translation> </message> <message> <location filename="../IOViewer.cpp" line="35"/> <source>Mode 4: Full 8-bit bitmap</source> - <translation>Modo 4: mapa de bits de 8 bits</translation> + <translation>Modo 4: Mapa de bits de 8 bits de tamaño completo</translation> </message> <message> <location filename="../IOViewer.cpp" line="36"/> <source>Mode 5: Small 15-bit bitmap</source> - <translation>Modo 5: mapa de bits pequeño de 15 bits</translation> + <translation>Modo 5: Mapa de bits de 15 bits de tamaño pequeño</translation> </message> <message> <location filename="../IOViewer.cpp" line="40"/>@@ -1112,12 +1274,12 @@ </message>
<message> <location filename="../IOViewer.cpp" line="41"/> <source>Frame select</source> - <translation>Selección de cuadros</translation> + <translation>Selección de cuadro</translation> </message> <message> <location filename="../IOViewer.cpp" line="42"/> <source>Unlocked HBlank</source> - <translation>HBlank sin bloqueo</translation> + <translation>HBlank desbloqueado</translation> </message> <message> <location filename="../IOViewer.cpp" line="43"/>@@ -1132,22 +1294,22 @@ </message>
<message> <location filename="../IOViewer.cpp" line="45"/> <source>Enable background 0</source> - <translation>Habilitar fondo 0</translation> + <translation>Habilitar BG 0</translation> </message> <message> <location filename="../IOViewer.cpp" line="46"/> <source>Enable background 1</source> - <translation>Habilitar fondo 1</translation> + <translation>Habilitar BG 1</translation> </message> <message> <location filename="../IOViewer.cpp" line="47"/> <source>Enable background 2</source> - <translation>Habilitar fondo 2</translation> + <translation>Habilitar BG 2</translation> </message> <message> <location filename="../IOViewer.cpp" line="48"/> <source>Enable background 3</source> - <translation>Habilitar fondo 3</translation> + <translation>Habilitar BG 3</translation> </message> <message> <location filename="../IOViewer.cpp" line="49"/>@@ -1162,42 +1324,42 @@ </message>
<message> <location filename="../IOViewer.cpp" line="51"/> <source>Enable Window 1</source> - <translation>Habilitar Window 1</translation> + <translation>Habilitar Windows 1</translation> </message> <message> <location filename="../IOViewer.cpp" line="52"/> <source>Enable OBJ Window</source> - <translation>Habilitar Window OBJ</translation> + <translation>Habilitar Window de OBJ</translation> </message> <message> <location filename="../IOViewer.cpp" line="58"/> <source>Currently in VBlank</source> - <translation>En VBlank actualmente</translation> + <translation>En VBlank ahora</translation> </message> <message> <location filename="../IOViewer.cpp" line="59"/> <source>Currently in HBlank</source> - <translation>En HBlank actualmente</translation> + <translation>En HBlank ahora</translation> </message> <message> <location filename="../IOViewer.cpp" line="60"/> <source>Currently in VCounter</source> - <translation>En VCounter actualmente</translation> + <translation>En VCounter ahora</translation> </message> <message> <location filename="../IOViewer.cpp" line="61"/> <source>Enable VBlank IRQ generation</source> - <translation>Generar IRQ por cada VBlank</translation> + <translation>Habilitar generación IRQ en VBlank</translation> </message> <message> <location filename="../IOViewer.cpp" line="62"/> <source>Enable HBlank IRQ generation</source> - <translation>Generar IRQ por cada HBlank</translation> + <translation>Habilitar generación IRQ en HBlank</translation> </message> <message> <location filename="../IOViewer.cpp" line="63"/> <source>Enable VCounter IRQ generation</source> - <translation>Generar IRQ por cada VCounter</translation> + <translation>Habilitar generación IRQ en VCounter</translation> </message> <message> <location filename="../IOViewer.cpp" line="64"/>@@ -1223,7 +1385,7 @@ <location filename="../IOViewer.cpp" line="82"/>
<location filename="../IOViewer.cpp" line="91"/> <location filename="../IOViewer.cpp" line="101"/> <source>Tile data base (* 16kB)</source> - <translation>Base de los tiles (* 16kB)</translation> + <translation>Dirección base de tiles (* 16kB)</translation> </message> <message> <location filename="../IOViewer.cpp" line="74"/>@@ -1231,7 +1393,7 @@ <location filename="../IOViewer.cpp" line="83"/>
<location filename="../IOViewer.cpp" line="92"/> <location filename="../IOViewer.cpp" line="102"/> <source>Enable mosaic</source> - <translation>Mosaico (pixelar)</translation> + <translation>Habilitar mosaico</translation> </message> <message> <location filename="../IOViewer.cpp" line="75"/>@@ -1239,7 +1401,7 @@ <location filename="../IOViewer.cpp" line="84"/>
<location filename="../IOViewer.cpp" line="93"/> <location filename="../IOViewer.cpp" line="103"/> <source>Enable 256-color</source> - <translation>256 colores</translation> + <translation>Habilitar 256 colores</translation> </message> <message> <location filename="../IOViewer.cpp" line="76"/>@@ -1247,7 +1409,7 @@ <location filename="../IOViewer.cpp" line="85"/>
<location filename="../IOViewer.cpp" line="94"/> <location filename="../IOViewer.cpp" line="104"/> <source>Tile map base (* 2kB)</source> - <translation>Base de asignación de tiles (* 2kB)</translation> + <translation>Dirección base de asignación de tiles (* 2kB)</translation> </message> <message> <location filename="../IOViewer.cpp" line="77"/>@@ -1255,13 +1417,13 @@ <location filename="../IOViewer.cpp" line="86"/>
<location filename="../IOViewer.cpp" line="96"/> <location filename="../IOViewer.cpp" line="106"/> <source>Background dimensions</source> - <translation>Dimensiones del fondo</translation> + <translation>Dimensiones de BG</translation> </message> <message> <location filename="../IOViewer.cpp" line="95"/> <location filename="../IOViewer.cpp" line="105"/> <source>Overflow wraps</source> - <translation>Envolver al desbordar</translation> + <translation>Envolver en desbordamiento</translation> </message> <message> <location filename="../IOViewer.cpp" line="110"/>@@ -1313,7 +1475,7 @@ <location filename="../IOViewer.cpp" line="172"/>
<location filename="../IOViewer.cpp" line="201"/> <location filename="../IOViewer.cpp" line="210"/> <source>Integer part (bottom)</source> - <translation>Parte entera (inferior)</translation> + <translation>Parte entera (función suelo)</translation> </message> <message> <location filename="../IOViewer.cpp" line="167"/>@@ -1321,7 +1483,7 @@ <location filename="../IOViewer.cpp" line="176"/>
<location filename="../IOViewer.cpp" line="205"/> <location filename="../IOViewer.cpp" line="214"/> <source>Integer part (top)</source> - <translation>Parte entera (superior)</translation> + <translation>Parte entera (función techo)</translation> </message> <message> <location filename="../IOViewer.cpp" line="218"/>@@ -1350,142 +1512,142 @@ </message>
<message> <location filename="../IOViewer.cpp" line="238"/> <source>Window 0 enable BG 0</source> - <translation>Window 0 BG 0</translation> + <translation>Window 0 habilitar BG 0</translation> </message> <message> <location filename="../IOViewer.cpp" line="239"/> <source>Window 0 enable BG 1</source> - <translation>Window 0 BG 1</translation> + <translation>Window 0 habilitar BG 1</translation> </message> <message> <location filename="../IOViewer.cpp" line="240"/> <source>Window 0 enable BG 2</source> - <translation>Window 0 BG 2</translation> + <translation>Window 0 habilitar BG 2</translation> </message> <message> <location filename="../IOViewer.cpp" line="241"/> <source>Window 0 enable BG 3</source> - <translation>Window 0 BG 3</translation> + <translation>Window 0 habilitar BG 3</translation> </message> <message> <location filename="../IOViewer.cpp" line="242"/> <source>Window 0 enable OBJ</source> - <translation>Window 0 OBJ</translation> + <translation>Window 0 habilitar OBJ</translation> </message> <message> <location filename="../IOViewer.cpp" line="243"/> <source>Window 0 enable blend</source> - <translation>Window 0 mezcla</translation> + <translation>Window 0 habilitar mezcla</translation> </message> <message> <location filename="../IOViewer.cpp" line="244"/> <source>Window 1 enable BG 0</source> - <translation>Window 1 BG 0</translation> + <translation>Window 1 habilitar BG 0</translation> </message> <message> <location filename="../IOViewer.cpp" line="245"/> <source>Window 1 enable BG 1</source> - <translation>Window 1 BG 1</translation> + <translation>Window 1 habilitar BG 1</translation> </message> <message> <location filename="../IOViewer.cpp" line="246"/> <source>Window 1 enable BG 2</source> - <translation>Window 1 BG 2</translation> + <translation>Window 1 habilitar BG 2</translation> </message> <message> <location filename="../IOViewer.cpp" line="247"/> <source>Window 1 enable BG 3</source> - <translation>Window 1 BG 3</translation> + <translation>Window 1 habilitar BG 3</translation> </message> <message> <location filename="../IOViewer.cpp" line="248"/> <source>Window 1 enable OBJ</source> - <translation>Window 1 OBJ</translation> + <translation>Window 1 habilitar OBJ</translation> </message> <message> <location filename="../IOViewer.cpp" line="249"/> <source>Window 1 enable blend</source> - <translation>Window 1 mezcla</translation> + <translation>Window 1 habilitar mezcla</translation> </message> <message> <location filename="../IOViewer.cpp" line="253"/> <source>Outside window enable BG 0</source> - <translation>Outside window BG 0</translation> + <translation>Window externa habilitar BG 0</translation> </message> <message> <location filename="../IOViewer.cpp" line="254"/> <source>Outside window enable BG 1</source> - <translation>Outside window BG 1</translation> + <translation>Window externa habilitar BG 1</translation> </message> <message> <location filename="../IOViewer.cpp" line="255"/> <source>Outside window enable BG 2</source> - <translation>Outside window BG 2</translation> + <translation>Window externa habilitar BG 2</translation> </message> <message> <location filename="../IOViewer.cpp" line="256"/> <source>Outside window enable BG 3</source> - <translation>Outside window BG 3</translation> + <translation>Window externa habilitar BG 3</translation> </message> <message> <location filename="../IOViewer.cpp" line="257"/> <source>Outside window enable OBJ</source> - <translation>Outside window OBJ</translation> + <translation>Window externa habilitar OBJ</translation> </message> <message> <location filename="../IOViewer.cpp" line="258"/> <source>Outside window enable blend</source> - <translation>Outside window mezcla</translation> + <translation>Outside window habilitar mezcla</translation> </message> <message> <location filename="../IOViewer.cpp" line="259"/> <source>OBJ window enable BG 0</source> - <translation>OBJ window BG 0</translation> + <translation>OBJ window habilitar BG 0</translation> </message> <message> <location filename="../IOViewer.cpp" line="260"/> <source>OBJ window enable BG 1</source> - <translation>OBJ window BG 1</translation> + <translation>OBJ window habilitar BG 1</translation> </message> <message> <location filename="../IOViewer.cpp" line="261"/> <source>OBJ window enable BG 2</source> - <translation>OBJ window BG 2</translation> + <translation>OBJ window habilitar BG 2</translation> </message> <message> <location filename="../IOViewer.cpp" line="262"/> <source>OBJ window enable BG 3</source> - <translation>OBJ window BG 3</translation> + <translation>OBJ window habilitar BG 3</translation> </message> <message> <location filename="../IOViewer.cpp" line="263"/> <source>OBJ window enable OBJ</source> - <translation>OBJ window OBJ</translation> + <translation>OBJ window habilitar OBJ</translation> </message> <message> <location filename="../IOViewer.cpp" line="264"/> <source>OBJ window enable blend</source> - <translation>OBJ window mezcla</translation> + <translation>OBJ window habilitar mezcla</translation> </message> <message> <location filename="../IOViewer.cpp" line="268"/> <source>Background mosaic size vertical</source> - <translation>Tamaño mosaico fondo vertical</translation> + <translation>Tamaño vertical mosaico BG</translation> </message> <message> <location filename="../IOViewer.cpp" line="269"/> <source>Background mosaic size horizontal</source> - <translation>Tamaño mosaico fondo horizontal</translation> + <translation>Tamaño horizontal mosaico BG</translation> </message> <message> <location filename="../IOViewer.cpp" line="270"/> <source>Object mosaic size vertical</source> - <translation>Tamaño mosaico objeto vertical</translation> + <translation>Tamaño vertical mosaico OBJ</translation> </message> <message> <location filename="../IOViewer.cpp" line="271"/> <source>Object mosaic size horizontal</source> - <translation>Tamaño mosaico objeto horizontal</translation> + <translation>Tamaño horizontal mosaico OBJ</translation> </message> <message> <location filename="../IOViewer.cpp" line="277"/>@@ -1530,7 +1692,7 @@ </message>
<message> <location filename="../IOViewer.cpp" line="285"/> <source>Additive blending</source> - <translation>Mezcla aditiva</translation> + <translation>Aditivo</translation> </message> <message> <location filename="../IOViewer.cpp" line="286"/>@@ -1595,12 +1757,12 @@ </message>
<message> <location filename="../IOViewer.cpp" line="318"/> <source>Sweep subtract</source> - <translation>Sustracción en barrido</translation> + <translation>Sustracción en barridos</translation> </message> <message> <location filename="../IOViewer.cpp" line="319"/> <source>Sweep time (in 1/128s)</source> - <translation>Tiempo de barrido (en 1/128seg)</translation> + <translation>Tiempo de barridos (in 1/128s)</translation> </message> <message> <location filename="../IOViewer.cpp" line="323"/>@@ -1608,7 +1770,7 @@ <location filename="../IOViewer.cpp" line="339"/>
<location filename="../IOViewer.cpp" line="363"/> <location filename="../IOViewer.cpp" line="385"/> <source>Sound length</source> - <translation>Longitud del sonido</translation> + <translation>Largo del sonido</translation> </message> <message> <location filename="../IOViewer.cpp" line="324"/>@@ -1621,14 +1783,14 @@ <location filename="../IOViewer.cpp" line="325"/>
<location filename="../IOViewer.cpp" line="341"/> <location filename="../IOViewer.cpp" line="386"/> <source>Envelope step time</source> - <translation>Tiempo paso envolvente</translation> + <translation>Tiempo de paso en envoltura</translation> </message> <message> <location filename="../IOViewer.cpp" line="326"/> <location filename="../IOViewer.cpp" line="342"/> <location filename="../IOViewer.cpp" line="387"/> <source>Envelope increase</source> - <translation>Aumento envolvente</translation> + <translation>Aumento en envoltura</translation> </message> <message> <location filename="../IOViewer.cpp" line="327"/>@@ -1642,7 +1804,7 @@ <location filename="../IOViewer.cpp" line="331"/>
<location filename="../IOViewer.cpp" line="349"/> <location filename="../IOViewer.cpp" line="377"/> <source>Sound frequency</source> - <translation>Frecuencia del sonido</translation> + <translation>Frecuencia de sonido</translation> </message> <message> <location filename="../IOViewer.cpp" line="332"/>@@ -1650,7 +1812,7 @@ <location filename="../IOViewer.cpp" line="350"/>
<location filename="../IOViewer.cpp" line="378"/> <location filename="../IOViewer.cpp" line="400"/> <source>Timed</source> - <translation>Cronometrado</translation> + <translation>Timed</translation> </message> <message> <location filename="../IOViewer.cpp" line="333"/>@@ -1663,7 +1825,7 @@ </message>
<message> <location filename="../IOViewer.cpp" line="357"/> <source>Double-size wave table</source> - <translation>Tabla de ondas de doble tamaño</translation> + <translation>Tabla de ondas de tamaño doble</translation> </message> <message> <location filename="../IOViewer.cpp" line="358"/>@@ -1673,7 +1835,7 @@ </message>
<message> <location filename="../IOViewer.cpp" line="359"/> <source>Enable channel 3</source> - <translation>Canal 3 activo</translation> + <translation>Habilitar canal 3</translation> </message> <message> <location filename="../IOViewer.cpp" line="364"/>@@ -1719,7 +1881,7 @@ </message>
<message> <location filename="../IOViewer.cpp" line="395"/> <source>Register stages</source> - <translation>Etapas de registros</translation> + <translation>Etapas del registro</translation> </message> <message> <location filename="../IOViewer.cpp" line="396"/>@@ -1739,57 +1901,57 @@ </message>
<message> <location filename="../IOViewer.cpp" line="407"/> <source>PSG volume right</source> - <translation>Volumen pulso derecha</translation> + <translation>PSG volumen derecha</translation> </message> <message> <location filename="../IOViewer.cpp" line="408"/> <source>PSG volume left</source> - <translation>Volumen pulso izquierda</translation> + <translation>PSG volumen izquierda</translation> </message> <message> <location filename="../IOViewer.cpp" line="409"/> <source>Enable channel 1 right</source> - <translation>Canal 1 derecha</translation> + <translation>Habilitar canal 1 derecha</translation> </message> <message> <location filename="../IOViewer.cpp" line="410"/> <source>Enable channel 2 right</source> - <translation>Canal 2 derecha</translation> + <translation>Habilitar canal 2 derecha</translation> </message> <message> <location filename="../IOViewer.cpp" line="411"/> <source>Enable channel 3 right</source> - <translation>Canal 3 derecha</translation> + <translation>Habilitar canal 3 derecha</translation> </message> <message> <location filename="../IOViewer.cpp" line="412"/> <source>Enable channel 4 right</source> - <translation>Canal 4 derecha</translation> + <translation>Habilitar canal 4 derecha</translation> </message> <message> <location filename="../IOViewer.cpp" line="413"/> <source>Enable channel 1 left</source> - <translation>Canal 1 izquierda</translation> + <translation>Habilitar canal 1 izquierda</translation> </message> <message> <location filename="../IOViewer.cpp" line="414"/> <source>Enable channel 2 left</source> - <translation>Canal 2 izquierda</translation> + <translation>Habilitar canal 2 izquierda</translation> </message> <message> <location filename="../IOViewer.cpp" line="415"/> <source>Enable channel 3 left</source> - <translation>Canal 3 izquierda</translation> + <translation>Habilitar canal 3 izquierda</translation> </message> <message> <location filename="../IOViewer.cpp" line="416"/> <source>Enable channel 4 left</source> - <translation>Canal 4 izquierda</translation> + <translation>Habilitar canal 4 izquierda</translation> </message> <message> <location filename="../IOViewer.cpp" line="420"/> <source>PSG master volume</source> - <translation>Volumen maestro pulso</translation> + <translation>PSG volumen maestro</translation> </message> <message> <location filename="../IOViewer.cpp" line="426"/>@@ -1804,17 +1966,17 @@ </message>
<message> <location filename="../IOViewer.cpp" line="428"/> <source>Enable channel A right</source> - <translation>Canal A derecha</translation> + <translation>Habilitar canal A derecha</translation> </message> <message> <location filename="../IOViewer.cpp" line="429"/> <source>Enable channel A left</source> - <translation>Canal A izquierda</translation> + <translation>Habilitar canal A izquierda</translation> </message> <message> <location filename="../IOViewer.cpp" line="430"/> <source>Channel A timer</source> - <translation>Temporizador canal A</translation> + <translation>Canal A temporizador</translation> </message> <message> <location filename="../IOViewer.cpp" line="431"/>@@ -1838,27 +2000,27 @@ </message>
<message> <location filename="../IOViewer.cpp" line="434"/> <source>Channel A reset</source> - <translation>Reinic. canal A</translation> + <translation>Canal A reinicializar</translation> </message> <message> <location filename="../IOViewer.cpp" line="435"/> <source>Enable channel B right</source> - <translation>Canal B derecha</translation> + <translation>Habilitar canal B derecha</translation> </message> <message> <location filename="../IOViewer.cpp" line="436"/> <source>Enable channel B left</source> - <translation>Canal B izquierda</translation> + <translation>Habilitar canal B izquierda</translation> </message> <message> <location filename="../IOViewer.cpp" line="437"/> <source>Channel B timer</source> - <translation>Temporizador canal B</translation> + <translation>Canal B temporizador</translation> </message> <message> <location filename="../IOViewer.cpp" line="441"/> <source>Channel B reset</source> - <translation>Reinic. canal B</translation> + <translation>Canal B reinicializar</translation> </message> <message> <location filename="../IOViewer.cpp" line="445"/>@@ -1949,7 +2111,7 @@ <location filename="../IOViewer.cpp" line="648"/>
<location filename="../IOViewer.cpp" line="685"/> <location filename="../IOViewer.cpp" line="693"/> <source>Address (bottom)</source> - <translation>Dirección (inferior)</translation> + <translation>Dirección (abajo)</translation> </message> <message> <location filename="../IOViewer.cpp" line="554"/>@@ -1961,7 +2123,7 @@ <location filename="../IOViewer.cpp" line="652"/>
<location filename="../IOViewer.cpp" line="689"/> <location filename="../IOViewer.cpp" line="697"/> <source>Address (top)</source> - <translation>Dirección (superior)</translation> + <translation>Dirección (arriba)</translation> </message> <message> <location filename="../IOViewer.cpp" line="566"/>@@ -1969,7 +2131,7 @@ <location filename="../IOViewer.cpp" line="611"/>
<location filename="../IOViewer.cpp" line="656"/> <location filename="../IOViewer.cpp" line="701"/> <source>Word count</source> - <translation>Contador de word</translation> + <translation>Tamaño palabra</translation> </message> <message> <location filename="../IOViewer.cpp" line="570"/>@@ -1977,7 +2139,7 @@ <location filename="../IOViewer.cpp" line="615"/>
<location filename="../IOViewer.cpp" line="660"/> <location filename="../IOViewer.cpp" line="705"/> <source>Destination offset</source> - <translation>Compensación de destino</translation> + <translation>Desplazamiento de destino</translation> </message> <message> <location filename="../IOViewer.cpp" line="571"/>@@ -2029,7 +2191,7 @@ <location filename="../IOViewer.cpp" line="621"/>
<location filename="../IOViewer.cpp" line="666"/> <location filename="../IOViewer.cpp" line="711"/> <source>Source offset</source> - <translation>Compensación de origen</translation> + <translation>Desplazamiento de origen</translation> </message> <message> <location filename="../IOViewer.cpp" line="582"/>@@ -2053,7 +2215,7 @@ <location filename="../IOViewer.cpp" line="629"/>
<location filename="../IOViewer.cpp" line="674"/> <location filename="../IOViewer.cpp" line="720"/> <source>Start timing</source> - <translation>Inicio de temporizador</translation> + <translation>Comienzo del tiempo</translation> </message> <message> <location filename="../IOViewer.cpp" line="585"/>@@ -2113,7 +2275,7 @@ <location filename="../IOViewer.cpp" line="633"/>
<location filename="../IOViewer.cpp" line="678"/> <location filename="../IOViewer.cpp" line="724"/> <source>Audio FIFO</source> - <translation>FIFO de audio</translation> + <translation>Audio FIFO</translation> </message> <message> <location filename="../IOViewer.cpp" line="715"/>@@ -2170,7 +2332,7 @@ <location filename="../IOViewer.cpp" line="788"/>
<location filename="../IOViewer.cpp" line="804"/> <location filename="../IOViewer.cpp" line="820"/> <source>Cascade</source> - <translation>Cacada</translation> + <translation>Cascada</translation> </message> <message> <location filename="../IOViewer.cpp" line="858"/>@@ -2321,7 +2483,7 @@ <message>
<location filename="../IOViewer.cpp" line="951"/> <location filename="../IOViewer.cpp" line="968"/> <source>Keypad</source> - <translation>Teclera</translation> + <translation>Keypad</translation> </message> <message> <location filename="../IOViewer.cpp" line="952"/>@@ -2332,7 +2494,7 @@ </message>
<message> <location filename="../IOViewer.cpp" line="973"/> <source>SRAM wait</source> - <translation>Espera SRAM</translation> + <translation>SRAM wait</translation> </message> <message> <location filename="../IOViewer.cpp" line="974"/>@@ -2407,7 +2569,7 @@ </message>
<message> <location filename="../IOViewer.cpp" line="1010"/> <source>Disable</source> - <translation>Desactivar</translation> + <translation>Deshabilitar</translation> </message> <message> <location filename="../IOViewer.cpp" line="1011"/>@@ -2436,37 +2598,6 @@ <translation>Habilitar IRQs</translation>
</message> </context> <context> - <name>QGBA::InputController</name> - <message> - <location filename="../InputController.cpp" line="68"/> - <source>Autofire</source> - <translation type="unfinished">Botones turbo</translation> - </message> - <message> - <location filename="../InputController.cpp" line="71"/> - <source>Bindings</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> - <name>QGBA::InputModel</name> - <message> - <location filename="../InputModel.cpp" line="65"/> - <source>Action</source> - <translation type="unfinished">Acción</translation> - </message> - <message> - <location filename="../InputModel.cpp" line="67"/> - <source>Keyboard</source> - <translation type="unfinished">Teclado</translation> - </message> - <message> - <location filename="../InputModel.cpp" line="69"/> - <source>Gamepad</source> - <translation type="unfinished">Mando</translation> - </message> -</context> -<context> <name>QGBA::KeyEditor</name> <message> <location filename="../KeyEditor.cpp" line="33"/>@@ -2480,12 +2611,12 @@ <name>QGBA::LoadSaveState</name>
<message> <location filename="../LoadSaveState.cpp" line="68"/> <source>Load State</source> - <translation>Cargar captura</translation> + <translation>Cargar estado</translation> </message> <message> <location filename="../LoadSaveState.cpp" line="68"/> <source>Save State</source> - <translation>Guardar captura</translation> + <translation>Guardar estado</translation> </message> <message> <location filename="../LoadSaveState.cpp" line="177"/>@@ -2495,10 +2626,10 @@ </message>
<message> <location filename="../LoadSaveState.cpp" line="186"/> <source>Corrupted</source> - <translation>Corrompido</translation> + <translation>Dañado</translation> </message> <message> - <location filename="../LoadSaveState.cpp" line="209"/> + <location filename="../LoadSaveState.cpp" line="215"/> <source>Slot %1</source> <translation>Espacio %1</translation> </message>@@ -2513,7 +2644,7 @@ </message>
<message> <location filename="../LogController.cpp" line="59"/> <source>STUB</source> - <translation>AUXILIAR</translation> + <translation>STUB</translation> </message> <message> <location filename="../LogController.cpp" line="61"/>@@ -2538,7 +2669,7 @@ </message>
<message> <location filename="../LogController.cpp" line="69"/> <source>GAME ERROR</source> - <translation>ERROR DEL JUEGO</translation> + <translation>ERROR DE JUEGO</translation> </message> </context> <context>@@ -2606,58 +2737,81 @@ <translation>ISO-8859-1</translation>
</message> </context> <context> + <name>QGBA::MemorySearch</name> + <message> + <location filename="../MemorySearch.cpp" line="188"/> + <source> (⅟%0×)</source> + <translation> (⅟%0×)</translation> + </message> + <message> + <location filename="../MemorySearch.cpp" line="192"/> + <source>1 byte%0</source> + <translation>1 byte%0</translation> + </message> + <message> + <location filename="../MemorySearch.cpp" line="195"/> + <source>2 bytes%0</source> + <translation>2 bytes%0</translation> + </message> + <message> + <location filename="../MemorySearch.cpp" line="199"/> + <source>4 bytes%0</source> + <translation>4 bytes%0</translation> + </message> +</context> +<context> <name>QGBA::ObjView</name> <message> - <location filename="../ObjView.cpp" line="142"/> - <location filename="../ObjView.cpp" line="234"/> + <location filename="../ObjView.cpp" line="143"/> + <location filename="../ObjView.cpp" line="236"/> <source>0x%0</source> <translation>0x%0</translation> </message> <message> - <location filename="../ObjView.cpp" line="153"/> + <location filename="../ObjView.cpp" line="154"/> <source>Off</source> <translation>No</translation> </message> <message> - <location filename="../ObjView.cpp" line="158"/> + <location filename="../ObjView.cpp" line="159"/> <source>Normal</source> <translation>Normal</translation> </message> <message> - <location filename="../ObjView.cpp" line="161"/> + <location filename="../ObjView.cpp" line="162"/> <source>Trans</source> <translation>Trans</translation> </message> <message> - <location filename="../ObjView.cpp" line="164"/> + <location filename="../ObjView.cpp" line="165"/> <source>OBJWIN</source> <translation>OBJWIN</translation> </message> <message> - <location filename="../ObjView.cpp" line="167"/> + <location filename="../ObjView.cpp" line="168"/> <source>Invalid</source> <translation>Inválido</translation> </message> <message> - <location filename="../ObjView.cpp" line="241"/> - <location filename="../ObjView.cpp" line="242"/> + <location filename="../ObjView.cpp" line="243"/> + <location filename="../ObjView.cpp" line="244"/> <source>N/A</source> <translation>n/d</translation> </message> <message> - <location filename="../ObjView.cpp" line="249"/> + <location filename="../ObjView.cpp" line="251"/> <source>Export sprite</source> - <translation type="unfinished"></translation> + <translation>Exportar sprite</translation> </message> <message> - <location filename="../ObjView.cpp" line="250"/> + <location filename="../ObjView.cpp" line="252"/> <source>Portable Network Graphics (*.png)</source> - <translation type="unfinished"></translation> + <translation>Portable Network Graphics (*.png)</translation> </message> <message> - <location filename="../ObjView.cpp" line="253"/> + <location filename="../ObjView.cpp" line="255"/> <source>Failed to open output PNG file: %1</source> - <translation type="unfinished"></translation> + <translation>Error al abrir el archivo PNG de salida: %1</translation> </message> </context> <context>@@ -2692,12 +2846,12 @@ </message>
<message> <location filename="../PaletteView.cpp" line="138"/> <source>Windows PAL (*.pal);;Adobe Color Table (*.act)</source> - <translation>Paleta de WIndows (*.pal);;Tabla de colores Adobe (*.act)</translation> + <translation>Windows PAL (*.pal);;Adobe Color Table (*.act)</translation> </message> <message> <location filename="../PaletteView.cpp" line="141"/> <source>Failed to open output palette file: %1</source> - <translation>Error al abrir el archivo de salida de paleta: %1</translation> + <translation>Error al abrir el archivo de paleta de salida: %1</translation> </message> </context> <context>@@ -2720,843 +2874,837 @@ </message>
<message> <location filename="../ROMInfo.cpp" line="83"/> <source>(no database present)</source> - <translation>(no se encuentra la base de datos)</translation> + <translation>(no hay base de datos)</translation> </message> </context> <context> <name>QGBA::SettingsView</name> <message> - <location filename="../SettingsView.cpp" line="95"/> + <location filename="../SettingsView.cpp" line="99"/> <source>Qt Multimedia</source> <translation>Qt Multimedia</translation> </message> <message> - <location filename="../SettingsView.cpp" line="102"/> + <location filename="../SettingsView.cpp" line="106"/> <source>SDL</source> <translation>SDL</translation> </message> <message> - <location filename="../SettingsView.cpp" line="110"/> + <location filename="../SettingsView.cpp" line="114"/> <source>Software (Qt)</source> <translation>Software (Qt)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="116"/> + <location filename="../SettingsView.cpp" line="120"/> <source>OpenGL</source> <translation>OpenGL</translation> </message> <message> - <location filename="../SettingsView.cpp" line="123"/> + <location filename="../SettingsView.cpp" line="127"/> <source>OpenGL (force version 1.x)</source> <translation>OpenGL (forzar versión 1.x)</translation> </message> <message> - <location filename="../SettingsView.cpp" line="159"/> - <source>Bindings</source> - <translation type="unfinished"></translation> + <location filename="../SettingsView.cpp" line="145"/> + <source>Keyboard</source> + <translation>Teclado</translation> + </message> + <message> + <location filename="../SettingsView.cpp" line="154"/> + <source>Controllers</source> + <translation>Controladores</translation> + </message> + <message> + <location filename="../SettingsView.cpp" line="186"/> + <source>Shortcuts</source> + <translation>Atajos de teclado</translation> + </message> + <message> + <location filename="../SettingsView.cpp" line="202"/> + <source>Shaders</source> + <translation>Shaders</translation> </message> <message> - <location filename="../SettingsView.cpp" line="163"/> + <location filename="../SettingsView.cpp" line="208"/> <source>Select BIOS</source> - <translation>Elegir BIOS</translation> + <translation>Seleccionar BIOS</translation> </message> </context> <context> <name>QGBA::ShaderSelector</name> <message> - <location filename="../ShaderSelector.cpp" line="49"/> + <location filename="../ShaderSelector.cpp" line="54"/> <source>No shader active</source> - <translation>No hay programa shader activo</translation> + <translation>No hay shader activo</translation> </message> <message> - <location filename="../ShaderSelector.cpp" line="62"/> + <location filename="../ShaderSelector.cpp" line="67"/> <source>Load shader</source> - <translation>Cargar programa shader</translation> + <translation>Cargar shader</translation> </message> <message> - <location filename="../ShaderSelector.cpp" line="62"/> - <source>%1 Shader (%.shader)</source> - <translation>Programa shader de %1 (%.shader)</translation> - </message> - <message> - <location filename="../ShaderSelector.cpp" line="101"/> + <location filename="../ShaderSelector.cpp" line="105"/> <source>No shader loaded</source> - <translation>No hay programa shader cargado</translation> + <translation>No hay shader cargado</translation> </message> <message> - <location filename="../ShaderSelector.cpp" line="109"/> + <location filename="../ShaderSelector.cpp" line="113"/> <source>by %1</source> <translation>por %1</translation> </message> <message> - <location filename="../ShaderSelector.cpp" line="120"/> + <location filename="../ShaderSelector.cpp" line="128"/> <source>Preprocessing</source> - <translation>preprocesamiento</translation> + <translation>Preproceso</translation> </message> <message> - <location filename="../ShaderSelector.cpp" line="127"/> + <location filename="../ShaderSelector.cpp" line="135"/> <source>Pass %1</source> <translation>Paso %1</translation> </message> </context> <context> + <name>QGBA::ShortcutController</name> + <message> + <location filename="../ShortcutController.cpp" line="64"/> + <source>Action</source> + <translation>Acción</translation> + </message> + <message> + <location filename="../ShortcutController.cpp" line="66"/> + <source>Keyboard</source> + <translation>Teclado</translation> + </message> + <message> + <location filename="../ShortcutController.cpp" line="68"/> + <source>Gamepad</source> + <translation>Mando</translation> + </message> +</context> +<context> <name>QGBA::VideoView</name> <message> <location filename="../VideoView.cpp" line="203"/> <source>Failed to open output video file: %1</source> - <translation>Error al abrir el archivo de salida de video: %1</translation> + <translation>Error al abrir el archivo de video de salida: %1</translation> </message> <message> <location filename="../VideoView.cpp" line="221"/> <source>Native (%0x%1)</source> - <translation>Nativo (%0x%1)</translation> + <translation>Native (%0x%1)</translation> </message> <message> - <location filename="../VideoView.cpp" line="240"/> + <location filename="../VideoView.cpp" line="236"/> <source>Select output file</source> - <translation>Elegir archivo de salida</translation> + <translation>Seleccionar archivo de salida</translation> </message> </context> <context> <name>QGBA::Window</name> <message> - <location filename="../Window.cpp" line="357"/> + <location filename="../Window.cpp" line="332"/> <source>Game Boy Advance ROMs (%1)</source> <translation>ROMs de Game Boy Advance (%1)</translation> </message> <message> - <location filename="../Window.cpp" line="373"/> - <source>DS ROMs (%1)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../Window.cpp" line="389"/> + <location filename="../Window.cpp" line="348"/> <source>Game Boy ROMs (%1)</source> <translation>ROMs de Game Boy (%1)</translation> </message> <message> - <location filename="../Window.cpp" line="393"/> + <location filename="../Window.cpp" line="352"/> <source>All ROMs (%1)</source> <translation>Todas las ROMs (%1)</translation> </message> <message> - <location filename="../Window.cpp" line="394"/> + <location filename="../Window.cpp" line="353"/> <source>%1 Video Logs (*.mvl)</source> - <translation type="unfinished"></translation> + <translation>Video-registros de %1 (*.mvl)</translation> </message> <message> - <location filename="../Window.cpp" line="409"/> + <location filename="../Window.cpp" line="368"/> <source>Archives (%1)</source> - <translation>Archivos (%1)</translation> + <translation>Contenedores (%1)</translation> </message> <message> - <location filename="../Window.cpp" line="414"/> - <location filename="../Window.cpp" line="422"/> - <location filename="../Window.cpp" line="449"/> + <location filename="../Window.cpp" line="373"/> + <location filename="../Window.cpp" line="381"/> + <location filename="../Window.cpp" line="408"/> <source>Select ROM</source> - <translation>Elegir ROM</translation> + <translation>Seleccionar ROM</translation> </message> <message> - <location filename="../Window.cpp" line="457"/> + <location filename="../Window.cpp" line="399"/> + <source>Select folder</source> + <translation>Seleccionar carpeta</translation> + </message> + <message> + <location filename="../Window.cpp" line="416"/> <source>Game Boy Advance save files (%1)</source> <translation>Archivos de guardado de Game Boy Advance (%1)</translation> </message> <message> + <location filename="../Window.cpp" line="417"/> + <location filename="../Window.cpp" line="451"/> <location filename="../Window.cpp" line="458"/> - <location filename="../Window.cpp" line="492"/> - <location filename="../Window.cpp" line="499"/> <source>Select save</source> - <translation>Elegir guardado</translation> + <translation>Seleccionar guardado</translation> </message> <message> - <location filename="../Window.cpp" line="478"/> + <location filename="../Window.cpp" line="437"/> <source>Select patch</source> - <translation>Elegir parche</translation> + <translation>Seleccionar parche</translation> </message> <message> - <location filename="../Window.cpp" line="478"/> + <location filename="../Window.cpp" line="437"/> <source>Patches (*.ips *.ups *.bps)</source> <translation>Parches (*.ips *.ups *.bps)</translation> </message> <message> - <location filename="../Window.cpp" line="492"/> - <location filename="../Window.cpp" line="499"/> + <location filename="../Window.cpp" line="451"/> + <location filename="../Window.cpp" line="458"/> <source>GameShark saves (*.sps *.xps)</source> <translation>Guardados de GameShark (*.sps *.xps)</translation> </message> <message> - <location filename="../Window.cpp" line="520"/> + <location filename="../Window.cpp" line="486"/> <source>Select video log</source> - <translation type="unfinished"></translation> + <translation>Seleccionar video-registro</translation> </message> <message> - <location filename="../Window.cpp" line="520"/> + <location filename="../Window.cpp" line="486"/> <source>Video logs (*.mvl)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../Window.cpp" line="770"/> - <source>BIOS required</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../Window.cpp" line="771"/> - <source>DS support requires dumps of the BIOS and firmware.</source> - <translation type="unfinished"></translation> + <translation>Video-registros (*.mvl)</translation> </message> <message> - <location filename="../Window.cpp" line="878"/> + <location filename="../Window.cpp" line="828"/> <source>Crash</source> <translation>Error fatal</translation> </message> <message> - <location filename="../Window.cpp" line="879"/> + <location filename="../Window.cpp" line="829"/> <source>The game has crashed with the following error: %1</source> - <translation>El juego dejó de funcionar inesperadamente debido a este error: + <translation>El juego ha fallado fatalmente por esta razón: %1</translation> </message> <message> - <location filename="../Window.cpp" line="886"/> + <location filename="../Window.cpp" line="837"/> <source>Couldn't Load</source> <translation>No se pudo cargar</translation> </message> <message> - <location filename="../Window.cpp" line="887"/> + <location filename="../Window.cpp" line="838"/> <source>Could not load game. Are you sure it'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="900"/> + <location filename="../Window.cpp" line="852"/> <source>Unimplemented BIOS call</source> <translation>Llamada a BIOS no implementada</translation> </message> <message> - <location filename="../Window.cpp" line="901"/> + <location filename="../Window.cpp" line="853"/> <source>This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience.</source> - <translation>Este juego hizo una llamada al BIOS que no está implementada. Usa el BIOS oficial para obtener la mejor experiencia.</translation> + <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="908"/> + <location filename="../Window.cpp" line="860"/> <source>Really make portable?</source> - <translation>¿Realmente hacer "portable"?</translation> + <translation>¿Hacer "portable"?</translation> </message> <message> - <location filename="../Window.cpp" line="909"/> + <location filename="../Window.cpp" line="861"/> <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 su ejecutable. ¿Quieres continuar?</translation> + <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="917"/> + <location filename="../Window.cpp" line="869"/> <source>Restart needed</source> <translation>Reinicio necesario</translation> </message> <message> - <location filename="../Window.cpp" line="918"/> + <location filename="../Window.cpp" line="870"/> <source>Some changes will not take effect until the emulator is restarted.</source> - <translation>Algunos cambios no tendrán efecto hasta que se reinicie el emulador.</translation> + <translation>Algunos cambios no surtirán efecto hasta que se reinicie el emulador.</translation> </message> <message> - <location filename="../Window.cpp" line="965"/> + <location filename="../Window.cpp" line="917"/> <source> - Player %1 of %2</source> <translation> - Jugador %1 de %2</translation> </message> <message> - <location filename="../Window.cpp" line="976"/> + <location filename="../Window.cpp" line="928"/> <source>%1 - %2</source> <translation>%1 - %2</translation> </message> <message> - <location filename="../Window.cpp" line="978"/> + <location filename="../Window.cpp" line="930"/> <source>%1 - %2 - %3</source> <translation>%1 - %2 - %3</translation> </message> <message> - <location filename="../Window.cpp" line="980"/> + <location filename="../Window.cpp" line="932"/> <source>%1 - %2 (%3 fps) - %4</source> <translation>%1 - %2 (%3 fps) - %4</translation> </message> <message> - <location filename="../Window.cpp" line="1012"/> + <location filename="../Window.cpp" line="964"/> <source>&File</source> <translation>&Archivo</translation> </message> <message> - <location filename="../Window.cpp" line="1015"/> + <location filename="../Window.cpp" line="967"/> <source>Load &ROM...</source> <translation>Cargar &ROM...</translation> </message> <message> - <location filename="../Window.cpp" line="1018"/> + <location filename="../Window.cpp" line="970"/> <source>Load ROM in archive...</source> - <translation>Cargar ROM dentro de archivo...</translation> + <translation>Cargar ROM desde contenedor...</translation> + </message> + <message> + <location filename="../Window.cpp" line="972"/> + <source>Add folder to library...</source> + <translation>Agregar carpeta a la biblioteca...</translation> </message> <message> - <location filename="../Window.cpp" line="1024"/> + <location filename="../Window.cpp" line="976"/> <source>Load temporary save...</source> <translation>Cargar guardado temporal...</translation> </message> <message> - <location filename="../Window.cpp" line="1029"/> + <location filename="../Window.cpp" line="981"/> <source>Load &patch...</source> <translation>Cargar &parche...</translation> </message> <message> - <location filename="../Window.cpp" line="1031"/> + <location filename="../Window.cpp" line="983"/> <source>Boot BIOS</source> - <translation>Iniciar al BIOS</translation> + <translation>Arrancar BIOS</translation> </message> <message> - <location filename="../Window.cpp" line="1038"/> + <location filename="../Window.cpp" line="990"/> <source>Replace ROM...</source> <translation>Reemplazar ROM...</translation> </message> <message> - <location filename="../Window.cpp" line="1040"/> + <location filename="../Window.cpp" line="992"/> <source>ROM &info...</source> - <translation>&Información de ROM...</translation> + <translation>&Información de la ROM...</translation> </message> <message> - <location filename="../Window.cpp" line="1045"/> + <location filename="../Window.cpp" line="997"/> <source>Recent</source> - <translation>Reciente</translation> + <translation>Recientes</translation> </message> <message> - <location filename="../Window.cpp" line="1049"/> + <location filename="../Window.cpp" line="1001"/> <source>Make portable</source> <translation>Hacer "portable"</translation> </message> <message> - <location filename="../Window.cpp" line="1053"/> + <location filename="../Window.cpp" line="1005"/> <source>&Load state</source> - <translation>Cargar captura de estado (&L)</translation> + <translation>Ca&rgar estado</translation> </message> <message> - <location filename="../Window.cpp" line="1054"/> + <location filename="../Window.cpp" line="1006"/> <source>F10</source> <translation>F10</translation> </message> <message> - <location filename="../Window.cpp" line="1061"/> + <location filename="../Window.cpp" line="1012"/> <source>&Save state</source> - <translation>Guardar captura de e&stado</translation> + <translation>Guardar e&stado</translation> </message> <message> - <location filename="../Window.cpp" line="1062"/> + <location filename="../Window.cpp" line="1013"/> <source>Shift+F10</source> - <translatorcomment>DO NOT TRANSLATE</translatorcomment> <translation>Shift+F10</translation> </message> <message> - <location filename="../Window.cpp" line="1069"/> + <location filename="../Window.cpp" line="1019"/> <source>Quick load</source> <translation>Cargado rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1070"/> + <location filename="../Window.cpp" line="1020"/> <source>Quick save</source> <translation>Guardado rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1074"/> + <location filename="../Window.cpp" line="1024"/> <source>Load recent</source> <translation>Cargar reciente</translation> </message> <message> - <location filename="../Window.cpp" line="1081"/> + <location filename="../Window.cpp" line="1030"/> <source>Save recent</source> <translation>Guardar reciente</translation> </message> <message> - <location filename="../Window.cpp" line="1091"/> + <location filename="../Window.cpp" line="1039"/> <source>Undo load state</source> - <translation>Deshacer cargar la captura de estado</translation> + <translation>Deshacer cargar estado</translation> </message> <message> - <location filename="../Window.cpp" line="1092"/> + <location filename="../Window.cpp" line="1040"/> <source>F11</source> - <translatorcomment>DO NOT TRANSLATE</translatorcomment> <translation>F11</translation> </message> <message> - <location filename="../Window.cpp" line="1099"/> + <location filename="../Window.cpp" line="1046"/> <source>Undo save state</source> - <translation>Deshacer guardar la captura de estado</translation> + <translation>Deshacer guardar estado</translation> </message> <message> - <location filename="../Window.cpp" line="1100"/> + <location filename="../Window.cpp" line="1047"/> <source>Shift+F11</source> - <translatorcomment>DO NOT TRANSLATE</translatorcomment> <translation>Shift+F11</translation> </message> <message> - <location filename="../Window.cpp" line="1112"/> - <location filename="../Window.cpp" line="1120"/> + <location filename="../Window.cpp" line="1058"/> + <location filename="../Window.cpp" line="1065"/> <source>State &%1</source> - <translation>Captura de estado &%1</translation> + <translation>Estado &%1</translation> </message> <message> - <location filename="../Window.cpp" line="1113"/> + <location filename="../Window.cpp" line="1059"/> <source>F%1</source> <translation>F%1</translation> </message> <message> - <location filename="../Window.cpp" line="1121"/> + <location filename="../Window.cpp" line="1066"/> <source>Shift+F%1</source> - <translatorcomment>DO NOT TRANSLATE</translatorcomment> <translation>Shift+F%1</translation> </message> <message> - <location filename="../Window.cpp" line="1131"/> + <location filename="../Window.cpp" line="1075"/> <source>Import GameShark Save</source> <translation>Importar guardado de GameShark</translation> </message> <message> - <location filename="../Window.cpp" line="1137"/> + <location filename="../Window.cpp" line="1081"/> <source>Export GameShark Save</source> <translation>Exportar guardado de GameShark</translation> </message> <message> - <location filename="../Window.cpp" line="1145"/> + <location filename="../Window.cpp" line="1089"/> <source>New multiplayer window</source> <translation>Nueva ventana multijugador</translation> </message> <message> - <location filename="../Window.cpp" line="1155"/> + <location filename="../Window.cpp" line="1099"/> <source>About</source> <translation>Acerca de</translation> </message> <message> - <location filename="../Window.cpp" line="1160"/> + <location filename="../Window.cpp" line="1104"/> <source>E&xit</source> <translation>Salir (&X)</translation> </message> <message> - <location filename="../Window.cpp" line="1163"/> + <location filename="../Window.cpp" line="1107"/> <source>&Emulation</source> <translation>&Emulación</translation> </message> <message> - <location filename="../Window.cpp" line="1165"/> + <location filename="../Window.cpp" line="1109"/> <source>&Reset</source> <translation>&Reinicializar</translation> </message> <message> - <location filename="../Window.cpp" line="1166"/> + <location filename="../Window.cpp" line="1110"/> <source>Ctrl+R</source> <translation>Ctrl+R</translation> </message> <message> - <location filename="../Window.cpp" line="1171"/> + <location filename="../Window.cpp" line="1115"/> <source>Sh&utdown</source> <translation>Apagar (&U)</translation> </message> <message> - <location filename="../Window.cpp" line="1177"/> + <location filename="../Window.cpp" line="1121"/> <source>Yank game pak</source> - <translation>Arrancar el game pak de su ranura</translation> + <translation>Tirar del cartucho</translation> </message> <message> - <location filename="../Window.cpp" line="1185"/> + <location filename="../Window.cpp" line="1129"/> <source>&Pause</source> <translation>&Pausar</translation> </message> <message> - <location filename="../Window.cpp" line="1188"/> + <location filename="../Window.cpp" line="1132"/> <source>Ctrl+P</source> <translation>Ctrl+P</translation> </message> <message> - <location filename="../Window.cpp" line="1197"/> + <location filename="../Window.cpp" line="1141"/> <source>&Next frame</source> - <translation>Saltar al próximo cuadro (&N)</translation> + <translation>Cuadro siguie&nte</translation> </message> <message> - <location filename="../Window.cpp" line="1198"/> + <location filename="../Window.cpp" line="1142"/> <source>Ctrl+N</source> <translation>Ctrl+N</translation> </message> <message> - <location filename="../Window.cpp" line="1209"/> + <location filename="../Window.cpp" line="1153"/> <source>Fast forward (held)</source> <translation>Avance rápido (mantener)</translation> </message> <message> - <location filename="../Window.cpp" line="1211"/> + <location filename="../Window.cpp" line="1155"/> <source>&Fast forward</source> - <translation>Avance rápido (&F)</translation> + <translation>&Avance rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1214"/> + <location filename="../Window.cpp" line="1158"/> <source>Shift+Tab</source> <translation>Shift+Tab</translation> </message> <message> - <location filename="../Window.cpp" line="1218"/> + <location filename="../Window.cpp" line="1162"/> <source>Fast forward speed</source> <translation>Velocidad de avance rápido</translation> </message> <message> - <location filename="../Window.cpp" line="1223"/> + <location filename="../Window.cpp" line="1167"/> <source>Unbounded</source> - <translation>Ilimitado</translation> + <translation>Sin límite</translation> </message> <message> - <location filename="../Window.cpp" line="1227"/> + <location filename="../Window.cpp" line="1171"/> <source>%0x</source> <translation>%0x</translation> </message> <message> - <location filename="../Window.cpp" line="1235"/> + <location filename="../Window.cpp" line="1179"/> <source>Rewind (held)</source> - <translation>Retroceder (mantener)</translation> + <translation>Rebobinar (mantener)</translation> </message> <message> - <location filename="../Window.cpp" line="1237"/> + <location filename="../Window.cpp" line="1181"/> <source>Re&wind</source> - <translation>Retroceder (&W)</translation> + <translation>Re&bobinar</translation> </message> <message> - <location filename="../Window.cpp" line="1238"/> + <location filename="../Window.cpp" line="1182"/> <source>~</source> <translation>~</translation> </message> <message> - <location filename="../Window.cpp" line="1245"/> + <location filename="../Window.cpp" line="1188"/> <source>Step backwards</source> <translation>Paso hacia atrás</translation> </message> <message> - <location filename="../Window.cpp" line="1246"/> + <location filename="../Window.cpp" line="1189"/> <source>Ctrl+B</source> <translation>Ctrl+B</translation> </message> <message> - <location filename="../Window.cpp" line="1256"/> + <location filename="../Window.cpp" line="1198"/> <source>Sync to &video</source> <translation>Sincronizar a &video</translation> </message> <message> - <location filename="../Window.cpp" line="1263"/> + <location filename="../Window.cpp" line="1205"/> <source>Sync to &audio</source> - <translation>Sincronizar a &audio</translation> + <translation>Sincronizar a au&dio</translation> </message> <message> - <location filename="../Window.cpp" line="1271"/> + <location filename="../Window.cpp" line="1213"/> <source>Solar sensor</source> <translation>Sensor solar</translation> </message> <message> - <location filename="../Window.cpp" line="1273"/> + <location filename="../Window.cpp" line="1215"/> <source>Increase solar level</source> - <translation>Aumentar nivel solar</translation> + <translation>Subir nivel</translation> </message> <message> - <location filename="../Window.cpp" line="1277"/> + <location filename="../Window.cpp" line="1219"/> <source>Decrease solar level</source> - <translation>Disminuir nivel solar</translation> + <translation>Bajar nivel</translation> </message> <message> - <location filename="../Window.cpp" line="1281"/> + <location filename="../Window.cpp" line="1223"/> <source>Brightest solar level</source> - <translation>Nivel solar más brillante</translation> + <translation>Más claro</translation> </message> <message> - <location filename="../Window.cpp" line="1285"/> + <location filename="../Window.cpp" line="1227"/> <source>Darkest solar level</source> - <translation>Nivel solar más oscuro</translation> + <translation>Más oscuro</translation> </message> <message> - <location filename="../Window.cpp" line="1291"/> + <location filename="../Window.cpp" line="1233"/> <source>Brightness %1</source> <translation>Brillo %1</translation> </message> <message> - <location filename="../Window.cpp" line="1298"/> + <location filename="../Window.cpp" line="1240"/> <source>Audio/&Video</source> - <translation>Audio/&Video</translation> + <translation>Audio/&video</translation> </message> <message> - <location filename="../Window.cpp" line="1300"/> + <location filename="../Window.cpp" line="1242"/> <source>Frame size</source> <translation>Tamaño del cuadro</translation> </message> <message> - <location filename="../Window.cpp" line="1303"/> + <location filename="../Window.cpp" line="1245"/> <source>%1x</source> <translation>%1x</translation> </message> <message> - <location filename="../Window.cpp" line="1331"/> + <location filename="../Window.cpp" line="1273"/> <source>Toggle fullscreen</source> <translation>Pantalla completa</translation> </message> <message> - <location filename="../Window.cpp" line="1334"/> + <location filename="../Window.cpp" line="1276"/> <source>Lock aspect ratio</source> - <translation>Bloquear relación de aspecto</translation> + <translation>Bloquear proporción de aspecto</translation> </message> <message> - <location filename="../Window.cpp" line="1341"/> + <location filename="../Window.cpp" line="1283"/> <source>Force integer scaling</source> - <translation type="unfinished"></translation> + <translation>Forzar escala a enteros</translation> </message> <message> - <location filename="../Window.cpp" line="1357"/> + <location filename="../Window.cpp" line="1293"/> + <source>Bilinear filtering</source> + <translation>Filtro bilineal</translation> + </message> + <message> + <location filename="../Window.cpp" line="1299"/> <source>Frame&skip</source> <translation>&Salto de cuadros</translation> </message> <message> - <location filename="../Window.cpp" line="1367"/> - <source>Shader options...</source> - <translation>Opciones del programa shader...</translation> - </message> - <message> - <location filename="../Window.cpp" line="1377"/> + <location filename="../Window.cpp" line="1312"/> <source>Mute</source> <translation>Silenciar</translation> </message> <message> - <location filename="../Window.cpp" line="1384"/> + <location filename="../Window.cpp" line="1319"/> <source>FPS target</source> <translation>Objetivo de FPS</translation> </message> <message> - <location filename="../Window.cpp" line="1389"/> + <location filename="../Window.cpp" line="1324"/> <source>15</source> <translation>15</translation> </message> <message> - <location filename="../Window.cpp" line="1390"/> + <location filename="../Window.cpp" line="1325"/> <source>30</source> <translation>30</translation> </message> <message> - <location filename="../Window.cpp" line="1391"/> + <location filename="../Window.cpp" line="1326"/> <source>45</source> <translation>45</translation> </message> <message> - <location filename="../Window.cpp" line="1392"/> + <location filename="../Window.cpp" line="1327"/> <source>Native (59.7)</source> <translation>Nativo (59.7)</translation> </message> <message> - <location filename="../Window.cpp" line="1393"/> + <location filename="../Window.cpp" line="1328"/> <source>60</source> <translation>60</translation> </message> <message> - <location filename="../Window.cpp" line="1394"/> + <location filename="../Window.cpp" line="1329"/> <source>90</source> <translation>90</translation> </message> <message> - <location filename="../Window.cpp" line="1395"/> + <location filename="../Window.cpp" line="1330"/> <source>120</source> - <translation>120</translation> + <translation>Bilineal120</translation> </message> <message> - <location filename="../Window.cpp" line="1396"/> + <location filename="../Window.cpp" line="1331"/> <source>240</source> <translation>240</translation> </message> <message> - <location filename="../Window.cpp" line="1404"/> + <location filename="../Window.cpp" line="1339"/> <source>Take &screenshot</source> - <translation>Tomar pantallazo (&S)</translation> + <translation>Tomar pan&tallazo</translation> </message> <message> - <location filename="../Window.cpp" line="1405"/> + <location filename="../Window.cpp" line="1340"/> <source>F12</source> <translation>F12</translation> </message> <message> - <location filename="../Window.cpp" line="1412"/> + <location filename="../Window.cpp" line="1347"/> <source>Record output...</source> <translation>Grabar salida...</translation> </message> <message> - <location filename="../Window.cpp" line="1419"/> + <location filename="../Window.cpp" line="1354"/> <source>Record GIF...</source> <translation>Grabar GIF...</translation> </message> <message> - <location filename="../Window.cpp" line="1424"/> + <location filename="../Window.cpp" line="1359"/> <source>Record video log...</source> - <translation type="unfinished"></translation> + <translation>Grabar video-registro...</translation> </message> <message> - <location filename="../Window.cpp" line="1429"/> + <location filename="../Window.cpp" line="1364"/> <source>Stop video log</source> - <translation type="unfinished"></translation> + <translation>Detener video-registro</translation> </message> <message> - <location filename="../Window.cpp" line="1435"/> + <location filename="../Window.cpp" line="1370"/> <source>Video layers</source> <translation>Capas de video</translation> </message> <message> - <location filename="../Window.cpp" line="1438"/> + <location filename="../Window.cpp" line="1373"/> <source>Audio channels</source> <translation>Canales de audio</translation> </message> <message> - <location filename="../Window.cpp" line="1441"/> + <location filename="../Window.cpp" line="1376"/> <source>&Tools</source> <translation>Herramien&tas</translation> </message> <message> - <location filename="../Window.cpp" line="1443"/> + <location filename="../Window.cpp" line="1378"/> <source>View &logs...</source> - <translation>Ver registros... (&L)</translation> + <translation>Ver re&gistros...</translation> </message> <message> - <location filename="../Window.cpp" line="1447"/> + <location filename="../Window.cpp" line="1382"/> <source>Game &overrides...</source> - <translation>Val&ores específicos por juego...</translation> + <translation>Ajustes específic&os por juego...</translation> </message> <message> - <location filename="../Window.cpp" line="1451"/> + <location filename="../Window.cpp" line="1386"/> <source>Game &Pak sensors...</source> - <translation>Sensores en el Game &Pak...</translation> + <translation>Sensores del Game &Pak...</translation> </message> <message> - <location filename="../Window.cpp" line="1455"/> + <location filename="../Window.cpp" line="1390"/> <source>&Cheats...</source> <translation>Tru&cos...</translation> </message> <message> - <location filename="../Window.cpp" line="1468"/> - <source>Open debugger console...</source> - <translation>Abrir la consola de depuración...</translation> - </message> - <message> - <location filename="../Window.cpp" line="1474"/> - <source>Start &GDB server...</source> - <translation>Iniciar servidor &GDB...</translation> - </message> - <message> - <location filename="../Window.cpp" line="1462"/> + <location filename="../Window.cpp" line="1396"/> <source>Settings...</source> <translation>Ajustes...</translation> </message> <message> - <location filename="../Window.cpp" line="218"/> - <source>Game Boy Advance</source> - <translation type="unfinished">Game Boy Advance</translation> - </message> - <message> - <location filename="../Window.cpp" line="221"/> - <source>Game Boy</source> - <translation type="unfinished">Game Boy</translation> - </message> - <message> - <location filename="../Window.cpp" line="224"/> - <source>DS</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../Window.cpp" line="440"/> - <source>Select folder</source> - <translation>Elegir carpeta</translation> + <location filename="../Window.cpp" line="1402"/> + <source>Open debugger console...</source> + <translation>Abrir consola de depuración...</translation> </message> <message> - <location filename="../Window.cpp" line="1020"/> - <source>Add folder to library...</source> - <translation>Agregar carpeta a la biblioteca...</translation> + <location filename="../Window.cpp" line="1408"/> + <source>Start &GDB server...</source> + <translation>Iniciar servidor &GDB...</translation> </message> <message> - <location filename="../Window.cpp" line="1351"/> - <source>Bilinear filtering</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../Window.cpp" line="1481"/> + <location filename="../Window.cpp" line="1415"/> <source>View &palette...</source> <translation>Ver &paleta...</translation> </message> <message> - <location filename="../Window.cpp" line="1487"/> + <location filename="../Window.cpp" line="1420"/> <source>View &sprites...</source> <translation>Ver &sprites...</translation> </message> <message> - <location filename="../Window.cpp" line="1493"/> + <location filename="../Window.cpp" line="1425"/> <source>View &tiles...</source> <translation>Ver &tiles...</translation> </message> <message> - <location filename="../Window.cpp" line="1499"/> + <location filename="../Window.cpp" line="1430"/> <source>View memory...</source> <translation>Ver memoria...</translation> </message> <message> - <location filename="../Window.cpp" line="1505"/> + <location filename="../Window.cpp" line="1435"/> + <source>Search memory...</source> + <translation>Buscar memoria...</translation> + </message> + <message> + <location filename="../Window.cpp" line="1441"/> <source>View &I/O registers...</source> - <translation>Ver reg&istros E/S...</translation> + <translation>Ver registros &I/O...</translation> </message> <message> - <location filename="../Window.cpp" line="1575"/> + <location filename="../Window.cpp" line="1511"/> <source>Exit fullscreen</source> <translation>Salir de pantalla completa</translation> </message> <message> - <location filename="../Window.cpp" line="1580"/> + <location filename="../Window.cpp" line="1516"/> <source>Autofire</source> - <translation>Botones turbo</translation> + <translation>Disparo automático</translation> </message> <message> - <location filename="../Window.cpp" line="1587"/> + <location filename="../Window.cpp" line="1523"/> <source>Autofire A</source> - <translation>Turbo A</translation> + <translation>Disparo automático A</translation> </message> <message> - <location filename="../Window.cpp" line="1593"/> + <location filename="../Window.cpp" line="1529"/> <source>Autofire B</source> - <translation>Turbo B</translation> + <translation>Disparo automático B</translation> </message> <message> - <location filename="../Window.cpp" line="1599"/> + <location filename="../Window.cpp" line="1535"/> <source>Autofire L</source> - <translation>Turbo L</translation> + <translation>Disparo automático L</translation> </message> <message> - <location filename="../Window.cpp" line="1605"/> + <location filename="../Window.cpp" line="1541"/> <source>Autofire R</source> - <translation>Turbo R</translation> + <translation>Disparo automático R</translation> </message> <message> - <location filename="../Window.cpp" line="1611"/> + <location filename="../Window.cpp" line="1547"/> <source>Autofire Start</source> - <translation>Turbo Start</translation> + <translation>Disparo automático Start</translation> </message> <message> - <location filename="../Window.cpp" line="1617"/> + <location filename="../Window.cpp" line="1553"/> <source>Autofire Select</source> - <translation>Turbo Select</translation> + <translation>Disparo automático Select</translation> </message> <message> - <location filename="../Window.cpp" line="1623"/> + <location filename="../Window.cpp" line="1559"/> <source>Autofire Up</source> - <translation>Turbo Arriba</translation> + <translation>Disparo automático Arriba</translation> </message> <message> - <location filename="../Window.cpp" line="1629"/> + <location filename="../Window.cpp" line="1565"/> <source>Autofire Right</source> - <translation>Turbo Derecha</translation> + <translation>Disparo automático Derecha</translation> </message> <message> - <location filename="../Window.cpp" line="1635"/> + <location filename="../Window.cpp" line="1571"/> <source>Autofire Down</source> - <translation>Turbo Abajo</translation> + <translation>Disparo automático Abajo</translation> </message> <message> - <location filename="../Window.cpp" line="1641"/> + <location filename="../Window.cpp" line="1577"/> <source>Autofire Left</source> - <translation>Turbo Izquierda</translation> + <translation>Disparo automático Izquierda</translation> </message> </context> <context>@@ -3564,17 +3712,17 @@ <name>QObject</name>
<message> <location filename="../utils.cpp" line="29"/> <source>GBA</source> - <translation type="unfinished">GBA</translation> + <translation>GBA</translation> </message> <message> <location filename="../utils.cpp" line="33"/> <source>GB</source> - <translation type="unfinished">GB</translation> + <translation>GB</translation> </message> <message> <location filename="../utils.cpp" line="36"/> <source>?</source> - <translation type="unfinished">?</translation> + <translation>?</translation> </message> </context> <context>@@ -3607,7 +3755,7 @@ </message>
<message> <location filename="../ROMInfo.ui" line="63"/> <source>Game ID:</source> - <translation>ID del juego:</translation> + <translation>ID de juego:</translation> </message> <message> <location filename="../ROMInfo.ui" line="70"/>@@ -3660,7 +3808,7 @@ </message>
<message> <location filename="../SensorView.ui" line="60"/> <source>Start time at</source> - <translation>Contar desde el</translation> + <translation>Empezar desde esta hora</translation> </message> <message> <location filename="../SensorView.ui" line="70"/>@@ -3691,13 +3839,13 @@ <message>
<location filename="../SensorView.ui" line="161"/> <location filename="../SensorView.ui" line="250"/> <source>Set Y</source> - <translation>Config. Y</translation> + <translation>Ajustar Y</translation> </message> <message> <location filename="../SensorView.ui" line="171"/> <location filename="../SensorView.ui" line="260"/> <source>Set X</source> - <translation>Config. X</translation> + <translation>Ajustar X</translation> </message> <message> <location filename="../SensorView.ui" line="242"/>@@ -3720,7 +3868,7 @@ </message>
<message> <location filename="../SettingsView.ui" line="45"/> <source>Audio/Video</source> - <translation>Audio/Video</translation> + <translation>Audio/video</translation> </message> <message> <location filename="../SettingsView.ui" line="50"/>@@ -3733,6 +3881,11 @@ <source>Emulation</source>
<translation>Emulación</translation> </message> <message> + <location filename="../SettingsView.ui" line="60"/> + <source>BIOS</source> + <translation>BIOS</translation> + </message> + <message> <location filename="../SettingsView.ui" line="65"/> <source>Paths</source> <translation>Rutas</translation>@@ -3740,7 +3893,7 @@ </message>
<message> <location filename="../SettingsView.ui" line="90"/> <source>Audio driver:</source> - <translation>Controlador de audio:</translation> + <translation>Sistema de audio:</translation> </message> <message> <location filename="../SettingsView.ui" line="107"/>@@ -3832,7 +3985,7 @@ </message>
<message> <location filename="../SettingsView.ui" line="271"/> <source>Display driver:</source> - <translation>Controlador de video:</translation> + <translation>Sistema de video:</translation> </message> <message> <location filename="../SettingsView.ui" line="288"/>@@ -3846,7 +3999,7 @@ <translation>Saltar cada</translation>
</message> <message> <location filename="../SettingsView.ui" line="307"/> - <location filename="../SettingsView.ui" line="556"/> + <location filename="../SettingsView.ui" line="576"/> <source>frames</source> <translation>cuadros</translation> </message>@@ -3863,7 +4016,7 @@ </message>
<message> <location filename="../SettingsView.ui" line="354"/> <source>Sync:</source> - <translation>SIncronizar a:</translation> + <translation>Sincronizar con:</translation> </message> <message> <location filename="../SettingsView.ui" line="363"/>@@ -3878,225 +4031,212 @@ </message>
<message> <location filename="../SettingsView.ui" line="379"/> <source>Lock aspect ratio</source> - <translation>Bloquear relación de aspecto</translation> + <translation>Bloquear proporción de aspecto</translation> + </message> + <message> + <location filename="../SettingsView.ui" line="386"/> + <source>Bilinear filtering</source> + <translation>Filtro bilineal</translation> </message> <message> <location filename="../SettingsView.ui" line="393"/> <source>Force integer scaling</source> - <translation type="unfinished"></translation> + <translation>Forzar escala a enteros</translation> </message> <message> - <location filename="../SettingsView.ui" line="415"/> - <source>List view</source> - <translation type="unfinished"></translation> + <location filename="../SettingsView.ui" line="404"/> + <source>Language</source> + <translation>Idioma</translation> </message> <message> - <location filename="../SettingsView.ui" line="420"/> - <source>Tree view</source> - <translation type="unfinished"></translation> + <location filename="../SettingsView.ui" line="412"/> + <source>English</source> + <translation>English</translation> </message> <message> - <location filename="../SettingsView.ui" line="428"/> + <location filename="../SettingsView.ui" line="420"/> <source>Library:</source> <translation>Biblioteca:</translation> </message> <message> - <location filename="../SettingsView.ui" line="404"/> - <source>Show when no game open</source> - <translation>Mostrar al no haber juego abierto</translation> + <location filename="../SettingsView.ui" line="428"/> + <source>List view</source> + <translation>Lista</translation> </message> <message> - <location filename="../SettingsView.ui" line="438"/> - <source>Clear cache</source> - <translation>Limpiar caché</translation> + <location filename="../SettingsView.ui" line="433"/> + <source>Tree view</source> + <translation>Árbol</translation> </message> <message> - <location filename="../SettingsView.ui" line="483"/> - <source>Fast forward speed:</source> - <translation>Velocidad de avance rápido:</translation> + <location filename="../SettingsView.ui" line="441"/> + <source>Show when no game open</source> + <translation>Mostrar cuando no haya un juego abierto</translation> </message> <message> - <location filename="../SettingsView.ui" line="723"/> - <location filename="../SettingsView.ui" line="751"/> - <location filename="../SettingsView.ui" line="779"/> - <location filename="../SettingsView.ui" line="807"/> - <location filename="../SettingsView.ui" line="835"/> - <location filename="../SettingsView.ui" line="856"/> - <location filename="../SettingsView.ui" line="921"/> - <location filename="../SettingsView.ui" line="969"/> - <location filename="../SettingsView.ui" line="1017"/> - <location filename="../SettingsView.ui" line="1065"/> - <source>Browse</source> - <translation>Examinar</translation> + <location filename="../SettingsView.ui" line="451"/> + <source>Clear cache</source> + <translation>Limpiar caché</translation> </message> <message> - <location filename="../SettingsView.ui" line="788"/> - <source>DS BIOS 7 file:</source> - <translation type="unfinished"></translation> + <location filename="../SettingsView.ui" line="465"/> + <source>Allow opposing input directions</source> + <translation>Permitir direcciones opuestas al mismo tiempo</translation> </message> <message> - <location filename="../SettingsView.ui" line="816"/> - <source>DS BIOS 9 file:</source> - <translation type="unfinished"></translation> + <location filename="../SettingsView.ui" line="472"/> + <source>Suspend screensaver</source> + <translation>Suspender protector de pantalla</translation> </message> <message> - <location filename="../SettingsView.ui" line="865"/> - <source>Use BIOS file if found</source> - <translation>Usar archivo BIOS si hay</translation> + <location filename="../SettingsView.ui" line="482"/> + <source>Pause when inactive</source> + <translation>Pausar al no estar activo</translation> </message> <message> - <location filename="../SettingsView.ui" line="875"/> - <source>Skip BIOS intro</source> - <translation>Saltar pantalla de inicio de la BIOS</translation> + <location filename="../SettingsView.ui" line="503"/> + <source>Fast forward speed:</source> + <translation>Velocidad de avance rápido:</translation> </message> <message> - <location filename="../SettingsView.ui" line="495"/> + <location filename="../SettingsView.ui" line="515"/> <source>×</source> <translation>×</translation> </message> <message> - <location filename="../SettingsView.ui" line="514"/> + <location filename="../SettingsView.ui" line="534"/> <source>Unbounded</source> - <translation>Ilimitado</translation> + <translation>Sin límite</translation> </message> <message> - <location filename="../SettingsView.ui" line="459"/> - <source>Suspend screensaver</source> - <translation>No permitir protector de pantalla</translation> + <location filename="../SettingsView.ui" line="553"/> + <source>Enable rewind</source> + <translation>Habilitar el rebobinar</translation> </message> <message> - <location filename="../SettingsView.ui" line="60"/> - <source>BIOS</source> - <translation>BIOS</translation> + <location filename="../SettingsView.ui" line="560"/> + <source>Rewind history:</source> + <translation>Historial de rebobinado:</translation> </message> <message> - <location filename="../SettingsView.ui" line="469"/> - <source>Pause when inactive</source> - <translation>Pausar al estar inactivo</translation> + <location filename="../SettingsView.ui" line="592"/> + <source>Idle loops:</source> + <translation>Bucles inactivos:</translation> </message> <message> - <location filename="../SettingsView.ui" line="580"/> + <location filename="../SettingsView.ui" line="600"/> <source>Run all</source> - <translation>Ejecutar todos</translation> + <translation>Ejecutarlos todos</translation> </message> <message> - <location filename="../SettingsView.ui" line="585"/> + <location filename="../SettingsView.ui" line="605"/> <source>Remove known</source> <translation>Eliminar los conocidos</translation> </message> <message> - <location filename="../SettingsView.ui" line="590"/> + <location filename="../SettingsView.ui" line="610"/> <source>Detect and remove</source> <translation>Detectar y eliminar</translation> </message> <message> - <location filename="../SettingsView.ui" line="452"/> - <source>Allow opposing input directions</source> - <translation>Permitir direcciones opuestas</translation> + <location filename="../SettingsView.ui" line="625"/> + <source>Savestate extra data:</source> + <translation>Guardar datos extra con el estado:</translation> </message> <message> - <location filename="../SettingsView.ui" line="612"/> - <location filename="../SettingsView.ui" line="649"/> + <location filename="../SettingsView.ui" line="632"/> + <location filename="../SettingsView.ui" line="669"/> <source>Screenshot</source> <translation>Pantallazo</translation> </message> <message> - <location filename="../SettingsView.ui" line="622"/> - <location filename="../SettingsView.ui" line="659"/> + <location filename="../SettingsView.ui" line="642"/> + <location filename="../SettingsView.ui" line="679"/> <source>Save data</source> <translation>Datos de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="632"/> - <location filename="../SettingsView.ui" line="666"/> + <location filename="../SettingsView.ui" line="652"/> + <location filename="../SettingsView.ui" line="686"/> <source>Cheat codes</source> <translation>Trucos</translation> </message> <message> - <location filename="../SettingsView.ui" line="533"/> - <source>Enable rewind</source> - <translation>Habilitar retroceso</translation> + <location filename="../SettingsView.ui" line="662"/> + <source>Load extra data:</source> + <translation>Cargar datos extra con el estado:</translation> </message> <message> - <location filename="../SettingsView.ui" line="386"/> - <source>Bilinear filtering</source> - <translation type="unfinished"></translation> + <location filename="../SettingsView.ui" line="700"/> + <source>Rewind affects save data</source> + <translation>El rebobinar afecta los datos de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="540"/> - <source>Rewind history:</source> - <translation>Historial de retroceso:</translation> + <location filename="../SettingsView.ui" line="710"/> + <source>Preload entire ROM into memory</source> + <translation>Cargar ROM completa a la memoria</translation> </message> <message> - <location filename="../SettingsView.ui" line="572"/> - <source>Idle loops:</source> - <translation>Bucles inactivos:</translation> + <location filename="../SettingsView.ui" line="721"/> + <source>GB BIOS file:</source> + <translation>Archivo BIOS GB:</translation> </message> <message> - <location filename="../SettingsView.ui" line="605"/> - <source>Savestate extra data:</source> - <translation>Datos extras en capturas de estado:</translation> + <location filename="../SettingsView.ui" line="740"/> + <location filename="../SettingsView.ui" line="778"/> + <location filename="../SettingsView.ui" line="813"/> + <location filename="../SettingsView.ui" line="854"/> + <location filename="../SettingsView.ui" line="902"/> + <location filename="../SettingsView.ui" line="950"/> + <location filename="../SettingsView.ui" line="998"/> + <source>Browse</source> + <translation>Examinar</translation> </message> <message> - <location filename="../SettingsView.ui" line="642"/> - <source>Load extra data:</source> - <translation>Cargar datos extra:</translation> + <location filename="../SettingsView.ui" line="749"/> + <source>Use BIOS file if found</source> + <translation>Usar archivo BIOS si fue encontrado</translation> </message> <message> - <location filename="../SettingsView.ui" line="680"/> - <source>Rewind affects save data</source> - <translation type="unfinished"></translation> + <location filename="../SettingsView.ui" line="759"/> + <source>Skip BIOS intro</source> + <translation>Saltar animación de entrada del BIOS</translation> </message> <message> - <location filename="../SettingsView.ui" line="690"/> - <source>Preload entire ROM into memory</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../SettingsView.ui" line="704"/> - <source>GB BIOS file:</source> - <translation>Archivo de BIOS GB:</translation> - </message> - <message> - <location filename="../SettingsView.ui" line="760"/> + <location filename="../SettingsView.ui" line="787"/> <source>GBA BIOS file:</source> - <translation>Archivo de BIOS GBA:</translation> + <translation>Archivo BIOS GBA:</translation> </message> <message> - <location filename="../SettingsView.ui" line="732"/> + <location filename="../SettingsView.ui" line="794"/> <source>GBC BIOS file:</source> - <translation>Archivo de BIOS GBC:</translation> - </message> - <message> - <location filename="../SettingsView.ui" line="882"/> - <source>DS firmware file:</source> - <translation type="unfinished"></translation> + <translation>Archivo BIOS GBC:</translation> </message> <message> - <location filename="../SettingsView.ui" line="896"/> + <location filename="../SettingsView.ui" line="829"/> <source>Save games</source> - <translation>Guardados de juego</translation> + <translation>Datos de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="930"/> - <location filename="../SettingsView.ui" line="978"/> - <location filename="../SettingsView.ui" line="1026"/> - <location filename="../SettingsView.ui" line="1074"/> + <location filename="../SettingsView.ui" line="863"/> + <location filename="../SettingsView.ui" line="911"/> + <location filename="../SettingsView.ui" line="959"/> + <location filename="../SettingsView.ui" line="1007"/> <source>Same directory as the ROM</source> - <translation>Mismo directorio de la ROM</translation> + <translation>Al mismo directorio que la ROM</translation> </message> <message> - <location filename="../SettingsView.ui" line="944"/> + <location filename="../SettingsView.ui" line="877"/> <source>Save states</source> - <translation>Capturas de estado</translation> + <translation>Estados de guardado</translation> </message> <message> - <location filename="../SettingsView.ui" line="992"/> + <location filename="../SettingsView.ui" line="925"/> <source>Screenshots</source> <translation>Pantallazos</translation> </message> <message> - <location filename="../SettingsView.ui" line="1040"/> + <location filename="../SettingsView.ui" line="973"/> <source>Patches</source> <translation>Parches</translation> </message>@@ -4106,12 +4246,12 @@ <name>ShaderSelector</name>
<message> <location filename="../ShaderSelector.ui" line="14"/> <source>Shaders</source> - <translation>Programas shader</translation> + <translation>Shaders</translation> </message> <message> <location filename="../ShaderSelector.ui" line="28"/> <source>Active Shader:</source> - <translation>Programa shader activo:</translation> + <translation>Shader activo:</translation> </message> <message> <location filename="../ShaderSelector.ui" line="35"/>@@ -4131,12 +4271,12 @@ </message>
<message> <location filename="../ShaderSelector.ui" line="88"/> <source>Unload Shader</source> - <translation>Cerrar programa shader</translation> + <translation>Cerrar shader</translation> </message> <message> <location filename="../ShaderSelector.ui" line="95"/> <source>Load New Shader</source> - <translation>Cargar nuevo p. shader</translation> + <translation>Cargar nuevo shader</translation> </message> </context> <context>@@ -4144,7 +4284,7 @@ <name>ShortcutView</name>
<message> <location filename="../ShortcutView.ui" line="14"/> <source>Edit Shortcuts</source> - <translation>Editar accesos directos de teclado</translation> + <translation>Editar atajos de teclado</translation> </message> <message> <location filename="../ShortcutView.ui" line="29"/>@@ -4182,7 +4322,7 @@ </message>
<message> <location filename="../TileView.ui" line="83"/> <source>Magnification</source> - <translation>Magnificación</translation> + <translation>Ampliación</translation> </message> </context> <context>@@ -4205,12 +4345,12 @@ </message>
<message> <location filename="../VideoView.ui" line="69"/> <source>Select File</source> - <translation>Elegir archivo</translation> + <translation>Seleccionar archivo</translation> </message> <message> <location filename="../VideoView.ui" line="101"/> <source>Presets</source> - <translation>Ajustes predeterminados</translation> + <translation>Ajustes predefinidos</translation> </message> <message> <location filename="../VideoView.ui" line="109"/>@@ -4251,7 +4391,7 @@ </message>
<message> <location filename="../VideoView.ui" line="189"/> <source>Native</source> - <translation>Nativo</translation> + <translation>Nativa</translation> </message> <message> <location filename="../VideoView.ui" line="222"/>@@ -4286,17 +4426,17 @@ </message>
<message> <location filename="../VideoView.ui" line="269"/> <source>h.264 (NVENC)</source> - <translation type="unfinished"></translation> + <translation>h.264 (NVENC)</translation> </message> <message> <location filename="../VideoView.ui" line="274"/> <source>HEVC</source> - <translation type="unfinished"></translation> + <translation>HEVC</translation> </message> <message> <location filename="../VideoView.ui" line="279"/> <source>VP8</source> - <translation></translation> + <translation>VP8</translation> </message> <message> <location filename="../VideoView.ui" line="284"/>@@ -4336,7 +4476,7 @@ </message>
<message> <location filename="../VideoView.ui" line="332"/> <source> Bitrate (kbps)</source> - <translation>Tasa de bits (kbps)</translation> + <translation> Tasa de bits (kbps)</translation> </message> <message> <location filename="../VideoView.ui" line="338"/>@@ -4366,7 +4506,7 @@ </message>
<message> <location filename="../VideoView.ui" line="468"/> <source>Lock aspect ratio</source> - <translation>Bloquear relación de aspecto</translation> + <translation>Bloquear proporción de aspecto</translation> </message> <message> <location filename="../VideoView.ui" line="483"/>
@@ -86,11 +86,17 @@ list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
endif() endif() +if(ENABLE_SCRIPTING) + if(BUILD_PYTHON) + list(APPEND PLATFORM_LIBRARY "${PYTHON_LIBRARY}") + endif() +endif() + add_executable(${BINARY_NAME}-sdl WIN32 ${PLATFORM_SRC} ${MAIN_SRC}) set_target_properties(${BINARY_NAME}-sdl PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES}") target_link_libraries(${BINARY_NAME}-sdl ${BINARY_NAME} ${PLATFORM_LIBRARY} ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY}) set_target_properties(${BINARY_NAME}-sdl PROPERTIES OUTPUT_NAME ${BINARY_NAME}) -install(TARGETS ${BINARY_NAME}-sdl DESTINATION bin COMPONENT ${BINARY_NAME}-sdl) +install(TARGETS ${BINARY_NAME}-sdl DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT ${BINARY_NAME}-sdl) if(UNIX) install(FILES ${CMAKE_SOURCE_DIR}/doc/${BINARY_NAME}.6 DESTINATION ${MANDIR}/man6 COMPONENT ${BINARY_NAME}-sdl) endif()
@@ -53,7 +53,7 @@ struct mCoreThread* context = user;
SDL_Event event; struct VideoBackend* v = &renderer->gl.d; - while (context->state < THREAD_EXITING) { + while (mCoreThreadIsActive(context)) { while (SDL_PollEvent(&event)) { mSDLHandleEvent(context, &renderer->player, &event); #if SDL_VERSION_ATLEAST(2, 0, 0)@@ -66,10 +66,10 @@ }
#endif } - if (mCoreSyncWaitFrameStart(&context->sync)) { + if (mCoreSyncWaitFrameStart(&context->impl->sync)) { v->postFrame(v, renderer->outputBuffer); } - mCoreSyncWaitFrameEnd(&context->sync); + mCoreSyncWaitFrameEnd(&context->impl->sync); v->drawFrame(v); v->swap(v); }
@@ -13,6 +13,13 @@ #endif
#ifdef USE_EDITLINE #include "feature/editline/cli-el-backend.h" #endif +#ifdef ENABLE_SCRIPTING +#include <mgba/core/scripting.h> + +#ifdef ENABLE_PYTHON +#include "platform/python/engine.h" +#endif +#endif #include <mgba/core/core.h> #include <mgba/core/config.h>@@ -56,7 +63,7 @@ struct mSubParser subparser;
initParserForGraphics(&subparser, &graphicsOpts); bool parsed = parseArguments(&args, argc, argv, &subparser); - if (!args.fname) { + if (!args.fname && !args.showVersion) { parsed = false; } if (!parsed || args.showHelp) {@@ -159,6 +166,13 @@ if (!mCoreLoadFile(renderer->core, args->fname)) {
return 1; } mCoreAutoloadSave(renderer->core); +#ifdef ENABLE_SCRIPTING + struct mScriptBridge* bridge = mScriptBridgeCreate(); +#ifdef ENABLE_PYTHON + mPythonSetup(bridge); +#endif +#endif + #ifdef USE_DEBUGGERS struct mDebugger* debugger = mDebuggerCreate(args->debuggerType, renderer->core); if (debugger) {@@ -171,6 +185,9 @@ #endif
mDebuggerAttach(debugger, renderer->core); mDebuggerEnter(debugger, DEBUGGER_ENTER_MANUAL, NULL); } +#ifdef ENABLE_SCRIPTING + mScriptBridgeSetDebugger(bridge, debugger); +#endif #endif if (args->patch) {@@ -212,6 +229,11 @@ } else {
printf("Could not run game. Are you sure the file exists and is a compatible game?\n"); } renderer->core->unloadROM(renderer->core); + +#ifdef ENABLE_SCRIPTING + mScriptBridgeDestroy(bridge); +#endif + return didFail; }
@@ -40,12 +40,11 @@ #endif
mLOG(SDL_AUDIO, ERROR, "Could not open SDL sound system"); return false; } - context->samples = context->obtainedSpec.samples; context->core = 0; if (threadContext) { context->core = threadContext->core; - context->sync = &threadContext->sync; + context->sync = &threadContext->impl->sync; #if SDL_VERSION_ATLEAST(2, 0, 0) SDL_PauseAudioDevice(context->deviceId, 0);
@@ -416,7 +416,7 @@ }
return; } if (event->keysym.sym == SDLK_TAB) { - context->sync.audioWait = event->type != SDL_KEYDOWN; + context->impl->sync.audioWait = event->type != SDL_KEYDOWN; return; } if (event->keysym.sym == SDLK_BACKQUOTE) {
@@ -24,6 +24,7 @@ #include <mgba-util/gui.h>
#include <mgba-util/gui/file-select.h> #include <mgba-util/gui/font.h> #include <mgba-util/gui/menu.h> +#include <mgba-util/memory.h> #include <mgba-util/vfs.h> #define GCN1_INPUT 0x47434E31@@ -113,6 +114,9 @@ static uint32_t referenceRetraceCount;
static bool frameLimiter = true; static int scaleFactor; static unsigned corew, coreh; + +uint32_t* romBuffer; +size_t romBufferSize; static void* framebuffer[2] = { 0, 0 }; static int whichFb = 0;@@ -242,6 +246,10 @@ AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
AUDIO_RegisterDMACallback(_audioDMA); memset(audioBuffer, 0, sizeof(audioBuffer)); +#ifdef FIXED_ROM_BUFFER + romBufferSize = SIZE_CART0; + romBuffer = anonymousMemoryMap(romBufferSize); +#endif #if !defined(COLOR_16_BIT) && !defined(COLOR_5_6_5) #error This pixel format is unsupported. Please use -DCOLOR_16-BIT -DCOLOR_5_6_5@@ -509,6 +517,10 @@ } else {
mGUIRunloop(&runner); } mGUIDeinit(&runner); + +#ifdef FIXED_ROM_BUFFER + mappedMemoryFree(romBuffer, romBufferSize); +#endif free(fifo); free(texmem);