diff --git a/README.md b/README.md
index e8fc6376a..d91a4fa6f 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ Up-to-date news and downloads can be found at [mgba.io](https://mgba.io/).
Features
--------
-- Near full Game Boy Advance hardware support[[1]](#missing).
+- Highly accurate Game Boy Advance hardware support[[1]](#missing).
- Partial DS hardware support[[1]](#missing).
- Game Boy/Game Boy Color hardware support.
- Fast emulation for Game Boy and Game Boy Advance. Known to run at full speed even on low end hardware, such as netbooks[[2]](#dscaveat).
@@ -19,6 +19,7 @@ Features
- Save type detection, even for flash memory size[[3]](#flashdetect).
- Support for cartridges with motion sensors and rumble (only usable with game controllers)[[2]](#dscaveat).
- Real-time clock support, even without configuration.
+- Solar sensor support for Boktai games.
- Game Boy Camera and Game Boy Printer support.
- A built-in GBA BIOS implementation, and ability to load external BIOS files. DS currently requires BIOS and firmware dumps[[2]](#dscaveat).
- Turbo/fast-forward support by holding Tab.
@@ -37,6 +38,31 @@ Features
- Cores available for RetroArch/Libretro and OpenEmu.
- Many, many smaller things.
+#### Game Boy mappers
+
+The following mappers are fully supported:
+
+- MBC1
+- MBC1M
+- MBC2
+- MBC3
+- MBC3+RTC
+- MBC5
+- MBC5+Rumble
+- MBC7
+
+The following mappers are partially supported:
+
+- Pocket Cam
+- TAMA5
+- HuC-3
+
+The following mappers are not currently supported:
+
+- MBC6
+- HuC-1
+- MMM01
+
### Planned features
- Networked multiplayer link cable support.
@@ -128,11 +154,11 @@ To build on Windows for development, using MSYS2 is recommended. Follow the inst
For x86 (32 bit) builds:
- pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libzip,pkg-config,qt5,SDL2,ntldd-git}
+ pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git}
For x86_64 (64 bit) builds:
- pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libzip,pkg-config,qt5,SDL2,ntldd-git}
+ pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git}
Check out the source code by running this command:
diff --git a/README_DE.md b/README_DE.md
index ddf87480f..f5b7affe3 100644
--- a/README_DE.md
+++ b/README_DE.md
@@ -10,7 +10,7 @@ Aktuelle Neuigkeiten und Downloads findest Du auf [mgba.io](https://mgba.io).
Features
--------
-- Nahzu vollständige Unterstützung der Game Boy Advance-Hardware[[1]](#missing).
+- Sehr genaue Unterstützung der Game Boy Advance-Hardware[[1]](#missing).
- Unterstützung der Game Boy-/Game Boy Color-Hardware.
- Schnelle Emulation. mGBA ist dafür bekannt, auch auf schwacher Hardware wie Netbooks mit voller Geschwindigkeit zu laufen.
- Qt- und SDL-Portierungen für eine vollwertige und eine "leichtgewichtige" Benutzeroberfläche.
@@ -18,6 +18,7 @@ Features
- Erkennung des Speichertypes, einschließlich der Größe des Flash-Speichers[[2]](#flashdetect).
- Unterstützung für Spielmodule mit Bewegungssensoren und Rüttel-Effekten (nur verwendbar mit Spiele-Controllern).
- Unterstützung für Echtzeituhren, selbst ohne Konfiguration.
+- Unterstützung für den Lichtsensor in Boktai-Spielen
- Unterstützung für Game Boy Printer und Game Boy Camera.
- Eingebaute BIOS-Implementierung mit der Möglichkeit, externe BIOS-Dateien zu laden.
- Turbo/Vorlauf-Unterstützung durch drücken der Tab-Taste.
@@ -36,6 +37,31 @@ Features
- Verfügbare Cores für RetroArch/Libretro und OpenEmu.
- Viele, viele kleinere Dinge.
+### Game Boy-Mapper
+
+Die folgenden Mapper werden vollständig unterstützt:
+
+- MBC1
+- MBC1M
+- MBC2
+- MBC3
+- MBC3+RTC (MBC3+Echtzeituhr)
+- MBC5
+- MBC5+Rumble (MBC5+Rüttel-Modul)
+- MBC7
+
+Die folgenden Mapper werden teilweise unterstützt:
+
+- Pocket Cam
+- TAMA5
+- HuC-3
+
+Die folgenden Mapper werden derzeit nicht unterstützt:
+
+- MBC6
+- HuC-1
+- MMM01
+
### Geplante Features
- Unterstützung für Link-Kabel-Multiplayer über ein Netzwerk.
@@ -110,11 +136,11 @@ Um mGBA auf Windows zu kompilieren, wird MSYS2 empfohlen. Befolge die Installati
Für x86 (32 Bit):
- pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libzip,pkg-config,qt5,SDL2,ntldd-git}
+ pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git}
Für x86_64 (64 Bit):
- pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libzip,pkg-config,qt5,SDL2,ntldd-git}
+ pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git}
Lade den aktuellen mGBA-Quellcode mithilfe des folgenden Kommandos herunter:
diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h
index 484b19c71..bea207b1b 100644
--- a/include/mgba/core/core.h
+++ b/include/mgba/core/core.h
@@ -203,8 +203,10 @@ void* mCoreGetMemoryBlock(struct mCore* core, uint32_t start, size_t* size);
#ifdef USE_ELF
struct ELF;
bool mCoreLoadELF(struct mCore* core, struct ELF* elf);
+#ifdef USE_DEBUGGERS
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF*);
#endif
+#endif
CXX_GUARD_END
diff --git a/src/core/core.c b/src/core/core.c
index 18775af32..baaed50f2 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -357,6 +357,7 @@ bool mCoreLoadELF(struct mCore* core, struct ELF* elf) {
return true;
}
+#ifdef USE_DEBUGGERS
void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF* elf) {
size_t symIndex = ELFFindSection(elf, ".symtab");
size_t names = ELFFindSection(elf, ".strtab");
@@ -376,5 +377,5 @@ void mCoreLoadELFSymbols(struct mDebuggerSymbols* symbols, struct ELF* elf) {
mDebuggerSymbolAdd(symbols, name, syms[i].st_value, -1);
}
}
-
+#endif
#endif
diff --git a/src/gb/gb.c b/src/gb/gb.c
index dd99b2bac..4d404e83c 100644
--- a/src/gb/gb.c
+++ b/src/gb/gb.c
@@ -612,6 +612,7 @@ void GBDetectModel(struct GB* gb) {
void GBUpdateIRQs(struct GB* gb) {
int irqs = gb->memory.ie & gb->memory.io[REG_IF];
if (!irqs) {
+ gb->cpu->irqPending = false;
return;
}
gb->cpu->halted = false;
diff --git a/src/gba/core.c b/src/gba/core.c
index d2fdfe9ae..3b781fb4a 100644
--- a/src/gba/core.c
+++ b/src/gba/core.c
@@ -738,7 +738,9 @@ static void _GBACoreLoadSymbols(struct mCore* core, struct VFile* vf) {
}
struct ELF* elf = ELFOpen(vf);
if (elf) {
+#ifdef USE_DEBUGGERS
mCoreLoadELFSymbols(core->symbolTable, elf);
+#endif
ELFClose(elf);
}
if (closeAfter) {
diff --git a/src/gba/memory.c b/src/gba/memory.c
index 299b3a15d..3fd6fb0ad 100644
--- a/src/gba/memory.c
+++ b/src/gba/memory.c
@@ -1629,7 +1629,7 @@ void _pristineCow(struct GBA* gba) {
if (!gba->isPristine) {
return;
}
-#ifndef FIXED_ROM_BUFFER
+#if !defined(FIXED_ROM_BUFFER) && !defined(__wii__)
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);
diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c
index 707f3eaf6..046e64180 100644
--- a/src/platform/libretro/libretro.c
+++ b/src/platform/libretro/libretro.c
@@ -76,6 +76,16 @@ static void _reloadSettings(void) {
opts.skipBios = strcmp(var.value, "ON") == 0;
}
+ var.key = "mgba_sgb_borders";
+ var.value = 0;
+ if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
+ if (strcmp(var.value, "ON") == 0) {
+ mCoreConfigSetDefaultIntValue(&core->config, "sgb.borders", true);
+ } else {
+ mCoreConfigSetDefaultIntValue(&core->config, "sgb.borders", false);
+ }
+ }
+
var.key = "mgba_idle_optimization";
var.value = 0;
if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
@@ -111,6 +121,7 @@ void retro_set_environment(retro_environment_t env) {
{ "mgba_allow_opposing_directions", "Allow opposing directional input; OFF|ON" },
{ "mgba_use_bios", "Use BIOS file if found (requires restart); ON|OFF" },
{ "mgba_skip_bios", "Skip BIOS intro (requires restart); OFF|ON" },
+ { "mgba_sgb_borders", "Use Super Game Boy borders (requires restart); ON|OFF" },
{ "mgba_idle_optimization", "Idle loop removal; Remove Known|Detect and Remove|Don't Remove" },
{ "mgba_frameskip", "Frameskip; 0|1|2|3|4|5|6|7|8|9|10" },
{ 0, 0 }
diff --git a/src/platform/python/engine.c b/src/platform/python/engine.c
index 6222039a0..e6b2c0cf6 100644
--- a/src/platform/python/engine.c
+++ b/src/platform/python/engine.c
@@ -83,10 +83,12 @@ bool mPythonScriptEngineLoadScript(struct mScriptEngine* se, const char* name, s
void mPythonScriptEngineRun(struct mScriptEngine* se) {
struct mPythonScriptEngine* engine = (struct mPythonScriptEngine*) se;
+#ifdef USE_DEBUGGERS
struct mDebugger* debugger = mScriptBridgeGetDebugger(engine->sb);
if (debugger) {
mPythonSetDebugger(debugger);
}
+#endif
mPythonRunPending();
}
diff --git a/src/platform/qt/Display.cpp b/src/platform/qt/Display.cpp
index 515254e23..5e0de4b1c 100644
--- a/src/platform/qt/Display.cpp
+++ b/src/platform/qt/Display.cpp
@@ -8,12 +8,6 @@
#include "DisplayGL.h"
#include "DisplayQt.h"
-#ifdef M_CORE_GB
-#include
-#elif defined(M_CORE_GBA)
-#include
-#endif
-
using namespace QGBA;
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY)
@@ -55,11 +49,6 @@ Display::Display(QWidget* parent)
: QWidget(parent)
{
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
-#ifdef M_CORE_GB
- setMinimumSize(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
-#elif defined(M_CORE_GBA)
- setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
-#endif
connect(&m_mouseTimer, &QTimer::timeout, this, &Display::hideCursor);
m_mouseTimer.setSingleShot(true);
m_mouseTimer.setInterval(MOUSE_DISAPPEAR_TIMER);
diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp
index 3670d1b6c..99e33bd56 100644
--- a/src/platform/qt/Window.cpp
+++ b/src/platform/qt/Window.cpp
@@ -458,7 +458,9 @@ void Window::openSettingsWindow() {
connect(settingsWindow, &SettingsView::cameraDriverChanged, this, &Window::mustRestart);
connect(settingsWindow, &SettingsView::languageChanged, this, &Window::mustRestart);
connect(settingsWindow, &SettingsView::pathsChanged, this, &Window::reloadConfig);
+#ifdef USE_SQLITE3
connect(settingsWindow, &SettingsView::libraryCleared, m_libraryView, &LibraryController::clear);
+#endif
openView(settingsWindow);
}
@@ -723,8 +725,6 @@ void Window::gameStarted() {
multiplayerChanged();
updateTitle();
QSize size = m_controller->screenDimensions();
- m_display->setMinimumSize(size);
- m_screenWidget->setMinimumSize(m_display->minimumSize());
m_screenWidget->setDimensions(size.width(), size.height());
m_config->updateOption("lockIntegerScaling");
m_config->updateOption("lockAspectRatio");
@@ -733,6 +733,7 @@ void Window::gameStarted() {
}
attachWidget(m_display.get());
setMouseTracking(true);
+ m_display->setMinimumSize(size);
#ifndef Q_OS_MAC
if (isFullScreen()) {
@@ -805,7 +806,6 @@ void Window::gameStopped() {
#elif defined(M_CORE_GBA)
m_display->setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
#endif
- m_screenWidget->setMinimumSize(m_display->minimumSize());
setMouseTracking(false);
m_videoLayers->clear();
@@ -858,8 +858,7 @@ void Window::reloadDisplayDriver() {
m_shaderView.reset();
m_shaderView = std::make_unique(m_display.get(), m_config);
#endif
- m_screenWidget->setMinimumSize(m_display->minimumSize());
- m_screenWidget->setSizePolicy(m_display->sizePolicy());
+
connect(this, &Window::shutdown, m_display.get(), &Display::stopDrawing);
connect(m_display.get(), &Display::hideCursor, [this]() {
if (static_cast(m_screenWidget->layout())->currentWidget() == m_display.get()) {
@@ -885,6 +884,7 @@ void Window::reloadDisplayDriver() {
#endif
if (m_controller) {
+ m_display->setMinimumSize(m_controller->screenDimensions());
connect(m_controller.get(), &CoreController::stopping, m_display.get(), &Display::stopDrawing);
connect(m_controller.get(), &CoreController::stateLoaded, m_display.get(), &Display::forceDraw);
connect(m_controller.get(), &CoreController::rewound, m_display.get(), &Display::forceDraw);
@@ -895,6 +895,12 @@ void Window::reloadDisplayDriver() {
attachWidget(m_display.get());
m_display->startDrawing(m_controller);
+ } else {
+#ifdef M_CORE_GB
+ m_display->setMinimumSize(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
+#elif defined(M_CORE_GBA)
+ m_display->setMinimumSize(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
+#endif
}
}
@@ -1018,6 +1024,7 @@ void Window::openStateWindow(LoadSave ls) {
}
m_stateWindow->setAttribute(Qt::WA_DeleteOnClose);
m_stateWindow->setMode(ls);
+ updateFrame();
attachWidget(m_stateWindow);
}
@@ -1757,6 +1764,16 @@ void Window::focusCheck() {
}
}
+void Window::updateFrame() {
+ QSize size = m_controller->screenDimensions();
+ QImage currentImage(reinterpret_cast(m_controller->drawContext()), size.width(), size.height(),
+ size.width() * BYTES_PER_PIXEL, QImage::Format_RGBX8888);
+ QPixmap pixmap;
+ pixmap.convertFromImage(currentImage);
+ m_screenWidget->setPixmap(pixmap);
+ emit paused(true);
+}
+
void Window::setController(CoreController* controller, const QString& fname) {
if (!controller) {
return;
@@ -1793,15 +1810,7 @@ void Window::setController(CoreController* controller, const QString& fname) {
});
}
connect(m_controller.get(), &CoreController::stopping, &m_inputController, &InputController::resumeScreensaver);
- connect(m_controller.get(), &CoreController::paused, [this]() {
- QSize size = m_controller->screenDimensions();
- QImage currentImage(reinterpret_cast(m_controller->drawContext()), size.width(), size.height(),
- size.width() * BYTES_PER_PIXEL, QImage::Format_RGBX8888);
- QPixmap pixmap;
- pixmap.convertFromImage(currentImage);
- m_screenWidget->setPixmap(pixmap);
- emit paused(true);
- });
+ connect(m_controller.get(), &CoreController::paused, this, &Window::updateFrame);
#ifndef Q_OS_MAC
connect(m_controller.get(), &CoreController::paused, menuBar(), &QWidget::show);
@@ -1831,13 +1840,17 @@ void Window::setController(CoreController* controller, const QString& fname) {
connect(m_controller.get(), &CoreController::failed, this, &Window::gameFailed);
connect(m_controller.get(), &CoreController::unimplementedBiosCall, this, &Window::unimplementedBiosCall);
+#ifdef USE_GDB_STUB
if (m_gdbController) {
m_gdbController->setController(m_controller);
}
+#endif
+#ifdef USE_DEBUGGERS
if (m_console) {
m_console->setController(m_controller);
}
+#endif
#ifdef USE_MAGICK
if (m_gifView) {
@@ -1869,11 +1882,15 @@ void Window::setController(CoreController* controller, const QString& fname) {
}
WindowBackground::WindowBackground(QWidget* parent)
- : QLabel(parent)
+ : QWidget(parent)
{
setLayout(new QStackedLayout());
layout()->setContentsMargins(0, 0, 0, 0);
- setAlignment(Qt::AlignCenter);
+}
+
+void WindowBackground::setPixmap(const QPixmap& pmap) {
+ m_pixmap = pmap;
+ update();
}
void WindowBackground::setSizeHint(const QSize& hint) {
@@ -1904,11 +1921,9 @@ void WindowBackground::setLockAspectRatio(bool lock) {
m_lockAspectRatio = lock;
}
-void WindowBackground::paintEvent(QPaintEvent*) {
- const QPixmap* logo = pixmap();
- if (!logo) {
- return;
- }
+void WindowBackground::paintEvent(QPaintEvent* event) {
+ QWidget::paintEvent(event);
+ const QPixmap& logo = pixmap();
QPainter painter(this);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.fillRect(QRect(QPoint(), size()), Qt::black);
@@ -1933,5 +1948,5 @@ void WindowBackground::paintEvent(QPaintEvent*) {
}
QPoint origin = QPoint((s.width() - ds.width()) / 2, (s.height() - ds.height()) / 2);
QRect full(origin, ds);
- painter.drawPixmap(full, *logo);
+ painter.drawPixmap(full, logo);
}
diff --git a/src/platform/qt/Window.h b/src/platform/qt/Window.h
index c9808f203..f50aa5933 100644
--- a/src/platform/qt/Window.h
+++ b/src/platform/qt/Window.h
@@ -133,6 +133,8 @@ private slots:
void showFPS();
void focusCheck();
+ void updateFrame();
+
private:
static const int FPS_TIMER_INTERVAL = 2000;
static const int FRAME_LIST_SIZE = 120;
@@ -218,12 +220,13 @@ private:
#endif
};
-class WindowBackground : public QLabel {
+class WindowBackground : public QWidget {
Q_OBJECT
public:
WindowBackground(QWidget* parent = 0);
+ void setPixmap(const QPixmap& pixmap);
void setSizeHint(const QSize& size);
virtual QSize sizeHint() const override;
void setDimensions(int width, int height);
@@ -231,10 +234,13 @@ public:
void setLockIntegerScaling(bool lock);
void setLockAspectRatio(bool lock);
+ const QPixmap& pixmap() const { return m_pixmap; }
+
protected:
virtual void paintEvent(QPaintEvent*) override;
private:
+ QPixmap m_pixmap;
QSize m_sizeHint;
bool m_centered;
int m_aspectWidth;