get some of the shit going, I guess

atleast the emuthread is going and we have its control system down

and other fun shit, too
This commit is contained in:
Arisotura 2020-04-27 12:06:44 +02:00
parent 439ca1b2b5
commit 690f9f3874
7 changed files with 1397 additions and 9 deletions

View File

@ -21,6 +21,7 @@ add_library(core STATIC
NDS.cpp
NDSCart.cpp
OpenGLSupport.cpp
Platform.h
RTC.cpp
Savestate.cpp
SPI.cpp

View File

@ -2,6 +2,8 @@ project(qt_sdl)
SET(SOURCES_QT_SDL
main.cpp
Platform.cpp
PlatformConfig.cpp
)
if (WIN32)

View File

@ -0,0 +1,558 @@
/*
Copyright 2016-2020 Arisotura
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <SDL2/SDL.h>
#include "Platform.h"
#include "PlatformConfig.h"
//#include "LAN_Socket.h"
//#include "LAN_PCap.h"
#include <string>
#ifdef __WIN32__
#define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK
#include <windows.h>
//#include <knownfolders.h> // FUCK THAT SHIT
extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_RoamingAppData = {0x3eb685db, 0x65f9, 0x4cf6, {0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}};
#include <shlobj.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define socket_t SOCKET
#define sockaddr_t SOCKADDR
#else
#include <glib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#define socket_t int
#define sockaddr_t struct sockaddr
#define closesocket close
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET (socket_t)-1
#endif
extern char* EmuDirectory;
void Stop(bool internal);
namespace Platform
{
typedef struct
{
SDL_Thread* ID;
void (*Func)();
} ThreadData;
int ThreadEntry(void* data)
{
ThreadData* thread = (ThreadData*)data;
thread->Func();
return 0;
}
socket_t MPSocket;
sockaddr_t MPSendAddr;
u8 PacketBuffer[2048];
#define NIFI_VER 1
void StopEmu()
{
//Stop(true);
}
FILE* OpenFile(const char* path, const char* mode, bool mustexist)
{
FILE* ret;
#ifdef __WIN32__
int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
if (len < 1) return NULL;
WCHAR* fatpath = new WCHAR[len];
int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, fatpath, len);
if (res != len) { delete[] fatpath; return NULL; } // checkme?
// this will be more than enough
WCHAR fatmode[4];
fatmode[0] = mode[0];
fatmode[1] = mode[1];
fatmode[2] = mode[2];
fatmode[3] = 0;
if (mustexist)
{
ret = _wfopen(fatpath, L"rb");
if (ret) ret = _wfreopen(fatpath, fatmode, ret);
}
else
ret = _wfopen(fatpath, fatmode);
delete[] fatpath;
#else
if (mustexist)
{
ret = fopen(path, "rb");
if (ret) ret = freopen(path, mode, ret);
}
else
ret = fopen(path, mode);
#endif
return ret;
}
#if !defined(UNIX_PORTABLE) && !defined(__WIN32__)
FILE* OpenLocalFile(const char* path, const char* mode)
{
std::string fullpath;
if (path[0] == '/')
{
// If it's an absolute path, just open that.
fullpath = std::string(path);
}
else
{
// Check user configuration directory
std::string confpath = std::string(g_get_user_config_dir()) + "/melonDS/";
g_mkdir_with_parents(confpath.c_str(), 0755);
fullpath = confpath + path;
}
return OpenFile(fullpath.c_str(), mode, mode[0] != 'w');
}
FILE* OpenDataFile(const char* path)
{
const char* melondir = "melonDS";
const char* const* sys_dirs = g_get_system_data_dirs();
const char* user_dir = g_get_user_data_dir();
// First check the user's data directory
char* fullpath = g_build_path("/", user_dir, melondir, path, NULL);
if (access(fullpath, R_OK) == 0)
{
FILE* f = fopen(fullpath, "r");
g_free(fullpath);
return f;
}
free(fullpath);
// Then check the system data directories
for (size_t i = 0; sys_dirs[i] != NULL; i++)
{
const char* dir = sys_dirs[i];
char* fullpath = g_build_path("/", dir, melondir, path, NULL);
if (access(fullpath, R_OK) == 0)
{
FILE* f = fopen(fullpath, "r");
g_free(fullpath);
return f;
}
free(fullpath);
}
FILE* f = fopen(path, "rb");
if (f) return f;
return NULL;
}
#else
FILE* OpenLocalFile(const char* path, const char* mode)
{
bool relpath = false;
int pathlen = strlen(path);
#ifdef __WIN32__
if (pathlen > 3)
{
if (path[1] == ':' && path[2] == '\\')
return OpenFile(path, mode);
}
#else
if (pathlen > 1)
{
if (path[0] == '/')
return OpenFile(path, mode);
}
#endif
if (pathlen >= 3)
{
if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path[2] == '\\'))
relpath = true;
}
int emudirlen = strlen(EmuDirectory);
char* emudirpath;
if (emudirlen)
{
int len = emudirlen + 1 + pathlen + 1;
emudirpath = new char[len];
strncpy(&emudirpath[0], EmuDirectory, emudirlen);
emudirpath[emudirlen] = '/';
strncpy(&emudirpath[emudirlen+1], path, pathlen);
emudirpath[emudirlen+1+pathlen] = '\0';
}
else
{
emudirpath = new char[pathlen+1];
strncpy(&emudirpath[0], path, pathlen);
emudirpath[pathlen] = '\0';
}
// Locations are application directory, and AppData/melonDS on Windows or XDG_CONFIG_HOME/melonDS on Linux
FILE* f;
// First check current working directory
f = OpenFile(path, mode, true);
if (f) { delete[] emudirpath; return f; }
// then emu directory
f = OpenFile(emudirpath, mode, true);
if (f) { delete[] emudirpath; return f; }
#ifdef __WIN32__
// a path relative to AppData wouldn't make much sense
if (!relpath)
{
// Now check AppData
PWSTR appDataPath = NULL;
SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appDataPath);
if (!appDataPath)
{
delete[] emudirpath;
return NULL;
}
// this will be more than enough
WCHAR fatperm[4];
fatperm[0] = mode[0];
fatperm[1] = mode[1];
fatperm[2] = mode[2];
fatperm[3] = 0;
int fnlen = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
if (fnlen < 1) { delete[] emudirpath; return NULL; }
WCHAR* wfileName = new WCHAR[fnlen];
int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, wfileName, fnlen);
if (res != fnlen) { delete[] wfileName; delete[] emudirpath; return NULL; } // checkme?
const WCHAR* appdir = L"\\melonDS\\";
int pos = wcslen(appDataPath);
void* ptr = CoTaskMemRealloc(appDataPath, (pos+wcslen(appdir)+fnlen+1)*sizeof(WCHAR));
if (!ptr) { delete[] wfileName; delete[] emudirpath; return NULL; } // oh well
appDataPath = (PWSTR)ptr;
wcscpy(&appDataPath[pos], appdir); pos += wcslen(appdir);
wcscpy(&appDataPath[pos], wfileName);
f = _wfopen(appDataPath, L"rb");
if (f) f = _wfreopen(appDataPath, fatperm, f);
CoTaskMemFree(appDataPath);
delete[] wfileName;
if (f) { delete[] emudirpath; return f; }
}
#else
if (!relpath)
{
// Now check XDG_CONFIG_HOME
// TODO: check for memory leak there
std::string fullpath = std::string(g_get_user_config_dir()) + "/melonDS/" + path;
f = OpenFile(fullpath.c_str(), mode, true);
if (f) { delete[] emudirpath; return f; }
}
#endif
if (mode[0] != 'r')
{
f = OpenFile(emudirpath, mode);
if (f) { delete[] emudirpath; return f; }
}
delete[] emudirpath;
return NULL;
}
FILE* OpenDataFile(const char* path)
{
return OpenLocalFile(path, "rb");
}
#endif
void* Thread_Create(void (*func)())
{
ThreadData* data = new ThreadData;
data->Func = func;
data->ID = SDL_CreateThread(ThreadEntry, "melonDS core thread", data);
return data;
}
void Thread_Free(void* thread)
{
delete (ThreadData*)thread;
}
void Thread_Wait(void* thread)
{
SDL_WaitThread((SDL_Thread*)((ThreadData*)thread)->ID, NULL);
}
void* Semaphore_Create()
{
return SDL_CreateSemaphore(0);
}
void Semaphore_Free(void* sema)
{
SDL_DestroySemaphore((SDL_sem*)sema);
}
void Semaphore_Reset(void* sema)
{
while (SDL_SemTryWait((SDL_sem*)sema) == 0);
}
void Semaphore_Wait(void* sema)
{
SDL_SemWait((SDL_sem*)sema);
}
void Semaphore_Post(void* sema)
{
SDL_SemPost((SDL_sem*)sema);
}
void* GL_GetProcAddress(const char* proc)
{
return NULL;//uiGLGetProcAddress(proc);
}
bool MP_Init()
{
int opt_true = 1;
int res;
#ifdef __WIN32__
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
{
return false;
}
#endif // __WIN32__
MPSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (MPSocket < 0)
{
return false;
}
res = setsockopt(MPSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt_true, sizeof(int));
if (res < 0)
{
closesocket(MPSocket);
MPSocket = INVALID_SOCKET;
return false;
}
sockaddr_t saddr;
saddr.sa_family = AF_INET;
*(u32*)&saddr.sa_data[2] = htonl(Config::SocketBindAnyAddr ? INADDR_ANY : INADDR_LOOPBACK);
*(u16*)&saddr.sa_data[0] = htons(7064);
res = bind(MPSocket, &saddr, sizeof(sockaddr_t));
if (res < 0)
{
closesocket(MPSocket);
MPSocket = INVALID_SOCKET;
return false;
}
res = setsockopt(MPSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&opt_true, sizeof(int));
if (res < 0)
{
closesocket(MPSocket);
MPSocket = INVALID_SOCKET;
return false;
}
MPSendAddr.sa_family = AF_INET;
*(u32*)&MPSendAddr.sa_data[2] = htonl(INADDR_BROADCAST);
*(u16*)&MPSendAddr.sa_data[0] = htons(7064);
return true;
}
void MP_DeInit()
{
if (MPSocket >= 0)
closesocket(MPSocket);
#ifdef __WIN32__
WSACleanup();
#endif // __WIN32__
}
int MP_SendPacket(u8* data, int len)
{
if (MPSocket < 0)
return 0;
if (len > 2048-8)
{
printf("MP_SendPacket: error: packet too long (%d)\n", len);
return 0;
}
*(u32*)&PacketBuffer[0] = htonl(0x4946494E); // NIFI
PacketBuffer[4] = NIFI_VER;
PacketBuffer[5] = 0;
*(u16*)&PacketBuffer[6] = htons(len);
memcpy(&PacketBuffer[8], data, len);
int slen = sendto(MPSocket, (const char*)PacketBuffer, len+8, 0, &MPSendAddr, sizeof(sockaddr_t));
if (slen < 8) return 0;
return slen - 8;
}
int MP_RecvPacket(u8* data, bool block)
{
if (MPSocket < 0)
return 0;
fd_set fd;
struct timeval tv;
FD_ZERO(&fd);
FD_SET(MPSocket, &fd);
tv.tv_sec = 0;
tv.tv_usec = block ? 5000 : 0;
if (!select(MPSocket+1, &fd, 0, 0, &tv))
{
return 0;
}
sockaddr_t fromAddr;
socklen_t fromLen = sizeof(sockaddr_t);
int rlen = recvfrom(MPSocket, (char*)PacketBuffer, 2048, 0, &fromAddr, &fromLen);
if (rlen < 8+24)
{
return 0;
}
rlen -= 8;
if (ntohl(*(u32*)&PacketBuffer[0]) != 0x4946494E)
{
return 0;
}
if (PacketBuffer[4] != NIFI_VER)
{
return 0;
}
if (ntohs(*(u16*)&PacketBuffer[6]) != rlen)
{
return 0;
}
memcpy(data, &PacketBuffer[8], rlen);
return rlen;
}
bool LAN_Init()
{
/*if (Config::DirectLAN)
{
if (!LAN_PCap::Init(true))
return false;
}
else
{
if (!LAN_Socket::Init())
return false;
}*/
return true;
}
void LAN_DeInit()
{
// checkme. blarg
//if (Config::DirectLAN)
// LAN_PCap::DeInit();
//else
// LAN_Socket::DeInit();
/*LAN_PCap::DeInit();
LAN_Socket::DeInit();*/
}
int LAN_SendPacket(u8* data, int len)
{
/*if (Config::DirectLAN)
return LAN_PCap::SendPacket(data, len);
else
return LAN_Socket::SendPacket(data, len);*/
return 0;
}
int LAN_RecvPacket(u8* data)
{
/*if (Config::DirectLAN)
return LAN_PCap::RecvPacket(data);
else
return LAN_Socket::RecvPacket(data);*/
return 0;
}
}

