From 7e909803bc46f69aeef4c8dd23411545c956e44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Doncam=20Demian=20L=C3=B3pez=20Brante?= Date: Wed, 1 Feb 2017 02:02:32 -0300 Subject: [PATCH 01/43] Qt: Surrounded remaining strings with tr() --- src/platform/qt/CheatsView.cpp | 10 +++++----- src/platform/qt/SettingsView.cpp | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/platform/qt/CheatsView.cpp b/src/platform/qt/CheatsView.cpp index b3e912c55..f8ae9b77d 100644 --- a/src/platform/qt/CheatsView.cpp +++ b/src/platform/qt/CheatsView.cpp @@ -46,19 +46,19 @@ CheatsView::CheatsView(GameController* controller, QWidget* parent) enterCheat(GBA_CHEAT_AUTODETECT); }); - add = new QPushButton("Add GameShark"); + add = new QPushButton(tr("Add GameShark")); m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2); connect(add, &QPushButton::clicked, [this]() { enterCheat(GBA_CHEAT_GAMESHARK); }); - add = new QPushButton("Add Pro Action Replay"); + add = new QPushButton(tr("Add Pro Action Replay")); m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2); connect(add, &QPushButton::clicked, [this]() { enterCheat(GBA_CHEAT_PRO_ACTION_REPLAY); }); - add = new QPushButton("Add CodeBreaker"); + add = new QPushButton(tr("Add CodeBreaker")); m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2); connect(add, &QPushButton::clicked, [this]() { enterCheat(GBA_CHEAT_CODEBREAKER); @@ -71,13 +71,13 @@ CheatsView::CheatsView(GameController* controller, QWidget* parent) enterCheat(GB_CHEAT_AUTODETECT); }); - add = new QPushButton("Add GameShark"); + add = new QPushButton(tr("Add GameShark")); m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2); connect(add, &QPushButton::clicked, [this]() { enterCheat(GB_CHEAT_GAMESHARK); }); - add = new QPushButton("Add GameGenie"); + add = new QPushButton(tr("Add GameGenie")); m_ui.gridLayout->addWidget(add, m_ui.gridLayout->rowCount(), 2, 1, 2); connect(add, &QPushButton::clicked, [this]() { enterCheat(GB_CHEAT_GAME_GENIE); diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 09df40cbf..57c27049d 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -139,7 +139,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC GBAKeyEditor* editor = new GBAKeyEditor(inputController, InputController::KEYBOARD, QString(), this); m_ui.stackedWidget->addWidget(editor); - m_ui.tabs->addItem("Keyboard"); + m_ui.tabs->addItem(tr("Keyboard")); connect(m_ui.buttonBox, SIGNAL(accepted()), editor, SLOT(save())); GBAKeyEditor* buttonEditor = nullptr; @@ -148,7 +148,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC const char* profile = inputController->profileForType(SDL_BINDING_BUTTON); buttonEditor = new GBAKeyEditor(inputController, SDL_BINDING_BUTTON, profile); m_ui.stackedWidget->addWidget(buttonEditor); - m_ui.tabs->addItem("Controllers"); + m_ui.tabs->addItem(tr("Controllers")); connect(m_ui.buttonBox, SIGNAL(accepted()), buttonEditor, SLOT(save())); #endif @@ -167,7 +167,7 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC shortcutView->setController(shortcutController); shortcutView->setInputController(inputController); m_ui.stackedWidget->addWidget(shortcutView); - m_ui.tabs->addItem("Shortcuts"); + m_ui.tabs->addItem(tr("Shortcuts")); } void SettingsView::selectBios(QLineEdit* bios) { From 6758c97c1e0be4eaff46bbafa9251d96c7d27464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Doncam=20Demian=20L=C3=B3pez=20Brante?= Date: Wed, 1 Feb 2017 02:02:56 -0300 Subject: [PATCH 02/43] Qt: Created Spanish translation --- CHANGES | 1 + src/platform/qt/ts/mgba-es.ts | 1563 +++++++++++++++++---------------- 2 files changed, 804 insertions(+), 760 deletions(-) diff --git a/CHANGES b/CHANGES index eb79aabf3..50aeba077 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,7 @@ Features: - Improved memory viewer - GB: LR35902/GB-Z80 disassembler - Configuration of gamepad hats + - Qt: Spanish translation (by Kevin López) Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior diff --git a/src/platform/qt/ts/mgba-es.ts b/src/platform/qt/ts/mgba-es.ts index 0b242df8d..610255ddf 100644 --- a/src/platform/qt/ts/mgba-es.ts +++ b/src/platform/qt/ts/mgba-es.ts @@ -6,53 +6,54 @@ About - + Acerca de <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> - + <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> {projectName} - + {projectName} {projectName} would like to thank the following patrons from Patreon: - + {projectName} desea agradecer a los siguientes mecenas de Patreon: © 2013 – 2016 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - + © 2013 - 2016 Jeffrey Pfau, licenciado bajo la Licencia Pública de Mozilla, versión 2.0 +Game Boy Advance es una marca registrada de Nintendo Co., Ltd. {patrons} - + {patrons} {projectVersion} - + {projectVersion} {logo} - + {logo} {projectName} is an open-source Game Boy Advance emulator - + {projectName} es un emulador de Game Boy Advance de código abierto Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> - + Rama Git: <tt>{gitBranch}</tt><br/>Revisión: <tt>{gitCommit}</tt> @@ -60,12 +61,12 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Open in archive... - + Abrir dentro de archivo ... Loading... - + Cargando... @@ -73,49 +74,49 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. AssetTile - + AssetTile Tile # - + Tile Nº 0 - + 0 Address - + Dirección 0x06000000 - + 0x06000000 Red - + Rojo Green - + Verde Blue - + Azul 0x00 (00) - + 0x00 (00) @@ -123,32 +124,32 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Cheats - + Trucos Remove - + Eliminar Save - + Guardar Load - + Cargar Add New Set - + Agregar nuevo conjunto Add - + Agregar @@ -156,17 +157,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Debugger - + Depurador Enter command (try `help` for more info) - + Ingresa un comando (prueba con 'help' para más información) Break - + Entrar en depuración @@ -174,37 +175,37 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Record GIF - + Grabar GIF Start - + Iniciar Stop - + Detener Select File - + Elegir archivo Frameskip - + Salto de cuadros Frame delay (ms) - + Retraso entre cuadros (ms) Automatic - + Automático @@ -212,92 +213,92 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. I/O Viewer - + Visor de E/S 0x0000 - + 0x0000 2 - + 2 5 - + 5 4 - + 4 7 - + 7 0 - + 0 9 - + 9 1 - + 1 3 - + 3 8 - + 8 C - + C E - + E 6 - + 6 D - + D F - + F A - + A B - + B @@ -305,7 +306,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Library - + Biblioteca @@ -314,7 +315,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. %1 State - + %1 captura de estado @@ -327,52 +328,52 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. No Save - + Sin captura 1 - + 1 2 - + 2 3 - + 3 4 - + 4 5 - + 5 6 - + 6 7 - + 7 8 - + 8 9 - + 9 @@ -380,57 +381,57 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Logs - + Registros Enabled Levels - + Niveles habilitados Debug - + Depuración Stub - + Auxiliar Info - + Información Warning - + Advertencia Error - + Error Fatal - + Fatal Game Error - + Error del juego Clear - + Limpiar Max Lines - + Máximo de líneas @@ -438,77 +439,77 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Memory - + Memoría Inspect Address: - + Inspeccionar dirección: 0x - + 0x Set Alignment: - + Alinear en: 1 Byte - + 1 byte 2 Bytes - + 2 bytes 4 Bytes - + 4 bytes Signed Integer: - + Entero con signo: String: - + Cadena: Load TBL - + Cargar TBL Copy Selection - + Copiar selección Paste - + Pegar Save Selection - + Guardar selección Load - + Cargar Unsigned Integer: - + Entero sin signo: @@ -516,38 +517,38 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Sprites - + Sprites × - + × Magnification - + Magnificación Attributes - + Atributos Transform - + Transformación Off - + No Palette - + Paleta @@ -555,12 +556,12 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 0 - + 0 Double Size - + Doble tamaño @@ -568,88 +569,88 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Return, Ctrl+R - + Volver, Ctrl+R Flipped - + Volteo H - + H V - + V Mode - + Modo Normal - + Normal Mosaic - + Mosaico Enabled - + Habilitado Priority - + Prioridad Tile - + Tile Geometry - + Geometría Position - + Posición , - + , Dimensions - + Dimensiones 8 - + 8 Address - + Dirección 0x07000000 - + 0x07000000 @@ -657,12 +658,12 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Game Overrides - + Valores específicos por juego Game Boy Advance - + Game Boy Advance @@ -670,143 +671,143 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Autodetect - + Detección automática Realtime clock - + Reloj de tiempo real Gyroscope - + Giroscopio Tilt - + Inclinación Light sensor - + Sensor de luz Rumble - + Vibración Save type - + Tipo de guardado None - + Ninguno SRAM - + SRAM Flash 512kb - + Flash 512kb Flash 1Mb - + Flash 1Mb EEPROM - + EEPROM Idle loop - + Bucle inactivo Game Boy Player features - + Habilitar Game Boy Player Game Boy - + Game Boy Game Boy model - + Modelo de Game Boy Game Boy (DMG) - + Game Boy (DMG) Game Boy Color (CGB) - + Game Boy Color (CGB) Game Boy Advance (AGB) - + Game Boy Advance (AGB) Memory bank controller - + Controlador de banco de memoria MBC1 - + MBC1 MBC2 - + MBC2 MBC3 - + MBC3 MBC3 + RTC - + MBC3 + Reloj MBC5 - + MBC5 MBC5 + Rumble - + MBC5 + Vibración MBC7 - + MBC7 HuC-3 - + HuC-3 @@ -814,84 +815,84 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Palette - + Paleta Background - + Fondo (BG) Objects - + Objetos (OBJ) Selection - + Selección Red - + Rojo Green - + Verde Blue - + Azul 0x00 (00) - + 0x00 (00) 16-bit value - + Valor en 16 bits Hex code - + Código hexadecimal Palette index - + Índice en paleta 0x0000 - + 0x0000 #000000 - + #000000 000 - + 000 Export BG - + Exportar BG Export OBJ - + Exportar OBJ @@ -899,14 +900,14 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. %0%1%2 - + %0%1%2 0x%0 (%1) - + 0x%0 (%1) @@ -914,21 +915,42 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. (untitled) - + (sin título) Failed to open cheats file: %1 - + Ocurrió un error al cargar el archivo de trucos: %1 QGBA::CheatsView + + + + Add GameShark + Agregar GameShark + + + + Add Pro Action Replay + Agregar Pro Action Replay + + + + Add CodeBreaker + Agregar CodeBreaker + + + + Add GameGenie + Agregar GameGenie + Select cheats file - + Elegir archivo de trucos @@ -936,22 +958,22 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Clear Button - + Limpiar botones Clear Analog - + Limpiar análogos Refresh - + Actualizar Set all - + Configurar todo @@ -959,42 +981,42 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Server settings - + Ajustes del servidor Local port - + Puerto local Bind address - + Dirección de enlace Break - + Entrar en depuración Stop - + Detener Start - + Iniciar Crash - + Error Could not start GDB server - + No se pudo iniciar el servidor GDB @@ -1002,17 +1024,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Failed to open output GIF file: %1 - + Error al abrir el archivo de salida GIF: %1 Select output file - + Elegir archivo de salida Graphics Interchange Format (*.gif) - + Formato de intercambio de gráficos (*.gif) @@ -1021,27 +1043,27 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Failed to open game file: %1 - + Error al abrir el archivo del juego: %1 Failed to open save file: %1 - + Error al abrir el archivo de guardado: %1 Failed to open snapshot file for reading: %1 - + Error al leer el archivo de captura: %1 Failed to open snapshot file for writing: %1 - + Error al escribir al archivo de captura: %1 Failed to start audio processor - + Error al iniciar el procesador de audio @@ -1049,142 +1071,142 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Background mode - + Modo de fondo (BG) Mode 0: 4 tile layers - + Modo 0: 4 capas de tiles Mode 1: 2 tile layers + 1 rotated/scaled tile layer - + Modo 1: 2 capas de tiles + 1 capa de tiles rotados/escalados Mode 2: 2 rotated/scaled tile layers - + Modo 2: 2 capas de tiles rotados/escalados Mode 3: Full 15-bit bitmap - + Modo 3: mapa de bits de 15 bits Mode 4: Full 8-bit bitmap - + Modo 4: mapa de bits de 8 bits Mode 5: Small 15-bit bitmap - + Modo 5: mapa de bits pequeño de 15 bits CGB Mode - + Modo CGB Frame select - + Selección de cuadros Unlocked HBlank - + HBlank sin bloqueo Linear OBJ tile mapping - + Asignación de tiles OBJ lineal Force blank screen - + Forzar pantalla en blanco Enable background 0 - + Habilitar fondo 0 Enable background 1 - + Habilitar fondo 1 Enable background 2 - + Habilitar fondo 2 Enable background 3 - + Habilitar fondo 3 Enable OBJ - + Habilitar OBJ Enable Window 0 - + Habilitar Window 0 Enable Window 1 - + Habilitar Window 1 Enable OBJ Window - + Habilitar Window OBJ Currently in VBlank - + En VBlank actualmente Currently in HBlank - + En HBlank actualmente Currently in VCounter - + En VCounter actualmente Enable VBlank IRQ generation - + Generar IRQ por cada VBlank Enable HBlank IRQ generation - + Generar IRQ por cada HBlank Enable VCounter IRQ generation - + Generar IRQ por cada VCounter VCounter scanline - + Línea de exploración VCounter Current scanline - + Línea de exploración actual @@ -1192,7 +1214,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Priority - + Prioridad @@ -1200,7 +1222,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Tile data base (* 16kB) - + Base de los tiles (* 16kB) @@ -1208,7 +1230,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Enable mosaic - + Mosaico (pixelar) @@ -1216,7 +1238,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Enable 256-color - + 256 colores @@ -1224,7 +1246,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Tile map base (* 2kB) - + Base de asignación de tiles (* 2kB) @@ -1232,13 +1254,13 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Background dimensions - + Dimensiones del fondo Overflow wraps - + Envolver al desbordar @@ -1246,7 +1268,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Horizontal offset - + Compensación horizontal @@ -1254,7 +1276,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Vertical offset - + Compensación vertical @@ -1270,7 +1292,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Fractional part - + Parte fraccionaria @@ -1282,7 +1304,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Integer part - + Parte entera @@ -1290,7 +1312,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Integer part (bottom) - + Parte entera (inferior) @@ -1298,286 +1320,286 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Integer part (top) - + Parte entera (superior) End x - + Fin x Start x - + Inicio x End y - + Fin y Start y - + Inicio y Window 0 enable BG 0 - + Window 0 BG 0 Window 0 enable BG 1 - + Window 0 BG 1 Window 0 enable BG 2 - + Window 0 BG 2 Window 0 enable BG 3 - + Window 0 BG 3 Window 0 enable OBJ - + Window 0 OBJ Window 0 enable blend - + Window 0 mezcla Window 1 enable BG 0 - + Window 1 BG 0 Window 1 enable BG 1 - + Window 1 BG 1 Window 1 enable BG 2 - + Window 1 BG 2 Window 1 enable BG 3 - + Window 1 BG 3 Window 1 enable OBJ - + Window 1 OBJ Window 1 enable blend - + Window 1 mezcla Outside window enable BG 0 - + Outside window BG 0 Outside window enable BG 1 - + Outside window BG 1 Outside window enable BG 2 - + Outside window BG 2 Outside window enable BG 3 - + Outside window BG 3 Outside window enable OBJ - + Outside window OBJ Outside window enable blend - + Outside window mezcla OBJ window enable BG 0 - + OBJ window BG 0 OBJ window enable BG 1 - + OBJ window BG 1 OBJ window enable BG 2 - + OBJ window BG 2 OBJ window enable BG 3 - + OBJ window BG 3 OBJ window enable OBJ - + OBJ window OBJ OBJ window enable blend - + OBJ window mezcla Background mosaic size vertical - + Tamaño mosaico fondo vertical Background mosaic size horizontal - + Tamaño mosaico fondo horizontal Object mosaic size vertical - + Tamaño mosaico objeto vertical Object mosaic size horizontal - + Tamaño mosaico objeto horizontal BG 0 target 1 - + BG 0 target 1 BG 1 target 1 - + BG 1 target 1 BG 2 target 1 - + BG 2 target 1 BG 3 target 1 - + BG 3 target 1 OBJ target 1 - + OBJ target 1 Backdrop target 1 - + Backdrop target 1 Blend mode - + Modo mezcla Disabled - + Desactivado Additive blending - + Mezcla aditiva Brighten - + Aclarar Darken - + Oscurecer BG 0 target 2 - + BG 0 target 2 BG 1 target 2 - + BG 1 target 2 BG 2 target 2 - + BG 2 target 2 BG 3 target 2 - + BG 3 target 2 OBJ target 2 - + OBJ target 2 Backdrop target 2 - + Backdrop target 2 Blend A (target 1) - + Mezcla A (target 1) Blend B (target 2) - + Mezcla B (target 2) Blend Y - + Mezcla Y Sweep shifts - + Cambio en barrido Sweep subtract - + Sustracción en barrido Sweep time (in 1/128s) - + Tiempo de barrido (en 1/128seg) @@ -1585,41 +1607,41 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Sound length - + Longitud del sonido Duty cycle - + Ciclo de trabajo Envelope step time - + Tiempo paso envolvente Envelope increase - + Aumento envolvente Initial volume - + Volumen inicial Sound frequency - + Frecuencia del sonido @@ -1627,7 +1649,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Timed - + Cronometrado @@ -1635,50 +1657,50 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Reset - + Reinicializar Double-size wave table - + Tabla de ondas de doble tamaño Active wave table - + Tabla de ondas activa Enable channel 3 - + Canal 3 activo Volume - + Volumen 0% - + 0% 100% - + 100% 50% - + 50% 25% - + 25% @@ -1686,118 +1708,118 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 75% - + 75% Clock divider - + Divisor de reloj Register stages - + Etapas de registros 15 - + 15 7 - + 7 Shifter frequency - + Frecuencia de cambio PSG volume right - + Volumen pulso derecha PSG volume left - + Volumen pulso izquierda Enable channel 1 right - + Canal 1 derecha Enable channel 2 right - + Canal 2 derecha Enable channel 3 right - + Canal 3 derecha Enable channel 4 right - + Canal 4 derecha Enable channel 1 left - + Canal 1 izquierda Enable channel 2 left - + Canal 2 izquierda Enable channel 3 left - + Canal 3 izquierda Enable channel 4 left - + Canal 4 izquierda PSG master volume - + Volumen maestro pulso Loud channel A - + Canal A fuerte Loud channel B - + Canal B fuerte Enable channel A right - + Canal A derecha Enable channel A left - + Canal A izquierda Channel A timer - + Temporizador canal A 0 - + 0 @@ -1810,67 +1832,67 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 1 - + 1 Channel A reset - + Reinic. canal A Enable channel B right - + Canal B derecha Enable channel B left - + Canal B izquierda Channel B timer - + Temporizador canal B Channel B reset - + Reinic. canal B Active channel 1 - + Canal 1 activo Active channel 2 - + Canal 2 activo Active channel 3 - + Canal 3 activo Active channel 4 - + Canal 4 activo Enable audio - + Habilitar audio Bias - + Polarización Resolution - + Resolución @@ -1914,7 +1936,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Sample - + Muestra @@ -1926,7 +1948,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Address (bottom) - + Dirección (inferior) @@ -1938,7 +1960,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Address (top) - + Dirección (superior) @@ -1946,7 +1968,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Word count - + Contador de word @@ -1954,7 +1976,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Destination offset - + Compensación de destino @@ -1966,7 +1988,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Increment - + Incremento @@ -1978,7 +2000,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Decrement - + Decremento @@ -1990,7 +2012,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Fixed - + Fijo @@ -1998,7 +2020,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Increment and reload - + Incremento y recarga @@ -2006,7 +2028,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Source offset - + Compensación de origen @@ -2014,7 +2036,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Repeat - + Repetir @@ -2022,7 +2044,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 32-bit - + 32 bits @@ -2030,7 +2052,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Start timing - + Inicio de temporizador @@ -2038,7 +2060,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Immediate - + Inmediato @@ -2048,7 +2070,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. VBlank - + VBlank @@ -2058,7 +2080,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. HBlank - + HBlank @@ -2071,7 +2093,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. IRQ - + IRQ @@ -2083,24 +2105,24 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Enable - + Habilitar Audio FIFO - + FIFO de audio Video Capture - + Captura de video DRQ - + DRQ @@ -2108,7 +2130,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Value - + Valor @@ -2116,7 +2138,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Scale - + Escala @@ -2124,7 +2146,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 1/64 - + 1/64 @@ -2132,7 +2154,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 1/256 - + 1/256 @@ -2140,176 +2162,176 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 1/1024 - + 1/1024 Cascade - + Cacada A - + A B - + B Select - + Select Start - + Start Right - + Derecha Left - + Izquierda Up - + Arriba Down - + Abajo R - + R L - + L Condition - + Condición SC - + SC SD - + SD SI - + SI SO - + SO VCounter - + VCounter Timer 0 - + Timer 0 Timer 1 - + Timer 1 Timer 2 - + Timer 2 Timer 3 - + Timer 3 SIO - + SIO DMA 0 - + DMA 0 DMA 1 - + DMA 1 DMA 2 - + DMA 2 DMA 3 - + DMA 3 Keypad - + Teclera Gamepak - + Gamepak SRAM wait - + Espera SRAM @@ -2318,7 +2340,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 4 - + 4 @@ -2326,7 +2348,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 3 - + 3 @@ -2335,7 +2357,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 2 - + 2 @@ -2344,72 +2366,72 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 8 - + 8 Cart 0 non-sequential - + Cart 0 no secuencial Cart 0 sequential - + Cart 0 secuencial Cart 1 non-sequential - + Cart 1 no secuencial Cart 1 sequential - + Cart 1 secuencial Cart 2 non-sequential - + Cart 2 no secuencial Cart 2 sequential - + Cart 2 secuencial PHI terminal - + PHI terminal Disable - + Desactivar 4.19MHz - + 4.19MHz 8.38MHz - + 8.38MHz 16.78MHz - + 16.78MHz Gamepak prefetch - + Gamepak prefetch Enable IRQs - + Habilitar IRQs @@ -2418,7 +2440,7 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. --- - + --- @@ -2426,47 +2448,47 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Name - + Nombre Filename - + Nombre de archivo Size - + Tamaño Platform - + Plataforma GBA - + GBA GB - + GB ? - + ? Location - + Ubicación CRC32 - + CRC32 @@ -2474,27 +2496,27 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Load State - + Cargar captura Save State - + Guardar captura Empty - + Vacío Corrupted - + Corrompido Slot %1 - + Espacio %1 @@ -2502,37 +2524,37 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. DEBUG - + DEPURACIÓN STUB - + AUXILIAR INFO - + INFORMACIÓN WARN - + ADVERTENCIA ERROR - + ERROR FATAL - + FATAL GAME ERROR - + ERROR DEL JUEGO @@ -2540,63 +2562,63 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Copy selection - + Copiar selección Save selection - + Guardar selección Paste - + Pegar Load - + Cargar All - + Todo Load TBL - + Cargar TBL Save selected memory - + Guardar memoria seleccionada Failed to open output file: %1 - + Error al abrir el archivo de salida: %1 Load memory - + Cargar memoria Failed to open input file: %1 - + Error al abrir el archivo de entrada: %1 TBL - + TBL ISO-8859-1 - + ISO-8859-1 @@ -2605,38 +2627,38 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. 0x%0 - + 0x%0 Off - + No Normal - + Normal Trans - + Trans OBJWIN - + OBJWIN Invalid - + Inválido N/A - + n/d @@ -2644,39 +2666,39 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. #%0 - + #%0 0x%0 - + 0x%0 %0 - + %0 0x%0 (%1) - + 0x%0 (%1) Export palette - + Exportar paleta Windows PAL (*.pal);;Adobe Color Table (*.act) - + Paleta de WIndows (*.pal);;Tabla de colores Adobe (*.act) Failed to open output palette file: %1 - + Error al abrir el archivo de salida de paleta: %1 @@ -2688,18 +2710,18 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. (unknown) - + (desconocido) bytes - + bytes (no database present) - + (no se encuentra la base de datos) @@ -2707,32 +2729,47 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Qt Multimedia - + Qt Multimedia SDL - + SDL Software (Qt) - + Software (Qt) OpenGL - + OpenGL OpenGL (force version 1.x) - + OpenGL (forzar versión 1.x) + + + + Keyboard + Teclado + + + + Controllers + Mandos + + + + Shortcuts + Accesos directos Select BIOS - + Elegir BIOS @@ -2740,37 +2777,37 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. No shader active - + No hay programa shader activo Load shader - + Cargar programa shader %1 Shader (%.shader) - + Programa shader de %1 (%.shader) No shader loaded - + No hay programa shader cargado by %1 - + por %1 Preprocessing - + preprocesamiento Pass %1 - + Paso %1 @@ -2778,17 +2815,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Action - + Acción Keyboard - + Teclado Gamepad - + Mando @@ -2796,17 +2833,17 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Failed to open output video file: %1 - + Error al abrir el archivo de salida de video: %1 Native (%0x%1) - + Nativo (%0x%1) Select output file - + Elegir archivo de salida @@ -2814,700 +2851,706 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Game Boy Advance ROMs (%1) - + ROMs de Game Boy Advance (%1) Game Boy ROMs (%1) - + ROMs de Game Boy (%1) All ROMs (%1) - + Todas las ROMs (%1) Archives (%1) - + Archivos (%1) Select ROM - + Elegir ROM Game Boy Advance save files (%1) - + Archivos de guardado de Game Boy Advance (%1) Select save - + Elegir guardado Select patch - + Elegir parche Patches (*.ips *.ups *.bps) - + Parches (*.ips *.ups *.bps) GameShark saves (*.sps *.xps) - + Guardados de GameShark (*.sps *.xps) Crash - + Error fatal The game has crashed with the following error: %1 - + El juego dejó de funcionar inesperadamente debido a este error: + +%1 Couldn't Load - + No se pudo cargar Could not load game. Are you sure it's in the correct format? - + No se pudo cargar el juego. ¿Estás seguro de que está en el formato correcto? Unimplemented BIOS call - + Llamada a BIOS no implementada This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. - + Este juego hizo una llamada al BIOS que no está implementada. Usa el BIOS oficial para obtener la mejor experiencia. Really make portable? - + ¿Realmente hacer "portable"? This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? - + Esto hará que el emulador cargue su configuración desde el mismo directorio que su ejecutable. ¿Quieres continuar? Restart needed - + Reinicio necesario Some changes will not take effect until the emulator is restarted. - + Algunos cambios no tendrán efecto hasta que se reinicie el emulador. - Player %1 of %2 - + - Jugador %1 de %2 %1 - %2 - + %1 - %2 %1 - %2 - %3 - + %1 - %2 - %3 %1 - %2 (%3 fps) - %4 - + %1 - %2 (%3 fps) - %4 &File - + &Archivo Load &ROM... - + Cargar &ROM... Load ROM in archive... - + Cargar ROM dentro de archivo... Load temporary save... - + Cargar guardado temporal... Load &patch... - + Cargar &parche... Boot BIOS - + Iniciar al BIOS Replace ROM... - + Reemplazar ROM... ROM &info... - + &Información de ROM... Recent - + Reciente Make portable - + Hacer "portable" &Load state - + Cargar captura de estado (&L) F10 - + F10 &Save state - + Guardar captura de e&stado Shift+F10 - + DO NOT TRANSLATE + Shift+F10 Quick load - + Cargado rápido Quick save - + Guardado rápido Load recent - + Cargar reciente Save recent - + Guardar reciente Undo load state - + Deshacer cargar la captura de estado F11 - + DO NOT TRANSLATE + F11 Undo save state - + Deshacer guardar la captura de estado Shift+F11 - + DO NOT TRANSLATE + Shift+F11 State &%1 - + Captura de estado &%1 F%1 - + F%1 Shift+F%1 - + DO NOT TRANSLATE + Shift+F%1 Import GameShark Save - + Importar guardado de GameShark Export GameShark Save - + Exportar guardado de GameShark New multiplayer window - + Nueva ventana multijugador About - + Acerca de E&xit - + Salir (&X) &Emulation - + &Emulación &Reset - + &Reinicializar Ctrl+R - + Ctrl+R Sh&utdown - + Apagar (&U) Yank game pak - + Arrancar el game pak de su ranura &Pause - + &Pausar Ctrl+P - + Ctrl+P &Next frame - + Saltar al próximo cuadro (&N) Ctrl+N - + Ctrl+N Fast forward (held) - + Avance rápido (mantener) &Fast forward - + Avance rápido (&F) Shift+Tab - + Shift+Tab Fast forward speed - + Velocidad de avance rápido Unbounded - + Ilimitado %0x - + %0x Rewind (held) - + Retroceder (mantener) Re&wind - + Retroceder (&W) ~ - + ~ Step backwards - + Paso hacia atrás Ctrl+B - + Ctrl+B Sync to &video - + Sincronizar a &video Sync to &audio - + Sincronizar a &audio Solar sensor - + Sensor solar Increase solar level - + Aumentar nivel solar Decrease solar level - + Disminuir nivel solar Brightest solar level - + Nivel solar más brillante Darkest solar level - + Nivel solar más oscuro Brightness %1 - + Brillo %1 Audio/&Video - + Audio/&Video Frame size - + Tamaño del cuadro %1x - + %1x Toggle fullscreen - + Pantalla completa Lock aspect ratio - + Bloquear relación de aspecto Resample video - + Remuestrear video Frame&skip - + &Salto de cuadros Shader options... - + Opciones del programa shader... Mute - + Silenciar FPS target - + Objetivo de FPS 15 - + 15 30 - + 30 45 - + 45 Native (59.7) - + Nativo (59.7) 60 - + 60 90 - + 90 120 - + 120 240 - + 240 Take &screenshot - + Tomar pantallazo (&S) F12 - + F12 Record output... - + Grabar salida... Record GIF... - + Grabar GIF... Video layers - + Capas de video Background %0 - + Fondo %0 OBJ (sprites) - + OBJ (sprites) Audio channels - + Canales de audio Channel %0 - + Canal %0 Channel A - + Canal A Channel B - + Canal B &Tools - + Herramien&tas View &logs... - + Ver registros... (&L) Game &overrides... - + Val&ores específicos por juego... Game &Pak sensors... - + Sensores en el Game &Pak... &Cheats... - + Tru&cos... Open debugger console... - + Abrir la consola de depuración... Start &GDB server... - + Iniciar servidor &GDB... Settings... - + Ajustes... Select folder - + Elegir carpeta Add folder to library... - + Agregar carpeta a la biblioteca... View &palette... - + Ver &paleta... View &sprites... - + Ver &sprites... View &tiles... - + Ver &tiles... View memory... - + Ver memoria... View &I/O registers... - + Ver reg&istros E/S... Exit fullscreen - + Salir de pantalla completa Autofire - + Botones turbo Autofire A - + Turbo A Autofire B - + Turbo B Autofire L - + Turbo L Autofire R - + Turbo R Autofire Start - + Turbo Start Autofire Select - + Turbo Select Autofire Up - + Turbo Arriba Autofire Right - + Turbo Derecha Autofire Down - + Turbo Abajo Autofire Left - + Turbo Izquierda @@ -3515,57 +3558,57 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. ROM Info - + Información de la ROM Game name: - + Nombre del juego: {NAME} - + {NAME} Internal name: - + Nombre interno: {TITLE} - + {TITLE} Game ID: - + ID del juego: {ID} - + {ID} File size: - + Tamaño del archivo: {SIZE} - + {SIZE} CRC32: - + CRC32: {CRC} - + {CRC} @@ -3573,74 +3616,74 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Sensors - + Sensores Realtime clock - + Reloj en tiempo real Fixed time - + Hora fija System time - + Hora del sistema Start time at - + Contar desde el Now - + Ahora MM/dd/yy hh:mm:ss AP - + dd/MM/yy HH:mm:ss Light sensor - + Sensor de luz Brightness - + Brillo Tilt sensor - + Sensor de inclinación Set Y - + Config. Y Set X - + Config. X Gyroscope - + Giroscopio Sensitivity - + Sensibilidad @@ -3648,195 +3691,195 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Settings - + Ajustes Audio/Video - + Audio/Video Interface - + Interfaz Emulation - + Emulación Paths - + Rutas Audio driver: - + Controlador de audio: Audio buffer: - + Búfer de audio: 1536 - + 1536 512 - + 512 768 - + 768 1024 - + 1024 2048 - + 2048 3072 - + 3072 4096 - + 4096 samples - + muestras Sample rate: - + Tasa de muestreo: 44100 - + 44100 22050 - + 22050 32000 - + 32000 48000 - + 48000 Hz - + Hz Volume: - + Volumen: Mute - + Silenciar Display driver: - + Controlador de video: Frameskip: - + Salto de cuadros: Skip every - + Saltar cada frames - + cuadros FPS target: - + Objetivo de FPS: frames per second - + cuadros por segundo Sync: - + SIncronizar a: Video - + Video Audio - + Audio Lock aspect ratio - + Bloquear relación de aspecto Resample video - + Remuestrar video Library: - + Biblioteca: Show when no game open - + Mostrar al no haber juego abierto Clear cache - + Limpiar caché Fast forward speed: - + Velocidad de avance rápido: @@ -3847,125 +3890,125 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Browse - + Examinar Use BIOS file if found - + Usar archivo BIOS si hay Skip BIOS intro - + Saltar pantalla de inicio de la BIOS × - + × Unbounded - + Ilimitado Suspend screensaver - + No permitir protector de pantalla BIOS - + BIOS Pause when inactive - + Pausar al estar inactivo Run all - + Ejecutar todos Remove known - + Eliminar los conocidos Detect and remove - + Detectar y eliminar Allow opposing input directions - + Permitir direcciones opuestas Screenshot - + Pantallazo Save data - + Datos de guardado Cheat codes - + Trucos Enable rewind - + Habilitar retroceso Rewind history: - + Historial de retroceso: Idle loops: - + Bucles inactivos: Savestate extra data: - + Datos extras en capturas de estado: Load extra data: - + Cargar datos extra: GB BIOS file: - + Archivo de BIOS GB: GBA BIOS file: - + Archivo de BIOS GBA: GBC BIOS file: - + Archivo de BIOS GBC: Save games - + Guardados de juego @@ -3973,22 +4016,22 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Same directory as the ROM - + Mismo directorio de la ROM Save states - + Capturas de estado Screenshots - + Pantallazos Patches - + Parches @@ -3996,37 +4039,37 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Shaders - + Programas shader Active Shader: - + Programa shader activo: Name - + Nombre Author - + Autor Description - + Descripción Unload Shader - + Cerrar programa shader Load New Shader - + Cargar nuevo p. shader @@ -4034,22 +4077,22 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Edit Shortcuts - + Editar accesos directos de teclado Keyboard - + Teclado Gamepad - + Mando Clear - + Limpiar @@ -4057,22 +4100,22 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Tiles - + Tiles 256 colors - + 256 colores × - + × Magnification - + Magnificación @@ -4080,183 +4123,183 @@ Game Boy Advance is a registered trademark of Nintendo Co., Ltd. Record Video - + Grabar video Start - + Iniciar Stop - + Detener Select File - + Elegir archivo Presets - + Ajustes predeterminados High Quality - + Alta calidad YouTube - + YouTube WebM - + WebM Lossless - + Sin pérdidas 1080p - + 1080p 720p - + 720p 480p - + 480p Native - + Nativo Format - + Formato MKV - + MKV AVI - + AVI MP4 - + MP4 PNG - + PNG h.264 - + h.264 VP8 - + Xvid - + Xvid FFV1 - + FFV1 FLAC - + FLAC Opus - + Opus Vorbis - + Vorbis MP3 - + MP3 AAC - + AAC Uncompressed - + Sin comprimir Bitrate (kbps) - + Tasa de bits (kbps) VBR - + VBR ABR - + ABR Dimensions - + Dimensiones : - + : × - + × Lock aspect ratio - + Bloquear relación de aspecto Show advanced - + Mostrar ajustes avanzados From 181c05c7ac8a739cd6d9dea393ac9a30e1898d96 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 1 Feb 2017 09:35:53 -0800 Subject: [PATCH 03/43] GBA Hardware: Fix GBP event scheduling --- src/gba/hardware.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gba/hardware.c b/src/gba/hardware.c index 5c9032de4..2027b949d 100644 --- a/src/gba/hardware.c +++ b/src/gba/hardware.c @@ -554,6 +554,7 @@ uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uin gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22); } } + mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent); mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048); } value &= 0x78FB; From af77e5ab62a920000b8e33544ba2f2efa0cb42e9 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 1 Feb 2017 13:21:26 -0800 Subject: [PATCH 04/43] Util: Fix overflow when loading invalid UPS patches --- CHANGES | 1 + src/util/patch-ups.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 50aeba077..d1bb8c2d0 100644 --- a/CHANGES +++ b/CHANGES @@ -21,6 +21,7 @@ Bugfixes: - GB MBC: Fix ROM bank overflows getting set to bank 0 - 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 Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/src/util/patch-ups.c b/src/util/patch-ups.c index d58ee2216..5f24311ef 100644 --- a/src/util/patch-ups.c +++ b/src/util/patch-ups.c @@ -87,6 +87,9 @@ bool _UPSApplyPatch(struct Patch* patch, const void* in, size_t inSize, void* ou if (patch->vf->read(patch->vf, &byte, 1) != 1) { return false; } + if (offset >= outSize) { + return false; + } buf[offset] ^= byte; ++offset; if (!byte) { From 28a3ac50a6a6592594ca4336c4632cffbf75e004 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 1 Feb 2017 13:38:11 -0800 Subject: [PATCH 05/43] GBA, GB: ROM is now unloaded if a patch is applied --- include/mgba/internal/gb/gb.h | 2 +- include/mgba/internal/gb/mbc.h | 2 +- include/mgba/internal/gba/gba.h | 2 +- src/gb/gb.c | 52 ++++++++++++++++++--------------- src/gb/mbc.c | 33 +++++++++++---------- src/gb/memory.c | 17 ++++++----- src/gba/core.c | 2 +- src/gba/gba.c | 52 +++++++++++++++++++-------------- src/gba/memory.c | 30 ++++++++++++------- 9 files changed, 108 insertions(+), 84 deletions(-) diff --git a/include/mgba/internal/gb/gb.h b/include/mgba/internal/gb/gb.h index d047f1c2c..db3adf6cc 100644 --- a/include/mgba/internal/gb/gb.h +++ b/include/mgba/internal/gb/gb.h @@ -63,7 +63,7 @@ struct GB { uint8_t* keySource; - void* pristineRom; + bool isPristine; size_t pristineRomSize; size_t yankedRomSize; uint32_t romCrc32; diff --git a/include/mgba/internal/gb/mbc.h b/include/mgba/internal/gb/mbc.h index 32496177f..6242343e8 100644 --- a/include/mgba/internal/gb/mbc.h +++ b/include/mgba/internal/gb/mbc.h @@ -17,7 +17,7 @@ mLOG_DECLARE_CATEGORY(GB_MBC); struct GB; struct GBMemory; void GBMBCInit(struct GB* gb); -void GBMBCSwitchBank(struct GBMemory* memory, int bank); +void GBMBCSwitchBank(struct GB* gb, int bank); void GBMBCSwitchSramBank(struct GB* gb, int bank); struct GBMBCRTCSaveBuffer { diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index 73171095b..e27f6cbc0 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -90,7 +90,7 @@ struct GBA { struct mRumble* rumble; struct GBARRContext* rr; - void* pristineRom; + bool isPristine; size_t pristineRomSize; size_t yankedRomSize; uint32_t romCrc32; diff --git a/src/gb/gb.c b/src/gb/gb.c index e53a7e579..aee05205c 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -79,7 +79,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) { gb->sramVf = NULL; gb->sramRealVf = NULL; - gb->pristineRom = 0; + gb->isPristine = false; gb->pristineRomSize = 0; gb->yankedRomSize = 0; @@ -108,24 +108,23 @@ bool GBLoadROM(struct GB* gb, struct VFile* vf) { gb->romVf = vf; gb->pristineRomSize = vf->size(vf); vf->seek(vf, 0, SEEK_SET); + gb->isPristine = true; #ifdef _3DS - gb->pristineRom = 0; if (gb->pristineRomSize <= romBufferSize) { - gb->pristineRom = romBuffer; + gb->memory.rom = romBuffer; vf->read(vf, romBuffer, gb->pristineRomSize); } #else - gb->pristineRom = vf->map(vf, gb->pristineRomSize, MAP_READ); + gb->memory.rom = vf->map(vf, gb->pristineRomSize, MAP_READ); #endif - if (!gb->pristineRom) { + if (!gb->memory.rom) { return false; } gb->yankedRomSize = 0; - gb->memory.rom = gb->pristineRom; gb->memory.romBase = gb->memory.rom; gb->memory.romSize = gb->pristineRomSize; gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); - GBMBCSwitchBank(&gb->memory, gb->memory.currentBank); + GBMBCSwitchBank(gb, gb->memory.currentBank); if (gb->cpu) { struct LR35902Core* cpu = gb->cpu; @@ -263,26 +262,25 @@ void GBSavedataUnmask(struct GB* gb) { void GBUnloadROM(struct GB* gb) { // TODO: Share with GBAUnloadROM - if (gb->memory.rom && gb->memory.romBase != gb->memory.rom && gb->memory.romBase != gb->pristineRom) { + if (gb->memory.rom && gb->memory.romBase != gb->memory.rom && !gb->isPristine) { free(gb->memory.romBase); } - if (gb->memory.rom && gb->pristineRom != gb->memory.rom) { + if (gb->memory.rom && !gb->isPristine) { if (gb->yankedRomSize) { gb->yankedRomSize = 0; } mappedMemoryFree(gb->memory.rom, GB_SIZE_CART_MAX); - gb->memory.rom = gb->pristineRom; } - gb->memory.rom = 0; if (gb->romVf) { #ifndef _3DS - gb->romVf->unmap(gb->romVf, gb->pristineRom, gb->pristineRomSize); + gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); #endif gb->romVf->close(gb->romVf); - gb->romVf = 0; + gb->romVf = NULL; } - gb->pristineRom = 0; + gb->memory.rom = NULL; + gb->isPristine = false; GBSavedataUnmask(gb); GBSramDeinit(gb); @@ -317,14 +315,26 @@ void GBApplyPatch(struct GB* gb, struct Patch* patch) { if (patchedSize > GB_SIZE_CART_MAX) { patchedSize = GB_SIZE_CART_MAX; } - gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); - if (!patch->applyPatch(patch, gb->pristineRom, gb->pristineRomSize, gb->memory.rom, patchedSize)) { - mappedMemoryFree(gb->memory.rom, patchedSize); - gb->memory.rom = gb->pristineRom; + void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX); + if (!patch->applyPatch(patch, gb->memory.rom, gb->pristineRomSize, newRom, patchedSize)) { + mappedMemoryFree(newRom, GB_SIZE_CART_MAX); return; } + if (gb->romVf) { +#ifndef _3DS + gb->romVf->unmap(gb->romVf, gb->memory.rom, gb->pristineRomSize); +#endif + gb->romVf->close(gb->romVf); + gb->romVf = NULL; + } + gb->isPristine = false; + if (gb->memory.romBase == gb->memory.rom) { + gb->memory.romBase = newRom; + } + gb->memory.rom = newRom; gb->memory.romSize = patchedSize; gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); + gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); } void GBDestroy(struct GB* gb) { @@ -652,9 +662,6 @@ void GBGetGameTitle(const struct GB* gb, char* out) { if (gb->memory.rom) { cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; } - if (gb->pristineRom) { - cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100]; - } if (!cart) { return; } @@ -671,9 +678,6 @@ void GBGetGameCode(const struct GB* gb, char* out) { if (gb->memory.rom) { cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; } - if (gb->pristineRom) { - cart = (const struct GBCartridge*) &((uint8_t*) gb->pristineRom)[0x100]; - } if (!cart) { return; } diff --git a/src/gb/mbc.c b/src/gb/mbc.c index 9e8072dc8..7ef41695e 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -28,18 +29,21 @@ static void _GBMBC6(struct GB*, uint16_t address, uint8_t value); static void _GBMBC7(struct GB*, uint16_t address, uint8_t value); static void _GBHuC3(struct GB*, uint16_t address, uint8_t value); -void GBMBCSwitchBank(struct GBMemory* memory, int bank) { +void GBMBCSwitchBank(struct GB* gb, int bank) { size_t bankStart = bank * GB_SIZE_CART_BANK0; - if (bankStart + GB_SIZE_CART_BANK0 > memory->romSize) { + if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) { mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); - bankStart &= (memory->romSize - 1); + bankStart &= (gb->memory.romSize - 1); bank = bankStart / GB_SIZE_CART_BANK0; if (!bank) { ++bank; } } - memory->romBank = &memory->rom[bankStart]; - memory->currentBank = bank; + gb->memory.romBank = &gb->memory.rom[bankStart]; + gb->memory.currentBank = bank; + if (gb->cpu->pc < GB_BASE_VRAM) { + gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); + } } void GBMBCSwitchSramBank(struct GB* gb, int bank) { @@ -249,12 +253,12 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) { if (!bank) { ++bank; } - GBMBCSwitchBank(memory, bank | (memory->currentBank & 0x60)); + GBMBCSwitchBank(gb, bank | (memory->currentBank & 0x60)); break; case 0x2: bank &= 3; if (!memory->mbcState.mbc1.mode) { - GBMBCSwitchBank(memory, (bank << 5) | (memory->currentBank & 0x1F)); + GBMBCSwitchBank(gb, (bank << 5) | (memory->currentBank & 0x1F)); } else { GBMBCSwitchSramBank(gb, bank); } @@ -262,7 +266,7 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) { case 0x3: memory->mbcState.mbc1.mode = value & 1; if (memory->mbcState.mbc1.mode) { - GBMBCSwitchBank(memory, memory->currentBank & 0x1F); + GBMBCSwitchBank(gb, memory->currentBank & 0x1F); } else { GBMBCSwitchSramBank(gb, 0); } @@ -297,7 +301,7 @@ void _GBMBC2(struct GB* gb, uint16_t address, uint8_t value) { if (!bank) { ++bank; } - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; default: // TODO @@ -328,7 +332,7 @@ void _GBMBC3(struct GB* gb, uint16_t address, uint8_t value) { if (!bank) { ++bank; } - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x2: if (value < 4) { @@ -372,11 +376,11 @@ void _GBMBC5(struct GB* gb, uint16_t address, uint8_t value) { break; case 0x2: bank = (memory->currentBank & 0x100) | value; - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x3: bank = (memory->currentBank & 0xFF) | ((value & 1) << 8); - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x4: case 0x5: @@ -402,11 +406,10 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) { } void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) { - struct GBMemory* memory = &gb->memory; int bank = value & 0x7F; switch (address >> 13) { case 0x1: - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x2: if (value < 0x10) { @@ -616,7 +619,7 @@ void _GBHuC3(struct GB* gb, uint16_t address, uint8_t value) { } break; case 0x1: - GBMBCSwitchBank(memory, bank); + GBMBCSwitchBank(gb, bank); break; case 0x2: GBMBCSwitchSramBank(gb, bank); diff --git a/src/gb/memory.c b/src/gb/memory.c index 6e7eb2a33..94e665712 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -614,7 +614,7 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) { memory->wramCurrentBank = state->memory.wramCurrentBank; memory->sramCurrentBank = state->memory.sramCurrentBank; - GBMBCSwitchBank(memory, memory->currentBank); + GBMBCSwitchBank(gb, memory->currentBank); GBMemorySwitchWramBank(memory, memory->wramCurrentBank); GBMBCSwitchSramBank(gb, memory->sramCurrentBank); @@ -651,14 +651,15 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) { } void _pristineCow(struct GB* gb) { - if (gb->memory.rom != gb->pristineRom) { + if (!gb->isPristine) { return; } - gb->memory.rom = anonymousMemoryMap(GB_SIZE_CART_MAX); - memcpy(gb->memory.rom, gb->pristineRom, gb->memory.romSize); - memset(((uint8_t*) gb->memory.rom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize); - if (gb->pristineRom == gb->memory.romBase) { - gb->memory.romBase = gb->memory.rom; + void* newRom = anonymousMemoryMap(GB_SIZE_CART_MAX); + memcpy(newRom, gb->memory.rom, gb->memory.romSize); + memset(((uint8_t*) newRom) + gb->memory.romSize, 0xFF, GB_SIZE_CART_MAX - gb->memory.romSize); + if (gb->memory.rom == gb->memory.romBase) { + gb->memory.romBase = newRom; } - GBMBCSwitchBank(&gb->memory, gb->memory.currentBank); + gb->memory.rom = newRom; + GBMBCSwitchBank(gb, gb->memory.currentBank); } diff --git a/src/gba/core.c b/src/gba/core.c index 41f038427..1c6002fbe 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -323,7 +323,7 @@ static void _GBACoreReset(struct mCore* core) { #endif ARMReset(core->cpu); - if (core->opts.skipBios && gba->pristineRom) { + if (core->opts.skipBios && gba->isPristine) { GBASkipBIOS(core->board); } } diff --git a/src/gba/gba.c b/src/gba/gba.c index 0a62183f8..22dafd89a 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -104,7 +104,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->performingDMA = false; - gba->pristineRom = 0; + gba->isPristine = false; gba->pristineRomSize = 0; gba->yankedRomSize = 0; @@ -112,22 +112,22 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { } void GBAUnloadROM(struct GBA* gba) { - if (gba->memory.rom && gba->pristineRom != gba->memory.rom) { + if (gba->memory.rom && !gba->isPristine) { if (gba->yankedRomSize) { gba->yankedRomSize = 0; } mappedMemoryFree(gba->memory.rom, SIZE_CART0); } - gba->memory.rom = 0; if (gba->romVf) { #ifndef _3DS - gba->romVf->unmap(gba->romVf, gba->pristineRom, gba->pristineRomSize); + gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize); #endif gba->romVf->close(gba->romVf); - gba->romVf = 0; + gba->romVf = NULL; } - gba->pristineRom = 0; + gba->memory.rom = NULL; + gba->isPristine = false; GBASavedataDeinit(&gba->memory.savedata); if (gba->memory.savedata.realVf) { @@ -291,23 +291,23 @@ bool GBALoadMB(struct GBA* gba, struct VFile* vf) { if (gba->pristineRomSize > SIZE_WORKING_RAM) { gba->pristineRomSize = SIZE_WORKING_RAM; } + gba->isPristine = true; #ifdef _3DS - gba->pristineRom = 0; if (gba->pristineRomSize <= romBufferSize) { - gba->pristineRom = romBuffer; + gba->memory.wram = romBuffer; vf->read(vf, romBuffer, gba->pristineRomSize); } #else - gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); + gba->memory.wram = vf->map(vf, gba->pristineRomSize, MAP_READ); #endif - if (!gba->pristineRom) { + if (!gba->memory.wram) { mLOG(GBA, WARN, "Couldn't map ROM"); return false; } gba->yankedRomSize = 0; gba->memory.romSize = 0; gba->memory.romMask = 0; - gba->romCrc32 = doCrc32(gba->pristineRom, gba->pristineRomSize); + gba->romCrc32 = doCrc32(gba->memory.wram, gba->pristineRomSize); return true; } @@ -322,21 +322,20 @@ bool GBALoadROM(struct GBA* gba, struct VFile* vf) { if (gba->pristineRomSize > SIZE_CART0) { gba->pristineRomSize = SIZE_CART0; } + gba->isPristine = true; #ifdef _3DS - gba->pristineRom = 0; if (gba->pristineRomSize <= romBufferSize) { - gba->pristineRom = romBuffer; + gba->memory.rom = romBuffer; vf->read(vf, romBuffer, gba->pristineRomSize); } #else - gba->pristineRom = vf->map(vf, gba->pristineRomSize, MAP_READ); + gba->memory.rom = vf->map(vf, gba->pristineRomSize, MAP_READ); #endif - if (!gba->pristineRom) { + if (!gba->memory.rom) { mLOG(GBA, WARN, "Couldn't map ROM"); return false; } gba->yankedRomSize = 0; - gba->memory.rom = gba->pristineRom; gba->memory.romSize = gba->pristineRomSize; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; gba->memory.mirroring = false; @@ -389,12 +388,21 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) { if (!patchedSize || patchedSize > SIZE_CART0) { return; } - gba->memory.rom = anonymousMemoryMap(SIZE_CART0); - if (!patch->applyPatch(patch, gba->pristineRom, gba->pristineRomSize, gba->memory.rom, patchedSize)) { - mappedMemoryFree(gba->memory.rom, patchedSize); - gba->memory.rom = gba->pristineRom; + void* newRom = anonymousMemoryMap(SIZE_CART0); + if (!patch->applyPatch(patch, gba->memory.rom, gba->pristineRomSize, newRom, patchedSize)) { + mappedMemoryFree(newRom, SIZE_CART0); return; } + if (gba->romVf) { +#ifndef _3DS + gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->pristineRomSize); +#endif + gba->romVf->close(gba->romVf); + gba->romVf = NULL; + } + gba->isPristine = false; + gba->memory.rom = newRom; + gba->memory.hw.gpioBase = &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]; gba->memory.romSize = patchedSize; gba->memory.romMask = SIZE_CART0 - 1; gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); @@ -540,8 +548,8 @@ void GBAGetGameTitle(const struct GBA* gba, char* out) { memcpy(out, &((struct GBACartridge*) gba->memory.rom)->title, 12); return; } - if (gba->pristineRom) { - memcpy(out, &((struct GBACartridge*) gba->pristineRom)->title, 12); + if (gba->isPristine && gba->memory.wram) { + memcpy(out, &((struct GBACartridge*) gba->memory.wram)->title, 12); return; } strncpy(out, "(BIOS)", 12); diff --git a/src/gba/memory.c b/src/gba/memory.c index 674ba5a7d..0e425cd3e 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -102,13 +102,12 @@ void GBAMemoryDeinit(struct GBA* gba) { } void GBAMemoryReset(struct GBA* gba) { - if (gba->memory.wram) { - mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM); - } - gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM); - if (gba->pristineRom && !gba->memory.rom) { - // Multiboot - memcpy(gba->memory.wram, gba->pristineRom, gba->pristineRomSize); + if (gba->memory.rom || gb->fullBios) { + // Not multiboot + if (gba->memory.wram) { + mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM); + } + gba->memory.wram = anonymousMemoryMap(SIZE_WORKING_RAM); } if (gba->memory.iwram) { @@ -1541,10 +1540,19 @@ void GBAMemoryDeserialize(struct GBAMemory* memory, const struct GBASerializedSt } void _pristineCow(struct GBA* gba) { - if (gba->memory.rom != gba->pristineRom) { + if (!gba->isPristine) { return; } - gba->memory.rom = anonymousMemoryMap(SIZE_CART0); - memcpy(gba->memory.rom, gba->pristineRom, gba->memory.romSize); - memset(((uint8_t*) gba->memory.rom) + gba->memory.romSize, 0xFF, SIZE_CART0 - gba->memory.romSize); + void* newRom = anonymousMemoryMap(SIZE_CART0); + memcpy(newRom, gba->memory.rom, gba->memory.romSize); + memset(((uint8_t*) newRom) + gba->memory.romSize, 0xFF, SIZE_CART0 - gba->memory.romSize); + if (gba->romVf) { +#ifndef _3DS + gba->romVf->unmap(gba->romVf, gba->memory.rom, gba->memory.romSize); +#endif + gba->romVf->close(gba->romVf); + gba->romVf = NULL; + } + gba->memory.rom = newRom; + gba->memory.hw.gpioBase = &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]; } From 658013091407d401728b9a0fa1a24f2256be02a2 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 1 Feb 2017 14:06:27 -0800 Subject: [PATCH 06/43] All: Update CHANGES --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index d1bb8c2d0..81cc7d899 100644 --- a/CHANGES +++ b/CHANGES @@ -59,6 +59,7 @@ Misc: - 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 0.5.2: (2016-12-31) Bugfixes: From 1ab6d36fa29c522d50eac3d9515568e99138c4f7 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 1 Feb 2017 14:07:13 -0800 Subject: [PATCH 07/43] GBA Memory: Fix build --- src/gba/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gba/memory.c b/src/gba/memory.c index 0e425cd3e..eb4316569 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -102,7 +102,7 @@ void GBAMemoryDeinit(struct GBA* gba) { } void GBAMemoryReset(struct GBA* gba) { - if (gba->memory.rom || gb->fullBios) { + if (gba->memory.rom || gba->memory.fullBios) { // Not multiboot if (gba->memory.wram) { mappedMemoryFree(gba->memory.wram, SIZE_WORKING_RAM); From bb1965a8d0e30e004bb7e9ecfd4807338544dee0 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 2 Feb 2017 09:59:28 -0800 Subject: [PATCH 08/43] Qt: Fix race condition in AssetView --- src/platform/qt/AssetView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/qt/AssetView.cpp b/src/platform/qt/AssetView.cpp index 29fb35617..2844562f9 100644 --- a/src/platform/qt/AssetView.cpp +++ b/src/platform/qt/AssetView.cpp @@ -24,7 +24,7 @@ AssetView::AssetView(GameController* controller, QWidget* parent) } void AssetView::updateTiles(bool force) { - if (!m_controller->thread() || !m_controller->thread()->core) { + if (!m_controller->isLoaded()) { return; } From e4d3aefb4abe52e2aed7a77bb962ff91560908e7 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 2 Feb 2017 15:08:05 -0800 Subject: [PATCH 09/43] Qt: Clean up ObjView --- src/platform/qt/ObjView.cpp | 115 +++++++++++++++++------------------- 1 file changed, 54 insertions(+), 61 deletions(-) diff --git a/src/platform/qt/ObjView.cpp b/src/platform/qt/ObjView.cpp index f543adc27..6d705ad4b 100644 --- a/src/platform/qt/ObjView.cpp +++ b/src/platform/qt/ObjView.cpp @@ -68,64 +68,55 @@ void ObjView::updateTilesGBA(bool force) { unsigned width = GBAVideoObjSizes[shape * 4 + size][0]; unsigned height = GBAVideoObjSizes[shape * 4 + size][1]; unsigned tile = GBAObjAttributesCGetTile(obj->c); + m_ui.tiles->setTileCount(width * height / 64); + m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value()); + m_ui.tiles->resize(QSize(width, height) * m_ui.magnification->value()); + unsigned palette = GBAObjAttributesCGetPalette(obj->c); + unsigned tileBase = tile; + if (GBAObjAttributesAIs256Color(obj->a)) { + m_ui.palette->setText("256-color"); + mTileCacheSetPalette(m_tileCache.get(), 1); + m_ui.tile->setPalette(0); + m_ui.tile->setPaletteSet(1, 1024, 1536); + palette = 1; + tile = tile / 2 + 1024; + } else { + m_ui.palette->setText(QString::number(palette)); + mTileCacheSetPalette(m_tileCache.get(), 0); + m_ui.tile->setPalette(palette); + m_ui.tile->setPaletteSet(0, 2048, 3072); + palette += 16; + tile += 2048; + } ObjInfo newInfo{ tile, width / 8, height / 8, width / 8 }; - m_ui.tiles->setTileCount(width * height / 64); - m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value()); - m_ui.tiles->resize(QSize(width, height) * m_ui.magnification->value()); - unsigned palette = GBAObjAttributesCGetPalette(obj->c); - GBARegisterDISPCNT dispcnt = gba->memory.io[0]; // FIXME: Register name can't be imported due to namespacing issues - if (!GBARegisterDISPCNTIsObjCharacterMapping(dispcnt)) { - newInfo.stride = 0x20 >> (GBAObjAttributesAGet256Color(obj->a)); - }; if (newInfo != m_objInfo) { force = true; } m_objInfo = newInfo; - int i = 0; - if (GBAObjAttributesAIs256Color(obj->a)) { - m_ui.palette->setText("256-color"); - mTileCacheSetPalette(m_tileCache.get(), 1); - m_ui.tile->setPalette(0); - m_ui.tile->setPaletteSet(1, 1024, 1536); - tile /= 2; - unsigned t = tile + i; - for (int y = 0; y < height / 8; ++y) { - for (int x = 0; x < width / 8; ++x, ++i, ++t) { - const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * t], t + 1024, 1); - if (data) { - m_ui.tiles->setTile(i, data); - } else if (force) { - m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t + 1024, 1)); - } - } - t += newInfo.stride - width / 8; - } - tile += 1024; - } else { - m_ui.palette->setText(QString::number(palette)); - mTileCacheSetPalette(m_tileCache.get(), 0); - m_ui.tile->setPalette(palette); - m_ui.tile->setPaletteSet(0, 2048, 3072); - unsigned t = tile + i; - for (int y = 0; y < height / 8; ++y) { - for (int x = 0; x < width / 8; ++x, ++i, ++t) { - const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * t], t + 2048, palette + 16); - if (data) { - m_ui.tiles->setTile(i, data); - } else if (force) { - m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t + 2048, palette + 16)); - } - } - t += newInfo.stride - width / 8; - } - tile += 2048; - } m_tileOffset = tile; + GBARegisterDISPCNT dispcnt = gba->memory.io[0]; // FIXME: Register name can't be imported due to namespacing issues + if (!GBARegisterDISPCNTIsObjCharacterMapping(dispcnt)) { + newInfo.stride = 0x20 >> (GBAObjAttributesAGet256Color(obj->a)); + }; + + int i = 0; + for (int y = 0; y < height / 8; ++y) { + for (int x = 0; x < width / 8; ++x, ++i, ++tile, ++tileBase) { + const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[32 * tileBase], tile, palette); + if (data) { + m_ui.tiles->setTile(i, data); + } else if (force) { + m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), tile, palette)); + } + } + tile += newInfo.stride - width / 8; + tileBase += newInfo.stride - width / 8; + } m_ui.x->setText(QString::number(GBAObjAttributesBGetX(obj->b))); m_ui.y->setText(QString::number(GBAObjAttributesAGetY(obj->a))); @@ -175,16 +166,6 @@ void ObjView::updateTilesGB(bool force) { height = 16; } unsigned tile = obj->tile; - ObjInfo newInfo{ - tile, - 1, - height / 8, - 1 - }; - if (newInfo != m_objInfo) { - force = true; - } - m_objInfo = newInfo; m_ui.tiles->setTileCount(width * height / 64); m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value()); m_ui.tiles->resize(QSize(width, height) * m_ui.magnification->value()); @@ -197,21 +178,33 @@ void ObjView::updateTilesGB(bool force) { } else { palette = GBObjAttributesGetPalette(obj->attr); } + ObjInfo newInfo{ + tile, + 1, + height / 8, + 1 + }; + if (newInfo != m_objInfo) { + force = true; + } + m_objInfo = newInfo; + m_tileOffset = tile; + int i = 0; m_ui.palette->setText(QString::number(palette)); + palette += 8; mTileCacheSetPalette(m_tileCache.get(), 0); - m_ui.tile->setPalette(palette + 8); + m_ui.tile->setPalette(palette); m_ui.tile->setPaletteSet(0, 512, 1024); for (int y = 0; y < height / 8; ++y, ++i) { unsigned t = tile + i; - const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[16 * t], t, palette + 8); + const uint16_t* data = mTileCacheGetTileIfDirty(m_tileCache.get(), &m_tileStatus[16 * t], t, palette); if (data) { m_ui.tiles->setTile(i, data); } else if (force) { - m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t, palette + 8)); + m_ui.tiles->setTile(i, mTileCacheGetTile(m_tileCache.get(), t, palette)); } } - m_tileOffset = tile; m_ui.x->setText(QString::number(obj->x)); m_ui.y->setText(QString::number(obj->y)); From cea83a54442957023710fb6cd6101163fdc76948 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 2 Feb 2017 16:33:27 -0800 Subject: [PATCH 10/43] Util: Add 8-bit PNG write support --- CHANGES | 1 + include/mgba-util/png-io.h | 3 +++ src/util/png-io.c | 47 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/CHANGES b/CHANGES index 81cc7d899..a4fd7a4a0 100644 --- a/CHANGES +++ b/CHANGES @@ -60,6 +60,7 @@ Misc: - 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 0.5.2: (2016-12-31) Bugfixes: diff --git a/include/mgba-util/png-io.h b/include/mgba-util/png-io.h index 1f8fea331..20803303e 100644 --- a/include/mgba-util/png-io.h +++ b/include/mgba-util/png-io.h @@ -22,7 +22,10 @@ enum { png_structp PNGWriteOpen(struct VFile* source); png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height); +png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height); +bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries); bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); +bool PNGWritePixels8(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels); bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data); void PNGWriteClose(png_structp png, png_infop info); diff --git a/src/util/png-io.c b/src/util/png-io.c index e3e17ff5e..0cb721b83 100644 --- a/src/util/png-io.c +++ b/src/util/png-io.c @@ -51,6 +51,40 @@ png_infop PNGWriteHeader(png_structp png, unsigned width, unsigned height) { return info; } +png_infop PNGWriteHeader8(png_structp png, unsigned width, unsigned height) { + png_infop info = png_create_info_struct(png); + if (!info) { + return 0; + } + if (setjmp(png_jmpbuf(png))) { + return 0; + } + png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + return info; +} + +bool PNGWritePalette(png_structp png, png_infop info, const uint32_t* palette, unsigned entries) { + if (!palette || !entries) { + return false; + } + if (setjmp(png_jmpbuf(png))) { + return false; + } + png_color colors[256]; + png_byte trans[256]; + unsigned i; + for (i = 0; i < entries && i < 256; ++i) { + colors[i].red = palette[i]; + colors[i].green = palette[i] >> 8; + colors[i].blue = palette[i] >> 16; + trans[i] = palette[i] >> 24; + } + png_set_PLTE(png, info, colors, entries); + png_set_tRNS(png, info, trans, entries, NULL); + png_write_info(png, info); + return true; +} + bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { png_bytep row = malloc(sizeof(png_byte) * width * 3); if (!row) { @@ -94,6 +128,19 @@ bool PNGWritePixels(png_structp png, unsigned width, unsigned height, unsigned s return true; } +bool PNGWritePixels8(png_structp png, unsigned width, unsigned height, unsigned stride, const void* pixels) { + UNUSED(width); + const png_byte* pixelData = pixels; + if (setjmp(png_jmpbuf(png))) { + return false; + } + unsigned i; + for (i = 0; i < height; ++i) { + png_write_row(png, &pixelData[stride * i]); + } + return true; +} + bool PNGWriteCustomChunk(png_structp png, const char* name, size_t size, void* data) { char realName[5]; strncpy(realName, name, 4); From f3b66397a2a598e5cfb63acd0c0b84f5796d0802 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 2 Feb 2017 16:33:48 -0800 Subject: [PATCH 11/43] Core: Extend tile cache to return raw bits --- include/mgba/core/tile-cache.h | 2 ++ src/core/tile-cache.c | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/mgba/core/tile-cache.h b/include/mgba/core/tile-cache.h index 0a71c690a..540705af9 100644 --- a/include/mgba/core/tile-cache.h +++ b/include/mgba/core/tile-cache.h @@ -58,6 +58,8 @@ void mTileCacheSetPalette(struct mTileCache* cache, int palette); const uint16_t* mTileCacheGetTile(struct mTileCache* cache, unsigned tileId, unsigned paletteId); const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileCacheEntry* entry, unsigned tileId, unsigned paletteId); +const uint8_t* mTileCacheGetRawTile(struct mTileCache* cache, unsigned tileId); +const uint16_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId); CXX_GUARD_END diff --git a/src/core/tile-cache.c b/src/core/tile-cache.c index 85c2f7032..3c34a8d86 100644 --- a/src/core/tile-cache.c +++ b/src/core/tile-cache.c @@ -283,3 +283,27 @@ const uint16_t* mTileCacheGetTileIfDirty(struct mTileCache* cache, struct mTileC } return tile; } + +const uint8_t* mTileCacheGetRawTile(struct mTileCache* cache, unsigned tileId) { + unsigned bpp = cache->bpp; + switch (bpp) { + case 0: + return NULL; + default: + return (uint8_t*) &cache->vram[tileId << (2 + bpp)]; + } +} + +const uint16_t* mTileCacheGetPalette(struct mTileCache* cache, unsigned paletteId) { + unsigned bpp = cache->bpp; + switch (bpp) { + default: + return NULL; + case 1: + return &cache->palette[paletteId << 2]; + case 2: + return &cache->palette[paletteId << 4]; + case 3: + return &cache->palette[paletteId << 8]; + } +} From ae60489d990dfaf413846958aa08c971ff6ecaf3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 2 Feb 2017 16:34:18 -0800 Subject: [PATCH 12/43] Qt: Add export capability for sprites --- src/platform/qt/AssetView.cpp | 46 +++++++++++++++++++ src/platform/qt/AssetView.h | 2 + src/platform/qt/ObjView.cpp | 85 ++++++++++++++++++++++++++++++----- src/platform/qt/ObjView.h | 6 +++ src/platform/qt/ObjView.ui | 9 +++- 5 files changed, 137 insertions(+), 11 deletions(-) diff --git a/src/platform/qt/AssetView.cpp b/src/platform/qt/AssetView.cpp index 2844562f9..964b40761 100644 --- a/src/platform/qt/AssetView.cpp +++ b/src/platform/qt/AssetView.cpp @@ -7,6 +7,8 @@ #include +#include + using namespace QGBA; AssetView::AssetView(GameController* controller, QWidget* parent) @@ -51,3 +53,47 @@ void AssetView::resizeEvent(QResizeEvent*) { void AssetView::showEvent(QShowEvent*) { updateTiles(true); } + +void AssetView::compositeTile(unsigned tileId, void* buffer, size_t stride, size_t x, size_t y, int depth) { + const uint8_t* tile = mTileCacheGetRawTile(m_tileCache.get(), tileId); + uint8_t* pixels = static_cast(buffer); + size_t base = stride * y + x; + switch (depth) { + case 2: + for (size_t i = 0; i < 8; ++i) { + uint8_t tileDataLower = tile[i * 2]; + uint8_t tileDataUpper = tile[i * 2 + 1]; + uint8_t pixel; + pixel = ((tileDataUpper & 128) >> 6) | ((tileDataLower & 128) >> 7); + pixels[base + i * stride] = pixel; + pixel = ((tileDataUpper & 64) >> 5) | ((tileDataLower & 64) >> 6); + pixels[base + i * stride + 1] = pixel; + pixel = ((tileDataUpper & 32) >> 4) | ((tileDataLower & 32) >> 5); + pixels[base + i * stride + 2] = pixel; + pixel = ((tileDataUpper & 16) >> 3) | ((tileDataLower & 16) >> 4); + pixels[base + i * stride + 3] = pixel; + pixel = ((tileDataUpper & 8) >> 2) | ((tileDataLower & 8) >> 3); + pixels[base + i * stride + 4] = pixel; + pixel = ((tileDataUpper & 4) >> 1) | ((tileDataLower & 4) >> 2); + pixels[base + i * stride + 5] = pixel; + pixel = (tileDataUpper & 2) | ((tileDataLower & 2) >> 1); + pixels[base + i * stride + 6] = pixel; + pixel = ((tileDataUpper & 1) << 1) | (tileDataLower & 1); + pixels[base + i * stride + 7] = pixel; + } + break; + case 4: + for (size_t j = 0; j < 8; ++j) { + for (size_t i = 0; i < 4; ++i) { + pixels[base + j * stride + i * 2] = tile[j * 4 + i] & 0xF; + pixels[base + j * stride + i * 2 + 1] = tile[j * 4 + i] >> 4; + } + } + break; + case 8: + for (size_t i = 0; i < 8; ++i) { + memcpy(&pixels[base + i * stride], &tile[i * 8], 8); + } + break; + } +} diff --git a/src/platform/qt/AssetView.h b/src/platform/qt/AssetView.h index a30ccbd9c..76dae708b 100644 --- a/src/platform/qt/AssetView.h +++ b/src/platform/qt/AssetView.h @@ -18,6 +18,8 @@ Q_OBJECT public: AssetView(GameController* controller, QWidget* parent = nullptr); + void compositeTile(unsigned tileId, void* image, size_t stride, size_t x, size_t y, int depth = 8); + protected slots: void updateTiles(bool force = false); diff --git a/src/platform/qt/ObjView.cpp b/src/platform/qt/ObjView.cpp index 6d705ad4b..2749d7a50 100644 --- a/src/platform/qt/ObjView.cpp +++ b/src/platform/qt/ObjView.cpp @@ -10,11 +10,17 @@ #include #include +#include "LogController.h" +#include "VFileDevice.h" + +#ifdef M_CORE_GBA #include +#endif #ifdef M_CORE_GB #include #include #endif +#include using namespace QGBA; @@ -45,6 +51,7 @@ ObjView::ObjView(GameController* controller, QWidget* parent) connect(m_ui.magnification, static_cast(&QSpinBox::valueChanged), [this]() { updateTiles(true); }); + connect(m_ui.exportButton, SIGNAL(clicked()), this, SLOT(exportObj())); } void ObjView::selectObj(int obj) { @@ -73,36 +80,44 @@ void ObjView::updateTilesGBA(bool force) { m_ui.tiles->resize(QSize(width, height) * m_ui.magnification->value()); unsigned palette = GBAObjAttributesCGetPalette(obj->c); unsigned tileBase = tile; + unsigned paletteSet; + unsigned bits; if (GBAObjAttributesAIs256Color(obj->a)) { m_ui.palette->setText("256-color"); - mTileCacheSetPalette(m_tileCache.get(), 1); + paletteSet = 1; m_ui.tile->setPalette(0); m_ui.tile->setPaletteSet(1, 1024, 1536); palette = 1; tile = tile / 2 + 1024; + bits = 8; } else { m_ui.palette->setText(QString::number(palette)); - mTileCacheSetPalette(m_tileCache.get(), 0); + paletteSet = 0; m_ui.tile->setPalette(palette); m_ui.tile->setPaletteSet(0, 2048, 3072); palette += 16; tile += 2048; + bits = 4; } ObjInfo newInfo{ tile, width / 8, height / 8, - width / 8 + width / 8, + palette, + paletteSet, + bits }; if (newInfo != m_objInfo) { force = true; } - m_objInfo = newInfo; - m_tileOffset = tile; GBARegisterDISPCNT dispcnt = gba->memory.io[0]; // FIXME: Register name can't be imported due to namespacing issues if (!GBARegisterDISPCNTIsObjCharacterMapping(dispcnt)) { newInfo.stride = 0x20 >> (GBAObjAttributesAGet256Color(obj->a)); }; + m_objInfo = newInfo; + m_tileOffset = tile; + mTileCacheSetPalette(m_tileCache.get(), paletteSet); int i = 0; for (int y = 0; y < height / 8; ++y) { @@ -169,7 +184,7 @@ void ObjView::updateTilesGB(bool force) { m_ui.tiles->setTileCount(width * height / 64); m_ui.tiles->setMinimumSize(QSize(width, height) * m_ui.magnification->value()); m_ui.tiles->resize(QSize(width, height) * m_ui.magnification->value()); - int palette = 0; + unsigned palette = 0; if (gb->model >= GB_MODEL_CGB) { if (GBObjAttributesIsBank(obj->attr)) { tile += 512; @@ -178,11 +193,17 @@ void ObjView::updateTilesGB(bool force) { } else { palette = GBObjAttributesGetPalette(obj->attr); } + m_ui.palette->setText(QString::number(palette)); + palette += 8; + ObjInfo newInfo{ tile, 1, height / 8, - 1 + 1, + palette, + 0, + 2 }; if (newInfo != m_objInfo) { force = true; @@ -191,8 +212,6 @@ void ObjView::updateTilesGB(bool force) { m_tileOffset = tile; int i = 0; - m_ui.palette->setText(QString::number(palette)); - palette += 8; mTileCacheSetPalette(m_tileCache.get(), 0); m_ui.tile->setPalette(palette); m_ui.tile->setPaletteSet(0, 512, 1024); @@ -223,10 +242,56 @@ void ObjView::updateTilesGB(bool force) { } #endif +void ObjView::exportObj() { + GameController::Interrupter interrupter(m_controller); + QFileDialog* dialog = GBAApp::app()->getSaveFileDialog(this, tr("Export sprite"), + tr("Portable Network Graphics (*.png)")); + if (!dialog->exec()) { + return; + } + QString filename = dialog->selectedFiles()[0]; + VFile* vf = VFileDevice::open(filename, O_WRONLY | O_CREAT | O_TRUNC); + if (!vf) { + LOG(QT, ERROR) << tr("Failed to open output PNG file: %1").arg(filename); + return; + } + + mTileCacheSetPalette(m_tileCache.get(), m_objInfo.paletteSet); + png_structp png = PNGWriteOpen(vf); + png_infop info = PNGWriteHeader8(png, m_objInfo.width * 8, m_objInfo.height * 8); + + const uint16_t* rawPalette = mTileCacheGetPalette(m_tileCache.get(), m_objInfo.paletteId); + unsigned colors = 1 << m_objInfo.bits; + uint32_t palette[256]; + for (unsigned c = 0; c < colors && c < 256; ++c) { + uint16_t color = rawPalette[c]; + palette[c] = M_R8(rawPalette[c]); + palette[c] |= M_G8(rawPalette[c]) << 8; + palette[c] |= M_B8(rawPalette[c]) << 16; + if (c) { + palette[c] |= 0xFF000000; + } + } + PNGWritePalette(png, info, palette, colors); + + uint8_t* buffer = new uint8_t[m_objInfo.width * m_objInfo.height * 8 * 8]; + unsigned t = m_objInfo.tile; + for (int y = 0; y < m_objInfo.height; ++y) { + for (int x = 0; x < m_objInfo.width; ++x, ++t) { + compositeTile(t, static_cast(buffer), m_objInfo.width * 8, x * 8, y * 8, m_objInfo.bits); + } + t += m_objInfo.stride - m_objInfo.width; + } + PNGWritePixels8(png, m_objInfo.width * 8, m_objInfo.height * 8, m_objInfo.width * 8, static_cast(buffer)); + PNGWriteClose(png, info); + delete[] buffer; +} bool ObjView::ObjInfo::operator!=(const ObjInfo& other) { return other.tile != tile || other.width != width || other.height != height || - other.stride != stride; + other.stride != stride || + other.paletteId != paletteId || + other.paletteSet != paletteSet; } diff --git a/src/platform/qt/ObjView.h b/src/platform/qt/ObjView.h index 725fabfd4..16a72961b 100644 --- a/src/platform/qt/ObjView.h +++ b/src/platform/qt/ObjView.h @@ -21,6 +21,9 @@ Q_OBJECT public: ObjView(GameController* controller, QWidget* parent = nullptr); +public slots: + void exportObj(); + private slots: void selectObj(int); void translateIndex(int); @@ -43,6 +46,9 @@ private: unsigned width; unsigned height; unsigned stride; + unsigned paletteId; + unsigned paletteSet; + unsigned bits; bool operator!=(const ObjInfo&); } m_objInfo; diff --git a/src/platform/qt/ObjView.ui b/src/platform/qt/ObjView.ui index f315866ec..37dcf9533 100644 --- a/src/platform/qt/ObjView.ui +++ b/src/platform/qt/ObjView.ui @@ -7,7 +7,7 @@ 0 0 454 - 375 + 385 @@ -70,6 +70,13 @@ + + + + Export + + + From e25db55ac5ca541039d441a45a8ca7c21e5f38a5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 2 Feb 2017 16:37:48 -0800 Subject: [PATCH 13/43] Qt: Rename "Resample video" option to "Bilinear filtering" --- CHANGES | 1 + src/platform/qt/Window.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index a4fd7a4a0..d563172c1 100644 --- a/CHANGES +++ b/CHANGES @@ -61,6 +61,7 @@ Misc: - 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" 0.5.2: (2016-12-31) Bugfixes: diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index cd7bfee78..fa4a47ee0 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1232,7 +1232,7 @@ void Window::setupMenu(QMenuBar* menubar) { m_config->updateOption("lockAspectRatio"); ConfigOption* resampleVideo = m_config->addOption("resampleVideo"); - resampleVideo->addBoolean(tr("Resample video"), avMenu); + resampleVideo->addBoolean(tr("Bilinear filtering"), avMenu); resampleVideo->connect([this](const QVariant& value) { m_display->filter(value.toBool()); }, this); From aaec68ee4896fd316660088a3c2c02c7bd3b7241 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 2 Feb 2017 20:04:45 -0800 Subject: [PATCH 14/43] LR35902: Fix LD x, (HL) disassembly (fixes #513) --- src/lr35902/decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lr35902/decoder.c b/src/lr35902/decoder.c index 641af7804..6abefc6cc 100644 --- a/src/lr35902/decoder.c +++ b/src/lr35902/decoder.c @@ -52,7 +52,7 @@ DEFINE_DECODER_LR35902(NOP, info->mnemonic = LR35902_MN_NOP;) #define DEFINE_LD_DECODER_LR35902_MEM(NAME, REG) \ DEFINE_DECODER_LR35902(LD ## NAME ## _ ## REG, info->mnemonic = LR35902_MN_LD; \ - info->op1.reg = LR35902_REG_ ## A; \ + info->op1.reg = LR35902_REG_ ## NAME; \ info->op2.reg = LR35902_REG_ ## REG; \ info->op2.flags = LR35902_OP_FLAG_MEMORY;) From ee5dbd9f82c768df23afbd5262b58496a2ec8d78 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 3 Feb 2017 09:37:28 -0800 Subject: [PATCH 15/43] Tools: Fix recurring multiple times over the same library --- CHANGES | 1 + tools/deploy-mac.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index d563172c1..dafa39d3c 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,7 @@ Bugfixes: - 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 Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/tools/deploy-mac.py b/tools/deploy-mac.py index 8305a4304..e525e3012 100755 --- a/tools/deploy-mac.py +++ b/tools/deploy-mac.py @@ -96,6 +96,7 @@ def updateMachO(bin, execPath, root): if os.access(newPath, os.F_OK): if verbose: print('Skipping copying {}, already done.'.format(oldPath)) + newPath = None elif os.path.abspath(oldPath) != os.path.abspath(newPath): if verbose: print('Copying {} to {}...'.format(oldPath, newPath)) @@ -111,7 +112,8 @@ def updateMachO(bin, execPath, root): args = [installNameTool] for path, oldExecPath, newExecPath in toUpdate: if path != bin: - updateMachO(path, execPath, root) + if path: + updateMachO(path, execPath, root) if verbose: print('Updating Mach-O load from {} to {}...'.format(oldExecPath, newExecPath)) args.extend(['-change', oldExecPath, newExecPath]) From 1bb496d0feee858eb964c0426ca6a97d6dc1aba6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 3 Feb 2017 16:50:05 -0800 Subject: [PATCH 16/43] GBA Video: Optimize when BLD* registers are written frequently --- CHANGES | 1 + .../internal/gba/renderers/video-software.h | 1 + src/gba/renderers/video-software.c | 18 +++++++++++++----- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index dafa39d3c..eb7f0c29f 100644 --- a/CHANGES +++ b/CHANGES @@ -63,6 +63,7 @@ Misc: - 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 0.5.2: (2016-12-31) Bugfixes: diff --git a/include/mgba/internal/gba/renderers/video-software.h b/include/mgba/internal/gba/renderers/video-software.h index ba9db50f7..853a6f335 100644 --- a/include/mgba/internal/gba/renderers/video-software.h +++ b/include/mgba/internal/gba/renderers/video-software.h @@ -126,6 +126,7 @@ struct GBAVideoSoftwareRenderer { unsigned target1Bd; unsigned target2Obj; unsigned target2Bd; + bool blendDirty; enum BlendEffect blendEffect; color_t normalPalette[512]; color_t variantPalette[512]; diff --git a/src/gba/renderers/video-software.c b/src/gba/renderers/video-software.c index 3e04be736..2c20a475a 100644 --- a/src/gba/renderers/video-software.c +++ b/src/gba/renderers/video-software.c @@ -97,6 +97,7 @@ static void GBAVideoSoftwareRendererReset(struct GBAVideoRenderer* renderer) { LOAD_16(entry, i, softwareRenderer->d.palette); GBAVideoSoftwareRendererWritePalette(renderer, i, entry); } + softwareRenderer->blendDirty = false; _updatePalettes(softwareRenderer); softwareRenderer->blda = 0; @@ -261,11 +262,14 @@ static uint16_t GBAVideoSoftwareRendererWriteVideoRegister(struct GBAVideoRender value &= 0x1F1F; break; case REG_BLDY: - softwareRenderer->bldy = value & 0x1F; - if (softwareRenderer->bldy > 0x10) { - softwareRenderer->bldy = 0x10; + value &= 0x1F; + if (value > 0x10) { + value = 0x10; + } + if (softwareRenderer->bldy != value) { + softwareRenderer->bldy = value; + softwareRenderer->blendDirty = true; } - _updatePalettes(softwareRenderer); break; case REG_WIN0H: softwareRenderer->winN[0].h.end = value; @@ -515,6 +519,10 @@ static void GBAVideoSoftwareRendererDrawScanline(struct GBAVideoRenderer* render } GBAVideoSoftwareRendererUpdateDISPCNT(softwareRenderer); + if (softwareRenderer->blendDirty) { + _updatePalettes(softwareRenderer); + softwareRenderer->blendDirty = false; + } int w; x = 0; @@ -702,7 +710,7 @@ static void GBAVideoSoftwareRendererWriteBLDCNT(struct GBAVideoSoftwareRenderer* renderer->target2Bd = GBARegisterBLDCNTGetTarget2Bd(value); if (oldEffect != renderer->blendEffect) { - _updatePalettes(renderer); + renderer->blendDirty = true; } } From 7fd25804f50318da2d33ea8314d20df1c14a5587 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 4 Feb 2017 11:49:07 -0800 Subject: [PATCH 17/43] GBA: Fix freeze when loading a savestate that was in the middle of saving --- src/gba/savedata.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gba/savedata.c b/src/gba/savedata.c index d82d80fd4..931ecab12 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -548,6 +548,7 @@ void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerial if (GBASerializedSavedataFlagsIsDustSettling(flags)) { uint32_t when; LOAD_32(when, 0, &state->savedata.settlingDust); + mTimingDeschedule(savedata->timing, &savedata->dust); mTimingSchedule(savedata->timing, &savedata->dust, when); } } From f17840169e615db9a5c5eb44efaea8ee71391a03 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 4 Feb 2017 12:26:58 -0800 Subject: [PATCH 18/43] Qt: Fix missed renamed string --- src/platform/qt/SettingsView.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index 3957a29a2..b7abd9c39 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -383,7 +383,7 @@ - Resample video + Bilinear filtering From c99450c51b3cc4144eebd69906abb944c4cdd72f Mon Sep 17 00:00:00 2001 From: rootfather Date: Sat, 4 Feb 2017 20:51:54 +0100 Subject: [PATCH 19/43] All: Improve MSYS2 notes (64-bit/Dependency Walker) in README --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8f90ba4a..703d9986a 100644 --- a/README.md +++ b/README.md @@ -96,10 +96,16 @@ This will build and install mGBA into `/usr/bin` and `/usr/lib`. Dependencies th #### Windows developer building -To build on Windows for development, using MSYS2 is recommended. Follow the installation steps found on their [website](https://msys2.github.io). Make sure you're running the 32-bit version ("MinGW-w64 Win32 Shell") and run this additional command (including the braces) to install the needed dependencies (please note that this involves downloading over 500MiB of packages, so it will take a long time): +To build on Windows for development, using MSYS2 is recommended. Follow the installation steps found on their [website](https://msys2.github.io). Make sure you're running the 32-bit version ("MinGW-w64 Win32 Shell") (or the 64-bit version "MinGW-w64 Win64 Shell" if you want to build for x86_64) and run this additional command (including the braces) to install the needed dependencies (please note that this involves downloading over 500MiB of packages, so it will take a long time): +For x86 (32 bit) builds: + pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libzip,pkg-config,qt5,SDL2} +For x86_64 (64 bit) builds: + + pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libzip,pkg-config,qt5,SDL2} + Check out the source code by running this command: git clone https://github.com/mgba-emu/mgba.git @@ -112,7 +118,7 @@ Then finally build it by running these commands: cmake .. -G "MSYS Makefiles" make -Please note that this build of mGBA for Windows is not suitable for distribution, due to the scattering of DLLs it needs to run, but is perfect for development. +Please note that this build of mGBA for Windows is not suitable for distribution, due to the scattering of DLLs it needs to run, but is perfect for development. However, if distributing such a build is desired (e.g. for testing on machines that don't have the MSYS2 environment installed), a tool called "[Dependency Walker](http://dependencywalker.com)" can be used to see which additional DLL files need to be shipped with the mGBA executable. ### Dependencies From 30ec43741b1a33c0d0fcbafbf3f3cfea67d621c3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 4 Feb 2017 18:30:50 -0800 Subject: [PATCH 20/43] GBA I/O: Handle audio registers specially when deserializing --- CHANGES | 1 + src/gba/io.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index eb7f0c29f..518621ede 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,7 @@ Bugfixes: - 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 Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/src/gba/io.c b/src/gba/io.c index c788fb243..719c2be53 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -251,8 +251,8 @@ static const int _isRSpecialRegister[REG_MAX >> 1] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // Audio - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, @@ -292,9 +292,9 @@ static const int _isWSpecialRegister[REG_MAX >> 1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Audio - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // DMA From d2016e382a49dd79d46477902308ec46726b496a Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 4 Feb 2017 12:50:09 -0800 Subject: [PATCH 21/43] GB, GBA: Improve savestate loading in new timing system --- src/gb/audio.c | 5 ----- src/gb/memory.c | 2 -- src/gb/serialize.c | 3 +-- src/gb/timer.c | 2 -- src/gb/video.c | 2 -- src/gba/audio.c | 1 - src/gba/io.c | 1 - src/gba/savedata.c | 1 - src/gba/serialize.c | 2 +- src/gba/video.c | 1 - 10 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/gb/audio.c b/src/gb/audio.c index 17f00351d..2a3535251 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -964,7 +964,6 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->ch1.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch1Flags); audio->ch1.sweep.realFrequency = GBSerializedAudioEnvelopeGetFrequency(ch1Flags); LOAD_32LE(when, 0, &state->ch1.nextEvent); - mTimingDeschedule(audio->timing, &audio->ch1Event); if (audio->ch1.envelope.dead < 2 && audio->playingCh1) { mTimingSchedule(audio->timing, &audio->ch1Event, when); } @@ -976,7 +975,6 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->ch2.control.length = GBSerializedAudioEnvelopeGetLength(ch2Flags); audio->ch2.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch2Flags); LOAD_32LE(when, 0, &state->ch2.nextEvent); - mTimingDeschedule(audio->timing, &audio->ch2Event); if (audio->ch2.envelope.dead < 2 && audio->playingCh2) { mTimingSchedule(audio->timing, &audio->ch2Event, when); } @@ -986,7 +984,6 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt memcpy(audio->ch3.wavedata32, state->ch3.wavebanks, sizeof(audio->ch3.wavedata32)); LOAD_16LE(audio->ch3.length, 0, &state->ch3.length); LOAD_32LE(when, 0, &state->ch3.nextEvent); - mTimingDeschedule(audio->timing, &audio->ch3Event); if (audio->playingCh3) { mTimingSchedule(audio->timing, &audio->ch3Event, when); } @@ -1002,7 +999,6 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->ch4.envelope.nextStep = GBSerializedAudioEnvelopeGetNextStep(ch4Flags); LOAD_32LE(audio->ch4.lfsr, 0, &state->ch4.lfsr); LOAD_32LE(when, 0, &state->ch4.nextEvent); - mTimingDeschedule(audio->timing, &audio->ch4Event); if (audio->ch4.envelope.dead < 2 && audio->playingCh4) { mTimingSchedule(audio->timing, &audio->ch4Event, when); } @@ -1017,6 +1013,5 @@ void GBAudioDeserialize(struct GBAudio* audio, const struct GBSerializedState* s GBAudioPSGDeserialize(audio, &state->audio.psg, &state->audio.flags); uint32_t when; LOAD_32LE(when, 0, &state->audio.nextSample); - mTimingDeschedule(audio->timing, &audio->sampleEvent); mTimingSchedule(audio->timing, &audio->sampleEvent, when); } diff --git a/src/gb/memory.c b/src/gb/memory.c index 94e665712..2a0f2e52c 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -630,12 +630,10 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) { uint32_t when; LOAD_32LE(when, 0, &state->memory.dmaNext); - mTimingDeschedule(&gb->timing, &memory->dmaEvent); if (memory->dmaRemaining) { mTimingSchedule(&gb->timing, &memory->dmaEvent, when); } LOAD_32LE(when, 0, &state->memory.hdmaNext); - mTimingDeschedule(&gb->timing, &memory->hdmaEvent); if (memory->hdmaRemaining) { mTimingSchedule(&gb->timing, &memory->hdmaEvent, when); } diff --git a/src/gb/serialize.c b/src/gb/serialize.c index ebea64a31..75fa33e82 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -170,14 +170,13 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { uint32_t when; LOAD_32LE(when, 0, &state->cpu.eiPending); - mTimingDeschedule(&gb->timing, &gb->eiPending); if (GBSerializedCpuFlagsIsEiPending(flags)) { mTimingSchedule(&gb->timing, &gb->eiPending, when); } LOAD_32LE(gb->cpu->cycles, 0, &state->cpu.cycles); LOAD_32LE(gb->cpu->nextEvent, 0, &state->cpu.nextEvent); - LOAD_32LE(gb->timing.masterCycles, 0, &state->masterCycles); + gb->timing.root = NULL; gb->model = state->model; diff --git a/src/gb/timer.c b/src/gb/timer.c index 0cd2571a9..e5bda7113 100644 --- a/src/gb/timer.c +++ b/src/gb/timer.c @@ -109,13 +109,11 @@ void GBTimerDeserialize(struct GBTimer* timer, const struct GBSerializedState* s uint32_t when; LOAD_32LE(when, 0, &state->timer.nextEvent); - mTimingDeschedule(&timer->p->timing, &timer->event); mTimingSchedule(&timer->p->timing, &timer->event, when); GBSerializedTimerFlags flags; LOAD_32LE(flags, 0, &state->timer.flags); - mTimingDeschedule(&timer->p->timing, &timer->irq); if (GBSerializedTimerFlagsIsIrqPending(flags)) { LOAD_32LE(when, 0, &state->timer.nextIRQ); mTimingSchedule(&timer->p->timing, &timer->irq, when); diff --git a/src/gb/video.c b/src/gb/video.c index d3f30a87e..27287959a 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -550,12 +550,10 @@ void GBVideoDeserialize(struct GBVideo* video, const struct GBSerializedState* s } uint32_t when; - mTimingDeschedule(&video->p->timing, &video->modeEvent); if (!GBSerializedVideoFlagsIsNotModeEventScheduled(flags)) { LOAD_32LE(when, 0, &state->video.nextMode); mTimingSchedule(&video->p->timing, &video->modeEvent, when); } - mTimingDeschedule(&video->p->timing, &video->frameEvent); if (!GBSerializedVideoFlagsIsNotFrameEventScheduled(flags)) { LOAD_32LE(when, 0, &state->video.nextFrame); mTimingSchedule(&video->p->timing, &video->frameEvent, when); diff --git a/src/gba/audio.c b/src/gba/audio.c index 52d99d883..02102f227 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -344,7 +344,6 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState uint32_t when; LOAD_32(when, 0, &state->audio.nextSample); - mTimingDeschedule(&audio->p->timing, &audio->sampleEvent); mTimingSchedule(&audio->p->timing, &audio->sampleEvent, when); } diff --git a/src/gba/io.c b/src/gba/io.c index 719c2be53..14f361316 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -956,7 +956,6 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { gba->timers[i].lastEvent = when + mTimingCurrentTime(&gba->timing); } LOAD_32(when, 0, &state->timers[i].nextEvent); - mTimingDeschedule(&gba->timing, &gba->timers[i].event); if (GBATimerFlagsIsEnable(gba->timers[i].flags)) { mTimingSchedule(&gba->timing, &gba->timers[i].event, when); } diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 931ecab12..d82d80fd4 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -548,7 +548,6 @@ void GBASavedataDeserialize(struct GBASavedata* savedata, const struct GBASerial if (GBASerializedSavedataFlagsIsDustSettling(flags)) { uint32_t when; LOAD_32(when, 0, &state->savedata.settlingDust); - mTimingDeschedule(savedata->timing, &savedata->dust); mTimingSchedule(savedata->timing, &savedata->dust, when); } } diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 18692c0d3..600bf6faa 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -146,7 +146,7 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) { if (error) { return false; } - LOAD_32(gba->timing.masterCycles, 0, &state->masterCycles); + gba->timing.root = NULL; size_t i; for (i = 0; i < 16; ++i) { LOAD_32(gba->cpu->gprs[i], i * sizeof(gba->cpu->gprs[0]), state->cpu.gprs); diff --git a/src/gba/video.c b/src/gba/video.c index bfd4e5175..a61087630 100644 --- a/src/gba/video.c +++ b/src/gba/video.c @@ -324,7 +324,6 @@ void GBAVideoDeserialize(struct GBAVideo* video, const struct GBASerializedState } else { video->event.callback = _startHblank; } - mTimingDeschedule(&video->p->timing, &video->event); mTimingSchedule(&video->p->timing, &video->event, when); LOAD_16(video->vcount, REG_VCOUNT, state->io); From f302df91782233169a485ae49538afc40461248d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 4 Feb 2017 18:33:26 -0800 Subject: [PATCH 22/43] All: Add option for whether rewinding restores save games --- CHANGES | 1 + include/mgba/core/config.h | 1 + include/mgba/core/rewind.h | 1 + src/core/config.c | 2 ++ src/core/rewind.c | 6 +++-- src/core/thread.c | 2 ++ src/platform/qt/ConfigController.cpp | 1 + src/platform/qt/GameController.cpp | 4 ++- src/platform/qt/GameController.h | 2 +- src/platform/qt/SettingsView.cpp | 2 ++ src/platform/qt/SettingsView.ui | 38 ++++++++++++++++++---------- src/platform/qt/Window.cpp | 9 +++++-- src/platform/sdl/main.c | 1 + 13 files changed, 50 insertions(+), 20 deletions(-) diff --git a/CHANGES b/CHANGES index 518621ede..af7f033bb 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,7 @@ Features: - GB: LR35902/GB-Z80 disassembler - Configuration of gamepad hats - Qt: Spanish translation (by Kevin López) + - Add option for whether rewinding restores save games Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index 2fac1ff37..aca655976 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -27,6 +27,7 @@ struct mCoreOptions { int frameskip; bool rewindEnable; int rewindBufferCapacity; + bool rewindSave; float fpsTarget; size_t audioBuffers; unsigned sampleRate; diff --git a/include/mgba/core/rewind.h b/include/mgba/core/rewind.h index a1a748d3d..8762ff76a 100644 --- a/include/mgba/core/rewind.h +++ b/include/mgba/core/rewind.h @@ -19,6 +19,7 @@ struct mCoreRewindContext { struct mCoreRewindPatches patchMemory; size_t current; size_t size; + int stateFlags; struct VFile* previousState; struct VFile* currentState; }; diff --git a/src/core/config.c b/src/core/config.c index 659efd3e8..ceca2bdfd 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -321,6 +321,7 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts) _lookupIntValue(config, "frameskip", &opts->frameskip); _lookupIntValue(config, "volume", &opts->volume); _lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity); + _lookupIntValue(config, "rewindSave", &opts->rewindSave); _lookupFloatValue(config, "fpsTarget", &opts->fpsTarget); unsigned audioBuffers; if (_lookupUIntValue(config, "audioBuffers", &audioBuffers)) { @@ -376,6 +377,7 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio ConfigurationSetIntValue(&config->defaultsTable, 0, "frameskip", opts->frameskip); ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindEnable", opts->rewindEnable); ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindBufferCapacity", opts->rewindBufferCapacity); + ConfigurationSetIntValue(&config->defaultsTable, 0, "rewindSave", opts->rewindSave); ConfigurationSetFloatValue(&config->defaultsTable, 0, "fpsTarget", opts->fpsTarget); ConfigurationSetUIntValue(&config->defaultsTable, 0, "audioBuffers", opts->audioBuffers); ConfigurationSetUIntValue(&config->defaultsTable, 0, "sampleRate", opts->sampleRate); diff --git a/src/core/rewind.c b/src/core/rewind.c index 56a59e47d..9919acf2e 100644 --- a/src/core/rewind.c +++ b/src/core/rewind.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -20,6 +21,7 @@ void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries) context->previousState = VFileMemChunk(0, 0); context->currentState = VFileMemChunk(0, 0); context->size = 0; + context->stateFlags = SAVESTATE_SAVEDATA; } void mCoreRewindContextDeinit(struct mCoreRewindContext* context) { @@ -41,7 +43,7 @@ void mCoreRewindAppend(struct mCoreRewindContext* context, struct mCore* core) { if (context->current >= mCoreRewindPatchesSize(&context->patchMemory)) { context->current = 0; } - mCoreSaveStateNamed(core, nextState, 0); + mCoreSaveStateNamed(core, nextState, context->stateFlags); struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current); size_t size2 = nextState->size(nextState); size_t size = context->currentState->size(context->currentState); @@ -75,7 +77,7 @@ bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core) patch->d.applyPatch(&patch->d, current, size, previous, size); context->currentState->unmap(context->currentState, current, size); context->previousState->unmap(context->previousState, previous, size); - mCoreLoadStateNamed(core, context->previousState, 0); + mCoreLoadStateNamed(core, context->previousState, context->stateFlags); struct VFile* nextState = context->previousState; context->previousState = context->currentState; context->currentState = nextState; diff --git a/src/core/thread.c b/src/core/thread.c index f3509071e..3ffa7c477 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -148,6 +149,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { if (core->opts.rewindEnable && core->opts.rewindBufferCapacity > 0) { mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity); + threadContext->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0; } _changeState(threadContext, THREAD_RUNNING, true); diff --git a/src/platform/qt/ConfigController.cpp b/src/platform/qt/ConfigController.cpp index 6f25326c5..520b6d9f2 100644 --- a/src/platform/qt/ConfigController.cpp +++ b/src/platform/qt/ConfigController.cpp @@ -110,6 +110,7 @@ ConfigController::ConfigController(QObject* parent) m_opts.logLevel = mLOG_WARN | mLOG_ERROR | mLOG_FATAL; m_opts.rewindEnable = false; m_opts.rewindBufferCapacity = 300; + m_opts.rewindSave = true; m_opts.useBios = true; m_opts.suspendScreensaver = true; m_opts.lockAspectRatio = true; diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 84f089cfd..3889cb4c6 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -731,7 +731,7 @@ void GameController::frameAdvance() { } } -void GameController::setRewind(bool enable, int capacity) { +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) { @@ -739,8 +739,10 @@ void GameController::setRewind(bool enable, int capacity) { } 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); + m_threadContext.rewind.stateFlags = rewindSave ? SAVESTATE_SAVEDATA : 0; } } } diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 7a3bfbecc..9ea53de7b 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -127,7 +127,7 @@ public slots: void setPaused(bool paused); void reset(); void frameAdvance(); - void setRewind(bool enable, int capacity); + void setRewind(bool enable, int capacity, bool rewindSave); void rewind(int states = 0); void startRewinding(); void stopRewinding(); diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 57c27049d..da2d27be0 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -194,6 +194,7 @@ void SettingsView::updateConfig() { saveSetting("mute", m_ui.mute); saveSetting("rewindEnable", m_ui.rewind); saveSetting("rewindBufferCapacity", m_ui.rewindCapacity); + saveSetting("rewindSave", m_ui.rewindSave); saveSetting("resampleVideo", m_ui.resampleVideo); saveSetting("allowOpposingDirections", m_ui.allowOpposingDirections); saveSetting("suspendScreensaver", m_ui.suspendScreensaver); @@ -272,6 +273,7 @@ void SettingsView::reloadConfig() { loadSetting("mute", m_ui.mute); loadSetting("rewindEnable", m_ui.rewind); loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); + loadSetting("rewindSave", m_ui.rewindSave); loadSetting("resampleVideo", m_ui.resampleVideo); loadSetting("allowOpposingDirections", m_ui.allowOpposingDirections); loadSetting("suspendScreensaver", m_ui.suspendScreensaver); diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index b7abd9c39..ad59bc5bd 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -77,7 +77,7 @@ - 1 + 0 @@ -535,21 +535,21 @@ - + Qt::Horizontal - + Idle loops: - + @@ -568,21 +568,21 @@ - + Qt::Horizontal - + Savestate extra data: - + Screenshot @@ -592,7 +592,7 @@ - + Save data @@ -602,7 +602,7 @@ - + Cheat codes @@ -612,14 +612,14 @@ - + Load extra data: - + Screenshot @@ -629,27 +629,37 @@ - + Save data - + Cheat codes - + Qt::Horizontal + + + + Rewind affects save data + + + true + + + diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index fa4a47ee0..256c1581d 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1439,12 +1439,17 @@ void Window::setupMenu(QMenuBar* menubar) { ConfigOption* rewindEnable = m_config->addOption("rewindEnable"); rewindEnable->connect([this](const QVariant& value) { - m_controller->setRewind(value.toBool(), m_config->getOption("rewindBufferCapacity").toInt()); + m_controller->setRewind(value.toBool(), m_config->getOption("rewindBufferCapacity").toInt(), m_config->getOption("rewindSave").toInt()); }, this); ConfigOption* rewindBufferCapacity = m_config->addOption("rewindBufferCapacity"); rewindBufferCapacity->connect([this](const QVariant& value) { - m_controller->setRewind(m_config->getOption("rewindEnable").toInt(), value.toInt()); + m_controller->setRewind(m_config->getOption("rewindEnable").toInt(), value.toInt(), m_config->getOption("rewindSave").toInt()); + }, this); + + ConfigOption* rewindSave = m_config->addOption("rewindSave"); + rewindBufferCapacity->connect([this](const QVariant& value) { + m_controller->setRewind(m_config->getOption("rewindEnable").toInt(), m_config->getOption("rewindBufferCapacity").toInt(), value.toBool()); }, this); ConfigOption* allowOpposingDirections = m_config->addOption("allowOpposingDirections"); diff --git a/src/platform/sdl/main.c b/src/platform/sdl/main.c index 9bbabedbc..a5d960b23 100644 --- a/src/platform/sdl/main.c +++ b/src/platform/sdl/main.c @@ -43,6 +43,7 @@ int main(int argc, char** argv) { .useBios = true, .rewindEnable = true, .rewindBufferCapacity = 600, + .rewindSave = true, .audioBuffers = 1024, .videoSync = false, .audioSync = true, From af96097bb1cb1a0d2683f831370caa40a96541db Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 4 Feb 2017 18:34:11 -0800 Subject: [PATCH 23/43] Qt: Update strings --- src/platform/qt/ts/mgba-es.ts | 191 +++++++++++++++++++--------------- 1 file changed, 108 insertions(+), 83 deletions(-) diff --git a/src/platform/qt/ts/mgba-es.ts b/src/platform/qt/ts/mgba-es.ts index 610255ddf..3c48832a6 100644 --- a/src/platform/qt/ts/mgba-es.ts +++ b/src/platform/qt/ts/mgba-es.ts @@ -521,7 +521,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. - + × × @@ -531,124 +531,129 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Magnificación - + + Export + + + + Attributes Atributos - + Transform Transformación - + Off No - + Palette Paleta - - - - + + + + 0 0 - + Double Size Doble tamaño - - - - + + + + Return, Ctrl+R Volver, Ctrl+R - + Flipped Volteo - + H H - + V V - + Mode Modo - + Normal Normal - + Mosaic Mosaico - + Enabled Habilitado - + Priority Prioridad - + Tile Tile - + Geometry Geometría - + Position Posición - + , , - + Dimensions Dimensiones - - + + 8 8 - + Address Dirección - + 0x07000000 0x07000000 @@ -1061,7 +1066,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Error al escribir al archivo de captura: %1 - + Failed to start audio processor Error al iniciar el procesador de audio @@ -2624,42 +2629,57 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. QGBA::ObjView - - + + 0x%0 0x%0 - + Off No - + Normal Normal - + Trans Trans - + OBJWIN OBJWIN - + Invalid Inválido - - + + N/A n/d + + + Export sprite + + + + + Portable Network Graphics (*.png) + + + + + Failed to open output PNG file: %1 + + QGBA::PaletteView @@ -3297,11 +3317,6 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Lock aspect ratio Bloquear relación de aspecto - - - Resample video - Remuestrear video - Frame&skip @@ -3467,6 +3482,11 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Add folder to library... Agregar carpeta a la biblioteca... + + + Bilinear filtering + + View &palette... @@ -3493,62 +3513,62 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Ver reg&istros E/S... - + Exit fullscreen Salir de pantalla completa - + Autofire Botones turbo - + Autofire A Turbo A - + Autofire B Turbo B - + Autofire L Turbo L - + Autofire R Turbo R - + Autofire Start Turbo Start - + Autofire Select Turbo Select - + Autofire Up Turbo Arriba - + Autofire Right Turbo Derecha - + Autofire Down Turbo Abajo - + Autofire Left Turbo Izquierda @@ -3856,11 +3876,6 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Lock aspect ratio Bloquear relación de aspecto - - - Resample video - Remuestrar video - Library: @@ -3882,23 +3897,23 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Velocidad de avance rápido: - - - - - - - + + + + + + + Browse Examinar - + Use BIOS file if found Usar archivo BIOS si hay - + Skip BIOS intro Saltar pantalla de inicio de la BIOS @@ -3970,6 +3985,11 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Enable rewind Habilitar retroceso + + + Bilinear filtering + + Rewind history: @@ -3991,45 +4011,50 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Cargar datos extra: - + + Rewind affects save data + + + + GB BIOS file: Archivo de BIOS GB: - + GBA BIOS file: Archivo de BIOS GBA: - + GBC BIOS file: Archivo de BIOS GBC: - + Save games Guardados de juego - - - - + + + + Same directory as the ROM Mismo directorio de la ROM - + Save states Capturas de estado - + Screenshots Pantallazos - + Patches Parches From 00a01c7a8923343f0afab4a8b8f70db4b47049f8 Mon Sep 17 00:00:00 2001 From: rootfather Date: Wed, 1 Feb 2017 21:22:14 +0100 Subject: [PATCH 24/43] Qt: Add German GUI translation --- src/platform/qt/ts/mgba-de.ts | 4327 +++++++++++++++++++++++++++++++++ 1 file changed, 4327 insertions(+) create mode 100644 src/platform/qt/ts/mgba-de.ts diff --git a/src/platform/qt/ts/mgba-de.ts b/src/platform/qt/ts/mgba-de.ts new file mode 100644 index 000000000..6b748558c --- /dev/null +++ b/src/platform/qt/ts/mgba-de.ts @@ -0,0 +1,4327 @@ + + + + + AboutScreen + + + About + Über + + + + <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> + <a href="http://mgba.io/">Website</a> • <a href="https://forums.mgba.io/">Foren / Support</a> • <a href="https://patreon.com/mgba">Spenden</a> • <a href="https://github.com/mgba-emu/mgba/tree/{gitBranch}">Quellcode</a> + + + + {projectName} + {projectName} + + + + {projectName} would like to thank the following patrons from Patreon: + {projectName} möchte den folgenden Unterstützern auf Patreon danken: + + + + © 2013 – 2016 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 +Game Boy Advance is a registered trademark of Nintendo Co., Ltd. + © 2013 – 2016 Jeffrey Pfau, lizenziert unter der Mozilla Public License, Version 2.0 +Game Boy Advance ist ein eingetragenes Warenzeichen von Nintendo Co., Ltd. + + + + {patrons} + {patrons} + + + + {projectVersion} + {projectVersion} + + + + {logo} + {logo} + + + + {projectName} is an open-source Game Boy Advance emulator + {projectName} ist ein quelloffener Game Boy Advance-Emulator + + + + Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + + + + ArchiveInspector + + + Open in archive... + In Archiv öffnen... + + + + Loading... + Laden... + + + + AssetTile + + + AssetTile + AssetTile + + + + Tile # + Tile # + + + + 0 + 0 + + + + Address + Adresse + + + + 0x06000000 + 0x06000000 + + + + Red + Rot + + + + Green + Grün + + + + Blue + Blau + + + + + + 0x00 (00) + 0x00 (00) + + + + CheatsView + + + Cheats + Cheats + + + + Remove + Entfernen + + + + Save + Speichern + + + + Load + Laden + + + + Add New Set + Neues Set hinzufügen + + + + Add + Hinzufügen + + + + DebuggerConsole + + + Debugger + Debugger + + + + Enter command (try `help` for more info) + Geben Sie ein Kommando ein (versuchen Sie 'help' für weitere Informationen) + + + + Break + Unterbrechen + + + + GIFView + + + Record GIF + GIF aufzeichnen + + + + Start + Start + + + + Stop + Stop + + + + Select File + Datei wählen + + + + Frameskip + Frameskip + + + + Frame delay (ms) + Bildverzögerung (ms) + + + + Automatic + Automatisch + + + + IOViewer + + + I/O Viewer + I/O-Betrachter + + + + 0x0000 + 0x0000 + + + + 2 + 2 + + + + 5 + 5 + + + + 4 + 4 + + + + 7 + 7 + + + + 0 + 0 + + + + 9 + 9 + + + + 1 + 1 + + + + 3 + 3 + + + + 8 + 8 + + + + C + C + + + + E + E + + + + 6 + 6 + + + + D + D + + + + F + F + + + + A + A + + + + B + B + + + + LibraryView + + + Library + Bibliothek + + + + LoadSaveState + + + + %1 State + Savestate %1 + + + + + + + + + + + + No Save + Kein Savestate + + + + 1 + 1 + + + + 2 + 2 + + + + 3 + 3 + + + + 4 + 4 + + + + 5 + 5 + + + + 6 + 6 + + + + 7 + 7 + + + + 8 + 8 + + + + 9 + 9 + + + + LogView + + + Logs + Logs + + + + Enabled Levels + Aktivierte Log-Level + + + + Debug + Debug + + + + Stub + Stub + + + + Info + Info + + + + Warning + Warnung + + + + Error + Fehler + + + + Fatal + Fatal + + + + Game Error + Spiel-Fehler + + + + Clear + Leeren + + + + Max Lines + Max. Zeilen + + + + MemoryView + + + Memory + Speicher + + + + Inspect Address: + Untersuche Adresse: + + + + 0x + 0x + + + + Set Alignment: + Ausrichtung festlegen: + + + + 1 Byte + 1 Byte + + + + 2 Bytes + 2 Bytes + + + + 4 Bytes + 4 Bytes + + + + Signed Integer: + Signed Integer: + + + + String: + String: + + + + Load TBL + TBL laden + + + + Copy Selection + Auswahl kopieren + + + + Paste + Einfügen + + + + Save Selection + Auswahl speichern + + + + Load + Laden + + + + Unsigned Integer: + Unsigned Integer: + + + + ObjView + + + Sprites + Sprites + + + + + × + × + + + + Magnification + Vergrößerung + + + + Export + Exportieren + + + + Attributes + Eigenschaften + + + + Transform + Transform + + + + Off + Aus + + + + Palette + Palette + + + + + + + 0 + 0 + + + + Double Size + Doppelte Größe + + + + + + + Return, Ctrl+R + Eingabe, Strg+R + + + + Flipped + Gespiegelt + + + + H + H + + + + V + V + + + + Mode + Modus + + + + Normal + Normal + + + + Mosaic + Mosaic + + + + Enabled + Aktiviert + + + + Priority + Priorität + + + + Tile + + + + + Geometry + Geometrie + + + + Position + Position + + + + , + , + + + + Dimensions + Abmessungen + + + + + 8 + 8 + + + + Address + Adresse + + + + 0x07000000 + 0x07000000 + + + + OverrideView + + + Game Overrides + Spiel-Überschreibungen + + + + Game Boy Advance + Game Boy Advance + + + + + + + Autodetect + Automatisch erkennen + + + + Realtime clock + Echtzeituhr + + + + Gyroscope + Gyroskop + + + + Tilt + Neigungssensor + + + + Light sensor + Lichtsensor + + + + Rumble + Rüttel-Effekt + + + + Save type + Speichertyp + + + + + None + keiner + + + + SRAM + SRAM + + + + Flash 512kb + Flash 512kb + + + + Flash 1Mb + Flash 1Mb + + + + EEPROM + EEPROM + + + + Idle loop + Leerlaufprozess + + + + Game Boy Player features + Game Boy Player-Features + + + + Game Boy + Game Boy + + + + Game Boy model + Game Boy-Modell + + + + Game Boy (DMG) + Game Boy (DMG) + + + + Game Boy Color (CGB) + Game Boy Color (CGB) + + + + Game Boy Advance (AGB) + Game Boy Advance (AGB) + + + + Memory bank controller + Speicherbank-Controller + + + + MBC1 + MBC1 + + + + MBC2 + MBC2 + + + + MBC3 + MBC3 + + + + MBC3 + RTC + MBC3 + RTC + + + + MBC5 + MBC5 + + + + MBC5 + Rumble + MBC5 + Rumble + + + + MBC7 + MBC7 + + + + HuC-3 + HuC-3 + + + + PaletteView + + + Palette + Palette + + + + Background + Hintergrund + + + + Objects + Objekte + + + + Selection + Auswahl + + + + Red + Rot + + + + Green + Grün + + + + Blue + Blau + + + + + + 0x00 (00) + 0x00 (00) + + + + 16-bit value + 16-Bit-Wert + + + + Hex code + Hex-Code + + + + Palette index + Paletten-Index + + + + 0x0000 + 0x0000 + + + + #000000 + #000000 + + + + 000 + 000 + + + + Export BG + BG exportieren + + + + Export OBJ + OBJ exportieren + + + + QGBA::AssetTile + + + %0%1%2 + %0%1%2 + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + QGBA::CheatsModel + + + (untitled) + (unbenannt) + + + + Failed to open cheats file: %1 + Fehler beim Öffnen der Cheat-Datei: %1 + + + + QGBA::CheatsView + + + + Add GameShark + GameShark hinzufügen + + + + Add Pro Action Replay + Pro Action Replay hinzufügen + + + + Add CodeBreaker + CodeBreaker hinzufügen + + + + Add GameGenie + GameGenie hinzufügen + + + + + Select cheats file + Cheat-Datei auswählen + + + + QGBA::GBAKeyEditor + + + Clear Button + Button löschen + + + + Clear Analog + Analog löschen + + + + Refresh + Aktualisieren + + + + Set all + Alle belegen + + + + QGBA::GDBWindow + + + Server settings + Server-Einstellungen + + + + Local port + Lokaler Port + + + + Bind address + Bind-Adresse + + + + Break + Unterbrechen + + + + Stop + Stop + + + + Start + Start + + + + Crash + Absturz + + + + Could not start GDB server + Konnte GDB-Server nicht starten + + + + QGBA::GIFView + + + Failed to open output GIF file: %1 + Fehler beim Öffnen der Ausgabe-GIF-Datei: %1 + + + + Select output file + Ausgabedatei auswählen + + + + Graphics Interchange Format (*.gif) + Graphics Interchange Format (*.gif) + + + + QGBA::GameController + + + + Failed to open game file: %1 + Fehler beim Öffnen der Spieldatei: %1 + + + + Failed to open save file: %1 + Fehler beim Öffnen der Speicherdatei: %1 + + + + Failed to open snapshot file for reading: %1 + Konnte Snapshot-Datei %1 nicht zum Lesen öffnen + + + + Failed to open snapshot file for writing: %1 + Konnte Snapshot-Datei %1 nicht zum Schreiben öffnen + + + + Failed to start audio processor + Fehler beim Starten des Audio-Prozessors + + + + QGBA::IOViewer + + + Background mode + Hintergrund-Modus + + + + Mode 0: 4 tile layers + Mode 0: 4 Tile-Ebenen + + + + Mode 1: 2 tile layers + 1 rotated/scaled tile layer + Mode 1: 2 Tile-Ebenen + 1 rotierte/skalierte Tile-Ebene + + + + Mode 2: 2 rotated/scaled tile layers + Mode 2: 2 rotierte/skalierte Tile-Ebenen + + + + Mode 3: Full 15-bit bitmap + Mode 3: Volles 15-Bit-Bitmap + + + + Mode 4: Full 8-bit bitmap + Mode 4: Volles 8-Bit-Bitmap + + + + Mode 5: Small 15-bit bitmap + Mode 5: Kleines 15-Bit-Bitmap + + + + CGB Mode + CGB-Modus + + + + Frame select + Bildauswahl + + + + Unlocked HBlank + HBlank entsperrt + + + + Linear OBJ tile mapping + Lineares OBJ-Tile-Mapping + + + + Force blank screen + Leeren Bildschirm erzwingen + + + + Enable background 0 + Aktiviere Hintergrund 0 + + + + Enable background 1 + Aktiviere Hintergrund 1 + + + + Enable background 2 + Aktiviere Hintergrund 2 + + + + Enable background 3 + Aktiviere Hintergrund 3 + + + + Enable OBJ + Aktiviere OBJ + + + + Enable Window 0 + Aktiviere Fenster 0 + + + + Enable Window 1 + Aktiviere Fenster 1 + + + + Enable OBJ Window + Aktiviere OBJ-Fenster + + + + Currently in VBlank + Aktuell in VBlank + + + + Currently in HBlank + Aktuell in HBlank + + + + Currently in VCounter + Aktuell in VCounter + + + + Enable VBlank IRQ generation + Aktiviere VBlank IRQ-Generierung + + + + Enable HBlank IRQ generation + Aktiviere HBlank IRQ-Generierung + + + + Enable VCounter IRQ generation + Aktiviere VCounter IRQ-Generierung + + + + VCounter scanline + VCounter-Rasterzeile + + + + Current scanline + Aktuelle Rasterzeile + + + + + + + Priority + Priorität + + + + + + + Tile data base (* 16kB) + Tile-Daten-Basis (* 16kB) + + + + + + + Enable mosaic + Aktiviere Mosaic + + + + + + + Enable 256-color + Aktiviere 256 Farben + + + + + + + Tile map base (* 2kB) + Tile-Map-Basis (* 2kB) + + + + + + + Background dimensions + Hintergrund-Abmessungen + + + + + Overflow wraps + Umbrüche + + + + + + + Horizontal offset + Horizontaler Versatz + + + + + + + Vertical offset + Vertikaler Versatz + + + + + + + + + + + + + + + Fractional part + + + + + + + + + + + + Integer part + Ganzzahl-Anteil + + + + + + + Integer part (bottom) + Ganzzahl-Anteil (unten) + + + + + + + Integer part (top) + Ganzzahl-Anteil (oben) + + + + + End x + x-Endwert + + + + + Start x + x-Startwert + + + + + End y + y-Endwert + + + + + Start y + y-Startwert + + + + Window 0 enable BG 0 + Fenster 0: aktiviere BG 0 + + + + Window 0 enable BG 1 + Fenster 0: aktiviere BG 1 + + + + Window 0 enable BG 2 + Fenster 0: aktiviere BG2 + + + + Window 0 enable BG 3 + Fenster 0: aktiviere BG 3 + + + + Window 0 enable OBJ + Fenster 0: aktiviere OBJ + + + + Window 0 enable blend + Fenster 0: aktiviere Überblendung + + + + Window 1 enable BG 0 + Fenster 1: aktiviere BG 0 + + + + Window 1 enable BG 1 + Fenster 1: aktiviere BG 1 + + + + Window 1 enable BG 2 + Fenster 1: aktiviere BG 2 + + + + Window 1 enable BG 3 + Fenster 1: aktiviere BG 3 + + + + Window 1 enable OBJ + Fenster 1: Aktiviere OBJ + + + + Window 1 enable blend + Fenster 1: aktivieren Überblendung + + + + Outside window enable BG 0 + Äußeres Fenster: aktiviere BG 0 + + + + Outside window enable BG 1 + Äußeres Fenster: aktiviere BG 1 + + + + Outside window enable BG 2 + Äußeres Fenster: aktiviere BG 2 + + + + Outside window enable BG 3 + Äußeres Fenster: aktiviere BG 3 + + + + Outside window enable OBJ + Äußeres Fenster: aktiviere OBJ + + + + Outside window enable blend + Äußeres Fenster: aktiviere Überblendung + + + + OBJ window enable BG 0 + OBJ-Fenster: aktiviere BG 0 + + + + OBJ window enable BG 1 + OBJ-Fenster: aktiviere BG 1 + + + + OBJ window enable BG 2 + OBJ-Fenster: aktiviere BG 2 + + + + OBJ window enable BG 3 + OBJ-Fenster: aktiviere BG 3 + + + + OBJ window enable OBJ + OBJ-Fenster: aktiviere OBJ + + + + OBJ window enable blend + OBJ-Fenster: aktiviere Überblendung + + + + Background mosaic size vertical + Vertikale Größe der Hintergrund-Pixelierung + + + + Background mosaic size horizontal + Horizontale Größe der Hintergrund-Pixelierung + + + + Object mosaic size vertical + Vertikale Größe der Objekt-Pixelierung + + + + Object mosaic size horizontal + Horizontale Größe der Objekt-Pixelierung + + + + BG 0 target 1 + BG 0 Ziel 1 + + + + BG 1 target 1 + BG 1 Ziel 1 + + + + BG 2 target 1 + BG 2 Ziel 1 + + + + BG 3 target 1 + BG 3 Ziel 1 + + + + OBJ target 1 + OBJ Ziel 1 + + + + Backdrop target 1 + Hintergrund Ziel 1 + + + + Blend mode + Überblend-Modus + + + + Disabled + Deaktiviert + + + + Additive blending + Additive Überblendung + + + + Brighten + Aufhellen + + + + Darken + Abdunkeln + + + + BG 0 target 2 + BG 0 Ziel 2 + + + + BG 1 target 2 + BG 1 Ziel 2 + + + + BG 2 target 2 + BG 2 Ziel 2 + + + + BG 3 target 2 + BG 3 Ziel 2 + + + + OBJ target 2 + OBJ Ziel 2 + + + + Backdrop target 2 + Hintergrund Ziel 2 + + + + Blend A (target 1) + A Überblenden (Ziel 1) + + + + Blend B (target 2) + B Überblenden (Ziel 2) + + + + Blend Y + Y Überblenden + + + + Sweep shifts + + + + + Sweep subtract + + + + + Sweep time (in 1/128s) + + + + + + + + Sound length + Sound-Länge + + + + + Duty cycle + + + + + + + Envelope step time + + + + + + + Envelope increase + Hüllkurve erhöhen + + + + + + Initial volume + Initiale Lautstärke + + + + + + Sound frequency + Sound-Frequenz + + + + + + + Timed + + + + + + + + Reset + Reset + + + + Double-size wave table + + + + + Active wave table + Aktive Wave-Table + + + + Enable channel 3 + Aktiviere Kanal 3 + + + + Volume + Lautstärke + + + + 0% + 0% + + + + + 100% + 100% + + + + + 50% + 50% + + + + + 25% + 25% + + + + + + + 75% + 75% + + + + Clock divider + Frequenzteiler + + + + Register stages + + + + + 15 + 15 + + + + 7 + 7 + + + + Shifter frequency + + + + + PSG volume right + PSG-Lautstärke rechts + + + + PSG volume left + PSG-Lautstärke links + + + + Enable channel 1 right + Aktiviere Kanal 1 rechts + + + + Enable channel 2 right + Aktiviere Kanal 2 rechts + + + + Enable channel 3 right + Aktiviere Kanal 3 rechts + + + + Enable channel 4 right + Aktiviere Kanal 4 rechts + + + + Enable channel 1 left + Aktiviere Kanal 1 links + + + + Enable channel 2 left + Aktiviere Kanal 2 links + + + + Enable channel 3 left + Aktiviere Kanal 3 links + + + + Enable channel 4 left + Aktiviere Kanal 4 links + + + + PSG master volume + PSG-Master-Lauststärke + + + + Loud channel A + + + + + Loud channel B + + + + + Enable channel A right + Aktiviere Kanal A rechts + + + + Enable channel A left + Aktiviere Kanal A links + + + + Channel A timer + Kanal A-Zeitgeber + + + + + 0 + 0 + + + + + + + + + + + + 1 + 1 + + + + Channel A reset + Kanal A zurücksetzen + + + + Enable channel B right + Aktiviere Kanal B rechts + + + + Enable channel B left + Aktiviere Kanal B links + + + + Channel B timer + Kanal B-Zeitgeber + + + + Channel B reset + Kanal B zurücksetzen + + + + Active channel 1 + Kanal 1 aktiv + + + + Active channel 2 + Kanal 2 aktiv + + + + Active channel 3 + Kanal 3 aktiv + + + + Active channel 4 + Kanal 4 aktiv + + + + Enable audio + Audio aktivieren + + + + Bias + + + + + Resolution + Auflösung + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sample + Sample + + + + + + + + + + + Address (bottom) + Adresse (unten) + + + + + + + + + + + Address (top) + Adresse (oben) + + + + + + + Word count + Wort-Anzahl + + + + + + + Destination offset + Zielversatz + + + + + + + + + + + Increment + Erhöhen + + + + + + + + + + + Decrement + Verringern + + + + + + + + + + + Fixed + Fest + + + + + + + Increment and reload + Erhöhen und neu laden + + + + + + + Source offset + Quellversatz + + + + + + + Repeat + Wiederholen + + + + + + + 32-bit + 32-Bit + + + + + + + Start timing + + + + + + + + Immediate + Unmittelbar + + + + + + + + + VBlank + VBlank + + + + + + + + + HBlank + HBlank + + + + + + + + + + + + IRQ + IRQ + + + + + + + + + + + Enable + Aktivieren + + + + + + Audio FIFO + Audio FIFO + + + + Video Capture + Videoaufzeichnung + + + + DRQ + DRQ + + + + + + + Value + Wert + + + + + + + Scale + Skalierung + + + + + + + 1/64 + 1/64 + + + + + + + 1/256 + 1/256 + + + + + + + 1/1024 + 1/1024 + + + + + + Cascade + Kaskade + + + + + A + A + + + + + B + B + + + + + Select + Select + + + + + Start + Start + + + + + Right + Rechts + + + + + Left + Links + + + + + Up + Oben + + + + + Down + Unten + + + + + R + R + + + + + L + L + + + + Condition + Zustand + + + + SC + SC + + + + SD + SD + + + + SI + SI + + + + SO + SO + + + + + VCounter + VCounter + + + + + Timer 0 + Zähler 0 + + + + + Timer 1 + Zähler 1 + + + + + Timer 2 + Zähler 2 + + + + + Timer 3 + Zähler 3 + + + + + SIO + SIO + + + + + DMA 0 + DMA 0 + + + + + DMA 1 + DMA 1 + + + + + DMA 2 + DMA 2 + + + + + DMA 3 + DMA 3 + + + + + Keypad + + + + + + Gamepak + Spielmodul + + + + SRAM wait + Warten auf SRAM + + + + + + + + 4 + 4 + + + + + + + 3 + 3 + + + + + + + + 2 + 2 + + + + + + + + 8 + 8 + + + + Cart 0 non-sequential + Modul 0 nicht-sequenziell + + + + Cart 0 sequential + Modul 0 sequenziell + + + + Cart 1 non-sequential + Modul 1 nicht-sequenziell + + + + Cart 1 sequential + Modul 1 sequenziell + + + + Cart 2 non-sequential + Modul 2 nicht-sequenziell + + + + Cart 2 sequential + Modul 2 sequenziell + + + + PHI terminal + + + + + Disable + Deaktivieren + + + + 4.19MHz + 4.19MHz + + + + 8.38MHz + 8.38MHz + + + + 16.78MHz + 16.78MHz + + + + Gamepak prefetch + Spielmodul vorladen + + + + Enable IRQs + Aktiviere IRQs + + + + QGBA::KeyEditor + + + + --- + --- + + + + QGBA::LibraryModel + + + Name + Name + + + + Filename + Dateiname + + + + Size + Größe + + + + Platform + Plattform + + + + GBA + GBA + + + + GB + GB + + + + ? + ? + + + + Location + Ort + + + + CRC32 + CRC32 + + + + QGBA::LoadSaveState + + + Load State + Savestate laden + + + + Save State + Savestate speichern + + + + Empty + Leer + + + + Corrupted + Defekt + + + + Slot %1 + Speicherplatz %1 + + + + QGBA::LogController + + + DEBUG + DEBUG + + + + STUB + STUB + + + + INFO + INFO + + + + WARN + WARN + + + + ERROR + ERROR + + + + FATAL + FATAL + + + + GAME ERROR + GAME ERROR + + + + QGBA::MemoryModel + + + Copy selection + Auswahl kopieren + + + + Save selection + Auswahl speichern + + + + Paste + Einfügen + + + + Load + Laden + + + + + All + Alle + + + + Load TBL + TBL laden + + + + Save selected memory + Ausgewählten Speicher abspeichern + + + + Failed to open output file: %1 + Fehler beim Öffnen der Ausgabedatei: %1 + + + + Load memory + Lade Speicher + + + + Failed to open input file: %1 + Fehler beim Laden der Eingabedatei: %1 + + + + TBL + TBL + + + + ISO-8859-1 + ISO-8859-1 + + + + QGBA::ObjView + + + + 0x%0 + 0x%0 + + + + Off + Aus + + + + Normal + Normal + + + + Trans + Trans + + + + OBJWIN + OBJWIN + + + + Invalid + Ungültig + + + + + N/A + N/A + + + + Export sprite + Sprite exportieren + + + + Portable Network Graphics (*.png) + Portable Network Graphics (*.png) + + + + Failed to open output PNG file: %1 + Fehler beim Öffnen der Ausgabe-PNG-Datei: %1 + + + + QGBA::PaletteView + + + #%0 + #%0 + + + + 0x%0 + 0x%0 + + + + %0 + %0 + + + + + + 0x%0 (%1) + 0x%0 (%1) + + + + Export palette + Palette exportieren + + + + Windows PAL (*.pal);;Adobe Color Table (*.act) + Windows PAL (*.pal);;Adobe Color Table (*.act) + + + + Failed to open output palette file: %1 + Fehler beim Öffnen der Ausgabe-Palettendatei: %1 + + + + QGBA::ROMInfo + + + + + + + (unknown) + (unbekannt) + + + + + bytes + Bytes + + + + (no database present) + (keine Datenbank vorhanden) + + + + QGBA::SettingsView + + + Qt Multimedia + Qt Multimedia + + + + SDL + SDL + + + + Software (Qt) + Software (Qt) + + + + OpenGL + OpenGL + + + + OpenGL (force version 1.x) + OpenGL (erzwinge Version 1.x) + + + + Keyboard + Tastatur + + + + Controllers + Gamepads + + + + Shortcuts + Tastenkürzel + + + + Select BIOS + BIOS auswählen + + + + QGBA::ShaderSelector + + + No shader active + Kein Shader aktiv + + + + Load shader + Shader laden + + + + %1 Shader (%.shader) + %1 Shader (%.shader) + + + + No shader loaded + Kein Shader geladen + + + + by %1 + von %1 + + + + Preprocessing + Vorbehandlung + + + + Pass %1 + Durchlauf %1 + + + + QGBA::ShortcutController + + + Action + Aktion + + + + Keyboard + Tastatur + + + + Gamepad + Gamepad + + + + QGBA::VideoView + + + Failed to open output video file: %1 + Fehler beim Öffnen der Ausgabe-Videodatei: %1 + + + + Native (%0x%1) + Nativ (%0x%1) + + + + Select output file + Ausgabedatei auswählen + + + + QGBA::Window + + + Game Boy Advance ROMs (%1) + Game Boy Advance-ROMs (%1) + + + + Game Boy ROMs (%1) + Game Boy-ROMs (%1) + + + + All ROMs (%1) + Alle ROMs (%1) + + + + Archives (%1) + Archive (%1) + + + + + + Select ROM + ROM auswählen + + + + Game Boy Advance save files (%1) + Game Boy Advance-Speicherdateien (%1) + + + + + + Select save + Speicherdatei wählen + + + + Select patch + Patch wählen + + + + Patches (*.ips *.ups *.bps) + Patches (*.ips *.ups *.bps) + + + + + GameShark saves (*.sps *.xps) + GameShark-Speicherdaten (*.sps *.xps) + + + + Crash + Absturz + + + + The game has crashed with the following error: + +%1 + Das Spiel ist mit der folgenden Fehlermeldung abgestürzt: + +%1 + + + + Couldn't Load + Konnte nicht geladen werden + + + + Could not load game. Are you sure it's in the correct format? + Konnte das Spiel nicht laden. Sind Sie sicher, dass es im korrekten Format vorliegt? + + + + Unimplemented BIOS call + Nichtimplementierter BIOS-Aufruf + + + + This game uses a BIOS call that is not implemented. Please use the official BIOS for best experience. + Dieses Spiel verwendet einen BIOS-Aufruf, der nicht implementiert ist. Bitte verwenden Sie für die beste Spielerfahrung das offizielle BIOS. + + + + Really make portable? + Portablen Modus wirklich aktivieren? + + + + This will make the emulator load its configuration from the same directory as the executable. Do you want to continue? + Diese Einstellung wird den Emulator so konfigurieren, dass er seine Konfiguration aus dem gleichen Verzeichnis wie die Programmdatei lädt. Möchten Sie fortfahren? + + + + Restart needed + Neustart benötigt + + + + Some changes will not take effect until the emulator is restarted. + Einige Änderungen werden erst übernommen, wenn der Emulator neu gestartet wurde. + + + + - Player %1 of %2 + - Spieler %1 von %2 + + + + %1 - %2 + %1 - %2 + + + + %1 - %2 - %3 + %1 - %2 - %3 + + + + %1 - %2 (%3 fps) - %4 + %1 - %2 (%3 Bilder/Sekunde) - %4 + + + + &File + &Datei + + + + Load &ROM... + &ROM laden... + + + + Load ROM in archive... + ROM aus Archiv laden... + + + + Load temporary save... + Temporäre Speicherdatei laden... + + + + Load &patch... + &Patch laden... + + + + Boot BIOS + BIOS booten + + + + Replace ROM... + ROM ersetzen... + + + + ROM &info... + ROM-&Informationen... + + + + Recent + Zuletzt verwendet + + + + Make portable + Portablen Modus aktivieren + + + + &Load state + Savestate &laden + + + + F10 + F10 + + + + &Save state + Savestate &speichern + + + + Shift+F10 + Umschalt+F10 + + + + Quick load + Schnell laden + + + + Quick save + Schnell speichern + + + + Load recent + Lade zuletzt gespeicherten Savestate + + + + Save recent + Speichere aktuellen Stand + + + + Undo load state + Laden des Savestate rückgängig machen + + + + F11 + F11 + + + + Undo save state + Speichern des Savestate rückgängig machen + + + + Shift+F11 + Umschalt+F11 + + + + + State &%1 + Savestate &%1 + + + + F%1 + F%1 + + + + Shift+F%1 + Umschalt+F%1 + + + + Import GameShark Save + Importiere GameShark-Speicherstand + + + + Export GameShark Save + Exportiere GameShark-Speicherstand + + + + New multiplayer window + Neues Multiplayer-Fenster + + + + About + Über + + + + E&xit + &Beenden + + + + &Emulation + &Emulation + + + + &Reset + Zu&rücksetzen + + + + Ctrl+R + Strg+R + + + + Sh&utdown + B&eenden + + + + Yank game pak + Spielmodul herausziehen + + + + &Pause + &Pause + + + + Ctrl+P + Strg+P + + + + &Next frame + &Nächstes Bild + + + + Ctrl+N + Strg+N + + + + Fast forward (held) + Schneller Vorlauf (gehalten) + + + + &Fast forward + Schneller &Vorlauf + + + + Shift+Tab + Umschalt+Tab + + + + Fast forward speed + Vorlauf-Geschwindigkeit + + + + Unbounded + Unbegrenzt + + + + %0x + %0x + + + + Rewind (held) + Zurückspulen (gehalten) + + + + Re&wind + Zur&ückspulen + + + + ~ + ~ + + + + Step backwards + Schrittweiser Rücklauf + + + + Ctrl+B + Strg+B + + + + Sync to &video + Mit &Video synchronisieren + + + + Sync to &audio + Mit &Audio synchronisieren + + + + Solar sensor + Solar-Sensor + + + + Increase solar level + Sonnen-Level erhöhen + + + + Decrease solar level + Sonnen-Level verringern + + + + Brightest solar level + Hellster Sonnen-Level + + + + Darkest solar level + Dunkelster Sonnen-Level + + + + Brightness %1 + Helligkeit %1 + + + + Audio/&Video + Audio/&Video + + + + Frame size + Bildgröße + + + + %1x + %1x + + + + Toggle fullscreen + Vollbildmodus umschalten + + + + Lock aspect ratio + Seitenverhältnis sperren + + + + Frame&skip + Frame&skip + + + + Shader options... + Shader-Optionen... + + + + Mute + Stummschalten + + + + FPS target + Bildwiederholrate + + + + 15 + 15 + + + + 30 + 30 + + + + 45 + 45 + + + + Native (59.7) + Nativ (59.7) + + + + 60 + 60 + + + + 90 + 90 + + + + 120 + 120 + + + + 240 + 240 + + + + Take &screenshot + &Screenshot erstellen + + + + F12 + F12 + + + + Record output... + Ausgabe aufzeichen... + + + + Record GIF... + GIF aufzeichen... + + + + Video layers + Video-Ebenen + + + + Background %0 + Hintergrund %0 + + + + OBJ (sprites) + OBJ (Sprites) + + + + Audio channels + Audio-Kanäle + + + + Channel %0 + Kanal %0 + + + + Channel A + Kanal A + + + + Channel B + Kanal B + + + + &Tools + &Werkzeuge + + + + View &logs... + &Logs ansehen... + + + + Game &overrides... + Spiel-&Überschreibungen... + + + + Game &Pak sensors... + Game &Pak-Sensoren... + + + + &Cheats... + &Cheats... + + + + Open debugger console... + Debugger-Konsole äffnen... + + + + Start &GDB server... + &GDB-Server starten... + + + + Settings... + Einstellungen... + + + + Select folder + Ordner auswählen + + + + Add folder to library... + Ordner zur Bibliothek hinzufügen... + + + + Bilinear filtering + Bilineare Filterung + + + + View &palette... + &Palette betrachten... + + + + View &sprites... + &Sprites betrachten... + + + + View &tiles... + &Tiles betrachten... + + + + View memory... + Speicher betrachten... + + + + View &I/O registers... + &I/O-Register betrachten... + + + + Exit fullscreen + Vollbildmodus beenden + + + + Autofire + Autofeuer + + + + Autofire A + Autofeuer A + + + + Autofire B + Autofeuer B + + + + Autofire L + Autofeuer L + + + + Autofire R + Autofeuer R + + + + Autofire Start + Autofeuer Start + + + + Autofire Select + Autofeuer Select + + + + Autofire Up + Autofeuer nach oben + + + + Autofire Right + Autofeuer rechts + + + + Autofire Down + Autofeuer nach unten + + + + Autofire Left + Autofeuer links + + + + ROMInfo + + + ROM Info + ROM-Info + + + + Game name: + Spiel-Name: + + + + {NAME} + {NAME} + + + + Internal name: + Interner Name: + + + + {TITLE} + {TITLE} + + + + Game ID: + Spiele-ID: + + + + {ID} + {ID} + + + + File size: + Dateigröße: + + + + {SIZE} + {SIZE} + + + + CRC32: + CRC32: + + + + {CRC} + {CRC} + + + + SensorView + + + Sensors + Sensoren + + + + Realtime clock + Echtzeituhr + + + + Fixed time + Feste Zeit + + + + System time + Systemzeit + + + + Start time at + Starte Zeit ab + + + + Now + Jetzt + + + + MM/dd/yy hh:mm:ss AP + dd/mm/yy hh:mm:ss + + + + Light sensor + Lichtsensor + + + + Brightness + Helligkeit + + + + Tilt sensor + Neigungssensor + + + + + Set Y + Setze Y + + + + + Set X + Setze X + + + + Gyroscope + Gyroskop + + + + Sensitivity + Empfindlichkeit + + + + SettingsView + + + Settings + Einstellungen + + + + Audio/Video + Audio/Video + + + + Interface + Benutzeroberfläche + + + + Emulation + Emulation + + + + Paths + Verzeichnisse + + + + Audio driver: + Audio-Treiber: + + + + Audio buffer: + Audio-Puffer: + + + + + 1536 + 1536 + + + + 512 + 512 + + + + 768 + 768 + + + + 1024 + 1024 + + + + 2048 + 2048 + + + + 3072 + 3072 + + + + 4096 + 4096 + + + + samples + Samples + + + + Sample rate: + Sample-Rate: + + + + + 44100 + 44100 + + + + 22050 + 22050 + + + + 32000 + 32000 + + + + 48000 + 48000 + + + + Hz + Hz + + + + Volume: + Lautstärke: + + + + Mute + Stummschalten + + + + Display driver: + Anzeige-Treiber: + + + + Frameskip: + Frameskip: + + + + Skip every + Alle + + + + + frames + Bilder + + + + FPS target: + Bildwiederholrate: + + + + frames per second + Bilder pro Sekunde + + + + Sync: + Synchronisierung: + + + + Video + Video + + + + Audio + Audio + + + + Lock aspect ratio + Seitenverhältnis sperren + + + + Library: + Bibliothek: + + + + Show when no game open + Anzeigen, wenn kein Spiel geöffnet ist + + + + Clear cache + Cache leeren + + + + Fast forward speed: + Vorlauf-Geschwindigkeit: + + + + Rewind affects save data + Rücklauf beeinflusst +Speicherdaten + + + + + + + + + + Browse + Durchsuchen + + + + Use BIOS file if found + BIOS-Datei verwenden, wenn vorhanden + + + + Skip BIOS intro + BIOS-Intro überspringen + + + + × + × + + + + Unbounded + unbegrenzt + + + + Suspend screensaver + Bildschirmschoner deaktivieren + + + + BIOS + BIOS + + + + Pause when inactive + Pause, wenn inaktiv + + + + Run all + Alle ausführen + + + + Remove known + Bekannte entfernen + + + + Detect and remove + Erkennen und entfernen + + + + Allow opposing input directions + Gegensätzliche Eingaberichtungen erlauben + + + + + Screenshot + Screenshot + + + + + Save data + Speicherdaten + + + + + Cheat codes + Cheat-Codes + + + + Enable rewind + Rücklauf aktivieren + + + + Bilinear filtering + Bilineare Filterung + + + + Rewind history: + Rücklauf-Verlauf: + + + + Idle loops: + Leerlaufprozesse: + + + + Savestate extra data: + Zusätzliche Savestate-Daten: + + + + Load extra data: + Lade zusätzliche Daten: + + + + GB BIOS file: + BIOS-Datei für GB: + + + + GBA BIOS file: + BIOS-Datei für GBA: + + + + GBC BIOS file: + BIOS-Datei für GBC: + + + + Save games + Spielstände + + + + + + + Same directory as the ROM + Gleiches Verzeichnis wie ROM + + + + Save states + Savestates + + + + Screenshots + Screenshots + + + + Patches + Patches + + + + ShaderSelector + + + Shaders + Shader + + + + Active Shader: + Aktiver Shader: + + + + Name + Name + + + + Author + Autor + + + + Description + Beschreibung + + + + Unload Shader + Shader entladen + + + + Load New Shader + Neuen Shader laden + + + + ShortcutView + + + Edit Shortcuts + Tastenkürzel bearbeiten + + + + Keyboard + Tastatur + + + + Gamepad + Gamepad + + + + Clear + Löschen + + + + TileView + + + Tiles + Tiles + + + + 256 colors + 256 Farben + + + + × + × + + + + Magnification + Vergrößerung + + + + VideoView + + + Record Video + Video aufzeichen + + + + Start + Start + + + + Stop + Stop + + + + Select File + Datei wählen + + + + Presets + Vorgaben + + + + High Quality + Hohe Qualität + + + + YouTube + YouTube + + + + + WebM + WebM + + + + Lossless + Verlustfrei + + + + 1080p + 1080p + + + + 720p + 720p + + + + 480p + 480p + + + + Native + Nativ + + + + Format + Format + + + + MKV + MKV + + + + AVI + AVI + + + + MP4 + MP4 + + + + PNG + PNG + + + + h.264 + h.264 + + + + VP8 + VP8 + + + + Xvid + Xvid + + + + FFV1 + FFV1 + + + + FLAC + FLAC + + + + Opus + Opus + + + + Vorbis + Vorbis + + + + MP3 + MP3 + + + + AAC + AAC + + + + Uncompressed + Unkomprimiert + + + + Bitrate (kbps) + Bitrate (kbps) + + + + VBR + VBR + + + + ABR + ABR + + + + Dimensions + Abmessungen + + + + : + : + + + + × + × + + + + Lock aspect ratio + Seitenverhältnis sperren + + + + Show advanced + Erweiterte Optionen anzeigen + + + From d4a9b84b85a34969050b0a769a6816ffff2dc86c Mon Sep 17 00:00:00 2001 From: rootfather Date: Wed, 1 Feb 2017 21:23:44 +0100 Subject: [PATCH 25/43] Doc: Mention German GUI translation in CHANGES --- CHANGES | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES b/CHANGES index af7f033bb..b4745c48d 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,7 @@ Features: - 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) Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior From b54a4ba555eaac0de79107db1c321c811980187c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 7 Feb 2017 13:19:45 -0800 Subject: [PATCH 26/43] Util: Fix highest-fd socket not being returned by SocketAccept --- CHANGES | 1 + include/mgba-util/socket.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index af7f033bb..10372382f 100644 --- a/CHANGES +++ b/CHANGES @@ -25,6 +25,7 @@ Bugfixes: - 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 Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/include/mgba-util/socket.h b/include/mgba-util/socket.h index 327c2c69c..ad00696c0 100644 --- a/include/mgba-util/socket.h +++ b/include/mgba-util/socket.h @@ -293,10 +293,11 @@ static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Soc errors[i] = INVALID_SOCKET; } } + ++maxFd; struct timeval tv; tv.tv_sec = timeoutMillis / 1000; tv.tv_usec = (timeoutMillis % 1000) * 1000; - int result = select(maxFd + 1, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv); + int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv); int r = 0; int w = 0; int e = 0; From f026c900892409d92b588f5789108f9079732af2 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 7 Feb 2017 13:52:05 -0800 Subject: [PATCH 27/43] Util: Add Vector copy --- include/mgba-util/vector.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/mgba-util/vector.h b/include/mgba-util/vector.h index 0839d61b2..664221b7d 100644 --- a/include/mgba-util/vector.h +++ b/include/mgba-util/vector.h @@ -27,7 +27,8 @@ CXX_GUARD_START void NAME ## Unshift(struct NAME* vector, size_t location, size_t difference); \ void NAME ## EnsureCapacity(struct NAME* vector, size_t capacity); \ size_t NAME ## Size(const struct NAME* vector); \ - size_t NAME ## Index(const struct NAME* vector, const TYPE* member); + size_t NAME ## Index(const struct NAME* vector, const TYPE* member); \ + void NAME ## Copy(struct NAME* dest, const struct NAME* src); #define DEFINE_VECTOR(NAME, TYPE) \ void NAME ## Init(struct NAME* vector, size_t capacity) { \ @@ -85,6 +86,11 @@ CXX_GUARD_START size_t NAME ## Index(const struct NAME* vector, const TYPE* member) { \ return member - (const TYPE*) vector->vector; \ } \ + void NAME ## Copy(struct NAME* dest, const struct NAME* src) { \ + NAME ## EnsureCapacity(dest, src->size); \ + memcpy(dest->vector, src->vector, src->size * sizeof(TYPE)); \ + dest->size = src->size; \ + } \ CXX_GUARD_END From be3e884ba51609b058b0da46c7e8bded3d2a7376 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 7 Feb 2017 15:42:39 -0800 Subject: [PATCH 28/43] Qt: Fix linking after some windows have been closed --- CHANGES | 1 + src/platform/qt/GBAApp.cpp | 47 +++++++++++++++++++------------------- src/platform/qt/GBAApp.h | 7 +++--- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/CHANGES b/CHANGES index 10372382f..2559db215 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,7 @@ Bugfixes: - 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 Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/src/platform/qt/GBAApp.cpp b/src/platform/qt/GBAApp.cpp index 20e254d9e..f59368b83 100644 --- a/src/platform/qt/GBAApp.cpp +++ b/src/platform/qt/GBAApp.cpp @@ -33,7 +33,6 @@ mLOG_DEFINE_CATEGORY(QT, "Qt"); GBAApp::GBAApp(int& argc, char* argv[]) : QApplication(argc, argv) - , m_windows{} , m_db(nullptr) { g_app = this; @@ -80,10 +79,10 @@ GBAApp::GBAApp(int& argc, char* argv[]) AudioProcessor::setDriver(static_cast(m_configController.getQtOption("audioDriver").toInt())); } Window* w = new Window(&m_configController); - connect(w, &Window::destroyed, [this]() { - m_windows[0] = nullptr; + connect(w, &Window::destroyed, [this, w]() { + m_windows.removeAll(w); }); - m_windows[0] = w; + m_windows.append(w); if (loaded) { w->argumentsPassed(&args); @@ -121,15 +120,15 @@ bool GBAApp::event(QEvent* event) { } Window* GBAApp::newWindow() { - if (m_multiplayer.attached() >= MAX_GBAS) { + if (m_windows.count() >= MAX_GBAS) { return nullptr; } Window* w = new Window(&m_configController, m_multiplayer.attached()); int windowId = m_multiplayer.attached(); - connect(w, &Window::destroyed, [this, windowId]() { - m_windows[windowId] = nullptr; + connect(w, &Window::destroyed, [this, w]() { + m_windows.removeAll(w); }); - m_windows[windowId] = w; + m_windows.append(w); w->setAttribute(Qt::WA_DeleteOnClose); w->loadConfig(); w->show(); @@ -142,27 +141,27 @@ GBAApp* GBAApp::app() { return g_app; } -void GBAApp::pauseAll(QList* paused) { - for (int i = 0; i < MAX_GBAS; ++i) { - if (!m_windows[i] || !m_windows[i]->controller()->isLoaded() || m_windows[i]->controller()->isPaused()) { +void GBAApp::pauseAll(QList* paused) { + for (auto& window : m_windows) { + if (!window->controller()->isLoaded() || window->controller()->isPaused()) { continue; } - m_windows[i]->controller()->setPaused(true); - paused->append(i); + window->controller()->setPaused(true); + paused->append(window); } } -void GBAApp::continueAll(const QList* paused) { - for (int i : *paused) { - m_windows[i]->controller()->setPaused(false); +void GBAApp::continueAll(const QList& paused) { + for (auto& window : paused) { + window->controller()->setPaused(false); } } QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QString& filter) { - QList paused; + QList paused; pauseAll(&paused); QString filename = QFileDialog::getOpenFileName(owner, title, m_configController.getOption("lastDirectory"), filter); - continueAll(&paused); + continueAll(paused); if (!filename.isEmpty()) { m_configController.setOption("lastDirectory", QFileInfo(filename).dir().path()); } @@ -170,10 +169,10 @@ QString GBAApp::getOpenFileName(QWidget* owner, const QString& title, const QStr } QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QString& filter) { - QList paused; + QList paused; pauseAll(&paused); QString filename = QFileDialog::getSaveFileName(owner, title, m_configController.getOption("lastDirectory"), filter); - continueAll(&paused); + continueAll(paused); if (!filename.isEmpty()) { m_configController.setOption("lastDirectory", QFileInfo(filename).dir().path()); } @@ -181,10 +180,10 @@ QString GBAApp::getSaveFileName(QWidget* owner, const QString& title, const QStr } QString GBAApp::getOpenDirectoryName(QWidget* owner, const QString& title) { - QList paused; + QList paused; pauseAll(&paused); QString filename = QFileDialog::getExistingDirectory(owner, title, m_configController.getOption("lastDirectory")); - continueAll(&paused); + continueAll(paused); if (!filename.isEmpty()) { m_configController.setOption("lastDirectory", QFileInfo(filename).dir().path()); } @@ -249,14 +248,14 @@ GBAApp::FileDialog::FileDialog(GBAApp* app, QWidget* parent, const QString& capt } int GBAApp::FileDialog::exec() { - QList paused; + QList paused; m_app->pauseAll(&paused); bool didAccept = QFileDialog::exec() == QDialog::Accepted; QStringList filenames = selectedFiles(); if (!filenames.isEmpty()) { m_app->m_configController.setOption("lastDirectory", QFileInfo(filenames[0]).dir().path()); } - m_app->continueAll(&paused); + m_app->continueAll(paused); return didAccept; } diff --git a/src/platform/qt/GBAApp.h b/src/platform/qt/GBAApp.h index 29ddfa2d3..8ade195e1 100644 --- a/src/platform/qt/GBAApp.h +++ b/src/platform/qt/GBAApp.h @@ -39,7 +39,6 @@ private: }; #endif - class GBAApp : public QApplication { Q_OBJECT @@ -78,11 +77,11 @@ private: Window* newWindowInternal(); - void pauseAll(QList* paused); - void continueAll(const QList* paused); + void pauseAll(QList* paused); + void continueAll(const QList& paused); ConfigController m_configController; - Window* m_windows[MAX_GBAS]; + QList m_windows; MultiplayerController m_multiplayer; NoIntroDB* m_db; From 3ac0b20ff86438bcea93ad610aeef184781fa9e3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 8 Feb 2017 11:34:05 -0800 Subject: [PATCH 29/43] Core: Cores can now have multiple sets of callbacks --- CHANGES | 1 + include/mgba/core/core.h | 3 ++- include/mgba/core/interface.h | 4 ++++ include/mgba/internal/gb/gb.h | 4 ++-- include/mgba/internal/gba/gba.h | 2 +- src/core/interface.c | 2 ++ src/core/thread.c | 4 ++-- src/gb/core.c | 12 +++++++++--- src/gb/gb.c | 3 ++- src/gb/video.c | 18 ++++++++++++------ src/gba/core.c | 12 +++++++++--- src/gba/gba.c | 21 ++++++++++++++------- src/gba/memory.c | 10 ++++++++-- 13 files changed, 68 insertions(+), 28 deletions(-) diff --git a/CHANGES b/CHANGES index 2559db215..a14b55548 100644 --- a/CHANGES +++ b/CHANGES @@ -68,6 +68,7 @@ Misc: - 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 0.5.2: (2016-12-31) Bugfixes: diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 06c7a7184..980322ebd 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -73,7 +73,8 @@ struct mCore { void (*setAudioBufferSize)(struct mCore*, size_t samples); size_t (*getAudioBufferSize)(struct mCore*); - void (*setCoreCallbacks)(struct mCore*, struct mCoreCallbacks*); + void (*addCoreCallbacks)(struct mCore*, struct mCoreCallbacks*); + void (*clearCoreCallbacks)(struct mCore*); void (*setAVStream)(struct mCore*, struct mAVStream*); bool (*isROM)(struct VFile* vf); diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index 2e78390cf..40eb099d6 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -10,6 +10,8 @@ CXX_GUARD_START +#include + struct mCore; #ifdef COLOR_16_BIT @@ -37,6 +39,8 @@ struct mCoreCallbacks { void (*coreCrashed)(void* context); }; +DECLARE_VECTOR(mCoreCallbacksList, struct mCoreCallbacks); + struct mAVStream { void (*videoDimensionsChanged)(struct mAVStream*, unsigned width, unsigned height); void (*postVideoFrame)(struct mAVStream*, const color_t* buffer, size_t stride); diff --git a/include/mgba/internal/gb/gb.h b/include/mgba/internal/gb/gb.h index db3adf6cc..05362c7bd 100644 --- a/include/mgba/internal/gb/gb.h +++ b/include/mgba/internal/gb/gb.h @@ -11,6 +11,7 @@ CXX_GUARD_START #include +#include #include #include @@ -46,7 +47,6 @@ enum GBIRQVector { struct LR35902Core; struct mCoreSync; struct mAVStream; -struct mCoreCallbacks; struct GB { struct mCPUComponent d; @@ -76,7 +76,7 @@ struct GB { int32_t sramDirtAge; bool sramMaskWriteback; - struct mCoreCallbacks* coreCallbacks; + struct mCoreCallbacksList coreCallbacks; struct mAVStream* stream; bool cpuBlocked; diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index e27f6cbc0..e5b1f8899 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -100,7 +100,7 @@ struct GBA { struct mAVStream* stream; struct mKeyCallback* keyCallback; struct mStopCallback* stopCallback; - struct mCoreCallbacks* coreCallbacks; + struct mCoreCallbacksList coreCallbacks; enum GBAIdleLoopOptimization idleOptimization; uint32_t idleLoop; diff --git a/src/core/interface.c b/src/core/interface.c index 5317da562..75e171b3d 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -7,6 +7,8 @@ #include +DEFINE_VECTOR(mCoreCallbacksList, struct mCoreCallbacks); + static time_t _rtcGenericCallback(struct mRTCSource* source) { struct mRTCGenericSource* rtc = (struct mRTCGenericSource*) source; switch (rtc->override) { diff --git a/src/core/thread.c b/src/core/thread.c index 3ffa7c477..3ed5aeb1c 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -143,7 +143,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { .coreCrashed = _crashed, .context = threadContext }; - core->setCoreCallbacks(core, &callbacks); + core->addCoreCallbacks(core, &callbacks); core->setSync(core, &threadContext->sync); core->reset(core); @@ -223,7 +223,7 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { if (threadContext->cleanCallback) { threadContext->cleanCallback(threadContext); } - core->setCoreCallbacks(core, NULL); + core->clearCoreCallbacks(core); return 0; } diff --git a/src/gb/core.c b/src/gb/core.c index df64296c9..87ad3558a 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -156,9 +156,14 @@ static size_t _GBCoreGetAudioBufferSize(struct mCore* core) { return gb->audio.samples; } -static void _GBCoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { +static void _GBCoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { struct GB* gb = core->board; - gb->coreCallbacks = coreCallbacks; + *mCoreCallbacksListAppend(&gb->coreCallbacks) = *coreCallbacks; +} + +static void _GBCoreClearCoreCallbacks(struct mCore* core) { + struct GB* gb = core->board; + mCoreCallbacksListClear(&gb->coreCallbacks); } static void _GBCoreSetAVStream(struct mCore* core, struct mAVStream* stream) { @@ -576,7 +581,8 @@ struct mCore* GBCoreCreate(void) { core->setAudioBufferSize = _GBCoreSetAudioBufferSize; core->getAudioBufferSize = _GBCoreGetAudioBufferSize; core->setAVStream = _GBCoreSetAVStream; - core->setCoreCallbacks = _GBCoreSetCoreCallbacks; + core->addCoreCallbacks = _GBCoreAddCoreCallbacks; + core->clearCoreCallbacks = _GBCoreClearCoreCallbacks; core->isROM = GBIsROM; core->loadROM = _GBCoreLoadROM; core->loadBIOS = _GBCoreLoadBIOS; diff --git a/src/gb/gb.c b/src/gb/gb.c index aee05205c..e664e02b8 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -83,7 +83,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) { gb->pristineRomSize = 0; gb->yankedRomSize = 0; - gb->coreCallbacks = NULL; + mCoreCallbacksListInit(&gb->coreCallbacks, 0); gb->stream = NULL; mTimingInit(&gb->timing, &gb->cpu->cycles, &gb->cpu->nextEvent); @@ -349,6 +349,7 @@ void GBDestroy(struct GB* gb) { GBAudioDeinit(&gb->audio); GBVideoDeinit(&gb->video); GBSIODeinit(&gb->sio); + mCoreCallbacksListDeinit(&gb->coreCallbacks); } void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) { diff --git a/src/gb/video.c b/src/gb/video.c index 27287959a..fda0f6111 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -129,9 +129,12 @@ void _endMode0(struct mTiming* timing, void* context, uint32_t cyclesLate) { } video->p->memory.io[REG_IF] |= (1 << GB_IRQ_VBLANK); - struct mCoreCallbacks* callbacks = video->p->coreCallbacks; - if (callbacks && callbacks->videoFrameEnded) { - callbacks->videoFrameEnded(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&video->p->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&video->p->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameEnded(callbacks->context); + } } } if (!GBRegisterSTATIsHblankIRQ(video->stat) && GBRegisterSTATIsLYCIRQ(video->stat) && lyc == video->ly) { @@ -244,9 +247,12 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat video->p->stream->postVideoFrame(video->p->stream, pixels, stride); } - struct mCoreCallbacks* callbacks = video->p->coreCallbacks; - if (callbacks && callbacks->videoFrameStarted) { - callbacks->videoFrameStarted(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&video->p->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&video->p->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameStarted(callbacks->context); + } } if (!GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC])) { diff --git a/src/gba/core.c b/src/gba/core.c index 1c6002fbe..c7483bed0 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -186,9 +186,14 @@ static size_t _GBACoreGetAudioBufferSize(struct mCore* core) { return gba->audio.samples; } -static void _GBACoreSetCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { +static void _GBACoreAddCoreCallbacks(struct mCore* core, struct mCoreCallbacks* coreCallbacks) { struct GBA* gba = core->board; - gba->coreCallbacks = coreCallbacks; + *mCoreCallbacksListAppend(&gba->coreCallbacks) = *coreCallbacks; +} + +static void _GBACoreClearCoreCallbacks(struct mCore* core) { + struct GBA* gba = core->board; + mCoreCallbacksListClear(&gba->coreCallbacks); } static void _GBACoreSetAVStream(struct mCore* core, struct mAVStream* stream) { @@ -589,7 +594,8 @@ struct mCore* GBACoreCreate(void) { core->getAudioChannel = _GBACoreGetAudioChannel; core->setAudioBufferSize = _GBACoreSetAudioBufferSize; core->getAudioBufferSize = _GBACoreGetAudioBufferSize; - core->setCoreCallbacks = _GBACoreSetCoreCallbacks; + core->addCoreCallbacks = _GBACoreAddCoreCallbacks; + core->clearCoreCallbacks = _GBACoreClearCoreCallbacks; core->setAVStream = _GBACoreSetAVStream; core->isROM = GBAIsROM; core->loadROM = _GBACoreLoadROM; diff --git a/src/gba/gba.c b/src/gba/gba.c index 22dafd89a..49c96bd2d 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -91,7 +91,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->keyCallback = NULL; gba->stopCallback = NULL; gba->stopCallback = NULL; - gba->coreCallbacks = NULL; + mCoreCallbacksListInit(&gba->coreCallbacks, 0); gba->biosChecksum = GBAChecksum(gba->memory.bios, SIZE_BIOS); @@ -152,6 +152,7 @@ void GBADestroy(struct GBA* gba) { GBASIODeinit(&gba->sio); gba->rr = 0; mTimingDeinit(&gba->timing); + mCoreCallbacksListDeinit(&gba->coreCallbacks); } void GBAInterruptHandlerInit(struct ARMInterruptHandler* irqh) { @@ -632,9 +633,12 @@ void GBABreakpoint(struct ARMCore* cpu, int immediate) { void GBAFrameStarted(struct GBA* gba) { UNUSED(gba); - struct mCoreCallbacks* callbacks = gba->coreCallbacks; - if (callbacks && callbacks->videoFrameStarted) { - callbacks->videoFrameStarted(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameStarted(callbacks->context); + } } } @@ -665,9 +669,12 @@ void GBAFrameEnded(struct GBA* gba) { GBAHardwarePlayerUpdate(gba); } - struct mCoreCallbacks* callbacks = gba->coreCallbacks; - if (callbacks && callbacks->videoFrameEnded) { - callbacks->videoFrameEnded(callbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); + if (callbacks->videoFrameEnded) { + callbacks->videoFrameEnded(callbacks->context); + } } } diff --git a/src/gba/memory.c b/src/gba/memory.c index eb4316569..5c2c14511 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -303,9 +303,15 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { cpu->memory.activeMask = 0; if (gba->yankedRomSize || !gba->hardCrash) { mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); - } else if (gba->coreCallbacks && gba->coreCallbacks->coreCrashed) { + } else if (mCoreCallbacksListSize(&gba->coreCallbacks)) { mLOG(GBA_MEM, GAME_ERROR, "Jumped to invalid address: %08X", address); - gba->coreCallbacks->coreCrashed(gba->coreCallbacks->context); + size_t c; + for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { + struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); + if (callbacks->coreCrashed) { + callbacks->coreCrashed(callbacks->context); + } + } } else { mLOG(GBA_MEM, FATAL, "Jumped to invalid address: %08X", address); } From 3034253e53528d1772a808b2155aedcea9285de8 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 8 Feb 2017 23:49:42 -0800 Subject: [PATCH 30/43] GBA Timers: Fix timer count when disabling (fixes #519) --- src/gba/timer.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gba/timer.c b/src/gba/timer.c index 49722ed4d..c62f64506 100644 --- a/src/gba/timer.c +++ b/src/gba/timer.c @@ -132,9 +132,6 @@ void GBATimerWriteTMCNT_HI(struct GBA* gba, int timer, uint16_t control) { currentTimer->lastEvent = gba->timing.masterCycles + gba->cpu->cycles; } else if (wasEnabled && !GBATimerFlagsIsEnable(currentTimer->flags)) { mTimingDeschedule(&gba->timing, ¤tTimer->event); - if (!GBATimerFlagsIsCountUp(currentTimer->flags)) { - gba->memory.io[(REG_TM0CNT_LO + (timer << 2)) >> 1] = currentTimer->oldReload + ((gba->cpu->cycles - currentTimer->lastEvent) >> oldPrescale); - } } else if (GBATimerFlagsIsEnable(currentTimer->flags) && GBATimerFlagsGetPrescaleBits(currentTimer->flags) != oldPrescale && !GBATimerFlagsIsCountUp(currentTimer->flags)) { mTimingDeschedule(&gba->timing, ¤tTimer->event); mTimingSchedule(&gba->timing, ¤tTimer->event, currentTimer->overflowInterval - currentTimer->lastEvent); From 903ea6bc195855b298365870d348aec3d2bdc162 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 9 Feb 2017 22:32:56 -0800 Subject: [PATCH 31/43] GBA, GB: Fix FrameStarted callback --- src/gb/video.c | 2 +- src/gba/gba.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gb/video.c b/src/gb/video.c index fda0f6111..465380fa9 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -250,7 +250,7 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat size_t c; for (c = 0; c < mCoreCallbacksListSize(&video->p->coreCallbacks); ++c) { struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&video->p->coreCallbacks, c); - if (callbacks->videoFrameEnded) { + if (callbacks->videoFrameStarted) { callbacks->videoFrameStarted(callbacks->context); } } diff --git a/src/gba/gba.c b/src/gba/gba.c index 49c96bd2d..d7ff611fe 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -636,7 +636,7 @@ void GBAFrameStarted(struct GBA* gba) { size_t c; for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) { struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c); - if (callbacks->videoFrameEnded) { + if (callbacks->videoFrameStarted) { callbacks->videoFrameStarted(callbacks->context); } } From 012f0a33296c79f1717c09c4d2e9cbc9957a85dc Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 11 Feb 2017 15:45:08 -0800 Subject: [PATCH 32/43] Qt: Handle invalid libraries --- src/platform/qt/LibraryModel.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/platform/qt/LibraryModel.cpp b/src/platform/qt/LibraryModel.cpp index 0dc96fe2a..52173c622 100644 --- a/src/platform/qt/LibraryModel.cpp +++ b/src/platform/qt/LibraryModel.cpp @@ -89,7 +89,12 @@ LibraryModel::LibraryModel(const QString& path, QObject* parent) m_library->ref(); } else { m_library = new LibraryHandle(mLibraryLoad(path.toUtf8().constData()), path); - s_handles[path] = m_library; + if (m_library->library) { + s_handles[path] = m_library; + } else { + delete m_library; + m_library = new LibraryHandle(mLibraryCreateEmpty()); + } } } else { m_library = new LibraryHandle(mLibraryCreateEmpty()); @@ -280,7 +285,9 @@ LibraryModel::LibraryHandle::LibraryHandle(mLibrary* lib, const QString& p) LibraryModel::LibraryHandle::~LibraryHandle() { m_loaderThread.quit(); m_loaderThread.wait(); - mLibraryDestroy(library); + if (library) { + mLibraryDestroy(library); + } } void LibraryModel::LibraryHandle::ref() { From 36553b89d0cb70174da4d386565892c288a0e6f6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 Feb 2017 02:21:26 -0800 Subject: [PATCH 33/43] GB Audio: Fix audio frame timer deserialization --- src/gb/audio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gb/audio.c b/src/gb/audio.c index 2a3535251..7bed5d621 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -953,6 +953,9 @@ void GBAudioPSGDeserialize(struct GBAudio* audio, const struct GBSerializedPSGSt audio->playingCh4 = !!(*audio->nr52 & 0x0008); audio->enable = GBAudioEnableGetEnable(*audio->nr52); + LOAD_32LE(when, 0, &state->ch1.nextFrame); + mTimingSchedule(audio->timing, &audio->frameEvent, when); + LOAD_32LE(flags, 0, flagsIn); LOAD_32LE(ch1Flags, 0, &state->ch1.envelope); audio->ch1.envelope.currentVolume = GBSerializedAudioFlagsGetCh1Volume(flags); From 17cfee015d3d0c60128244551791d6f6b0c91fed Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 13 Feb 2017 14:14:26 -0800 Subject: [PATCH 34/43] GBA: Ignore invalid opcodes used by the Wii U VC emulator (fixes #471) --- CHANGES | 1 + src/gba/gba.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index c588c7d68..92a2e3db8 100644 --- a/CHANGES +++ b/CHANGES @@ -70,6 +70,7 @@ Misc: - 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 0.5.2: (2016-12-31) Bugfixes: diff --git a/src/gba/gba.c b/src/gba/gba.c index d7ff611fe..f1e0c392e 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -577,6 +577,10 @@ void GBAIllegal(struct ARMCore* cpu, uint32_t opcode) { // TODO: More sensible category? mLOG(GBA, WARN, "Illegal opcode: %08x", opcode); } + if (cpu->executionMode == MODE_THUMB && (opcode & 0xFFC0) == 0xE800) { + mLOG(GBA, DEBUG, "Hit Wii U VC opcode: %08x", opcode); + return; + } #ifdef USE_DEBUGGERS if (gba->debugger) { struct mDebuggerEntryInfo info = { From 9414f6fc1f13fe7a1c608aea9b16cdd6bcf3a25f Mon Sep 17 00:00:00 2001 From: "Prof. 9" Date: Tue, 14 Feb 2017 16:58:21 +0100 Subject: [PATCH 35/43] Add Wii U VC shader. --- res/shaders/wiiu.shader/manifest.ini | 11 +++++++++++ res/shaders/wiiu.shader/wiiu.fs | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 res/shaders/wiiu.shader/manifest.ini create mode 100644 res/shaders/wiiu.shader/wiiu.fs diff --git a/res/shaders/wiiu.shader/manifest.ini b/res/shaders/wiiu.shader/manifest.ini new file mode 100644 index 000000000..2b92c1d74 --- /dev/null +++ b/res/shaders/wiiu.shader/manifest.ini @@ -0,0 +1,11 @@ +[shader] +name=Wii U +author=Prof. 9 +description=Uses the color palette from the Wii U Virtual Console. Enable bilinear filtering to further mimic Wii U output. +passes=1 + +[pass.0] +fragmentShader=wiiu.fs +blend=1 +width=960 +height=640 diff --git a/res/shaders/wiiu.shader/wiiu.fs b/res/shaders/wiiu.shader/wiiu.fs new file mode 100644 index 000000000..268c5d229 --- /dev/null +++ b/res/shaders/wiiu.shader/wiiu.fs @@ -0,0 +1,22 @@ +varying vec2 texCoord; +uniform sampler2D tex; +uniform vec2 texSize; + +const float scale[32] = float[]( + 0.0/255.0, 6.0/255.0, 12.0/255.0, 18.0/255.0, 24.0/255.0, 31.0/255.0, 37.0/255.0, 43.0/255.0, + 49.0/255.0, 55.0/255.0, 61.0/255.0, 67.0/255.0, 73.0/255.0, 79.0/255.0, 86.0/255.0, 92.0/255.0, + 98.0/255.0, 104.0/255.0, 111.0/255.0, 117.0/255.0, 123.0/255.0, 129.0/255.0, 135.0/255.0, 141.0/255.0, + 148.0/255.0, 154.0/255.0, 159.0/255.0, 166.0/255.0, 172.0/255.0, 178.0/255.0, 184.0/255.0, 191.0/255.0 +); + +void main() { + vec4 color = texture2D(tex, texCoord); + color.rgb = round(color.rgb * 31.0); + color = vec4( + scale[int(color.r)], + scale[int(color.g)], + scale[int(color.b)], + 1.0 + ); + gl_FragColor = color; +} \ No newline at end of file From ba3b068df4a8fcb34c66b1bc5725a205a36d5807 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 15 Feb 2017 10:53:37 -0800 Subject: [PATCH 36/43] Core: Savestates now contain any RTC override data --- CHANGES | 1 + include/mgba/core/core.h | 6 ++- include/mgba/core/interface.h | 14 ++++- include/mgba/core/serialize.h | 2 + src/core/core.c | 5 ++ src/core/interface.c | 85 ++++++++++++++++++++++++++++-- src/core/serialize.c | 15 ++++++ src/feature/gui/gui-runner.c | 2 +- src/gb/core.c | 8 +-- src/gb/extra/cli.c | 4 +- src/gba/core.c | 8 +-- src/gba/extra/cli.c | 4 +- src/platform/qt/GameController.cpp | 25 +++++---- src/platform/qt/GameController.h | 2 - src/platform/qt/SettingsView.cpp | 8 +-- 15 files changed, 150 insertions(+), 39 deletions(-) diff --git a/CHANGES b/CHANGES index 92a2e3db8..af91cf03c 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,7 @@ Features: - 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 Bugfixes: - LR35902: Fix core never exiting with certain event patterns - GB Timer: Improve DIV reset behavior diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 980322ebd..82ee3d6d6 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -37,7 +37,6 @@ enum mCoreChecksumType { CHECKSUM_CRC32, }; -struct mRTCSource; struct mCoreConfig; struct mCoreSync; struct mStateExtdata; @@ -55,6 +54,8 @@ struct mCore { struct mCoreConfig config; struct mCoreOptions opts; + struct mRTCGenericSource rtc; + bool (*init)(struct mCore*); void (*deinit)(struct mCore*); @@ -109,7 +110,6 @@ struct mCore { void (*getGameTitle)(const struct mCore*, char* title); void (*getGameCode)(const struct mCore*, char* title); - void (*setRTC)(struct mCore*, struct mRTCSource*); void (*setRotation)(struct mCore*, struct mRotationSource*); void (*setRumble)(struct mCore*, struct mRumble*); @@ -168,6 +168,8 @@ void mCoreInitConfig(struct mCore* core, const char* port); void mCoreLoadConfig(struct mCore* core); void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config); +void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc); + CXX_GUARD_END #endif diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index 40eb099d6..933e8d2d5 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -13,6 +13,7 @@ CXX_GUARD_START #include struct mCore; +struct mStateExtdataItem; #ifdef COLOR_16_BIT typedef uint16_t color_t; @@ -69,12 +70,16 @@ struct mRTCSource { void (*sample)(struct mRTCSource*); time_t (*unixTime)(struct mRTCSource*); + + void (*serialize)(struct mRTCSource*, struct mStateExtdataItem*); + bool (*deserialize)(struct mRTCSource*, const struct mStateExtdataItem*); }; enum mRTCGenericType { RTC_NO_OVERRIDE, RTC_FIXED, - RTC_FAKE_EPOCH + RTC_FAKE_EPOCH, + RTC_CUSTOM_START = 0x1000 }; struct mRTCGenericSource { @@ -82,6 +87,13 @@ struct mRTCGenericSource { struct mCore* p; enum mRTCGenericType override; int64_t value; + struct mRTCSource* custom; +}; + +struct mRTCGenericState { + int32_t type; + int32_t padding; + int64_t value; }; void mRTCGenericSourceInit(struct mRTCGenericSource* rtc, struct mCore* core); diff --git a/include/mgba/core/serialize.h b/include/mgba/core/serialize.h index 266cab0ca..0951fc4c3 100644 --- a/include/mgba/core/serialize.h +++ b/include/mgba/core/serialize.h @@ -15,12 +15,14 @@ enum mStateExtdataTag { EXTDATA_SCREENSHOT = 1, EXTDATA_SAVEDATA = 2, EXTDATA_CHEATS = 3, + EXTDATA_RTC = 4, EXTDATA_MAX }; #define SAVESTATE_SCREENSHOT 1 #define SAVESTATE_SAVEDATA 2 #define SAVESTATE_CHEATS 4 +#define SAVESTATE_RTC 8 struct mStateExtdataItem { int32_t size; diff --git a/src/core/core.c b/src/core/core.c index 433c213b8..70e778841 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -233,3 +233,8 @@ void mCoreLoadForeignConfig(struct mCore* core, const struct mCoreConfig* config } core->loadConfig(core, config); } + +void mCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) { + core->rtc.custom = rtc; + core->rtc.override = RTC_CUSTOM_START; +} diff --git a/src/core/interface.c b/src/core/interface.c index 75e171b3d..961b83619 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -6,26 +6,103 @@ #include #include +#include DEFINE_VECTOR(mCoreCallbacksList, struct mCoreCallbacks); +static void _rtcGenericSample(struct mRTCSource* source) { + struct mRTCGenericSource* rtc = (struct mRTCGenericSource*) source; + switch (rtc->override) { + default: + if (rtc->custom->sample) { + return rtc->custom->sample(rtc->custom); + } + break; + case RTC_NO_OVERRIDE: + case RTC_FIXED: + case RTC_FAKE_EPOCH: + break; + } +} + static time_t _rtcGenericCallback(struct mRTCSource* source) { struct mRTCGenericSource* rtc = (struct mRTCGenericSource*) source; switch (rtc->override) { - case RTC_NO_OVERRIDE: default: + if (rtc->custom->unixTime) { + return rtc->custom->unixTime(rtc->custom); + } + // Fall through + case RTC_NO_OVERRIDE: return time(0); case RTC_FIXED: - return rtc->value; + return rtc->value / 1000LL; case RTC_FAKE_EPOCH: - return rtc->value + rtc->p->frameCounter(rtc->p) * (int64_t) rtc->p->frameCycles(rtc->p) / rtc->p->frequency(rtc->p); + return (rtc->value + rtc->p->frameCounter(rtc->p) * (rtc->p->frameCycles(rtc->p) * 1000LL) / rtc->p->frequency(rtc->p)) / 1000LL; } } +static void _rtcGenericSerialize(struct mRTCSource* source, struct mStateExtdataItem* item) { + struct mRTCGenericSource* rtc = (struct mRTCGenericSource*) source; + struct mRTCGenericState state = { + .type = rtc->override, + .padding = 0, + .value = rtc->value + }; + void* data; + if (rtc->override >= RTC_CUSTOM_START && rtc->custom->serialize) { + rtc->custom->serialize(rtc->custom, item); + data = malloc(item->size + sizeof(state)); + uint8_t* oldData = data; + oldData += sizeof(state); + memcpy(oldData, item->data, item->size); + item->size += sizeof(state); + if (item->clean) { + item->clean(item->data); + } + } else { + item->size = sizeof(state); + data = malloc(item->size); + } + memcpy(data, &state, sizeof(state)); + item->data = data; + item->clean = free; +} + +static bool _rtcGenericDeserialize(struct mRTCSource* source, const struct mStateExtdataItem* item) { + struct mRTCGenericSource* rtc = (struct mRTCGenericSource*) source; + struct mRTCGenericState* state = item->data; + if (!state || item->size < (ssize_t) sizeof(*state)) { + return false; + } + if (state->type >= RTC_CUSTOM_START) { + if (!rtc->custom) { + return false; + } + if (rtc->custom->deserialize) { + uint8_t* oldData = item->data; + oldData += sizeof(state); + struct mStateExtdataItem fakeItem = { + .size = item->size - sizeof(*state), + .data = oldData, + .clean = NULL + }; + if (!rtc->custom->deserialize(rtc->custom, &fakeItem)) { + return false; + } + } + } + rtc->value = state->value; + rtc->override = state->type; + return true; +} + void mRTCGenericSourceInit(struct mRTCGenericSource* rtc, struct mCore* core) { rtc->p = core; rtc->override = RTC_NO_OVERRIDE; rtc->value = 0; - rtc->d.sample = 0; + rtc->d.sample = _rtcGenericSample; rtc->d.unixTime = _rtcGenericCallback; + rtc->d.serialize = _rtcGenericSerialize; + rtc->d.deserialize = _rtcGenericDeserialize; } diff --git a/src/core/serialize.c b/src/core/serialize.c index f5b143fec..5994fc97b 100644 --- a/src/core/serialize.c +++ b/src/core/serialize.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -328,6 +329,14 @@ bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { mStateExtdataPut(&extdata, EXTDATA_CHEATS, &item); } } + if (flags & SAVESTATE_RTC) { + mLOG(SAVESTATE, INFO, "Loading RTC"); + struct mStateExtdataItem item; + if (core->rtc.d.serialize) { + core->rtc.d.serialize(&core->rtc.d, &item); + mStateExtdataPut(&extdata, EXTDATA_RTC, &item); + } + } #ifdef USE_PNG if (!(flags & SAVESTATE_SCREENSHOT)) { #else @@ -425,6 +434,12 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { } } } + if (flags & SAVESTATE_RTC && mStateExtdataGet(&extdata, EXTDATA_RTC, &item)) { + mLOG(SAVESTATE, INFO, "Loading RTC"); + if (core->rtc.d.deserialize) { + core->rtc.d.deserialize(&core->rtc.d, &item); + } + } mStateExtdataDeinit(&extdata); return success; } diff --git a/src/feature/gui/gui-runner.c b/src/feature/gui/gui-runner.c index c393086a0..6be83ef82 100644 --- a/src/feature/gui/gui-runner.c +++ b/src/feature/gui/gui-runner.c @@ -434,7 +434,7 @@ void mGUIRun(struct mGUIRunner* runner, const char* path) { mCoreSaveState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA); break; case RUNNER_LOAD_STATE: - mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT); + mCoreLoadState(runner->core, ((int) item->data) >> 16, SAVESTATE_SCREENSHOT | SAVESTATE_RTC); break; case RUNNER_SCREENSHOT: mCoreTakeScreenshot(runner->core); diff --git a/src/gb/core.c b/src/gb/core.c index 87ad3558a..496bca866 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -50,6 +50,8 @@ static bool _GBCoreInit(struct mCore* core) { memset(gbcore->components, 0, sizeof(gbcore->components)); LR35902SetComponents(cpu, &gb->d, CPU_COMPONENT_MAX, gbcore->components); LR35902Init(cpu); + mRTCGenericSourceInit(&core->rtc, core); + gb->memory.rtc = &core->rtc.d; GBVideoSoftwareRendererCreate(&gbcore->renderer); gbcore->renderer.outputBuffer = NULL; @@ -389,11 +391,6 @@ static void _GBCoreGetGameCode(const struct mCore* core, char* title) { GBGetGameCode(core->board, title); } -static void _GBCoreSetRTC(struct mCore* core, struct mRTCSource* rtc) { - struct GB* gb = core->board; - gb->memory.rtc = rtc; -} - static void _GBCoreSetRotation(struct mCore* core, struct mRotationSource* rotation) { struct GB* gb = core->board; gb->memory.rotation = rotation; @@ -606,7 +603,6 @@ struct mCore* GBCoreCreate(void) { core->frequency = _GBCoreFrequency; core->getGameTitle = _GBCoreGetGameTitle; core->getGameCode = _GBCoreGetGameCode; - core->setRTC = _GBCoreSetRTC; core->setRotation = _GBCoreSetRotation; core->setRumble = _GBCoreSetRumble; core->busRead8 = _GBCoreBusRead8; diff --git a/src/gb/extra/cli.c b/src/gb/extra/cli.c index 78e10a1b6..809961290 100644 --- a/src/gb/extra/cli.c +++ b/src/gb/extra/cli.c @@ -101,7 +101,7 @@ static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system; - mCoreLoadState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); + mCoreLoadState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC); } static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { @@ -118,5 +118,5 @@ static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { struct GBCLIDebugger* gbDebugger = (struct GBCLIDebugger*) debugger->system; - mCoreSaveState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); + mCoreSaveState(gbDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC); } diff --git a/src/gba/core.c b/src/gba/core.c index c7483bed0..3a53641a7 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -58,6 +58,8 @@ static bool _GBACoreInit(struct mCore* core) { memset(gbacore->components, 0, sizeof(gbacore->components)); ARMSetComponents(cpu, &gba->d, CPU_COMPONENT_MAX, gbacore->components); ARMInit(cpu); + mRTCGenericSourceInit(&core->rtc, core); + gba->rtcSource = &core->rtc.d; GBAVideoSoftwareRendererCreate(&gbacore->renderer); gbacore->renderer.outputBuffer = NULL; @@ -401,11 +403,6 @@ static void _GBACoreGetGameCode(const struct mCore* core, char* title) { GBAGetGameCode(core->board, title); } -static void _GBACoreSetRTC(struct mCore* core, struct mRTCSource* rtc) { - struct GBA* gba = core->board; - gba->rtcSource = rtc; -} - static void _GBACoreSetRotation(struct mCore* core, struct mRotationSource* rotation) { struct GBA* gba = core->board; gba->rotationSource = rotation; @@ -620,7 +617,6 @@ struct mCore* GBACoreCreate(void) { core->frequency = _GBACoreFrequency; core->getGameTitle = _GBACoreGetGameTitle; core->getGameCode = _GBACoreGetGameCode; - core->setRTC = _GBACoreSetRTC; core->setRotation = _GBACoreSetRotation; core->setRumble = _GBACoreSetRumble; core->busRead8 = _GBACoreBusRead8; diff --git a/src/gba/extra/cli.c b/src/gba/extra/cli.c index a9ad7841b..44ae46917 100644 --- a/src/gba/extra/cli.c +++ b/src/gba/extra/cli.c @@ -100,7 +100,7 @@ static void _load(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; - mCoreLoadState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); + mCoreLoadState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC); } // TODO: Put back rewind @@ -119,5 +119,5 @@ static void _save(struct CLIDebugger* debugger, struct CLIDebugVector* dv) { struct GBACLIDebugger* gbaDebugger = (struct GBACLIDebugger*) debugger->system; - mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT); + mCoreSaveState(gbaDebugger->core, dv->intValue, SAVESTATE_SCREENSHOT | SAVESTATE_RTC); } diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 3889cb4c6..701f5c542 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -70,8 +70,8 @@ GameController::GameController(QObject* parent) , m_stateSlot(1) , m_backupLoadState(nullptr) , m_backupSaveState(nullptr) - , m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS) - , m_loadStateFlags(SAVESTATE_SCREENSHOT) + , m_saveStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS | SAVESTATE_RTC) + , m_loadStateFlags(SAVESTATE_SCREENSHOT | SAVESTATE_RTC) , m_override(nullptr) { #ifdef M_CORE_GBA @@ -90,8 +90,6 @@ GameController::GameController(QObject* parent) m_threadContext.startCallback = [](mCoreThread* context) { GameController* controller = static_cast(context->userData); - mRTCGenericSourceInit(&controller->m_rtc, context->core); - context->core->setRTC(context->core, &controller->m_rtc.d); context->core->setRotation(context->core, controller->m_inputController->rotationSource()); context->core->setRumble(context->core, controller->m_inputController->rumble()); @@ -1182,17 +1180,26 @@ void GameController::setLuminanceLevel(int level) { } void GameController::setRealTime() { - m_rtc.override = RTC_NO_OVERRIDE; + if (!isLoaded()) { + return; + } + m_threadContext.core->rtc.override = RTC_NO_OVERRIDE; } void GameController::setFixedTime(const QDateTime& time) { - m_rtc.override = RTC_FIXED; - m_rtc.value = time.toMSecsSinceEpoch() / 1000; + if (!isLoaded()) { + return; + } + m_threadContext.core->rtc.override = RTC_FIXED; + m_threadContext.core->rtc.value = time.toMSecsSinceEpoch(); } void GameController::setFakeEpoch(const QDateTime& time) { - m_rtc.override = RTC_FAKE_EPOCH; - m_rtc.value = time.toMSecsSinceEpoch() / 1000; + if (!isLoaded()) { + return; + } + m_threadContext.core->rtc.override = RTC_FAKE_EPOCH; + m_threadContext.core->rtc.value = time.toMSecsSinceEpoch(); } void GameController::updateKeys() { diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 9ea53de7b..79b18d3bf 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -245,8 +245,6 @@ private: } m_lux; uint8_t m_luxValue; int m_luxLevel; - - mRTCGenericSource m_rtc; }; } diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index da2d27be0..15d13b4a1 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -223,13 +223,13 @@ void SettingsView::updateConfig() { break; } - int loadState = 0; + int loadState = SAVESTATE_RTC; loadState |= m_ui.loadStateScreenshot->isChecked() ? SAVESTATE_SCREENSHOT : 0; loadState |= m_ui.loadStateSave->isChecked() ? SAVESTATE_SAVEDATA : 0; loadState |= m_ui.loadStateCheats->isChecked() ? SAVESTATE_CHEATS : 0; saveSetting("loadStateExtdata", loadState); - int saveState = 0; + int saveState = SAVESTATE_RTC; saveState |= m_ui.saveStateScreenshot->isChecked() ? SAVESTATE_SCREENSHOT : 0; saveState |= m_ui.saveStateSave->isChecked() ? SAVESTATE_SAVEDATA : 0; saveState |= m_ui.saveStateCheats->isChecked() ? SAVESTATE_CHEATS : 0; @@ -306,7 +306,7 @@ void SettingsView::reloadConfig() { bool ok; int loadState = loadSetting("loadStateExtdata").toInt(&ok); if (!ok) { - loadState = SAVESTATE_SCREENSHOT; + loadState = SAVESTATE_SCREENSHOT | SAVESTATE_RTC; } m_ui.loadStateScreenshot->setChecked(loadState & SAVESTATE_SCREENSHOT); m_ui.loadStateSave->setChecked(loadState & SAVESTATE_SAVEDATA); @@ -314,7 +314,7 @@ void SettingsView::reloadConfig() { int saveState = loadSetting("saveStateExtdata").toInt(&ok); if (!ok) { - saveState = SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS; + saveState = SAVESTATE_SCREENSHOT | SAVESTATE_SAVEDATA | SAVESTATE_CHEATS | SAVESTATE_RTC; } m_ui.saveStateScreenshot->setChecked(saveState & SAVESTATE_SCREENSHOT); m_ui.saveStateSave->setChecked(saveState & SAVESTATE_SAVEDATA); From e0c2b3d68272e6c059f0f62f66f15756a27ce590 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 3 Mar 2017 18:51:50 -0800 Subject: [PATCH 37/43] GBA Video: Fix wrong palette on 256-color sprites in OBJWIN --- CHANGES | 1 + src/gba/renderers/software-obj.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index af91cf03c..3dd7b46cd 100644 --- a/CHANGES +++ b/CHANGES @@ -29,6 +29,7 @@ Bugfixes: - 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 Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/src/gba/renderers/software-obj.c b/src/gba/renderers/software-obj.c index f3ee2bd49..71a409f04 100644 --- a/src/gba/renderers/software-obj.c +++ b/src/gba/renderers/software-obj.c @@ -317,7 +317,6 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re SPRITE_NORMAL_LOOP(256, OBJWIN); } else if (mosaicH > 1) { if (objwinSlowPath) { - objwinPalette = &objwinPalette[GBAObjAttributesCGetPalette(sprite->c) << 4]; SPRITE_MOSAIC_LOOP(256, NORMAL_OBJWIN); } else { SPRITE_MOSAIC_LOOP(256, NORMAL); From 000f232c582b0981b66d48d7af799e97faffad8e Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 5 Mar 2017 15:58:00 -0800 Subject: [PATCH 38/43] Core: Begin log revamp --- include/mgba/core/log.h | 13 ++++++++----- src/core/cheats.c | 2 +- src/core/log.c | 27 +++++++++++++++++++++++---- src/core/serialize.c | 2 +- src/debugger/debugger.c | 2 +- src/feature/gui/gui-runner.c | 2 +- src/gb/gb.c | 2 +- src/gb/io.c | 2 +- src/gb/mbc.c | 2 +- src/gb/memory.c | 2 +- src/gb/serialize.c | 2 +- src/gb/sio.c | 2 +- src/gba/audio.c | 2 +- src/gba/bios.c | 2 +- src/gba/gba.c | 4 ++-- src/gba/hardware.c | 2 +- src/gba/io.c | 2 +- src/gba/memory.c | 2 +- src/gba/rr/rr.c | 2 +- src/gba/savedata.c | 2 +- src/gba/serialize.c | 2 +- src/gba/sio.c | 2 +- src/gba/video.c | 2 +- src/platform/opengl/gles2.c | 2 +- src/platform/qt/GBAApp.cpp | 2 +- src/platform/qt/GameController.cpp | 13 ++++++++++--- src/platform/sdl/sdl-audio.c | 2 +- src/platform/sdl/sdl-events.c | 2 +- 28 files changed, 67 insertions(+), 38 deletions(-) diff --git a/include/mgba/core/log.h b/include/mgba/core/log.h index 6c8615c93..3cdbe336e 100644 --- a/include/mgba/core/log.h +++ b/include/mgba/core/log.h @@ -28,23 +28,26 @@ struct mLogger { struct mLogger* mLogGetContext(void); void mLogSetDefaultLogger(struct mLogger*); -int mLogGenerateCategory(const char*); +int mLogGenerateCategory(const char*, const char*); const char* mLogCategoryName(int); +const char* mLogCategoryId(int); +int mLogCategoryById(const char*); ATTRIBUTE_FORMAT(printf, 3, 4) void mLog(int category, enum mLogLevel level, const char* format, ...); #define mLOG(CATEGORY, LEVEL, ...) mLog(_mLOG_CAT_ ## CATEGORY (), mLOG_ ## LEVEL, __VA_ARGS__) -#define mLOG_DECLARE_CATEGORY(CATEGORY) int _mLOG_CAT_ ## CATEGORY (void); -#define mLOG_DEFINE_CATEGORY(CATEGORY, NAME) \ +#define mLOG_DECLARE_CATEGORY(CATEGORY) int _mLOG_CAT_ ## CATEGORY (void); extern const char* _mLOG_CAT_ ## CATEGORY ## _ID; +#define mLOG_DEFINE_CATEGORY(CATEGORY, NAME, ID) \ int _mLOG_CAT_ ## CATEGORY (void) { \ static int category = 0; \ if (!category) { \ - category = mLogGenerateCategory(NAME); \ + category = mLogGenerateCategory(NAME, ID); \ } \ return category; \ - } + } \ + const char* _mLOG_CAT_ ## CATEGORY ## _ID = ID; mLOG_DECLARE_CATEGORY(STATUS) diff --git a/src/core/cheats.c b/src/core/cheats.c index fe6e59c99..83bdde0b8 100644 --- a/src/core/cheats.c +++ b/src/core/cheats.c @@ -13,7 +13,7 @@ const uint32_t M_CHEAT_DEVICE_ID = 0xABADC0DE; -mLOG_DEFINE_CATEGORY(CHEATS, "Cheats"); +mLOG_DEFINE_CATEGORY(CHEATS, "Cheats", "core.cheats"); DEFINE_VECTOR(mCheatList, struct mCheat); DEFINE_VECTOR(mCheatSets, struct mCheatSet*); diff --git a/src/core/log.c b/src/core/log.c index 65ec99924..04c6a1214 100644 --- a/src/core/log.c +++ b/src/core/log.c @@ -28,12 +28,14 @@ void mLogSetDefaultLogger(struct mLogger* logger) { static int _category = 0; static const char* _categoryNames[MAX_CATEGORY]; +static const char* _categoryIds[MAX_CATEGORY]; -int mLogGenerateCategory(const char* name) { - ++_category; +int mLogGenerateCategory(const char* name, const char* id) { if (_category < MAX_CATEGORY) { _categoryNames[_category] = name; + _categoryIds[_category] = id; } + ++_category; return _category; } @@ -41,7 +43,24 @@ const char* mLogCategoryName(int category) { if (category < MAX_CATEGORY) { return _categoryNames[category]; } - return 0; + return NULL; +} + +const char* mLogCategoryId(int category) { + if (category < MAX_CATEGORY) { + return _categoryIds[category]; + } + return NULL; +} + +int mLogCategoryById(const char* id) { + int i; + for (i = 0; i < _category; ++i) { + if (strcmp(_categoryIds[i], id) == 0) { + return i; + } + } + return -1; } void mLog(int category, enum mLogLevel level, const char* format, ...) { @@ -58,4 +77,4 @@ void mLog(int category, enum mLogLevel level, const char* format, ...) { va_end(args); } -mLOG_DEFINE_CATEGORY(STATUS, "Status") +mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status") diff --git a/src/core/serialize.c b/src/core/serialize.c index 5994fc97b..bd6abd112 100644 --- a/src/core/serialize.c +++ b/src/core/serialize.c @@ -17,7 +17,7 @@ #include #endif -mLOG_DEFINE_CATEGORY(SAVESTATE, "Savestate"); +mLOG_DEFINE_CATEGORY(SAVESTATE, "Savestate", "core.serialize"); struct mBundledState { size_t stateSize; diff --git a/src/debugger/debugger.c b/src/debugger/debugger.c index 0e7e3fc1a..49da5fde6 100644 --- a/src/debugger/debugger.c +++ b/src/debugger/debugger.c @@ -15,7 +15,7 @@ const uint32_t DEBUGGER_ID = 0xDEADBEEF; -mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger"); +mLOG_DEFINE_CATEGORY(DEBUGGER, "Debugger", "core.debugger"); static void mDebuggerInit(void* cpu, struct mCPUComponent* component); static void mDebuggerDeinit(struct mCPUComponent* component); diff --git a/src/feature/gui/gui-runner.c b/src/feature/gui/gui-runner.c index 6be83ef82..c26cbe662 100644 --- a/src/feature/gui/gui-runner.c +++ b/src/feature/gui/gui-runner.c @@ -25,7 +25,7 @@ #include mLOG_DECLARE_CATEGORY(GUI_RUNNER); -mLOG_DEFINE_CATEGORY(GUI_RUNNER, "GUI Runner"); +mLOG_DEFINE_CATEGORY(GUI_RUNNER, "GUI Runner", "gui.runner"); #define FPS_GRANULARITY 120 #define FPS_BUFFER_SIZE 3 diff --git a/src/gb/gb.c b/src/gb/gb.c index e664e02b8..8e227a816 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -30,7 +30,7 @@ static const uint8_t _knownHeader[4] = { 0xCE, 0xED, 0x66, 0x66}; #define DMG_2_BIOS_CHECKSUM 0x59C8598E #define CGB_BIOS_CHECKSUM 0x41884E46 -mLOG_DEFINE_CATEGORY(GB, "GB"); +mLOG_DEFINE_CATEGORY(GB, "GB", "gb"); static void GBInit(void* cpu, struct mCPUComponent* component); static void GBDeinit(struct mCPUComponent* component); diff --git a/src/gb/io.c b/src/gb/io.c index 82f3855ef..b7e234ca7 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -9,7 +9,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O"); +mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O", "gb.io"); const char* const GBIORegisterNames[] = { [REG_JOYP] = "JOYP", diff --git a/src/gb/mbc.c b/src/gb/mbc.c index 7ef41695e..efc294419 100644 --- a/src/gb/mbc.c +++ b/src/gb/mbc.c @@ -11,7 +11,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC"); +mLOG_DEFINE_CATEGORY(GB_MBC, "GB MBC", "gb.mbc"); static void _GBMBCNone(struct GB* gb, uint16_t address, uint8_t value) { UNUSED(gb); diff --git a/src/gb/memory.c b/src/gb/memory.c index 2a0f2e52c..eb709b01b 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -14,7 +14,7 @@ #include -mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory"); +mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory", "gb.memory"); static void _pristineCow(struct GB* gba); diff --git a/src/gb/serialize.c b/src/gb/serialize.c index 75fa33e82..3e60eadcd 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -9,7 +9,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate"); +mLOG_DEFINE_CATEGORY(GB_STATE, "GB Savestate", "gb.serialize"); const uint32_t GB_SAVESTATE_MAGIC = 0x00400000; const uint32_t GB_SAVESTATE_VERSION = 0x00000001; diff --git a/src/gb/sio.c b/src/gb/sio.c index 944064752..26a326966 100644 --- a/src/gb/sio.c +++ b/src/gb/sio.c @@ -9,7 +9,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GB_SIO, "GB Serial I/O"); +mLOG_DEFINE_CATEGORY(GB_SIO, "GB Serial I/O", "gb.sio"); const int GBSIOCyclesPerTransfer[2] = { 512, diff --git a/src/gba/audio.c b/src/gba/audio.c index 02102f227..2ceba8a5a 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -18,7 +18,7 @@ #define blip_add_delta blip_add_delta_fast #endif -mLOG_DEFINE_CATEGORY(GBA_AUDIO, "GBA Audio"); +mLOG_DEFINE_CATEGORY(GBA_AUDIO, "GBA Audio", "gba.audio"); const unsigned GBA_AUDIO_SAMPLES = 2048; const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t); diff --git a/src/gba/bios.c b/src/gba/bios.c index 83e43b302..9d8b6ccdc 100644 --- a/src/gba/bios.c +++ b/src/gba/bios.c @@ -14,7 +14,7 @@ const uint32_t GBA_BIOS_CHECKSUM = 0xBAAE187F; const uint32_t GBA_DS_BIOS_CHECKSUM = 0xBAAE1880; -mLOG_DEFINE_CATEGORY(GBA_BIOS, "GBA BIOS"); +mLOG_DEFINE_CATEGORY(GBA_BIOS, "GBA BIOS", "gba.bios"); static void _unLz77(struct GBA* gba, int width); static void _unHuffman(struct GBA* gba); diff --git a/src/gba/gba.c b/src/gba/gba.c index f1e0c392e..c7059df12 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -21,8 +21,8 @@ #include #include -mLOG_DEFINE_CATEGORY(GBA, "GBA"); -mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug"); +mLOG_DEFINE_CATEGORY(GBA, "GBA", "gba"); +mLOG_DEFINE_CATEGORY(GBA_DEBUG, "GBA Debug", "gba.debug"); const uint32_t GBA_COMPONENT_MAGIC = 0x1000000; diff --git a/src/gba/hardware.c b/src/gba/hardware.c index 2027b949d..ff7562840 100644 --- a/src/gba/hardware.c +++ b/src/gba/hardware.c @@ -11,7 +11,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GBA_HW, "GBA Pak Hardware"); +mLOG_DEFINE_CATEGORY(GBA_HW, "GBA Pak Hardware", "gba.hardware"); const int GBA_LUX_LEVELS[10] = { 5, 11, 18, 27, 42, 62, 84, 109, 139, 183 }; diff --git a/src/gba/io.c b/src/gba/io.c index 14f361316..9574ec9f9 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -11,7 +11,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O"); +mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O", "gba.io"); const char* const GBAIORegisterNames[] = { // Video diff --git a/src/gba/memory.c b/src/gba/memory.c index 5c2c14511..69cdc8b28 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -19,7 +19,7 @@ #define IDLE_LOOP_THRESHOLD 10000 -mLOG_DEFINE_CATEGORY(GBA_MEM, "GBA Memory"); +mLOG_DEFINE_CATEGORY(GBA_MEM, "GBA Memory", "gba.memory"); static void _pristineCow(struct GBA* gba); static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb diff --git a/src/gba/rr/rr.c b/src/gba/rr/rr.c index da6c48349..7ed957753 100644 --- a/src/gba/rr/rr.c +++ b/src/gba/rr/rr.c @@ -9,7 +9,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GBA_RR, "GBA RR"); +mLOG_DEFINE_CATEGORY(GBA_RR, "GBA RR", "gba.rr"); void GBARRInitRecord(struct GBA* gba) { if (!gba || !gba->rr) { diff --git a/src/gba/savedata.c b/src/gba/savedata.c index d82d80fd4..08eab40aa 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -26,7 +26,7 @@ #define EEPROM_SETTLE_CYCLES 115000 #define CLEANUP_THRESHOLD 15 -mLOG_DEFINE_CATEGORY(GBA_SAVE, "GBA Savedata"); +mLOG_DEFINE_CATEGORY(GBA_SAVE, "GBA Savedata", "gba.savedata"); static void _flashSwitchBank(struct GBASavedata* savedata, int bank); static void _flashErase(struct GBASavedata* savedata); diff --git a/src/gba/serialize.c b/src/gba/serialize.c index 600bf6faa..59c6ecc34 100644 --- a/src/gba/serialize.c +++ b/src/gba/serialize.c @@ -17,7 +17,7 @@ const uint32_t GBA_SAVESTATE_MAGIC = 0x01000000; const uint32_t GBA_SAVESTATE_VERSION = 0x00000002; -mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate"); +mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate", "gba.serialize"); struct GBABundledState { struct GBASerializedState* state; diff --git a/src/gba/sio.c b/src/gba/sio.c index 661d9d09b..33a7c99d7 100644 --- a/src/gba/sio.c +++ b/src/gba/sio.c @@ -8,7 +8,7 @@ #include #include -mLOG_DEFINE_CATEGORY(GBA_SIO, "GBA Serial I/O"); +mLOG_DEFINE_CATEGORY(GBA_SIO, "GBA Serial I/O", "gba.sio"); const int GBASIOCyclesPerTransfer[4][MAX_GBAS] = { { 38326, 73003, 107680, 142356 }, diff --git a/src/gba/video.c b/src/gba/video.c index a61087630..935d1fcea 100644 --- a/src/gba/video.c +++ b/src/gba/video.c @@ -15,7 +15,7 @@ #include -mLOG_DEFINE_CATEGORY(GBA_VIDEO, "GBA Video"); +mLOG_DEFINE_CATEGORY(GBA_VIDEO, "GBA Video", "gba.video"); static void GBAVideoDummyRendererInit(struct GBAVideoRenderer* renderer); static void GBAVideoDummyRendererReset(struct GBAVideoRenderer* renderer); diff --git a/src/platform/opengl/gles2.c b/src/platform/opengl/gles2.c index 781217e57..2dff30f3d 100644 --- a/src/platform/opengl/gles2.c +++ b/src/platform/opengl/gles2.c @@ -12,7 +12,7 @@ #include mLOG_DECLARE_CATEGORY(OPENGL); -mLOG_DEFINE_CATEGORY(OPENGL, "OpenGL"); +mLOG_DEFINE_CATEGORY(OPENGL, "OpenGL", "video.ogl"); #define MAX_PASSES 8 diff --git a/src/platform/qt/GBAApp.cpp b/src/platform/qt/GBAApp.cpp index f59368b83..b54ea49ee 100644 --- a/src/platform/qt/GBAApp.cpp +++ b/src/platform/qt/GBAApp.cpp @@ -29,7 +29,7 @@ using namespace QGBA; static GBAApp* g_app = nullptr; -mLOG_DEFINE_CATEGORY(QT, "Qt"); +mLOG_DEFINE_CATEGORY(QT, "Qt", "platform.qt"); GBAApp::GBAApp(int& argc, char* argv[]) : QApplication(argc, argv) diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 701f5c542..8614aaed5 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -23,7 +23,6 @@ #include #ifdef M_CORE_GBA #include -#include #include #include #include @@ -239,13 +238,21 @@ GameController::GameController(QObject* parent) static const char* savestateMessage = "State %i loaded"; static const char* savestateFailedMessage = "State %i failed to load"; + static int biosCat = -1; + static int statusCat = -1; if (!context) { return; } GameController* controller = static_cast(context->userData); QString message; + if (biosCat < 0) { + biosCat = mLogCategoryById("gba.bios"); + } + if (statusCat < 0) { + statusCat = mLogCategoryById("core.status"); + } #ifdef M_CORE_GBA - if (level == mLOG_STUB && category == _mLOG_CAT_GBA_BIOS()) { + if (level == mLOG_STUB && category == biosCat) { va_list argc; va_copy(argc, args); int immediate = va_arg(argc, int); @@ -253,7 +260,7 @@ GameController::GameController(QObject* parent) QMetaObject::invokeMethod(controller, "unimplementedBiosCall", Q_ARG(int, immediate)); } else #endif - if (category == _mLOG_CAT_STATUS()) { + if (category == statusCat) { // Slot 0 is reserved for suspend points if (strncmp(savestateMessage, format, strlen(savestateMessage)) == 0) { va_list argc; diff --git a/src/platform/sdl/sdl-audio.c b/src/platform/sdl/sdl-audio.c index 369592140..a58547497 100644 --- a/src/platform/sdl/sdl-audio.c +++ b/src/platform/sdl/sdl-audio.c @@ -14,7 +14,7 @@ #define BUFFER_SIZE (GBA_AUDIO_SAMPLES >> 2) -mLOG_DEFINE_CATEGORY(SDL_AUDIO, "SDL Audio"); +mLOG_DEFINE_CATEGORY(SDL_AUDIO, "SDL Audio", "platform.sdl.audio"); static void _mSDLAudioCallback(void* context, Uint8* data, int len); diff --git a/src/platform/sdl/sdl-events.c b/src/platform/sdl/sdl-events.c index 81eaffff2..896d473ca 100644 --- a/src/platform/sdl/sdl-events.c +++ b/src/platform/sdl/sdl-events.c @@ -25,7 +25,7 @@ #define RUMBLE_PWM 16 #define RUMBLE_STEPS 2 -mLOG_DEFINE_CATEGORY(SDL_EVENTS, "SDL Events"); +mLOG_DEFINE_CATEGORY(SDL_EVENTS, "SDL Events", "platform.sdl.events"); DEFINE_VECTOR(SDL_JoystickList, struct SDL_JoystickCombo); From 726986e4479a48322d15d40a9fba60fb6f6bf45c Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 5 Mar 2017 17:22:24 -0800 Subject: [PATCH 39/43] Util: Add startswith --- include/mgba-util/string.h | 1 + src/util/string.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/mgba-util/string.h b/include/mgba-util/string.h index 831ce8e44..7e9465719 100644 --- a/include/mgba-util/string.h +++ b/include/mgba-util/string.h @@ -21,6 +21,7 @@ char* strdup(const char* str); char* strnrstr(const char* restrict s1, const char* restrict s2, size_t len); bool endswith(const char* restrict s1, const char* restrict end); +bool startswith(const char* restrict s1, const char* restrict start); size_t toUtf8(uint32_t unichar, char* buffer); int utfcmp(const uint16_t* utf16, const char* utf8, size_t utf16Length, size_t utf8Length); diff --git a/src/util/string.c b/src/util/string.c index 7e18a8547..a776bc16d 100644 --- a/src/util/string.c +++ b/src/util/string.c @@ -48,6 +48,15 @@ bool endswith(const char* restrict s1, const char* restrict end) { return strcmp(&s1[len - endLen], end) == 0; } +bool startswith(const char* restrict s1, const char* restrict start) { + size_t len = strlen(s1); + size_t startLen = strlen(start); + if (len < startLen) { + return false; + } + return strncmp(s1, start, startLen) == 0; +} + uint32_t utf16Char(const uint16_t** unicode, size_t* length) { if (*length < 2) { *length = 0; From 6363a0817886183fefdcd544b190ef809bbb951d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 5 Mar 2017 17:23:08 -0800 Subject: [PATCH 40/43] Util: Add enumeration over a configuration section --- include/mgba-util/configuration.h | 1 + src/util/configuration.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/mgba-util/configuration.h b/include/mgba-util/configuration.h index e2e6ba7d3..d9aacddeb 100644 --- a/include/mgba-util/configuration.h +++ b/include/mgba-util/configuration.h @@ -38,6 +38,7 @@ bool ConfigurationWrite(const struct Configuration*, const char* path); bool ConfigurationWriteSection(const struct Configuration*, const char* path, const char* section); void ConfigurationEnumerateSections(const struct Configuration* configuration, void (*handler)(const char* sectionName, void* user), void* user); +void ConfigurationEnumerate(const struct Configuration* configuration, const char* section, void (*handler)(const char* key, const char* value, void* user), void* user); CXX_GUARD_END diff --git a/src/util/configuration.c b/src/util/configuration.c index 1021c5137..1cf26104c 100644 --- a/src/util/configuration.c +++ b/src/util/configuration.c @@ -18,6 +18,11 @@ struct ConfigurationSectionHandlerData { void* data; }; +struct ConfigurationHandlerData { + void (*handler)(const char* key, const char* value, void* data); + void* data; +}; + static void _tableDeinit(void* table) { TableDeinit(table); free(table); @@ -63,6 +68,11 @@ static void _sectionEnumHandler(const char* key, void* section, void* user) { data->handler(key, data->data); } +static void _enumHandler(const char* key, void* value, void* user) { + struct ConfigurationHandlerData* data = user; + data->handler(key, value, data->data); +} + void ConfigurationInit(struct Configuration* configuration) { HashTableInit(&configuration->sections, 0, _tableDeinit); HashTableInit(&configuration->root, 0, _sectionDeinit); @@ -199,3 +209,14 @@ void ConfigurationEnumerateSections(const struct Configuration* configuration, v struct ConfigurationSectionHandlerData handlerData = { handler, user }; HashTableEnumerate(&configuration->sections, _sectionEnumHandler, &handlerData); } + +void ConfigurationEnumerate(const struct Configuration* configuration, const char* section, void (*handler)(const char* key, const char* value, void* user), void* user) { + struct ConfigurationHandlerData handlerData = { handler, user }; + const struct Table* currentSection = &configuration->root; + if (section) { + currentSection = HashTableLookup(&configuration->sections, section); + } + if (currentSection) { + HashTableEnumerate(currentSection, _enumHandler, &handlerData); + } +} From 3c0c8a8f54a4798e61dd3a67645e91b91d2b0725 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 5 Mar 2017 17:23:32 -0800 Subject: [PATCH 41/43] Core: Add enumeration over config items --- include/mgba/core/config.h | 8 ++++++++ src/core/config.c | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index aca655976..6dbc73dc4 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -19,6 +19,12 @@ struct mCoreConfig { char* port; }; +enum mCoreConfigLevel { + mCONFIG_LEVEL_DEFAULT = 0, + mCONFIG_LEVEL_CUSTOM, + mCONFIG_LEVEL_OVERRIDE, +}; + struct mCoreOptions { char* bios; bool skipBios; @@ -90,6 +96,8 @@ void mCoreConfigCopyValue(struct mCoreConfig* config, const struct mCoreConfig* void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts); void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptions* opts); +void mCoreConfigEnumerate(const struct mCoreConfig* config, const char* prefix, void (*handler)(const char* key, const char* value, enum mCoreConfigLevel type, void* user), void* user); + struct Configuration* mCoreConfigGetInput(struct mCoreConfig*); struct Configuration* mCoreConfigGetOverrides(struct mCoreConfig*); const struct Configuration* mCoreConfigGetOverridesConst(const struct mCoreConfig*); diff --git a/src/core/config.c b/src/core/config.c index ceca2bdfd..b4d654c54 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -29,6 +29,13 @@ #define SECTION_NAME_MAX 128 +struct mCoreConfigEnumerateData { + void (*handler)(const char* key, const char* value, enum mCoreConfigLevel type, void* user); + const char* prefix; + void* user; + enum mCoreConfigLevel level; +}; + static const char* _lookupValue(const struct mCoreConfig* config, const char* key) { const char* value; if (config->port) { @@ -393,6 +400,22 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio ConfigurationSetIntValue(&config->defaultsTable, 0, "suspendScreensaver", opts->suspendScreensaver); } +static void _configEnum(const char* key, const char* value, void* user) { + struct mCoreConfigEnumerateData* data = user; + if (!data->prefix || startswith(key, data->prefix)) { + data->handler(key, value, data->level, data->user); + } +} + +void mCoreConfigEnumerate(const struct mCoreConfig* config, const char* prefix, void (*handler)(const char* key, const char* value, enum mCoreConfigLevel type, void* user), void* user) { + struct mCoreConfigEnumerateData handlerData = { handler, prefix, user, mCONFIG_LEVEL_DEFAULT }; + ConfigurationEnumerate(&config->defaultsTable, config->port, _configEnum, &handlerData); + handlerData.level = mCONFIG_LEVEL_CUSTOM; + ConfigurationEnumerate(&config->configTable, config->port, _configEnum, &handlerData); + handlerData.level = mCONFIG_LEVEL_OVERRIDE; + ConfigurationEnumerate(&config->overridesTable, config->port, _configEnum, &handlerData); +} + // These two are basically placeholders in case the internal layout changes, e.g. for loading separate files struct Configuration* mCoreConfigGetInput(struct mCoreConfig* config) { return &config->configTable; From ad7cb650dce79b8155be65663e37c337d8e67a71 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 5 Mar 2017 17:25:35 -0800 Subject: [PATCH 42/43] Core: Add logging filters --- include/mgba/core/log.h | 17 +++++++++ include/mgba/core/thread.h | 1 - src/core/log.c | 70 ++++++++++++++++++++++++++++++++++++-- src/core/thread.c | 24 ++++++++----- 4 files changed, 101 insertions(+), 11 deletions(-) diff --git a/include/mgba/core/log.h b/include/mgba/core/log.h index 3cdbe336e..5a6fc6128 100644 --- a/include/mgba/core/log.h +++ b/include/mgba/core/log.h @@ -10,6 +10,8 @@ CXX_GUARD_START +#include + enum mLogLevel { mLOG_FATAL = 0x01, mLOG_ERROR = 0x02, @@ -22,8 +24,16 @@ enum mLogLevel { mLOG_ALL = 0x7F }; +struct Table; +struct mLogFilter { + int defaultLevels; + struct Table categories; + struct Table levels; +}; + struct mLogger { void (*log)(struct mLogger*, int category, enum mLogLevel level, const char* format, va_list args); + struct mLogFilter* filter; }; struct mLogger* mLogGetContext(void); @@ -33,6 +43,13 @@ const char* mLogCategoryName(int); const char* mLogCategoryId(int); int mLogCategoryById(const char*); +struct mCoreConfig; +void mLogFilterInit(struct mLogFilter*); +void mLogFilterDeinit(struct mLogFilter*); +void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*); +void mLogFilterSet(struct mLogFilter*, const char* category, int levels); +bool mLogFilterTest(struct mLogFilter*, int category, enum mLogLevel level); + ATTRIBUTE_FORMAT(printf, 3, 4) void mLog(int category, enum mLogLevel level, const char* format, ...); diff --git a/include/mgba/core/thread.h b/include/mgba/core/thread.h index b0a60ac80..f586bfd3b 100644 --- a/include/mgba/core/thread.h +++ b/include/mgba/core/thread.h @@ -58,7 +58,6 @@ struct mCoreThread { bool frameWasOn; struct mThreadLogger logger; - enum mLogLevel logLevel; ThreadCallback startCallback; ThreadCallback resetCallback; ThreadCallback cleanCallback; diff --git a/src/core/log.c b/src/core/log.c index 04c6a1214..6af5724b9 100644 --- a/src/core/log.c +++ b/src/core/log.c @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include #include #define MAX_CATEGORY 64 @@ -36,7 +37,7 @@ int mLogGenerateCategory(const char* name, const char* id) { _categoryIds[_category] = id; } ++_category; - return _category; + return _category - 1; } const char* mLogCategoryName(int category) { @@ -68,7 +69,9 @@ void mLog(int category, enum mLogLevel level, const char* format, ...) { va_list args; va_start(args, format); if (context) { - context->log(context, category, level, format, args); + if (!context->filter || mLogFilterTest(context->filter, category, level)) { + context->log(context, category, level, format, args); + } } else { printf("%s: ", mLogCategoryName(category)); vprintf(format, args); @@ -77,4 +80,67 @@ void mLog(int category, enum mLogLevel level, const char* format, ...) { va_end(args); } +void mLogFilterInit(struct mLogFilter* filter) { + HashTableInit(&filter->categories, 8, NULL); + TableInit(&filter->levels, 8, NULL); +} + +void mLogFilterDeinit(struct mLogFilter* filter) { + HashTableDeinit(&filter->categories); + TableDeinit(&filter->levels); +} + +static void _setFilterLevel(const char* key, const char* value, enum mCoreConfigLevel level, void* user) { + UNUSED(level); + struct mLogFilter* filter = user; + key = strchr(key, '.'); + if (!key || !key[1]) { + return; + } + if (!value) { + return; + } + ++key; + char* end; + int ivalue = strtol(value, &end, 10); + if (ivalue == 0) { + ivalue = INT_MIN; // Zero is reserved + } + if (!end) { + return; + } + mLogFilterSet(filter, key, ivalue); +} + +void mLogFilterLoad(struct mLogFilter* filter, const struct mCoreConfig* config) { + mCoreConfigEnumerate(config, "logLevel.", _setFilterLevel, filter); + filter->defaultLevels = mLOG_ALL; + mCoreConfigGetIntValue(config, "logLevel", &filter->defaultLevels); +} + +void mLogFilterSet(struct mLogFilter* filter, const char* category, int levels) { + HashTableInsert(&filter->categories, category, (void*)(intptr_t) levels); + // Can't do this eagerly because not all categories are initialized immediately + int cat = mLogCategoryById(category); + if (cat >= 0) { + TableInsert(&filter->levels, cat, (void*)(intptr_t) levels); + } + +} +bool mLogFilterTest(struct mLogFilter* filter, int category, enum mLogLevel level) { + int value = (int) TableLookup(&filter->levels, category); + if (value) { + return value & level; + } + const char* cat = mLogCategoryId(category); + if (cat) { + value = (int) HashTableLookup(&filter->categories, cat); + if (value) { + TableInsert(&filter->levels, category, (void*)(intptr_t) value); + return value & level; + } + } + return level & filter->defaultLevels; +} + mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status") diff --git a/src/core/thread.c b/src/core/thread.c index 3ed5aeb1c..686330615 100644 --- a/src/core/thread.c +++ b/src/core/thread.c @@ -36,6 +36,8 @@ static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) { } #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) { MutexLock(&threadContext->stateMutex); threadContext->state = newState; @@ -147,6 +149,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { core->setSync(core, &threadContext->sync); core->reset(core); + struct mLogFilter filter; + if (!threadContext->logger.d.filter) { + threadContext->logger.d.filter = &filter; + mLogFilterInit(threadContext->logger.d.filter); + mLogFilterLoad(threadContext->logger.d.filter, &core->config); + } + if (core->opts.rewindEnable && core->opts.rewindBufferCapacity > 0) { mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity); threadContext->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0; @@ -225,13 +234,18 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) { } core->clearCoreCallbacks(core); + threadContext->logger.d.filter = NULL; + return 0; } bool mCoreThreadStart(struct mCoreThread* threadContext) { threadContext->state = THREAD_INITIALIZED; threadContext->logger.p = threadContext; - threadContext->logLevel = threadContext->core->opts.logLevel; + if (!threadContext->logger.d.log) { + threadContext->logger.d.log = _mCoreLog; + threadContext->logger.d.filter = NULL; + } if (!threadContext->sync.fpsTarget) { threadContext->sync.fpsTarget = _defaultFPSTarget; @@ -544,10 +558,7 @@ struct mCoreThread* mCoreThreadGet(void) { static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) { UNUSED(logger); - struct mCoreThread* thread = mCoreThreadGet(); - if (thread && !(thread->logLevel & level)) { - return; - } + UNUSED(level); printf("%s: ", mLogCategoryName(category)); vprintf(format, args); printf("\n"); @@ -556,9 +567,6 @@ static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level struct mLogger* mCoreThreadLogger(void) { struct mCoreThread* thread = mCoreThreadGet(); if (thread) { - if (!thread->logger.d.log) { - thread->logger.d.log = _mCoreLog; - } return &thread->logger.d; } return NULL; From 40ff1ea0c4dc514817d81dc7b2bd56659f4345dd Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 5 Mar 2017 17:54:36 -0800 Subject: [PATCH 43/43] GB Serialize: Fix clearing timing when loading state --- src/gb/serialize.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gb/serialize.c b/src/gb/serialize.c index 3e60eadcd..1cacc4224 100644 --- a/src/gb/serialize.c +++ b/src/gb/serialize.c @@ -144,6 +144,7 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) { if (error) { return false; } + gb->timing.root = NULL; gb->cpu->a = state->cpu.a; gb->cpu->f.packed = state->cpu.f;