diff options
Diffstat (limited to 'src/frontend/qt_sdl/main.cpp')
| -rw-r--r-- | src/frontend/qt_sdl/main.cpp | 570 | 
1 files changed, 562 insertions, 8 deletions
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 0eb84a5..9192685 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -22,20 +22,364 @@  #include <string.h>  #include <QApplication> -#include <QMainWindow> +#include <QMessageBox> +#include <QMenuBar> +#include <QFileDialog> +#include <QPaintEvent> +#include <QPainter> + +#include <SDL2/SDL.h>  #include "main.h" -#include "../../version.h" +#include "types.h" +#include "version.h" + +#include "NDS.h" +#include "GBACart.h" +#include "GPU.h" +#include "SPU.h" +#include "Wifi.h" +#include "Platform.h" +#include "Config.h" + +#include "Savestate.h" + + +char* EmuDirectory; + +bool RunningSomething; +char ROMPath[2][1024]; +char SRAMPath[2][1024]; +char PrevSRAMPath[2][1024]; // for savestate 'undo load' + +bool SavestateLoaded; + +MainWindow* mainWindow; +EmuThread* emuThread; + + +EmuThread::EmuThread(QObject* parent) : QThread(parent) +{ +    EmuStatus = 0; +    EmuRunning = 2; +} + +void EmuThread::run() +{ +    NDS::Init(); + +    /*MainScreenPos[0] = 0; +    MainScreenPos[1] = 0; +    MainScreenPos[2] = 0; +    AutoScreenSizing = 0;*/ + +    /*if (Screen_UseGL) +    { +        uiGLMakeContextCurrent(GLContext); +        GPU3D::InitRenderer(true); +        uiGLMakeContextCurrent(NULL); +    } +    else*/ +    { +        GPU3D::InitRenderer(false); +    } + +    /*Touching = false; +    KeyInputMask = 0xFFF; +    JoyInputMask = 0xFFF; +    KeyHotkeyMask = 0; +    JoyHotkeyMask = 0; +    HotkeyMask = 0; +    LastHotkeyMask = 0; +    LidStatus = false;*/ + +    u32 nframes = 0; +    u32 starttick = SDL_GetTicks(); +    u32 lasttick = starttick; +    u32 lastmeasuretick = lasttick; +    u32 fpslimitcount = 0; +    u64 perfcount = SDL_GetPerformanceCounter(); +    u64 perffreq = SDL_GetPerformanceFrequency(); +    float samplesleft = 0; +    u32 nsamples = 0; + +    char melontitle[100]; +    SDL_mutex* titlemutex = SDL_CreateMutex(); +    void* titledata[2] = {melontitle, titlemutex}; +printf("emu thread start: %d\n", EmuRunning); +    while (EmuRunning != 0) +    { +        /*ProcessInput(); + +        if (HotkeyPressed(HK_FastForwardToggle)) +        { +            Config::LimitFPS = !Config::LimitFPS; +            uiQueueMain(UpdateFPSLimit, NULL); +        } +        // TODO: similar hotkeys for video/audio sync? + +        if (HotkeyPressed(HK_Pause)) uiQueueMain(TogglePause, NULL); +        if (HotkeyPressed(HK_Reset)) uiQueueMain(Reset, NULL); + +        if (GBACart::CartInserted && GBACart::HasSolarSensor) +        { +            if (HotkeyPressed(HK_SolarSensorDecrease)) +            { +                if (GBACart_SolarSensor::LightLevel > 0) GBACart_SolarSensor::LightLevel--; +                char msg[64]; +                sprintf(msg, "Solar sensor level set to %d", GBACart_SolarSensor::LightLevel); +                OSD::AddMessage(0, msg); +            } +            if (HotkeyPressed(HK_SolarSensorIncrease)) +            { +                if (GBACart_SolarSensor::LightLevel < 10) GBACart_SolarSensor::LightLevel++; +                char msg[64]; +                sprintf(msg, "Solar sensor level set to %d", GBACart_SolarSensor::LightLevel); +                OSD::AddMessage(0, msg); +            } +        }*/ + +        if (EmuRunning == 1) +        { +            EmuStatus = 1; + +            // process input and hotkeys +            NDS::SetKeyMask(0xFFF); +            /*NDS::SetKeyMask(KeyInputMask & JoyInputMask); + +            if (HotkeyPressed(HK_Lid)) +            { +                LidStatus = !LidStatus; +                NDS::SetLidClosed(LidStatus); +                OSD::AddMessage(0, LidStatus ? "Lid closed" : "Lid opened"); +            }*/ + +            // microphone input +            /*FeedMicInput(); + +            if (Screen_UseGL) +            { +                uiGLBegin(GLContext); +                uiGLMakeContextCurrent(GLContext); +            }*/ + +            // auto screen layout +            /*{ +                MainScreenPos[2] = MainScreenPos[1]; +                MainScreenPos[1] = MainScreenPos[0]; +                MainScreenPos[0] = NDS::PowerControl9 >> 15; + +                int guess; +                if (MainScreenPos[0] == MainScreenPos[2] && +                    MainScreenPos[0] != MainScreenPos[1]) +                { +                    // constant flickering, likely displaying 3D on both screens +                    // TODO: when both screens are used for 2D only...??? +                    guess = 0; +                } +                else +                { +                    if (MainScreenPos[0] == 1) +                        guess = 1; +                    else +                        guess = 2; +                } + +                if (guess != AutoScreenSizing) +                { +                    AutoScreenSizing = guess; +                    SetupScreenRects(WindowWidth, WindowHeight); +                } +            }*/ + +            // emulate +            u32 nlines = NDS::RunFrame(); + +#ifdef MELONCAP +            MelonCap::Update(); +#endif // MELONCAP + +            if (EmuRunning == 0) break; + +            /*if (Screen_UseGL) +            { +                GLScreen_DrawScreen(); +                uiGLEnd(GLContext); +            } +            uiAreaQueueRedrawAll(MainDrawArea);*/ + +            /*bool fastforward = HotkeyDown(HK_FastForward); + +            if (Config::AudioSync && !fastforward) +            { +                SDL_LockMutex(AudioSyncLock); +                while (SPU::GetOutputSize() > 1024) +                { +                    int ret = SDL_CondWaitTimeout(AudioSync, AudioSyncLock, 500); +                    if (ret == SDL_MUTEX_TIMEDOUT) break; +                } +                SDL_UnlockMutex(AudioSyncLock); +            } + +            float framerate = (1000.0f * nlines) / (60.0f * 263.0f); + +            { +                u32 curtick = SDL_GetTicks(); +                u32 delay = curtick - lasttick; + +                bool limitfps = Config::LimitFPS && !fastforward; +                if (limitfps) +                { +                    float wantedtickF = starttick + (framerate * (fpslimitcount+1)); +                    u32 wantedtick = (u32)ceil(wantedtickF); +                    if (curtick < wantedtick) SDL_Delay(wantedtick - curtick); + +                    lasttick = SDL_GetTicks(); +                    fpslimitcount++; +                    if ((abs(wantedtickF - (float)wantedtick) < 0.001312) || (fpslimitcount > 60)) +                    { +                        fpslimitcount = 0; +                        nsamples = 0; +                        starttick = lasttick; +                    } +                } +                else +                { +                    if (delay < 1) SDL_Delay(1); +                    lasttick = SDL_GetTicks(); +                } +            } + +            nframes++; +            if (nframes >= 30) +            { +                u32 tick = SDL_GetTicks(); +                u32 diff = tick - lastmeasuretick; +                lastmeasuretick = tick; + +                u32 fps; +                if (diff < 1) fps = 77777; +                else fps = (nframes * 1000) / diff; +                nframes = 0; + +                float fpstarget; +                if (framerate < 1) fpstarget = 999; +                else fpstarget = 1000.0f/framerate; + +                SDL_LockMutex(titlemutex); +                sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, fpstarget); +                SDL_UnlockMutex(titlemutex); +                uiQueueMain(UpdateWindowTitle, titledata); +            }*/ +        } +        else +        { +            // paused +            nframes = 0; +            lasttick = SDL_GetTicks(); +            starttick = lasttick; +            lastmeasuretick = lasttick; +            fpslimitcount = 0; + +            if (EmuRunning == 2) +            { +                /*if (Screen_UseGL) +                { +                    uiGLBegin(GLContext); +                    uiGLMakeContextCurrent(GLContext); +                    GLScreen_DrawScreen(); +                    uiGLEnd(GLContext); +                } +                uiAreaQueueRedrawAll(MainDrawArea);*/ +            } + +            //if (Screen_UseGL) uiGLMakeContextCurrent(NULL); + +            EmuStatus = EmuRunning; + +            SDL_Delay(100); +        } +        printf("ran iteration: status=%d run=%d\n", EmuStatus, EmuRunning); +    } + +    EmuStatus = 0; + +    SDL_DestroyMutex(titlemutex); + +    //if (Screen_UseGL) uiGLMakeContextCurrent(GLContext); + +    NDS::DeInit(); +    //Platform::LAN_DeInit(); + +    /*if (Screen_UseGL) +    { +        OSD::DeInit(true); +        GLScreen_DeInit(); +    } +    else +        OSD::DeInit(false);*/ + +    //if (Screen_UseGL) uiGLMakeContextCurrent(NULL); +} + +void EmuThread::emuRun() +{ +    EmuRunning = 1; +} + +void EmuThread::emuPause(bool refresh) +{ +    int status = refresh ? 2:3; +    PrevEmuStatus = EmuRunning; +    EmuRunning = status;printf("emuPause %d -> %d %d\n", PrevEmuStatus, EmuRunning, EmuStatus); +    while (EmuStatus != status);printf("wait done\n"); +} + +void EmuThread::emuUnpause() +{ +    EmuRunning = PrevEmuStatus; +} + +void EmuThread::emuStop() +{ +    EmuRunning = 0; +} + + +MainWindowPanel::MainWindowPanel(QWidget* parent) : QWidget(parent) +{ +} + +MainWindowPanel::~MainWindowPanel() +{ +} + +void MainWindowPanel::paintEvent(QPaintEvent* event) +{ +    QPainter painter(this); + +    //painter. +}  MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)  {      setWindowTitle("melonDS - assfucking Qt version"); -    // burp -    QWidget *centralWidget = new QWidget(this); -    setCentralWidget(centralWidget); +    QMenuBar* menubar = new QMenuBar(); +    { +        QMenu* menu = menubar->addMenu("File"); +        QAction* act; + +        act = menu->addAction("Open file..."); +        connect(act, &QAction::triggered, this, &MainWindow::onOpenFile); +    } +    setMenuBar(menubar); + +    panel = new MainWindowPanel(this); +    setCentralWidget(panel); +    panel->setMinimumSize(256, 384);  }  MainWindow::~MainWindow() @@ -43,6 +387,13 @@ MainWindow::~MainWindow()  } +void MainWindow::onOpenFile() +{ +    QString filename = QFileDialog::getOpenFileName(this, "Open ROM", "", "DS ROMs (*.nds *.srl);;Any file (*.*)"); +    printf("fark: %p %d %s\n", filename, filename.isEmpty(), filename.toStdString().c_str()); +} + +  int main(int argc, char** argv)  {      srand(time(NULL)); @@ -50,12 +401,212 @@ int main(int argc, char** argv)      printf("melonDS " MELONDS_VERSION "\n");      printf(MELONDS_URL "\n"); +#if defined(__WIN32__) || defined(UNIX_PORTABLE) +    if (argc > 0 && strlen(argv[0]) > 0) +    { +        int len = strlen(argv[0]); +        while (len > 0) +        { +            if (argv[0][len] == '/') break; +            if (argv[0][len] == '\\') break; +            len--; +        } +        if (len > 0) +        { +            EmuDirectory = new char[len+1]; +            strncpy(EmuDirectory, argv[0], len); +            EmuDirectory[len] = '\0'; +        } +        else +        { +            EmuDirectory = new char[2]; +            strcpy(EmuDirectory, "."); +        } +    } +    else +    { +        EmuDirectory = new char[2]; +        strcpy(EmuDirectory, "."); +    } +#else +	const char* confdir = g_get_user_config_dir(); +	const char* confname = "/melonDS"; +	EmuDirectory = new char[strlen(confdir) + strlen(confname) + 1]; +	strcat(EmuDirectory, confdir); +	strcat(EmuDirectory, confname); +#endif +      QApplication melon(argc, argv); -    MainWindow win; -    win.show(); +    // http://stackoverflow.com/questions/14543333/joystick-wont-work-using-sdl +    SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); + +    if (SDL_Init(SDL_INIT_HAPTIC) < 0) +    { +        printf("SDL couldn't init rumble\n"); +    } +    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) +    { +        QMessageBox::critical(NULL, "melonDS", "SDL shat itself :("); +        return 1; +    } + +    SDL_JoystickEventState(SDL_ENABLE); + +    Config::Load(); + +    //if      (Config::AudioVolume < 0)   Config::AudioVolume = 0; +    //else if (Config::AudioVolume > 256) Config::AudioVolume = 256; -    return melon.exec(); +    // TODO: those should be checked before running anything +    // (as to let the user specify their own BIOS/firmware path etc) +#if 0 +    if (!Platform::LocalFileExists("bios7.bin") || +        !Platform::LocalFileExists("bios9.bin") || +        !Platform::LocalFileExists("firmware.bin")) +    { +#if defined(__WIN32__) || defined(UNIX_PORTABLE) +		const char* locationName = "the directory you run melonDS from"; +#else +		char* locationName = EmuDirectory; +#endif +		char msgboxtext[512]; +		sprintf(msgboxtext, +            "One or more of the following required files don't exist or couldn't be accessed:\n\n" +            "bios7.bin -- ARM7 BIOS\n" +            "bios9.bin -- ARM9 BIOS\n" +            "firmware.bin -- firmware image\n\n" +            "Dump the files from your DS and place them in %s.\n" +            "Make sure that the files can be accessed.", +			locationName +		); + +        uiMsgBoxError(NULL, "BIOS/Firmware not found", msgboxtext); + +        uiUninit(); +        SDL_Quit(); +        return 0; +    } +    if (!Platform::LocalFileExists("firmware.bin.bak")) +    { +        // verify the firmware +        // +        // there are dumps of an old hacked firmware floating around on the internet +        // and those are problematic +        // the hack predates WFC, and, due to this, any game that alters the WFC +        // access point data will brick that firmware due to it having critical +        // data in the same area. it has the same problem on hardware. +        // +        // but this should help stop users from reporting that issue over and over +        // again, when the issue is not from melonDS but from their firmware dump. +        // +        // I don't know about all the firmware hacks in existence, but the one I +        // looked at has 0x180 bytes from the header repeated at 0x3FC80, but +        // bytes 0x0C-0x14 are different. + +        FILE* f = Platform::OpenLocalFile("firmware.bin", "rb"); +        u8 chk1[0x180], chk2[0x180]; + +        fseek(f, 0, SEEK_SET); +        fread(chk1, 1, 0x180, f); +        fseek(f, -0x380, SEEK_END); +        fread(chk2, 1, 0x180, f); + +        memset(&chk1[0x0C], 0, 8); +        memset(&chk2[0x0C], 0, 8); + +        fclose(f); + +        if (!memcmp(chk1, chk2, 0x180)) +        { +            uiMsgBoxError(NULL, +                          "Problematic firmware dump", +                          "You are using an old hacked firmware dump.\n" +                          "Firmware boot will stop working if you run any game that alters WFC settings.\n\n" +                          "Note that the issue is not from melonDS, it would also happen on an actual DS."); +        } +    } +    { +        const char* romlist_missing = "Save memory type detection will not work correctly.\n\n" +            "You should use the latest version of romlist.bin (provided in melonDS release packages)."; +#if !defined(UNIX_PORTABLE) && !defined(__WIN32__) +        std::string missingstr = std::string(romlist_missing) + +            "\n\nThe ROM list should be placed in " + g_get_user_data_dir() + "/melonds/, otherwise " +            "melonDS will search for it in the current working directory."; +        const char* romlist_missing_text = missingstr.c_str(); +#else +        const char* romlist_missing_text = romlist_missing; +#endif + +        FILE* f = Platform::OpenDataFile("romlist.bin"); +        if (f) +        { +            u32 data; +            fread(&data, 4, 1, f); +            fclose(f); + +            if ((data >> 24) == 0) // old CRC-based list +            { +                uiMsgBoxError(NULL, "Your version of romlist.bin is outdated.", romlist_missing_text); +            } +        } +        else +        { +        	uiMsgBoxError(NULL, "romlist.bin not found.", romlist_missing_text); +        } +    } +#endif + +    mainWindow = new MainWindow(); +    mainWindow->show(); + +    emuThread = new EmuThread(); +    emuThread->start(); +    emuThread->emuPause(true); + +    if (argc > 1) +    { +        char* file = argv[1]; +        char* ext = &file[strlen(file)-3]; + +        if (!strcasecmp(ext, "nds") || !strcasecmp(ext, "srl")) +        { +            strncpy(ROMPath[0], file, 1023); +            ROMPath[0][1023] = '\0'; + +            //SetupSRAMPath(0); + +            //if (NDS::LoadROM(ROMPath[0], SRAMPath[0], Config::DirectBoot)) +            //    Run(); +        } + +        if (argc > 2) +        { +            file = argv[2]; +            ext = &file[strlen(file)-3]; + +            if (!strcasecmp(ext, "gba")) +            { +                strncpy(ROMPath[1], file, 1023); +                ROMPath[1][1023] = '\0'; + +                //SetupSRAMPath(1); + +                //NDS::LoadGBAROM(ROMPath[1], SRAMPath[1]); +            } +        } +    } + +    int ret = melon.exec(); +printf("melon over\n"); +    emuThread->emuStop();printf("STOP\n"); +    emuThread->wait();printf("farked\n"); + +    Config::Save(); + +    SDL_Quit(); +    delete[] EmuDirectory; +    return ret;  }  #ifdef __WIN32__ @@ -71,6 +622,7 @@ int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdsho      char** argv = new char*[argc];      for (int i = 0; i < argc; i++)      { +        if (!argv_w) { argv[i] = nullarg; continue; }          int len = WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, NULL, 0, NULL, NULL);          if (len < 1) { argv[i] = nullarg; continue; }          argv[i] = new char[len]; @@ -78,6 +630,8 @@ int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdsho          if (res != len) { delete[] argv[i]; argv[i] = nullarg; }      } +    if (argv_w) LocalFree(argv_w); +      if (AttachConsole(ATTACH_PARENT_PROCESS))      {          freopen("CONOUT$", "w", stdout);  |