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;