aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/qt_sdl/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/qt_sdl/main.cpp')
-rw-r--r--src/frontend/qt_sdl/main.cpp570
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);