View File

@ -0,0 +1,151 @@
/*
Copyright 2016-2020 Arisotura
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "PlatformConfig.h"
namespace Config
{
int KeyMapping[12];
int JoyMapping[12];
int HKKeyMapping[HK_MAX];
int HKJoyMapping[HK_MAX];
int JoystickID;
int WindowWidth;
int WindowHeight;
int WindowMaximized;
int ScreenRotation;
int ScreenGap;
int ScreenLayout;
int ScreenSizing;
int ScreenFilter;
int ScreenUseGL;
int ScreenVSync;
int ScreenRatio;
int LimitFPS;
int AudioSync;
int ShowOSD;
int DirectBoot;
int SocketBindAnyAddr;
char LANDevice[128];
int DirectLAN;
int SavestateRelocSRAM;
int AudioVolume;
int MicInputType;
char MicWavPath[512];
char LastROMFolder[512];
ConfigEntry PlatformConfigFile[] =
{
{"Key_A", 0, &KeyMapping[0], 32, NULL, 0},
{"Key_B", 0, &KeyMapping[1], 31, NULL, 0},
{"Key_Select", 0, &KeyMapping[2], 57, NULL, 0},
{"Key_Start", 0, &KeyMapping[3], 28, NULL, 0},
{"Key_Right", 0, &KeyMapping[4], 333, NULL, 0},
{"Key_Left", 0, &KeyMapping[5], 331, NULL, 0},
{"Key_Up", 0, &KeyMapping[6], 328, NULL, 0},
{"Key_Down", 0, &KeyMapping[7], 336, NULL, 0},
{"Key_R", 0, &KeyMapping[8], 54, NULL, 0},
{"Key_L", 0, &KeyMapping[9], 86, NULL, 0},
{"Key_X", 0, &KeyMapping[10], 17, NULL, 0},
{"Key_Y", 0, &KeyMapping[11], 30, NULL, 0},
{"Joy_A", 0, &JoyMapping[0], -1, NULL, 0},
{"Joy_B", 0, &JoyMapping[1], -1, NULL, 0},
{"Joy_Select", 0, &JoyMapping[2], -1, NULL, 0},
{"Joy_Start", 0, &JoyMapping[3], -1, NULL, 0},
{"Joy_Right", 0, &JoyMapping[4], -1, NULL, 0},
{"Joy_Left", 0, &JoyMapping[5], -1, NULL, 0},
{"Joy_Up", 0, &JoyMapping[6], -1, NULL, 0},
{"Joy_Down", 0, &JoyMapping[7], -1, NULL, 0},
{"Joy_R", 0, &JoyMapping[8], -1, NULL, 0},
{"Joy_L", 0, &JoyMapping[9], -1, NULL, 0},
{"Joy_X", 0, &JoyMapping[10], -1, NULL, 0},
{"Joy_Y", 0, &JoyMapping[11], -1, NULL, 0},
{"HKKey_Lid", 0, &HKKeyMapping[HK_Lid], 0x0D, NULL, 0},
{"HKKey_Mic", 0, &HKKeyMapping[HK_Mic], 0x35, NULL, 0},
{"HKKey_Pause", 0, &HKKeyMapping[HK_Pause], -1, NULL, 0},
{"HKKey_Reset", 0, &HKKeyMapping[HK_Reset], -1, NULL, 0},
{"HKKey_FastForward", 0, &HKKeyMapping[HK_FastForward], 0x0F, NULL, 0},
{"HKKey_FastForwardToggle", 0, &HKKeyMapping[HK_FastForwardToggle], -1, NULL, 0},
{"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], 0x4B, NULL, 0},
{"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], 0x4D, NULL, 0},
{"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1, NULL, 0},
{"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1, NULL, 0},
{"HKJoy_Pause", 0, &HKJoyMapping[HK_Pause], -1, NULL, 0},
{"HKJoy_Reset", 0, &HKJoyMapping[HK_Reset], -1, NULL, 0},
{"HKJoy_FastForward", 0, &HKJoyMapping[HK_FastForward], -1, NULL, 0},
{"HKJoy_FastForwardToggle", 0, &HKJoyMapping[HK_FastForwardToggle], -1, NULL, 0},
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, NULL, 0},
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, NULL, 0},
{"JoystickID", 0, &JoystickID, 0, NULL, 0},
{"WindowWidth", 0, &WindowWidth, 256, NULL, 0},
{"WindowHeight", 0, &WindowHeight, 384, NULL, 0},
{"WindowMax", 0, &WindowMaximized, 0, NULL, 0},
{"ScreenRotation", 0, &ScreenRotation, 0, NULL, 0},
{"ScreenGap", 0, &ScreenGap, 0, NULL, 0},
{"ScreenLayout", 0, &ScreenLayout, 0, NULL, 0},
{"ScreenSizing", 0, &ScreenSizing, 0, NULL, 0},
{"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0},
{"ScreenUseGL", 0, &ScreenUseGL, 1, NULL, 0},
{"ScreenVSync", 0, &ScreenVSync, 0, NULL, 0},
{"ScreenRatio", 0, &ScreenRatio, 0, NULL, 0},
{"LimitFPS", 0, &LimitFPS, 0, NULL, 0},
{"AudioSync", 0, &AudioSync, 1, NULL, 0},
{"ShowOSD", 0, &ShowOSD, 1, NULL, 0},
{"DirectBoot", 0, &DirectBoot, 1, NULL, 0},
{"SockBindAnyAddr", 0, &SocketBindAnyAddr, 0, NULL, 0},
{"LANDevice", 1, LANDevice, 0, "", 127},
{"DirectLAN", 0, &DirectLAN, 0, NULL, 0},
{"SavStaRelocSRAM", 0, &SavestateRelocSRAM, 0, NULL, 0},
{"AudioVolume", 0, &AudioVolume, 256, NULL, 0},
{"MicInputType", 0, &MicInputType, 1, NULL, 0},
{"MicWavPath", 1, MicWavPath, 0, "", 511},
{"LastROMFolder", 1, LastROMFolder, 0, "", 511},
{"", -1, NULL, 0, NULL, 0}
};
}

View File

@ -0,0 +1,82 @@
/*
Copyright 2016-2020 Arisotura
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 PLATFORMCONFIG_H
#define PLATFORMCONFIG_H
#include "Config.h"
enum
{
HK_Lid = 0,
HK_Mic,
HK_Pause,
HK_Reset,
HK_FastForward,
HK_FastForwardToggle,
HK_SolarSensorDecrease,
HK_SolarSensorIncrease,
HK_MAX
};
namespace Config
{
extern int KeyMapping[12];
extern int JoyMapping[12];
extern int HKKeyMapping[HK_MAX];
extern int HKJoyMapping[HK_MAX];
extern int JoystickID;
extern int WindowWidth;
extern int WindowHeight;
extern int WindowMaximized;
extern int ScreenRotation;
extern int ScreenGap;
extern int ScreenLayout;
extern int ScreenSizing;
extern int ScreenFilter;
extern int ScreenUseGL;
extern int ScreenVSync;
extern int ScreenRatio;
extern int LimitFPS;
extern int AudioSync;
extern int ShowOSD;
extern int DirectBoot;
extern int SocketBindAnyAddr;
extern char LANDevice[128];
extern int DirectLAN;
extern int SavestateRelocSRAM;
extern int AudioVolume;
extern int MicInputType;
extern char MicWavPath[512];
extern char LastROMFolder[512];
}
#endif // PLATFORMCONFIG_H

View File

@ -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");
return melon.exec();
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;
// 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);

View File

@ -19,8 +19,45 @@
#ifndef MAIN_H
#define MAIN_H
#include <QThread>
#include <QWidget>
#include <QMainWindow>
class EmuThread : public QThread
{
Q_OBJECT
void run() override;
public:
explicit EmuThread(QObject* parent = nullptr);
// to be called from the UI thread
void emuRun();
void emuPause(bool refresh);
void emuUnpause();
void emuStop();
private:
volatile int EmuStatus;
int PrevEmuStatus;
int EmuRunning;
};
class MainWindowPanel : public QWidget
{
Q_OBJECT
public:
explicit MainWindowPanel(QWidget* parent);
~MainWindowPanel();
protected:
void paintEvent(QPaintEvent* event) override;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -29,8 +66,11 @@ public:
explicit MainWindow(QWidget* parent = nullptr);
~MainWindow();
private slots:
void onOpenFile();
private:
// private shit goes here
MainWindowPanel* panel;
};
#endif // MAIN_H