diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index 290cb598..90caea20 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES_QT_SDL main_shaders.h Screen.cpp Window.cpp + EmuInstance.cpp EmuThread.cpp CheatsDialog.cpp Config.cpp @@ -36,7 +37,6 @@ set(SOURCES_QT_SDL font.h Platform.cpp QPathInput.h - ROMManager.cpp SaveManager.cpp CameraManager.cpp AudioInOut.cpp diff --git a/src/frontend/qt_sdl/CheatsDialog.cpp b/src/frontend/qt_sdl/CheatsDialog.cpp index df687230..594f06e3 100644 --- a/src/frontend/qt_sdl/CheatsDialog.cpp +++ b/src/frontend/qt_sdl/CheatsDialog.cpp @@ -24,7 +24,7 @@ #include "types.h" #include "Platform.h" #include "Config.h" -#include "ROMManager.h" +#include "EmuInstance.h" #include "CheatsDialog.h" #include "ui_CheatsDialog.h" @@ -43,6 +43,9 @@ CheatsDialog::CheatsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Cheats ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); + MainWindow* win = (MainWindow*)parent; + // + codeFile = ROMManager::GetCheatFile(); QStandardItemModel* model = new QStandardItemModel(); diff --git a/src/frontend/qt_sdl/EmuInstance.h b/src/frontend/qt_sdl/EmuInstance.h index 3e8276af..26d573ed 100644 --- a/src/frontend/qt_sdl/EmuInstance.h +++ b/src/frontend/qt_sdl/EmuInstance.h @@ -38,6 +38,8 @@ public: // return: empty string = setup OK, non-empty = error message QString verifySetup(); + bool updateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAArgs&& gbaargs) noexcept; + private: static int lastSep(const std::string& path); std::string getAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file); @@ -70,7 +72,6 @@ private: melonDS::ARCodeFile* getCheatFile(); void setBatteryLevels(); void setDateTime(); - bool updateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAArgs&& gbaargs) noexcept; void reset(); bool bootToMenu(); melonDS::u32 decompressROM(const melonDS::u8* inContent, const melonDS::u32 inSize, std::unique_ptr& outContent); @@ -125,6 +126,9 @@ private: melonDS::ARCodeFile* cheatFile; bool cheatsOn; + + friend class EmuThread; + friend class MainWindow; }; #endif //EMUINSTANCE_H diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 7273fb69..d05661c0 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -55,7 +55,7 @@ #include "Savestate.h" -#include "ROMManager.h" +#include "EmuInstance.h" //#include "ArchiveUtil.h" //#include "CameraManager.h" @@ -72,8 +72,10 @@ extern int videoRenderer; extern bool videoSettingsDirty; -EmuThread::EmuThread(QObject* parent) : QThread(parent) +EmuThread::EmuThread(EmuInstance* inst, QObject* parent) : QThread(parent) { + emuInstance = inst; + EmuStatus = emuStatus_Exit; EmuRunning = emuStatus_Paused; EmuPauseStack = EmuPauseStackRunning; @@ -133,218 +135,12 @@ void EmuThread::detachWindow(MainWindow* window) mainWindow = windowList.front(); } -std::unique_ptr EmuThread::CreateConsole( - std::unique_ptr&& ndscart, - std::unique_ptr&& gbacart -) noexcept -{ - auto arm7bios = ROMManager::LoadARM7BIOS(); - if (!arm7bios) - return nullptr; - - auto arm9bios = ROMManager::LoadARM9BIOS(); - if (!arm9bios) - return nullptr; - - auto firmware = ROMManager::LoadFirmware(Config::ConsoleType); - if (!firmware) - return nullptr; - -#ifdef JIT_ENABLED - JITArgs jitargs { - static_cast(Config::JIT_MaxBlockSize), - Config::JIT_LiteralOptimisations, - Config::JIT_BranchOptimisations, - Config::JIT_FastMemory, - }; -#endif - -#ifdef GDBSTUB_ENABLED - GDBArgs gdbargs { - static_cast(Config::GdbPortARM7), - static_cast(Config::GdbPortARM9), - Config::GdbARM7BreakOnStartup, - Config::GdbARM9BreakOnStartup, - }; -#endif - - NDSArgs ndsargs { - std::move(ndscart), - std::move(gbacart), - *arm9bios, - *arm7bios, - std::move(*firmware), -#ifdef JIT_ENABLED - Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt, -#else - std::nullopt, -#endif - static_cast(Config::AudioBitDepth), - static_cast(Config::AudioInterp), -#ifdef GDBSTUB_ENABLED - Config::GdbEnabled ? std::make_optional(gdbargs) : std::nullopt, -#else - std::nullopt, -#endif - }; - - if (Config::ConsoleType == 1) - { - auto arm7ibios = ROMManager::LoadDSiARM7BIOS(); - if (!arm7ibios) - return nullptr; - - auto arm9ibios = ROMManager::LoadDSiARM9BIOS(); - if (!arm9ibios) - return nullptr; - - auto nand = ROMManager::LoadNAND(*arm7ibios); - if (!nand) - return nullptr; - - auto sdcard = ROMManager::LoadDSiSDCard(); - DSiArgs args { - std::move(ndsargs), - *arm9ibios, - *arm7ibios, - std::move(*nand), - std::move(sdcard), - Config::DSiFullBIOSBoot, - }; - - args.GBAROM = nullptr; - - return std::make_unique(std::move(args)); - } - - return std::make_unique(std::move(ndsargs)); -} - -bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAArgs&& gbaargs) noexcept -{ - // Let's get the cart we want to use; - // if we wnat to keep the cart, we'll eject it from the existing console first. - std::unique_ptr nextndscart; - if (std::holds_alternative(ndsargs)) - { // If we want to keep the existing cart (if any)... - nextndscart = NDS ? NDS->EjectCart() : nullptr; - ndsargs = {}; - } - else if (const auto ptr = std::get_if>(&ndsargs)) - { - nextndscart = std::move(*ptr); - ndsargs = {}; - } - - if (auto* cartsd = dynamic_cast(nextndscart.get())) - { - // LoadDLDISDCard will return nullopt if the SD card is disabled; - // SetSDCard will accept nullopt, which means no SD card - cartsd->SetSDCard(ROMManager::GetDLDISDCardArgs()); - } - - std::unique_ptr nextgbacart; - if (std::holds_alternative(gbaargs)) - { - nextgbacart = NDS ? NDS->EjectGBACart() : nullptr; - } - else if (const auto ptr = std::get_if>(&gbaargs)) - { - nextgbacart = std::move(*ptr); - gbaargs = {}; - } - - if (!NDS || NDS->ConsoleType != Config::ConsoleType) - { // If we're switching between DS and DSi mode, or there's no console... - // To ensure the destructor is called before a new one is created, - // as the presence of global signal handlers still complicates things a bit - NDS = nullptr; - NDS::Current = nullptr; - - NDS = CreateConsole(std::move(nextndscart), std::move(nextgbacart)); - - if (NDS == nullptr) - return false; - - NDS->Reset(); - NDS::Current = NDS.get(); - - return true; - } - - auto arm9bios = ROMManager::LoadARM9BIOS(); - if (!arm9bios) - return false; - - auto arm7bios = ROMManager::LoadARM7BIOS(); - if (!arm7bios) - return false; - - auto firmware = ROMManager::LoadFirmware(NDS->ConsoleType); - if (!firmware) - return false; - - if (NDS->ConsoleType == 1) - { // If the console we're updating is a DSi... - DSi& dsi = static_cast(*NDS); - - auto arm9ibios = ROMManager::LoadDSiARM9BIOS(); - if (!arm9ibios) - return false; - - auto arm7ibios = ROMManager::LoadDSiARM7BIOS(); - if (!arm7ibios) - return false; - - auto nandimage = ROMManager::LoadNAND(*arm7ibios); - if (!nandimage) - return false; - - auto dsisdcard = ROMManager::LoadDSiSDCard(); - - dsi.SetFullBIOSBoot(Config::DSiFullBIOSBoot); - dsi.ARM7iBIOS = *arm7ibios; - dsi.ARM9iBIOS = *arm9ibios; - dsi.SetNAND(std::move(*nandimage)); - dsi.SetSDCard(std::move(dsisdcard)); - // We're moving the optional, not the card - // (inserting std::nullopt here is okay, it means no card) - - dsi.EjectGBACart(); - } - - if (NDS->ConsoleType == 0) - { - NDS->SetGBACart(std::move(nextgbacart)); - } - -#ifdef JIT_ENABLED - JITArgs jitargs { - static_cast(Config::JIT_MaxBlockSize), - Config::JIT_LiteralOptimisations, - Config::JIT_BranchOptimisations, - Config::JIT_FastMemory, - }; - NDS->SetJITArgs(Config::JIT_Enable ? std::make_optional(jitargs) : std::nullopt); -#endif - NDS->SetARM7BIOS(*arm7bios); - NDS->SetARM9BIOS(*arm9bios); - NDS->SetFirmware(std::move(*firmware)); - NDS->SetNDSCart(std::move(nextndscart)); - NDS->SPU.SetInterpolation(static_cast(Config::AudioInterp)); - NDS->SPU.SetDegrade10Bit(static_cast(Config::AudioBitDepth)); - - NDS::Current = NDS.get(); - - return true; -} - void EmuThread::run() { u32 mainScreenPos[3]; Platform::FileHandle* file; - UpdateConsole(nullptr, nullptr); + emuInstance->updateConsole(nullptr, nullptr); // No carts are inserted when melonDS first boots mainScreenPos[0] = 0; @@ -376,7 +172,7 @@ void EmuThread::run() if (videoRenderer == 0) { // If we're using the software renderer... - NDS->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); + emuInstance->nds->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); } else { @@ -384,7 +180,7 @@ void EmuThread::run() auto glrenderer = melonDS::GLRenderer::New(); glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor); - NDS->GPU.SetRenderer3D(std::move(glrenderer)); + emuInstance->nds->GPU.SetRenderer3D(std::move(glrenderer)); } Input::Init(); @@ -404,7 +200,7 @@ void EmuThread::run() RTC::StateData state; Platform::FileRead(&state, sizeof(state), 1, file); Platform::CloseFile(file); - NDS->RTC.SetState(state); + emuInstance->nds->RTC.SetState(state); } char melontitle[100]; @@ -431,7 +227,7 @@ void EmuThread::run() if (Input::HotkeyPressed(HK_SolarSensorDecrease)) { - int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true); + int level = emuInstance->nds->GBACartSlot.SetInput(GBACart::Input_SolarSensorDown, true); if (level != -1) { //mainWindow->osdAddMessage(0, "Solar sensor level: %d", level); @@ -439,48 +235,48 @@ void EmuThread::run() } if (Input::HotkeyPressed(HK_SolarSensorIncrease)) { - int level = NDS->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true); + int level = emuInstance->nds->GBACartSlot.SetInput(GBACart::Input_SolarSensorUp, true); if (level != -1) { //mainWindow->osdAddMessage(0, "Solar sensor level: %d", level); } } - if (NDS->ConsoleType == 1) + if (emuInstance->nds->ConsoleType == 1) { - DSi& dsi = static_cast(*NDS); + DSi* dsi = static_cast(emuInstance->nds); double currentTime = SDL_GetPerformanceCounter() * perfCountsSec; // Handle power button if (Input::HotkeyDown(HK_PowerButton)) { - dsi.I2C.GetBPTWL()->SetPowerButtonHeld(currentTime); + dsi->I2C.GetBPTWL()->SetPowerButtonHeld(currentTime); } else if (Input::HotkeyReleased(HK_PowerButton)) { - dsi.I2C.GetBPTWL()->SetPowerButtonReleased(currentTime); + dsi->I2C.GetBPTWL()->SetPowerButtonReleased(currentTime); } // Handle volume buttons if (Input::HotkeyDown(HK_VolumeUp)) { - dsi.I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Up); + dsi->I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Up); } else if (Input::HotkeyReleased(HK_VolumeUp)) { - dsi.I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Up); + dsi->I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Up); } if (Input::HotkeyDown(HK_VolumeDown)) { - dsi.I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Down); + dsi->I2C.GetBPTWL()->SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Down); } else if (Input::HotkeyReleased(HK_VolumeDown)) { - dsi.I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Down); + dsi->I2C.GetBPTWL()->SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Down); } - dsi.I2C.GetBPTWL()->ProcessVolumeSwitchInput(currentTime); + dsi->I2C.GetBPTWL()->ProcessVolumeSwitchInput(currentTime); } if (useOpenGL) @@ -512,35 +308,35 @@ void EmuThread::run() if (videoRenderer == 0) { // If we're using the software renderer... - NDS->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); + emuInstance->nds->GPU.SetRenderer3D(std::make_unique(Config::Threaded3D != 0)); } else { auto glrenderer = melonDS::GLRenderer::New(); glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor); - NDS->GPU.SetRenderer3D(std::move(glrenderer)); + emuInstance->nds->GPU.SetRenderer3D(std::move(glrenderer)); } } // process input and hotkeys - NDS->SetKeyMask(Input::InputMask); + emuInstance->nds->SetKeyMask(Input::InputMask); if (Input::HotkeyPressed(HK_Lid)) { - bool lid = !NDS->IsLidClosed(); - NDS->SetLidClosed(lid); + bool lid = !emuInstance->nds->IsLidClosed(); + emuInstance->nds->SetLidClosed(lid); //mainWindow->osdAddMessage(0, lid ? "Lid closed" : "Lid opened"); } // microphone input - AudioInOut::MicProcess(*NDS); + //AudioInOut::MicProcess(emuInstance->nds); // auto screen layout if (Config::ScreenSizing == Frontend::screenSizing_Auto) { mainScreenPos[2] = mainScreenPos[1]; mainScreenPos[1] = mainScreenPos[0]; - mainScreenPos[0] = NDS->PowerControl9 >> 15; + mainScreenPos[0] = emuInstance->nds->PowerControl9 >> 15; int guess; if (mainScreenPos[0] == mainScreenPos[2] && @@ -567,26 +363,26 @@ void EmuThread::run() // emulate - u32 nlines = NDS->RunFrame(); + u32 nlines = emuInstance->nds->RunFrame(); - if (ROMManager::NDSSave) - ROMManager::NDSSave->CheckFlush(); + if (emuInstance->ndsSave) + emuInstance->ndsSave->CheckFlush(); - if (ROMManager::GBASave) - ROMManager::GBASave->CheckFlush(); + if (emuInstance->gbaSave) + emuInstance->gbaSave->CheckFlush(); - if (ROMManager::FirmwareSave) - ROMManager::FirmwareSave->CheckFlush(); + if (emuInstance->firmwareSave) + emuInstance->firmwareSave->CheckFlush(); if (!useOpenGL) { FrontBufferLock.lock(); - FrontBuffer = NDS->GPU.FrontBuffer; + FrontBuffer = emuInstance->nds->GPU.FrontBuffer; FrontBufferLock.unlock(); } else { - FrontBuffer = NDS->GPU.FrontBuffer; + FrontBuffer = emuInstance->nds->GPU.FrontBuffer; //screenGL->drawScreenGL(); for (auto window : windowList) window->drawScreenGL(); @@ -614,10 +410,10 @@ void EmuThread::run() window->setGLSwapInterval(0); } - if (Config::DSiVolumeSync && NDS->ConsoleType == 1) + if (Config::DSiVolumeSync && emuInstance->nds->ConsoleType == 1) { - DSi& dsi = static_cast(*NDS); - u8 volumeLevel = dsi.I2C.GetBPTWL()->GetVolumeLevel(); + DSi* dsi = static_cast(emuInstance->nds); + u8 volumeLevel = dsi->I2C.GetBPTWL()->GetVolumeLevel(); if (volumeLevel != dsiVolumeLevel) { dsiVolumeLevel = volumeLevel; @@ -627,8 +423,8 @@ void EmuThread::run() Config::AudioVolume = volumeLevel * (256.0 / 31.0); } - if (Config::AudioSync && !fastforward) - AudioInOut::AudioSync(*this->NDS); + //if (Config::AudioSync && !fastforward) + // AudioInOut::AudioSync(emuInstance->nds); double frametimeStep = nlines / (60.0 * 263.0); @@ -734,7 +530,7 @@ void EmuThread::run() if (file) { RTC::StateData state; - NDS->RTC.GetState(state); + emuInstance->nds->RTC.GetState(state); Platform::FileWrite(&state, sizeof(state), 1, file); Platform::CloseFile(file); } diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h index aa9288e3..ff005f22 100644 --- a/src/frontend/qt_sdl/EmuThread.h +++ b/src/frontend/qt_sdl/EmuThread.h @@ -38,6 +38,7 @@ namespace melonDS class NDS; } +class EmuInstance; class MainWindow; class ScreenPanelGL; @@ -47,7 +48,7 @@ class EmuThread : public QThread void run() override; public: - explicit EmuThread(QObject* parent = nullptr); + explicit EmuThread(EmuInstance* inst, QObject* parent = nullptr); void attachWindow(MainWindow* window); void detachWindow(MainWindow* window); @@ -70,13 +71,6 @@ public: int FrontBuffer = 0; QMutex FrontBufferLock; - /// Applies the config in args. - /// Creates a new NDS console if needed, - /// modifies the existing one if possible. - /// @return \c true if the console was updated. - /// If this returns \c false, then the existing NDS console is not modified. - bool UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAArgs&& gbaargs) noexcept; - std::unique_ptr NDS; // TODO: Proper encapsulation and synchronization signals: void windowUpdate(); void windowTitleChange(QString title); @@ -99,11 +93,6 @@ signals: void syncVolumeLevel(); private: - std::unique_ptr CreateConsole( - std::unique_ptr&& ndscart, - std::unique_ptr&& gbacart - ) noexcept; - enum EmuStatusKind { emuStatus_Exit, @@ -128,6 +117,8 @@ private: }; std::atomic ContextRequest = contextRequest_None; + EmuInstance* emuInstance; + //ScreenPanelGL* screenGL; MainWindow* mainWindow; std::list windowList; diff --git a/src/frontend/qt_sdl/ROMInfoDialog.h b/src/frontend/qt_sdl/ROMInfoDialog.h index f7e3b5f5..d0634f4a 100644 --- a/src/frontend/qt_sdl/ROMInfoDialog.h +++ b/src/frontend/qt_sdl/ROMInfoDialog.h @@ -25,7 +25,6 @@ #include #include "types.h" -#include "ROMManager.h" namespace Ui { class ROMInfoDialog; } class ROMInfoDialog; diff --git a/src/frontend/qt_sdl/ROMManager.cpp b/src/frontend/qt_sdl/ROMManager.cpp deleted file mode 100644 index 53d86828..00000000 --- a/src/frontend/qt_sdl/ROMManager.cpp +++ /dev/null @@ -1,1647 +0,0 @@ -/* - Copyright 2016-2023 melonDS team - - This file is part of melonDS. - - melonDS is free software: you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation, either version 3 of the License, or (at your option) - any later version. - - melonDS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with melonDS. If not, see http://www.gnu.org/licenses/. -*/ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#ifdef ARCHIVE_SUPPORT_ENABLED -#include "ArchiveUtil.h" -#endif -#include "ROMManager.h" -#include "Config.h" -#include "Platform.h" - -#include "NDS.h" -#include "DSi.h" -#include "SPI.h" -#include "RTC.h" -#include "DSi_I2C.h" -#include "FreeBIOS.h" -#include "main.h" - -using std::make_unique; -using std::pair; -using std::string; -using std::tie; -using std::unique_ptr; -using std::wstring_convert; -using namespace melonDS; -using namespace melonDS::Platform; - -namespace ROMManager -{ - -int CartType = -1; -std::string BaseROMDir = ""; -std::string BaseROMName = ""; -std::string BaseAssetName = ""; - -int GBACartType = -1; -std::string BaseGBAROMDir = ""; -std::string BaseGBAROMName = ""; -std::string BaseGBAAssetName = ""; - -std::unique_ptr NDSSave = nullptr; -std::unique_ptr GBASave = nullptr; -std::unique_ptr FirmwareSave = nullptr; - -std::unique_ptr BackupState = nullptr; -bool SavestateLoaded = false; -std::string PreviousSaveFile = ""; - -ARCodeFile* CheatFile = nullptr; -bool CheatsOn = false; - -#if 0 -int LastSep(const std::string& path) -{ - int i = path.length() - 1; - while (i >= 0) - { - if (path[i] == '/' || path[i] == '\\') - return i; - - i--; - } - - return -1; -} - -std::string GetAssetPath(bool gba, const std::string& configpath, const std::string& ext, const std::string& file = "") -{ - std::string result; - - if (configpath.empty()) - result = gba ? BaseGBAROMDir : BaseROMDir; - else - result = configpath; - - // cut off trailing slashes - for (;;) - { - int i = result.length() - 1; - if (i < 0) break; - if (result[i] == '/' || result[i] == '\\') - result.resize(i); - else - break; - } - - if (!result.empty()) - result += '/'; - - if (file.empty()) - { - std::string& baseName = gba ? BaseGBAAssetName : BaseAssetName; - if (baseName.empty()) - result += "firmware"; - else - result += baseName; - } - else - { - result += file; - } - - result += ext; - - return result; -} - - -QString VerifyDSBIOS() -{ - FileHandle* f; - long len; - - Config::Table cfg = Config::GetGlobalTable(); - - f = Platform::OpenLocalFile(cfg.GetString("DS.BIOS9Path"), FileMode::Read); - if (!f) return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings."; - - len = FileLength(f); - if (len != 0x1000) - { - CloseFile(f); - return "DS ARM9 BIOS is not a valid BIOS dump."; - } - - CloseFile(f); - - f = Platform::OpenLocalFile(cfg.GetString("DS.BIOS7Path"), FileMode::Read); - if (!f) return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings."; - - len = FileLength(f); - if (len != 0x4000) - { - CloseFile(f); - return "DS ARM7 BIOS is not a valid BIOS dump."; - } - - CloseFile(f); - - return ""; -} - -QString VerifyDSiBIOS() -{ - FileHandle* f; - long len; - - Config::Table cfg = Config::GetGlobalTable(); - - // TODO: check the first 32 bytes - - f = Platform::OpenLocalFile(cfg.GetString("DSi.BIOS9Path"), FileMode::Read); - if (!f) return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings."; - - len = FileLength(f); - if (len != 0x10000) - { - CloseFile(f); - return "DSi ARM9 BIOS is not a valid BIOS dump."; - } - - CloseFile(f); - - f = Platform::OpenLocalFile(cfg.GetString("DSi.BIOS7Path"), FileMode::Read); - if (!f) return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings."; - - len = FileLength(f); - if (len != 0x10000) - { - CloseFile(f); - return "DSi ARM7 BIOS is not a valid BIOS dump."; - } - - CloseFile(f); - - return ""; -} - -QString VerifyDSFirmware() -{ - FileHandle* f; - long len; - - Config::Table cfg = Config::GetGlobalTable(); - std::string fwpath = cfg.GetString("DS.FirmwarePath"); - - f = Platform::OpenLocalFile(fwpath, FileMode::Read); - if (!f) return "DS firmware was not found or could not be accessed. Check your emu settings."; - - if (!Platform::CheckFileWritable(fwpath)) - return "DS firmware is unable to be written to.\nPlease check file/folder write permissions."; - - len = FileLength(f); - if (len == 0x20000) - { - // 128KB firmware, not bootable - CloseFile(f); - // TODO report it somehow? detect in core? - return ""; - } - else if (len != 0x40000 && len != 0x80000) - { - CloseFile(f); - return "DS firmware is not a valid firmware dump."; - } - - CloseFile(f); - - return ""; -} - -QString VerifyDSiFirmware() -{ - FileHandle* f; - long len; - - Config::Table cfg = Config::GetGlobalTable(); - std::string fwpath = cfg.GetString("DSi.FirmwarePath"); - - f = Platform::OpenLocalFile(fwpath, FileMode::Read); - if (!f) return "DSi firmware was not found or could not be accessed. Check your emu settings."; - - if (!Platform::CheckFileWritable(fwpath)) - return "DSi firmware is unable to be written to.\nPlease check file/folder write permissions."; - - len = FileLength(f); - if (len != 0x20000) - { - // not 128KB - // TODO: check whether those work - CloseFile(f); - return "DSi firmware is not a valid firmware dump."; - } - - CloseFile(f); - - return ""; -} - -QString VerifyDSiNAND() -{ - FileHandle* f; - long len; - - Config::Table cfg = Config::GetGlobalTable(); - std::string nandpath = cfg.GetString("DSi.NANDPath"); - - f = Platform::OpenLocalFile(nandpath, FileMode::ReadWriteExisting); - if (!f) return "DSi NAND was not found or could not be accessed. Check your emu settings."; - - if (!Platform::CheckFileWritable(nandpath)) - return "DSi NAND is unable to be written to.\nPlease check file/folder write permissions."; - - // TODO: some basic checks - // check that it has the nocash footer, and all - - CloseFile(f); - - return ""; -} - -QString VerifySetup() -{ - QString res; - - if (Config::ExternalBIOSEnable) - { - res = VerifyDSBIOS(); - if (!res.isEmpty()) return res; - } - - if (Config::ConsoleType == 1) - { - res = VerifyDSiBIOS(); - if (!res.isEmpty()) return res; - - if (Config::ExternalBIOSEnable) - { - res = VerifyDSiFirmware(); - if (!res.isEmpty()) return res; - } - - res = VerifyDSiNAND(); - if (!res.isEmpty()) return res; - } - else - { - if (Config::ExternalBIOSEnable) - { - res = VerifyDSFirmware(); - if (!res.isEmpty()) return res; - } - } - - return ""; -} - -std::string GetEffectiveFirmwareSavePath(EmuThread* thread) -{ - if (!Config::ExternalBIOSEnable) - { - return Config::WifiSettingsPath; - } - if (thread->NDS->ConsoleType == 1) - { - return Config::DSiFirmwarePath; - } - else - { - return Config::FirmwarePath; - } -} - -// Initializes the firmware save manager with the selected firmware image's path -// OR the path to the wi-fi settings. -void InitFirmwareSaveManager(EmuThread* thread) noexcept -{ - FirmwareSave = std::make_unique(GetEffectiveFirmwareSavePath(thread)); -} - -std::string GetSavestateName(int slot) -{ - std::string ext = ".ml"; - ext += (char)('0'+slot); - return GetAssetPath(false, Config::SavestatePath, ext); -} - -bool SavestateExists(int slot) -{ - std::string ssfile = GetSavestateName(slot); - return Platform::FileExists(ssfile); -} - -bool LoadState(NDS& nds, const std::string& filename) -{ - FILE* file = fopen(filename.c_str(), "rb"); - if (file == nullptr) - { // If we couldn't open the state file... - Platform::Log(Platform::LogLevel::Error, "Failed to open state file \"%s\"\n", filename.c_str()); - return false; - } - - std::unique_ptr backup = std::make_unique(Savestate::DEFAULT_SIZE); - if (backup->Error) - { // If we couldn't allocate memory for the backup... - Platform::Log(Platform::LogLevel::Error, "Failed to allocate memory for state backup\n"); - fclose(file); - return false; - } - - if (!nds.DoSavestate(backup.get()) || backup->Error) - { // Back up the emulator's state. If that failed... - Platform::Log(Platform::LogLevel::Error, "Failed to back up state, aborting load (from \"%s\")\n", filename.c_str()); - fclose(file); - return false; - } - // We'll store the backup once we're sure that the state was loaded. - // Now that we know the file and backup are both good, let's load the new state. - - // Get the size of the file that we opened - if (fseek(file, 0, SEEK_END) != 0) - { - Platform::Log(Platform::LogLevel::Error, "Failed to seek to end of state file \"%s\"\n", filename.c_str()); - fclose(file); - return false; - } - size_t size = ftell(file); - rewind(file); // reset the filebuf's position - - // Allocate exactly as much memory as we need for the savestate - std::vector buffer(size); - if (fread(buffer.data(), size, 1, file) == 0) - { // Read the state file into the buffer. If that failed... - Platform::Log(Platform::LogLevel::Error, "Failed to read %u-byte state file \"%s\"\n", size, filename.c_str()); - fclose(file); - return false; - } - fclose(file); // done with the file now - - // Get ready to load the state from the buffer into the emulator - std::unique_ptr state = std::make_unique(buffer.data(), size, false); - - if (!nds.DoSavestate(state.get()) || state->Error) - { // If we couldn't load the savestate from the buffer... - Platform::Log(Platform::LogLevel::Error, "Failed to load state file \"%s\" into emulator\n", filename.c_str()); - return false; - } - - // The backup was made and the state was loaded, so we can store the backup now. - BackupState = std::move(backup); // This will clean up any existing backup - assert(backup == nullptr); - - if (Config::SavestateRelocSRAM && NDSSave) - { - PreviousSaveFile = NDSSave->GetPath(); - - std::string savefile = filename.substr(LastSep(filename)+1); - savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile); - savefile += Platform::InstanceFileSuffix(); - NDSSave->SetPath(savefile, true); - } - - SavestateLoaded = true; - - return true; -} - -bool SaveState(NDS& nds, const std::string& filename) -{ - FILE* file = fopen(filename.c_str(), "wb"); - - if (file == nullptr) - { // If the file couldn't be opened... - return false; - } - - Savestate state; - if (state.Error) - { // If there was an error creating the state (and allocating its memory)... - fclose(file); - return false; - } - - // Write the savestate to the in-memory buffer - nds.DoSavestate(&state); - - if (state.Error) - { - fclose(file); - return false; - } - - if (fwrite(state.Buffer(), state.Length(), 1, file) == 0) - { // Write the Savestate buffer to the file. If that fails... - Platform::Log(Platform::Error, - "Failed to write %d-byte savestate to %s\n", - state.Length(), - filename.c_str() - ); - fclose(file); - return false; - } - - fclose(file); - - if (Config::SavestateRelocSRAM && NDSSave) - { - std::string savefile = filename.substr(LastSep(filename)+1); - savefile = GetAssetPath(false, Config::SaveFilePath, ".sav", savefile); - savefile += Platform::InstanceFileSuffix(); - NDSSave->SetPath(savefile, false); - } - - return true; -} - -void UndoStateLoad(NDS& nds) -{ - if (!SavestateLoaded || !BackupState) return; - - // Rewind the backup state and put it in load mode - BackupState->Rewind(false); - // pray that this works - // what do we do if it doesn't??? - // but it should work. - nds.DoSavestate(BackupState.get()); - - if (NDSSave && (!PreviousSaveFile.empty())) - { - NDSSave->SetPath(PreviousSaveFile, true); - } -} - - -void UnloadCheats(NDS& nds) -{ - if (CheatFile) - { - delete CheatFile; - CheatFile = nullptr; - nds.AREngine.SetCodeFile(nullptr); - } -} - -void LoadCheats(NDS& nds) -{ - UnloadCheats(nds); - - std::string filename = GetAssetPath(false, Config::CheatFilePath, ".mch"); - - // TODO: check for error (malformed cheat file, ...) - CheatFile = new ARCodeFile(filename); - - nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr); -} - -std::optional> LoadARM9BIOS() noexcept -{ - if (!Config::ExternalBIOSEnable) - { - return Config::ConsoleType == 0 ? std::make_optional(bios_arm9_bin) : std::nullopt; - } - - if (FileHandle* f = OpenLocalFile(Config::BIOS9Path, Read)) - { - std::array bios {}; - FileRewind(f); - FileRead(bios.data(), sizeof(bios), 1, f); - CloseFile(f); - Log(Info, "ARM9 BIOS loaded from %s\n", Config::BIOS9Path.c_str()); - return bios; - } - - Log(Warn, "ARM9 BIOS not found\n"); - return std::nullopt; -} - -std::optional> LoadARM7BIOS() noexcept -{ - if (!Config::ExternalBIOSEnable) - { - return Config::ConsoleType == 0 ? std::make_optional(bios_arm7_bin) : std::nullopt; - } - - if (FileHandle* f = OpenLocalFile(Config::BIOS7Path, Read)) - { - std::array bios {}; - FileRead(bios.data(), sizeof(bios), 1, f); - CloseFile(f); - Log(Info, "ARM7 BIOS loaded from %s\n", Config::BIOS7Path.c_str()); - return bios; - } - - Log(Warn, "ARM7 BIOS not found\n"); - return std::nullopt; -} - -std::optional> LoadDSiARM9BIOS() noexcept -{ - if (FileHandle* f = OpenLocalFile(Config::DSiBIOS9Path, Read)) - { - std::array bios {}; - FileRead(bios.data(), sizeof(bios), 1, f); - CloseFile(f); - - if (!Config::DSiFullBIOSBoot) - { - // herp - *(u32*)&bios[0] = 0xEAFFFFFE; // overwrites the reset vector - - // TODO!!!! - // hax the upper 32K out of the goddamn DSi - // done that :) -pcy - } - Log(Info, "ARM9i BIOS loaded from %s\n", Config::DSiBIOS9Path.c_str()); - return bios; - } - - Log(Warn, "ARM9i BIOS not found\n"); - return std::nullopt; -} - -std::optional> LoadDSiARM7BIOS() noexcept -{ - if (FileHandle* f = OpenLocalFile(Config::DSiBIOS7Path, Read)) - { - std::array bios {}; - FileRead(bios.data(), sizeof(bios), 1, f); - CloseFile(f); - - if (!Config::DSiFullBIOSBoot) - { - // herp - *(u32*)&bios[0] = 0xEAFFFFFE; // overwrites the reset vector - - // TODO!!!! - // hax the upper 32K out of the goddamn DSi - // done that :) -pcy - } - Log(Info, "ARM7i BIOS loaded from %s\n", Config::DSiBIOS7Path.c_str()); - return bios; - } - - Log(Warn, "ARM7i BIOS not found\n"); - return std::nullopt; -} - -Firmware GenerateFirmware(int type) noexcept -{ - // Construct the default firmware... - string settingspath; - Firmware firmware = Firmware(type); - assert(firmware.Buffer() != nullptr); - - // If using generated firmware, we keep the wi-fi settings on the host disk separately. - // Wi-fi access point data includes Nintendo WFC settings, - // and if we didn't keep them then the player would have to reset them in each session. - // We don't need to save the whole firmware, just the part that may actually change. - if (FileHandle* f = OpenLocalFile(Config::WifiSettingsPath, Read)) - {// If we have Wi-fi settings to load... - constexpr unsigned TOTAL_WFC_SETTINGS_SIZE = 3 * (sizeof(Firmware::WifiAccessPoint) + sizeof(Firmware::ExtendedWifiAccessPoint)); - - if (!FileRead(firmware.GetExtendedAccessPointPosition(), TOTAL_WFC_SETTINGS_SIZE, 1, f)) - { // If we couldn't read the Wi-fi settings from this file... - Log(Warn, "Failed to read Wi-fi settings from \"%s\"; using defaults instead\n", Config::WifiSettingsPath.c_str()); - - // The access point and extended access point segments might - // be in different locations depending on the firmware revision, - // but our generated firmware always keeps them next to each other. - // (Extended access points first, then regular ones.) - firmware.GetAccessPoints() = { - Firmware::WifiAccessPoint(type), - Firmware::WifiAccessPoint(), - Firmware::WifiAccessPoint(), - }; - - firmware.GetExtendedAccessPoints() = { - Firmware::ExtendedWifiAccessPoint(), - Firmware::ExtendedWifiAccessPoint(), - Firmware::ExtendedWifiAccessPoint(), - }; - firmware.UpdateChecksums(); - CloseFile(f); - } - } - - CustomizeFirmware(firmware); - - // If we don't have Wi-fi settings to load, - // then the defaults will have already been populated by the constructor. - return firmware; -} - -std::optional LoadFirmware(int type) noexcept -{ - if (!Config::ExternalBIOSEnable) - { // If we're using built-in firmware... - if (type == 1) - { - Log(Error, "DSi firmware: cannot use built-in firmware in DSi mode!\n"); - return std::nullopt; - } - - return GenerateFirmware(type); - } - const string& firmwarepath = type == 1 ? Config::DSiFirmwarePath : Config::FirmwarePath; - - Log(Debug, "SPI firmware: loading from file %s\n", firmwarepath.c_str()); - - FileHandle* file = OpenLocalFile(firmwarepath, Read); - - if (!file) - { - Log(Error, "SPI firmware: couldn't open firmware file!\n"); - return std::nullopt; - } - Firmware firmware(file); - CloseFile(file); - - if (!firmware.Buffer()) - { - Log(Error, "SPI firmware: couldn't read firmware file!\n"); - return std::nullopt; - } - - if (Config::FirmwareOverrideSettings) - { - CustomizeFirmware(firmware); - } - - return firmware; -} - - -std::optional LoadNAND(const std::array& arm7ibios) noexcept -{ - FileHandle* nandfile = OpenLocalFile(Config::DSiNANDPath, ReadWriteExisting); - if (!nandfile) - return std::nullopt; - - DSi_NAND::NANDImage nandImage(nandfile, &arm7ibios[0x8308]); - if (!nandImage) - { - Log(Error, "Failed to parse DSi NAND\n"); - return std::nullopt; - // the NANDImage takes ownership of the FileHandle, no need to clean it up here - } - - // scoped so that mount isn't alive when we move the NAND image to DSi::NANDImage - { - auto mount = DSi_NAND::NANDMount(nandImage); - if (!mount) - { - Log(Error, "Failed to mount DSi NAND\n"); - return std::nullopt; - } - - DSi_NAND::DSiFirmwareSystemSettings settings {}; - if (!mount.ReadUserData(settings)) - { - Log(Error, "Failed to read DSi NAND user data\n"); - return std::nullopt; - } - - // override user settings, if needed - if (Config::FirmwareOverrideSettings) - { - // we store relevant strings as UTF-8, so we need to convert them to UTF-16 - auto converter = wstring_convert, char16_t>{}; - - // setting up username - std::u16string username = converter.from_bytes(Config::FirmwareUsername); - size_t usernameLength = std::min(username.length(), (size_t) 10); - memset(&settings.Nickname, 0, sizeof(settings.Nickname)); - memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t)); - - // setting language - settings.Language = static_cast(Config::FirmwareLanguage); - - // setting up color - settings.FavoriteColor = Config::FirmwareFavouriteColour; - - // setting up birthday - settings.BirthdayMonth = Config::FirmwareBirthdayMonth; - settings.BirthdayDay = Config::FirmwareBirthdayDay; - - // setup message - std::u16string message = converter.from_bytes(Config::FirmwareMessage); - size_t messageLength = std::min(message.length(), (size_t) 26); - memset(&settings.Message, 0, sizeof(settings.Message)); - memcpy(&settings.Message, message.data(), messageLength * sizeof(char16_t)); - - // TODO: make other items configurable? - } - - // fix touchscreen coords - settings.TouchCalibrationADC1 = {0, 0}; - settings.TouchCalibrationPixel1 = {0, 0}; - settings.TouchCalibrationADC2 = {255 << 4, 191 << 4}; - settings.TouchCalibrationPixel2 = {255, 191}; - - settings.UpdateHash(); - - if (!mount.ApplyUserData(settings)) - { - Log(LogLevel::Error, "Failed to write patched DSi NAND user data\n"); - return std::nullopt; - } - } - - return nandImage; -} - -constexpr u64 MB(u64 i) -{ - return i * 1024 * 1024; -} - -constexpr u64 imgsizes[] = {0, MB(256), MB(512), MB(1024), MB(2048), MB(4096)}; -std::optional GetDSiSDCardArgs() noexcept -{ - if (!Config::DSiSDEnable) - return std::nullopt; - - return FATStorageArgs { - Config::DSiSDPath, - imgsizes[Config::DSiSDSize], - Config::DSiSDReadOnly, - Config::DSiSDFolderSync ? std::make_optional(Config::DSiSDFolderPath) : std::nullopt - }; -} - -std::optional LoadDSiSDCard() noexcept -{ - if (!Config::DSiSDEnable) - return std::nullopt; - - return FATStorage( - Config::DSiSDPath, - imgsizes[Config::DSiSDSize], - Config::DSiSDReadOnly, - Config::DSiSDFolderSync ? std::make_optional(Config::DSiSDFolderPath) : std::nullopt - ); -} - -std::optional GetDLDISDCardArgs() noexcept -{ - if (!Config::DLDIEnable) - return std::nullopt; - - return FATStorageArgs{ - Config::DLDISDPath, - imgsizes[Config::DLDISize], - Config::DLDIReadOnly, - Config::DLDIFolderSync ? std::make_optional(Config::DLDIFolderPath) : std::nullopt - }; -} - -std::optional LoadDLDISDCard() noexcept -{ - if (!Config::DLDIEnable) - return std::nullopt; - - return FATStorage(*GetDLDISDCardArgs()); -} - -void EnableCheats(NDS& nds, bool enable) -{ - CheatsOn = enable; - if (CheatFile) - nds.AREngine.SetCodeFile(CheatsOn ? CheatFile : nullptr); -} - -ARCodeFile* GetCheatFile() -{ - return CheatFile; -} -#endif - -void SetBatteryLevels(NDS& nds) -{ - if (nds.ConsoleType == 1) - { - auto& dsi = static_cast(nds); - dsi.I2C.GetBPTWL()->SetBatteryLevel(Config::DSiBatteryLevel); - dsi.I2C.GetBPTWL()->SetBatteryCharging(Config::DSiBatteryCharging); - } - else - { - nds.SPI.GetPowerMan()->SetBatteryLevelOkay(Config::DSBatteryLevelOkay); - } -} - -void SetDateTime(NDS& nds) -{ - QDateTime hosttime = QDateTime::currentDateTime(); - QDateTime time = hosttime.addSecs(Config::RTCOffset); - - nds.RTC.SetDateTime(time.date().year(), time.date().month(), time.date().day(), - time.time().hour(), time.time().minute(), time.time().second()); -} - -void Reset(EmuThread* thread) -{ - thread->UpdateConsole(Keep {}, Keep {}); - - if (Config::ConsoleType == 1) EjectGBACart(*thread->NDS); - - thread->NDS->Reset(); - SetBatteryLevels(*thread->NDS); - SetDateTime(*thread->NDS); - - if ((CartType != -1) && NDSSave) - { - std::string oldsave = NDSSave->GetPath(); - std::string newsave = GetAssetPath(false, Config::SaveFilePath, ".sav"); - newsave += Platform::InstanceFileSuffix(); - if (oldsave != newsave) - NDSSave->SetPath(newsave, false); - } - - if ((GBACartType != -1) && GBASave) - { - std::string oldsave = GBASave->GetPath(); - std::string newsave = GetAssetPath(true, Config::SaveFilePath, ".sav"); - newsave += Platform::InstanceFileSuffix(); - if (oldsave != newsave) - GBASave->SetPath(newsave, false); - } - - InitFirmwareSaveManager(thread); - if (FirmwareSave) - { - std::string oldsave = FirmwareSave->GetPath(); - string newsave; - if (Config::ExternalBIOSEnable) - { - if (Config::ConsoleType == 1) - newsave = Config::DSiFirmwarePath + Platform::InstanceFileSuffix(); - else - newsave = Config::FirmwarePath + Platform::InstanceFileSuffix(); - } - else - { - newsave = Config::WifiSettingsPath + Platform::InstanceFileSuffix(); - } - - if (oldsave != newsave) - { // If the player toggled the ConsoleType or ExternalBIOSEnable... - FirmwareSave->SetPath(newsave, true); - } - } - - if (!BaseROMName.empty()) - { - if (Config::DirectBoot || thread->NDS->NeedsDirectBoot()) - { - thread->NDS->SetupDirectBoot(BaseROMName); - } - } -} - - -bool BootToMenu(EmuThread* thread) -{ - // Keep whatever cart is in the console, if any. - if (!thread->UpdateConsole(Keep {}, Keep {})) - // Try to update the console, but keep the existing cart. If that fails... - return false; - - // BIOS and firmware files are loaded, patched, and installed in UpdateConsole - if (thread->NDS->NeedsDirectBoot()) - return false; - - InitFirmwareSaveManager(thread); - thread->NDS->Reset(); - SetBatteryLevels(*thread->NDS); - SetDateTime(*thread->NDS); - return true; -} - -u32 DecompressROM(const u8* inContent, const u32 inSize, unique_ptr& outContent) -{ - u64 realSize = ZSTD_getFrameContentSize(inContent, inSize); - const u32 maxSize = 0x40000000; - - if (realSize == ZSTD_CONTENTSIZE_ERROR || (realSize > maxSize && realSize != ZSTD_CONTENTSIZE_UNKNOWN)) - { - return 0; - } - - if (realSize != ZSTD_CONTENTSIZE_UNKNOWN) - { - outContent = make_unique(realSize); - u64 decompressed = ZSTD_decompress(outContent.get(), realSize, inContent, inSize); - - if (ZSTD_isError(decompressed)) - { - outContent = nullptr; - return 0; - } - - return realSize; - } - else - { - ZSTD_DStream* dStream = ZSTD_createDStream(); - ZSTD_initDStream(dStream); - - ZSTD_inBuffer inBuf = { - .src = inContent, - .size = inSize, - .pos = 0 - }; - - const u32 startSize = 1024 * 1024 * 16; - u8* partialOutContent = (u8*) malloc(startSize); - - ZSTD_outBuffer outBuf = { - .dst = partialOutContent, - .size = startSize, - .pos = 0 - }; - - size_t result; - - do - { - result = ZSTD_decompressStream(dStream, &outBuf, &inBuf); - - if (ZSTD_isError(result)) - { - ZSTD_freeDStream(dStream); - free(outBuf.dst); - return 0; - } - - // if result == 0 and not inBuf.pos < inBuf.size, go again to let zstd flush everything. - if (result == 0) - continue; - - if (outBuf.pos == outBuf.size) - { - outBuf.size *= 2; - - if (outBuf.size > maxSize) - { - ZSTD_freeDStream(dStream); - free(outBuf.dst); - return 0; - } - - outBuf.dst = realloc(outBuf.dst, outBuf.size); - } - } while (inBuf.pos < inBuf.size); - - ZSTD_freeDStream(dStream); - outContent = make_unique(outBuf.pos); - memcpy(outContent.get(), outBuf.dst, outBuf.pos); - - ZSTD_freeDStream(dStream); - free(outBuf.dst); - - return outBuf.size; - } -} - -void ClearBackupState() -{ - if (BackupState != nullptr) - { - BackupState = nullptr; - } -} - -pair, string> GenerateDefaultFirmware() -{ - // Construct the default firmware... - string settingspath; - std::unique_ptr firmware = std::make_unique(Config::ConsoleType); - assert(firmware->Buffer() != nullptr); - - // Try to open the instanced Wi-fi settings, falling back to the regular Wi-fi settings if they don't exist. - // We don't need to save the whole firmware, just the part that may actually change. - std::string wfcsettingspath = Config::WifiSettingsPath; - settingspath = wfcsettingspath + Platform::InstanceFileSuffix(); - FileHandle* f = Platform::OpenLocalFile(settingspath, FileMode::Read); - if (!f) - { - settingspath = wfcsettingspath; - f = Platform::OpenLocalFile(settingspath, FileMode::Read); - } - - // If using generated firmware, we keep the wi-fi settings on the host disk separately. - // Wi-fi access point data includes Nintendo WFC settings, - // and if we didn't keep them then the player would have to reset them in each session. - if (f) - { // If we have Wi-fi settings to load... - constexpr unsigned TOTAL_WFC_SETTINGS_SIZE = 3 * (sizeof(Firmware::WifiAccessPoint) + sizeof(Firmware::ExtendedWifiAccessPoint)); - - // The access point and extended access point segments might - // be in different locations depending on the firmware revision, - // but our generated firmware always keeps them next to each other. - // (Extended access points first, then regular ones.) - - if (!FileRead(firmware->GetExtendedAccessPointPosition(), TOTAL_WFC_SETTINGS_SIZE, 1, f)) - { // If we couldn't read the Wi-fi settings from this file... - Platform::Log(Platform::LogLevel::Warn, "Failed to read Wi-fi settings from \"%s\"; using defaults instead\n", wfcsettingspath.c_str()); - - firmware->GetAccessPoints() = { - Firmware::WifiAccessPoint(Config::ConsoleType), - Firmware::WifiAccessPoint(), - Firmware::WifiAccessPoint(), - }; - - firmware->GetExtendedAccessPoints() = { - Firmware::ExtendedWifiAccessPoint(), - Firmware::ExtendedWifiAccessPoint(), - Firmware::ExtendedWifiAccessPoint(), - }; - } - - firmware->UpdateChecksums(); - - CloseFile(f); - } - - // If we don't have Wi-fi settings to load, - // then the defaults will have already been populated by the constructor. - return std::make_pair(std::move(firmware), std::move(wfcsettingspath)); -} - -bool ParseMacAddress(void* data) -{ - const std::string& mac_in = Config::FirmwareMAC; - u8* mac_out = (u8*)data; - - int o = 0; - u8 tmp = 0; - for (int i = 0; i < 18; i++) - { - char c = mac_in[i]; - if (c == '\0') break; - - int n; - if (c >= '0' && c <= '9') n = c - '0'; - else if (c >= 'a' && c <= 'f') n = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') n = c - 'A' + 10; - else continue; - - if (!(o & 1)) - tmp = n; - else - mac_out[o >> 1] = n | (tmp << 4); - - o++; - if (o >= 12) return true; - } - - return false; -} - -void CustomizeFirmware(Firmware& firmware) noexcept -{ - auto& currentData = firmware.GetEffectiveUserData(); - - // setting up username - std::string orig_username = Config::FirmwareUsername; - if (!orig_username.empty()) - { // If the frontend defines a username, take it. If not, leave the existing one. - std::u16string username = std::wstring_convert, char16_t>{}.from_bytes(orig_username); - size_t usernameLength = std::min(username.length(), (size_t) 10); - currentData.NameLength = usernameLength; - memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t)); - } - - auto language = static_cast(Config::FirmwareLanguage); - if (language != Firmware::Language::Reserved) - { // If the frontend specifies a language (rather than using the existing value)... - currentData.Settings &= ~Firmware::Language::Reserved; // ..clear the existing language... - currentData.Settings |= language; // ...and set the new one. - } - - // setting up color - u8 favoritecolor = Config::FirmwareFavouriteColour; - if (favoritecolor != 0xFF) - { - currentData.FavoriteColor = favoritecolor; - } - - u8 birthmonth = Config::FirmwareBirthdayMonth; - if (birthmonth != 0) - { // If the frontend specifies a birth month (rather than using the existing value)... - currentData.BirthdayMonth = birthmonth; - } - - u8 birthday = Config::FirmwareBirthdayDay; - if (birthday != 0) - { // If the frontend specifies a birthday (rather than using the existing value)... - currentData.BirthdayDay = birthday; - } - - // setup message - std::string orig_message = Config::FirmwareMessage; - if (!orig_message.empty()) - { - std::u16string message = std::wstring_convert, char16_t>{}.from_bytes(orig_message); - size_t messageLength = std::min(message.length(), (size_t) 26); - currentData.MessageLength = messageLength; - memcpy(currentData.Message, message.data(), messageLength * sizeof(char16_t)); - } - - MacAddress mac; - bool rep = false; - auto& header = firmware.GetHeader(); - - memcpy(&mac, header.MacAddr.data(), sizeof(MacAddress)); - - - MacAddress configuredMac; - rep = ParseMacAddress(&configuredMac); - rep &= (configuredMac != MacAddress()); - - if (rep) - { - mac = configuredMac; - } - - int inst = Platform::InstanceID(); - if (inst > 0) - { - rep = true; - mac[3] += inst; - mac[4] += inst*0x44; - mac[5] += inst*0x10; - } - - if (rep) - { - mac[0] &= 0xFC; // ensure the MAC isn't a broadcast MAC - header.MacAddr = mac; - header.UpdateChecksum(); - } - - firmware.UpdateChecksums(); -} - -// Loads ROM data without parsing it. Works for GBA and NDS ROMs. -bool LoadROMData(const QStringList& filepath, std::unique_ptr& filedata, u32& filelen, string& basepath, string& romname) noexcept -{ - if (filepath.empty()) return false; - - if (int num = filepath.count(); num == 1) - { - // regular file - - std::string filename = filepath.at(0).toStdString(); - Platform::FileHandle* f = Platform::OpenFile(filename, FileMode::Read); - if (!f) return false; - - long len = Platform::FileLength(f); - if (len > 0x40000000) - { - Platform::CloseFile(f); - return false; - } - - Platform::FileRewind(f); - filedata = make_unique(len); - size_t nread = Platform::FileRead(filedata.get(), (size_t)len, 1, f); - Platform::CloseFile(f); - if (nread != 1) - { - filedata = nullptr; - return false; - } - - filelen = (u32)len; - - if (filename.length() > 4 && filename.substr(filename.length() - 4) == ".zst") - { - filelen = DecompressROM(filedata.get(), len, filedata); - - if (filelen > 0) - { - filename = filename.substr(0, filename.length() - 4); - } - else - { - filedata = nullptr; - filelen = 0; - basepath = ""; - romname = ""; - return false; - } - } - - int pos = LastSep(filename); - if(pos != -1) - basepath = filename.substr(0, pos); - - romname = filename.substr(pos+1); - return true; - } -#ifdef ARCHIVE_SUPPORT_ENABLED - else if (num == 2) - { - // file inside archive - - s32 lenread = Archive::ExtractFileFromArchive(filepath.at(0), filepath.at(1), filedata, &filelen); - if (lenread < 0) return false; - if (!filedata) return false; - if (lenread != filelen) - { - filedata = nullptr; - return false; - } - - std::string std_archivepath = filepath.at(0).toStdString(); - basepath = std_archivepath.substr(0, LastSep(std_archivepath)); - - std::string std_romname = filepath.at(1).toStdString(); - romname = std_romname.substr(LastSep(std_romname)+1); - return true; - } -#endif - else - return false; -} - -QString GetSavErrorString(std::string& filepath, bool gba) -{ - std::string console = gba ? "GBA" : "DS"; - std::string err1 = "Unable to write to "; - std::string err2 = " save.\nPlease check file/folder write permissions.\n\nAttempted to Access:\n"; - - err1 += console + err2 + filepath; - - return QString::fromStdString(err1); -} - -bool LoadROM(QMainWindow* mainWindow, EmuThread* emuthread, QStringList filepath, bool reset) -{ - unique_ptr filedata = nullptr; - u32 filelen; - std::string basepath; - std::string romname; - - if (!LoadROMData(filepath, filedata, filelen, basepath, romname)) - { - QMessageBox::critical(mainWindow, "melonDS", "Failed to load the DS ROM."); - return false; - } - - NDSSave = nullptr; - - BaseROMDir = basepath; - BaseROMName = romname; - BaseAssetName = romname.substr(0, romname.rfind('.')); - - u32 savelen = 0; - std::unique_ptr savedata = nullptr; - - std::string savname = GetAssetPath(false, Config::SaveFilePath, ".sav"); - std::string origsav = savname; - savname += Platform::InstanceFileSuffix(); - - FileHandle* sav = Platform::OpenFile(savname, FileMode::Read); - if (!sav) - { - if (!Platform::CheckFileWritable(origsav)) - { - QMessageBox::critical(mainWindow, "melonDS", GetSavErrorString(origsav, false)); - return false; - } - - sav = Platform::OpenFile(origsav, FileMode::Read); - } - else if (!Platform::CheckFileWritable(savname)) - { - QMessageBox::critical(mainWindow, "melonDS", GetSavErrorString(savname, false)); - return false; - } - - if (sav) - { - savelen = (u32)Platform::FileLength(sav); - - FileRewind(sav); - savedata = std::make_unique(savelen); - FileRead(savedata.get(), savelen, 1, sav); - CloseFile(sav); - } - - NDSCart::NDSCartArgs cartargs { - // Don't load the SD card itself yet, because we don't know if - // the ROM is homebrew or not. - // So this is the card we *would* load if the ROM were homebrew. - .SDCard = GetDLDISDCardArgs(), - .SRAM = std::move(savedata), - .SRAMLength = savelen, - }; - - auto cart = NDSCart::ParseROM(std::move(filedata), filelen, std::move(cartargs)); - if (!cart) - { - // If we couldn't parse the ROM... - QMessageBox::critical(mainWindow, "melonDS", "Failed to load the DS ROM."); - return false; - } - - if (reset) - { - if (!emuthread->UpdateConsole(std::move(cart), Keep {})) - { - QMessageBox::critical(mainWindow, "melonDS", "Failed to load the DS ROM."); - return false; - } - - InitFirmwareSaveManager(emuthread); - emuthread->NDS->Reset(); - - if (Config::DirectBoot || emuthread->NDS->NeedsDirectBoot()) - { // If direct boot is enabled or forced... - emuthread->NDS->SetupDirectBoot(romname); - } - - SetBatteryLevels(*emuthread->NDS); - SetDateTime(*emuthread->NDS); - } - else - { - assert(emuthread->NDS != nullptr); - emuthread->NDS->SetNDSCart(std::move(cart)); - } - - CartType = 0; - NDSSave = std::make_unique(savname); - LoadCheats(*emuthread->NDS); - - return true; // success -} - -void EjectCart(NDS& nds) -{ - NDSSave = nullptr; - - UnloadCheats(nds); - - nds.EjectCart(); - - CartType = -1; - BaseROMDir = ""; - BaseROMName = ""; - BaseAssetName = ""; -} - -bool CartInserted() -{ - return CartType != -1; -} - -QString CartLabel() -{ - if (CartType == -1) - return "(none)"; - - QString ret = QString::fromStdString(BaseROMName); - - int maxlen = 32; - if (ret.length() > maxlen) - ret = ret.left(maxlen-6) + "..." + ret.right(3); - - return ret; -} - - -bool LoadGBAROM(QMainWindow* mainWindow, NDS& nds, QStringList filepath) -{ - if (nds.ConsoleType == 1) - { - QMessageBox::critical(mainWindow, "melonDS", "The DSi doesn't have a GBA slot."); - return false; - } - - unique_ptr filedata = nullptr; - u32 filelen; - std::string basepath; - std::string romname; - - if (!LoadROMData(filepath, filedata, filelen, basepath, romname)) - { - QMessageBox::critical(mainWindow, "melonDS", "Failed to load the GBA ROM."); - return false; - } - - GBASave = nullptr; - - BaseGBAROMDir = basepath; - BaseGBAROMName = romname; - BaseGBAAssetName = romname.substr(0, romname.rfind('.')); - - u32 savelen = 0; - std::unique_ptr savedata = nullptr; - - std::string savname = GetAssetPath(true, Config::SaveFilePath, ".sav"); - std::string origsav = savname; - savname += Platform::InstanceFileSuffix(); - - FileHandle* sav = Platform::OpenFile(savname, FileMode::Read); - if (!sav) - { - if (!Platform::CheckFileWritable(origsav)) - { - QMessageBox::critical(mainWindow, "melonDS", GetSavErrorString(origsav, true)); - return false; - } - - sav = Platform::OpenFile(origsav, FileMode::Read); - } - else if (!Platform::CheckFileWritable(savname)) - { - QMessageBox::critical(mainWindow, "melonDS", GetSavErrorString(savname, true)); - return false; - } - - if (sav) - { - savelen = (u32)FileLength(sav); - - if (savelen > 0) - { - FileRewind(sav); - savedata = std::make_unique(savelen); - FileRead(savedata.get(), savelen, 1, sav); - } - CloseFile(sav); - } - - auto cart = GBACart::ParseROM(std::move(filedata), filelen, std::move(savedata), savelen); - if (!cart) - { - QMessageBox::critical(mainWindow, "melonDS", "Failed to load the GBA ROM."); - return false; - } - - nds.SetGBACart(std::move(cart)); - GBACartType = 0; - GBASave = std::make_unique(savname); - return true; -} - -void LoadGBAAddon(NDS& nds, int type) -{ - if (Config::ConsoleType == 1) return; - - GBASave = nullptr; - - nds.LoadGBAAddon(type); - - GBACartType = type; - BaseGBAROMDir = ""; - BaseGBAROMName = ""; - BaseGBAAssetName = ""; -} - -void EjectGBACart(NDS& nds) -{ - GBASave = nullptr; - - nds.EjectGBACart(); - - GBACartType = -1; - BaseGBAROMDir = ""; - BaseGBAROMName = ""; - BaseGBAAssetName = ""; -} - -bool GBACartInserted() -{ - return GBACartType != -1; -} - -QString GBACartLabel() -{ - if (Config::ConsoleType == 1) return "none (DSi)"; - - switch (GBACartType) - { - case 0: - { - QString ret = QString::fromStdString(BaseGBAROMName); - - int maxlen = 32; - if (ret.length() > maxlen) - ret = ret.left(maxlen-6) + "..." + ret.right(3); - - return ret; - } - - case GBAAddon_RAMExpansion: - return "Memory expansion"; - } - - return "(none)"; -} - - -void ROMIcon(const u8 (&data)[512], const u16 (&palette)[16], u32 (&iconRef)[32*32]) -{ - int index = 0; - for (int i = 0; i < 4; i++) - { - for (int j = 0; j < 4; j++) - { - for (int k = 0; k < 8; k++) - { - for (int l = 0; l < 8; l++) - { - u8 pal_index = index % 2 ? data[index/2] >> 4 : data[index/2] & 0x0F; - u8 r = ((palette[pal_index] >> 0) & 0x1F) * 255 / 31; - u8 g = ((palette[pal_index] >> 5) & 0x1F) * 255 / 31; - u8 b = ((palette[pal_index] >> 10) & 0x1F) * 255 / 31; - u8 a = pal_index ? 255: 0; - u32* row = &iconRef[256 * i + 32 * k + 8 * j]; - row[l] = r | (g << 8) | (b << 16) | (a << 24); - index++; - } - } - } - } -} - -#define SEQ_FLIPV(i) ((i & 0b1000000000000000) >> 15) -#define SEQ_FLIPH(i) ((i & 0b0100000000000000) >> 14) -#define SEQ_PAL(i) ((i & 0b0011100000000000) >> 11) -#define SEQ_BMP(i) ((i & 0b0000011100000000) >> 8) -#define SEQ_DUR(i) ((i & 0b0000000011111111) >> 0) - -void AnimatedROMIcon(const u8 (&data)[8][512], const u16 (&palette)[8][16], const u16 (&sequence)[64], u32 (&animatedIconRef)[64][32*32], std::vector &animatedSequenceRef) -{ - for (int i = 0; i < 64; i++) - { - if (!sequence[i]) - break; - - ROMIcon(data[SEQ_BMP(sequence[i])], palette[SEQ_PAL(sequence[i])], animatedIconRef[i]); - u32* frame = animatedIconRef[i]; - - if (SEQ_FLIPH(sequence[i])) - { - for (int x = 0; x < 32; x++) - { - for (int y = 0; y < 32/2; y++) - { - std::swap(frame[x * 32 + y], frame[x * 32 + (32 - 1 - y)]); - } - } - } - if (SEQ_FLIPV(sequence[i])) - { - for (int x = 0; x < 32/2; x++) - { - for (int y = 0; y < 32; y++) - { - std::swap(frame[x * 32 + y], frame[(32 - 1 - x) * 32 + y]); - } - } - } - - for (int j = 0; j < SEQ_DUR(sequence[i]); j++) - animatedSequenceRef.push_back(i); - } -} - -} diff --git a/src/frontend/qt_sdl/ROMManager.h b/src/frontend/qt_sdl/ROMManager.h deleted file mode 100644 index 38ed65cd..00000000 --- a/src/frontend/qt_sdl/ROMManager.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright 2016-2023 melonDS team - - This file is part of melonDS. - - melonDS is free software: you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation, either version 3 of the License, or (at your option) - any later version. - - melonDS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with melonDS. If not, see http://www.gnu.org/licenses/. -*/ - -#ifndef ROMMANAGER_H -#define ROMMANAGER_H - -#include "types.h" -#include "SaveManager.h" -#include "AREngine.h" -#include "DSi_NAND.h" -#include - -#include "MemConstants.h" -#include -#include -#include -#include - -namespace melonDS -{ -class NDS; -class DSi; -class FATStorage; -class FATStorageArgs; -} -class EmuThread; -namespace ROMManager -{ - -using namespace melonDS; -extern std::unique_ptr NDSSave; -extern std::unique_ptr GBASave; -extern std::unique_ptr FirmwareSave; - -QString VerifySetup(); -void Reset(EmuThread* thread); - -/// Boots the emulated console into its system menu without starting a game. -bool BootToMenu(EmuThread* thread); -void ClearBackupState(); - -/// Returns the configured ARM9 BIOS loaded from disk, -/// the FreeBIOS if external BIOS is disabled and we're in NDS mode, -/// or nullopt if loading failed. -std::optional> LoadARM9BIOS() noexcept; -std::optional> LoadARM7BIOS() noexcept; -std::optional> LoadDSiARM9BIOS() noexcept; -std::optional> LoadDSiARM7BIOS() noexcept; -std::optional GetDSiSDCardArgs() noexcept; -std::optional LoadDSiSDCard() noexcept; -std::optional GetDLDISDCardArgs() noexcept; -std::optional LoadDLDISDCard() noexcept; -void CustomizeFirmware(Firmware& firmware) noexcept; -Firmware GenerateFirmware(int type) noexcept; -/// Loads and customizes a firmware image based on the values in Config -std::optional LoadFirmware(int type) noexcept; -/// Loads and customizes a NAND image based on the values in Config -std::optional LoadNAND(const std::array& arm7ibios) noexcept; - -/// Inserts a ROM into the emulated console. -bool LoadROM(QMainWindow* mainWindow, EmuThread*, QStringList filepath, bool reset); -void EjectCart(NDS& nds); -bool CartInserted(); -QString CartLabel(); - -bool LoadGBAROM(QMainWindow* mainWindow, NDS& nds, QStringList filepath); -void LoadGBAAddon(NDS& nds, int type); -void EjectGBACart(NDS& nds); -bool GBACartInserted(); -QString GBACartLabel(); - -std::string GetSavestateName(int slot); -bool SavestateExists(int slot); -bool LoadState(NDS& nds, const std::string& filename); -bool SaveState(NDS& nds, const std::string& filename); -void UndoStateLoad(NDS& nds); - -void EnableCheats(NDS& nds, bool enable); -ARCodeFile* GetCheatFile(); - -void ROMIcon(const u8 (&data)[512], const u16 (&palette)[16], u32 (&iconRef)[32*32]); -void AnimatedROMIcon(const u8 (&data)[8][512], const u16 (&palette)[8][16], - const u16 (&sequence)[64], u32 (&animatedIconRef)[64][32*32], - std::vector &animatedSequenceRef); -} - -#endif // ROMMANAGER_H diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 8d59d72d..5cdcf0d5 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -77,7 +77,7 @@ //#include "main_shaders.h" -#include "ROMManager.h" +#include "EmuInstance.h" #include "ArchiveUtil.h" #include "CameraManager.h" @@ -198,8 +198,10 @@ static void signalHandler(int) int test = 0; -MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) +MainWindow::MainWindow(EmuInstance* inst, QWidget* parent) : QMainWindow(parent) { + emuInstance = inst; + test_num = test++; #ifndef _WIN32 if (!parent) @@ -231,7 +233,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) setAcceptDrops(true); setFocusPolicy(Qt::ClickFocus); - int inst = Platform::InstanceID(); + //int inst = Platform::InstanceID(); QMenuBar* menubar = new QMenuBar(); { @@ -260,7 +262,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) menu->addSeparator(); - actCurrentCart = menu->addAction("DS slot: " + ROMManager::CartLabel()); + actCurrentCart = menu->addAction("DS slot: " + emuInstance->cartLabel()); actCurrentCart->setEnabled(false); actInsertCart = menu->addAction("Insert cart..."); @@ -271,7 +273,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) menu->addSeparator(); - actCurrentGBACart = menu->addAction("GBA slot: " + ROMManager::GBACartLabel()); + actCurrentGBACart = menu->addAction("GBA slot: " + emuInstance->gbaCartLabel()); actCurrentGBACart->setEnabled(false); actInsertGBACart = menu->addAction("Insert ROM cart..."); @@ -675,7 +677,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) actLimitFramerate->setChecked(Config::LimitFPS); actAudioSync->setChecked(Config::AudioSync); - if (inst > 0) + if (emuInstance->instanceID > 0) { actEmuSettings->setEnabled(false); actVideoSettings->setEnabled(false); @@ -900,7 +902,7 @@ void MainWindow::dropEvent(QDropEvent* event) if (isNdsRom) { - if (!ROMManager::LoadROM(mainWindow, emuThread, file, true)) + if (!emuInstance->loadROM(file, true)) { emuThread->emuUnpause(); return; @@ -911,15 +913,15 @@ void MainWindow::dropEvent(QDropEvent* event) recentFileList.prepend(barredFilename); updateRecentFilesMenu(); - assert(emuThread->NDS != nullptr); - emuThread->NDS->Start(); + assert(emuInstance->nds != nullptr); + emuInstance->nds->Start(); emuThread->emuRun(); updateCartInserted(false); } else if (isGbaRom) { - if (!ROMManager::LoadGBAROM(mainWindow, *emuThread->NDS, file)) + if (!emuInstance->loadGBAROM(file)) { emuThread->emuUnpause(); return; @@ -963,7 +965,7 @@ void MainWindow::onAppStateChanged(Qt::ApplicationState state) bool MainWindow::verifySetup() { - QString res = ROMManager::VerifySetup(); + QString res = emuInstance->verifySetup(); if (!res.isEmpty()) { QMessageBox::critical(this, "melonDS", res); @@ -983,7 +985,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) bool gbaloaded = false; if (!gbafile.isEmpty()) { - if (!ROMManager::LoadGBAROM(mainWindow, *emuThread->NDS, gbafile)) return false; + if (!emuInstance->loadGBAROM(gbafile)) return false; gbaloaded = true; } @@ -991,7 +993,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) bool ndsloaded = false; if (!file.isEmpty()) { - if (!ROMManager::LoadROM(mainWindow, emuThread, file, true)) return false; + if (!emuInstance->loadROM(file, true)) return false; recentFileList.removeAll(file.join("|")); recentFileList.prepend(file.join("|")); @@ -1003,7 +1005,7 @@ bool MainWindow::preloadROMs(QStringList file, QStringList gbafile, bool boot) { if (ndsloaded) { - emuThread->NDS->Start(); + emuInstance->nds->Start(); emuThread->emuRun(); } else @@ -1163,14 +1165,14 @@ void MainWindow::updateCartInserted(bool gba) bool inserted; if (gba) { - inserted = ROMManager::GBACartInserted() && (Config::ConsoleType == 0); - actCurrentGBACart->setText("GBA slot: " + ROMManager::GBACartLabel()); + inserted = emuInstance->gbaCartInserted() && (Config::ConsoleType == 0); + actCurrentGBACart->setText("GBA slot: " + emuInstance->gbaCartLabel()); actEjectGBACart->setEnabled(inserted); } else { - inserted = ROMManager::CartInserted(); - actCurrentCart->setText("DS slot: " + ROMManager::CartLabel()); + inserted = emuInstance->cartInserted(); + actCurrentCart->setText("DS slot: " + emuInstance->cartLabel()); actEjectCart->setEnabled(inserted); actImportSavefile->setEnabled(inserted); actSetupCheats->setEnabled(inserted); @@ -1196,7 +1198,7 @@ void MainWindow::onOpenFile() return; } - if (!ROMManager::LoadROM(mainWindow, emuThread, file, true)) + if (!emuInstance->loadROM(file, true)) { emuThread->emuUnpause(); return; @@ -1207,8 +1209,8 @@ void MainWindow::onOpenFile() recentFileList.prepend(filename); updateRecentFilesMenu(); - assert(emuThread->NDS != nullptr); - emuThread->NDS->Start(); + assert(emuInstance->nds != nullptr); + emuInstance->nds->Start(); emuThread->emuRun(); updateCartInserted(false); @@ -1293,7 +1295,7 @@ void MainWindow::onClickRecentFile() return; } - if (!ROMManager::LoadROM(mainWindow, emuThread, file, true)) + if (!emuInstance->loadROM(file, true)) { emuThread->emuUnpause(); return; @@ -1303,8 +1305,8 @@ void MainWindow::onClickRecentFile() recentFileList.prepend(filename); updateRecentFilesMenu(); - assert(emuThread->NDS != nullptr); - emuThread->NDS->Start(); + assert(emuInstance->nds != nullptr); + emuInstance->nds->Start(); emuThread->emuRun(); updateCartInserted(false); @@ -1320,7 +1322,7 @@ void MainWindow::onBootFirmware() return; } - if (!ROMManager::BootToMenu(emuThread)) + if (!emuInstance->bootToMenu()) { // TODO: better error reporting? QMessageBox::critical(this, "melonDS", "This firmware is not bootable."); @@ -1328,8 +1330,8 @@ void MainWindow::onBootFirmware() return; } - assert(emuThread->NDS != nullptr); - emuThread->NDS->Start(); + assert(emuInstance->nds != nullptr); + emuInstance->nds->Start(); emuThread->emuRun(); } @@ -1344,7 +1346,7 @@ void MainWindow::onInsertCart() return; } - if (!ROMManager::LoadROM(mainWindow, emuThread, file, false)) + if (!emuInstance->loadROM(file, false)) { emuThread->emuUnpause(); return; @@ -1359,7 +1361,7 @@ void MainWindow::onEjectCart() { emuThread->emuPause(); - ROMManager::EjectCart(*emuThread->NDS); + emuInstance->ejectCart(); emuThread->emuUnpause(); @@ -1377,7 +1379,7 @@ void MainWindow::onInsertGBACart() return; } - if (!ROMManager::LoadGBAROM(mainWindow, *emuThread->NDS, file)) + if (!emuInstance->loadGBAROM(file)) { emuThread->emuUnpause(); return; @@ -1395,7 +1397,7 @@ void MainWindow::onInsertGBAAddon() emuThread->emuPause(); - ROMManager::LoadGBAAddon(*emuThread->NDS, type); + emuInstance->loadGBAAddon(type); emuThread->emuUnpause(); @@ -1406,7 +1408,7 @@ void MainWindow::onEjectGBACart() { emuThread->emuPause(); - ROMManager::EjectGBACart(*emuThread->NDS); + emuInstance->ejectGBACart(); emuThread->emuUnpause(); @@ -1422,7 +1424,7 @@ void MainWindow::onSaveState() std::string filename; if (slot > 0) { - filename = ROMManager::GetSavestateName(slot); + filename = emuInstance->getSavestateName(slot); } else { @@ -1440,7 +1442,7 @@ void MainWindow::onSaveState() filename = qfilename.toStdString(); } - if (ROMManager::SaveState(*emuThread->NDS, filename)) + if (emuInstance->saveState(filename)) { if (slot > 0) osdAddMessage(0, "State saved to slot %d", slot); else osdAddMessage(0, "State saved to file"); @@ -1464,7 +1466,7 @@ void MainWindow::onLoadState() std::string filename; if (slot > 0) { - filename = ROMManager::GetSavestateName(slot); + filename = emuInstance->getSavestateName(slot); } else { @@ -1491,7 +1493,7 @@ void MainWindow::onLoadState() return; } - if (ROMManager::LoadState(*emuThread->NDS, filename)) + if (emuInstance->loadState(filename)) { if (slot > 0) osdAddMessage(0, "State loaded from slot %d", slot); else osdAddMessage(0, "State loaded from file"); @@ -1509,7 +1511,7 @@ void MainWindow::onLoadState() void MainWindow::onUndoStateLoad() { emuThread->emuPause(); - ROMManager::UndoStateLoad(*emuThread->NDS); + emuInstance->undoStateLoad(); emuThread->emuUnpause(); osdAddMessage(0, "State load undone"); @@ -1548,7 +1550,7 @@ void MainWindow::onImportSavefile() return; } - ROMManager::Reset(emuThread); + emuInstance->reset(); } u32 len = FileLength(f); @@ -1557,8 +1559,8 @@ void MainWindow::onImportSavefile() Platform::FileRewind(f); Platform::FileRead(data.get(), len, 1, f); - assert(emuThread->NDS != nullptr); - emuThread->NDS->SetNDSSave(data.get(), len); + assert(emuInstance->nds != nullptr); + emuInstance->nds->SetNDSSave(data.get(), len); CloseFile(f); emuThread->emuUnpause(); @@ -1599,7 +1601,7 @@ void MainWindow::onReset() actUndoStateLoad->setEnabled(false); - ROMManager::Reset(emuThread); + emuInstance->reset(); osdAddMessage(0, "Reset"); emuThread->emuRun(); @@ -1610,7 +1612,7 @@ void MainWindow::onStop() if (!RunningSomething) return; emuThread->emuPause(); - emuThread->NDS->Stop(); + emuInstance->nds->Stop(); } void MainWindow::onFrameStep() @@ -1633,7 +1635,7 @@ void MainWindow::onOpenPowerManagement() void MainWindow::onEnableCheats(bool checked) { Config::EnableCheats = checked?1:0; - ROMManager::EnableCheats(*emuThread->NDS, Config::EnableCheats != 0); + emuInstance->enableCheats(Config::EnableCheats != 0); } void MainWindow::onSetupCheats() @@ -1651,7 +1653,7 @@ void MainWindow::onCheatsDialogFinished(int res) void MainWindow::onROMInfo() { - auto cart = emuThread->NDS->NDSCartSlot.GetCart(); + auto cart = emuInstance->nds->NDSCartSlot.GetCart(); if (cart) ROMInfoDialog* dlg = ROMInfoDialog::openDlg(this, *cart); } @@ -1707,13 +1709,13 @@ void MainWindow::onEmuSettingsDialogFinished(int res) actInsertGBACart->setEnabled(true); for (int i = 0; i < 1; i++) actInsertGBAAddon[i]->setEnabled(true); - actEjectGBACart->setEnabled(ROMManager::GBACartInserted()); + actEjectGBACart->setEnabled(emuInstance->gbaCartInserted()); } if (EmuSettingsDialog::needsReset) onReset(); - actCurrentGBACart->setText("GBA slot: " + ROMManager::GBACartLabel()); + actCurrentGBACart->setText("GBA slot: " + emuInstance->gbaCartLabel()); if (!RunningSomething) actTitleManager->setEnabled(!Config::DSiNANDPath.empty()); @@ -1802,18 +1804,18 @@ void MainWindow::onPathSettingsFinished(int res) void MainWindow::onUpdateAudioSettings() { - assert(emuThread->NDS != nullptr); - emuThread->NDS->SPU.SetInterpolation(static_cast(Config::AudioInterp)); + assert(emuInstance->nds != nullptr); + emuInstance->nds->SPU.SetInterpolation(static_cast(Config::AudioInterp)); if (Config::AudioBitDepth == 0) - emuThread->NDS->SPU.SetDegrade10Bit(emuThread->NDS->ConsoleType == 0); + emuInstance->nds->SPU.SetDegrade10Bit(emuInstance->nds->ConsoleType == 0); else - emuThread->NDS->SPU.SetDegrade10Bit(Config::AudioBitDepth == 1); + emuInstance->nds->SPU.SetDegrade10Bit(Config::AudioBitDepth == 1); } void MainWindow::onAudioSettingsFinished(int res) { - AudioInOut::UpdateSettings(*emuThread->NDS); + //AudioInOut::UpdateSettings(*emuThread->NDS); } void MainWindow::onOpenMPSettings() @@ -2029,7 +2031,7 @@ void MainWindow::onEmuStart() for (int i = 1; i < 9; i++) { actSaveState[i]->setEnabled(true); - actLoadState[i]->setEnabled(ROMManager::SavestateExists(i)); + actLoadState[i]->setEnabled(emuInstance->savestateExists(i)); } actSaveState[0]->setEnabled(true); actLoadState[0]->setEnabled(true); diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h index 9fb7cf1e..7e5bcbef 100644 --- a/src/frontend/qt_sdl/Window.h +++ b/src/frontend/qt_sdl/Window.h @@ -36,6 +36,7 @@ #include "Screen.h" +class EmuInstance; class EmuThread; /* @@ -100,7 +101,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(QWidget* parent = nullptr); + explicit MainWindow(EmuInstance* inst, QWidget* parent = nullptr); ~MainWindow(); void attachEmuThread(EmuThread* thread); @@ -236,6 +237,8 @@ private: int test_num; + EmuInstance* emuInstance; + EmuThread* emuThread; public: diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index d0508c59..df1f72f7 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -100,7 +100,7 @@ //#include "main_shaders.h" -#include "ROMManager.h" +#include "EmuInstance.h" #include "ArchiveUtil.h" #include "CameraManager.h" @@ -161,8 +161,9 @@ QStringList ArchiveExtensions bool RunningSomething; -MainWindow* mainWindow; -EmuThread* emuThread; +//MainWindow* mainWindow; +//EmuThread* emuThread; +EmuInstance* testinst; int autoScreenSizing = 0; @@ -258,7 +259,7 @@ void emuStop() { RunningSomething = false; - emit emuThread->windowEmuStop(); + //emit emuThread->windowEmuStop(); } MelonApplication::MelonApplication(int& argc, char** argv) @@ -278,10 +279,10 @@ bool MelonApplication::event(QEvent *event) { QFileOpenEvent *openEvent = static_cast(event); - emuThread->emuPause(); + /*emuThread->emuPause(); const QStringList file = mainWindow->splitArchivePath(openEvent->file(), true); if (!mainWindow->preloadROMs(file, {}, true)) - emuThread->emuUnpause(); + emuThread->emuUnpause();*/ } return QApplication::event(event); @@ -375,7 +376,7 @@ int main(int argc, char** argv) Input::JoystickID = Config::JoystickID; Input::OpenJoystick(); - mainWindow = new MainWindow(); + /* mainWindow = new MainWindow(); if (options->fullscreen) ToggleFullscreen(mainWindow); @@ -385,9 +386,11 @@ int main(int argc, char** argv) emuThread->attachWindow(mainWindow); emuThread->attachWindow(poop); emuThread->start(); - emuThread->emuPause(); + emuThread->emuPause();*/ - AudioInOut::Init(emuThread); + testinst = new EmuInstance(0); + + /*AudioInOut::Init(emuThread); ROMManager::EnableCheats(*emuThread->NDS, Config::EnableCheats != 0); AudioInOut::AudioMute(mainWindow); @@ -412,15 +415,16 @@ int main(int argc, char** argv) if (memberSyntaxUsed) printf("Warning: use the a.zip|b.nds format at your own risk!\n"); - mainWindow->preloadROMs(dsfile, gbafile, options->boot); + mainWindow->preloadROMs(dsfile, gbafile, options->boot);*/ int ret = melon.exec(); delete options; - emuThread->emuStop(); + /*emuThread->emuStop(); emuThread->wait(); - delete emuThread; + delete emuThread;*/ + delete testinst; Input::CloseJoystick();