From 690f9f38744ddda7fd65c299288227767e4b03f0 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 27 Apr 2020 12:06:44 +0200 Subject: 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 --- src/frontend/qt_sdl/Platform.cpp | 558 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 558 insertions(+) create mode 100644 src/frontend/qt_sdl/Platform.cpp (limited to 'src/frontend/qt_sdl/Platform.cpp') diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp new file mode 100644 index 0000000..31b5277 --- /dev/null +++ b/src/frontend/qt_sdl/Platform.cpp @@ -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 +#include +#include +#include +#include "Platform.h" +#include "PlatformConfig.h" +//#include "LAN_Socket.h" +//#include "LAN_PCap.h" +#include + +#ifdef __WIN32__ + #define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK + #include + //#include // FUCK THAT SHIT + extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_RoamingAppData = {0x3eb685db, 0x65f9, 0x4cf6, {0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}}; + #include + #include + #include + #define socket_t SOCKET + #define sockaddr_t SOCKADDR +#else + #include + #include + #include + #include + #include + #include + #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; +} + + +} -- cgit v1.2.3 From 0566c9e34c36f7f1841765b02147fd4c890e8550 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 17 May 2020 13:04:02 +0200 Subject: minor fix --- src/NDSCart.cpp | 5 +++ src/frontend/qt_sdl/Platform.cpp | 2 +- src/frontend/qt_sdl/main.cpp | 68 +--------------------------------------- 3 files changed, 7 insertions(+), 68 deletions(-) (limited to 'src/frontend/qt_sdl/Platform.cpp') diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 5a2a0d0..585eadf 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -867,6 +867,11 @@ bool ReadROMParams(u32 gamecode, u32* params) void DecryptSecureArea(u8* out) { + // TODO: source decryption data from different possible sources + // * original DS-mode ARM7 BIOS has the key data at 0x30 + // * .srl ROMs (VC dumps) have encrypted secure areas but have precomputed + // decryption data at 0x1000 (and at the beginning of the DSi region if any) + u32 gamecode = *(u32*)&CartROM[0x0C]; u32 arm9base = *(u32*)&CartROM[0x20]; diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 31b5277..fea9166 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -202,7 +202,7 @@ FILE* OpenLocalFile(const char* path, const char* mode) #ifdef __WIN32__ if (pathlen > 3) { - if (path[1] == ':' && path[2] == '\\') + if (path[1] == ':' && (path[2] == '\\' || path[2] == '/')) return OpenFile(path, mode); } #else diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index ec4b04b..67eb3d8 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -915,74 +915,8 @@ int main(int argc, char** argv) //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) + // TODO: this should be checked before running anything #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)."; -- cgit v1.2.3 From 9df8d91bdc12ab2e65569e26dc7c57246e384a8f Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 19 May 2020 21:34:24 +0200 Subject: keep the ugliness confined in Platform.cpp --- src/Platform.h | 3 +++ src/frontend/qt_sdl/Platform.cpp | 49 +++++++++++++++++++++++++++++++++++++++- src/frontend/qt_sdl/main.cpp | 47 ++------------------------------------ 3 files changed, 53 insertions(+), 46 deletions(-) (limited to 'src/frontend/qt_sdl/Platform.cpp') diff --git a/src/Platform.h b/src/Platform.h index b6effdc..fea98dd 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -24,6 +24,9 @@ namespace Platform { +void Init(int argc, char** argv); +void DeInit(); + void StopEmu(); // fopen() wrappers diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index fea9166..6a5b466 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -53,7 +53,7 @@ #endif -extern char* EmuDirectory; +char* EmuDirectory; void Stop(bool internal); @@ -84,6 +84,53 @@ u8 PacketBuffer[2048]; #define NIFI_VER 1 +void Init(int argc, char** argv) +{ +#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"; + int cdlen = strlen(confdir); + int cnlen = strlen(confname); + EmuDirectory = new char[cdlen + cnlen + 1]; + strncpy(&EmuDirectory[0], confdir, cdlen); + strncpy(&EmuDirectory[cdlen], confname, cnlen); + EmuDirectory[cdlen+cnlen] = '\0'; +#endif +} + +void DeInit() +{ + delete[] EmuDirectory; +} + + void StopEmu() { //Stop(true); diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 8fe776e..a68f933 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -54,8 +54,6 @@ // TODO: uniform variable spelling -char* EmuDirectory; - bool RunningSomething; MainWindow* mainWindow; @@ -865,11 +863,6 @@ void MainWindow::onInputConfigFinished(int res) } -// FIXME!!!! -#if (!defined(__WIN32__) && !defined(UNIX_PORTABLE)) -#include -#endif - int main(int argc, char** argv) { srand(time(NULL)); @@ -877,43 +870,7 @@ 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"; - int cdlen = strlen(confdir); - int cnlen = strlen(confname); - EmuDirectory = new char[cdlen + cnlen + 1]; - strncpy(&EmuDirectory[0], confdir, cdlen); - strncpy(&EmuDirectory[cdlen], confname, cnlen); - EmuDirectory[cdlen+cnlen] = '\0'; -#endif + Platform::Init(argc, argv); QApplication melon(argc, argv); @@ -1060,7 +1017,7 @@ int main(int argc, char** argv) Config::Save(); SDL_Quit(); - delete[] EmuDirectory; + Platform::DeInit(); return ret; } -- cgit v1.2.3 From a9b275bc253510d77b8b6fcd80e6d24b56bc8680 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 20 May 2020 22:58:04 +0200 Subject: reimplement Stop --- src/SPU.cpp | 3 +++ src/frontend/FrontendUtil.h | 4 ++++ src/frontend/Util_ROM.cpp | 14 ++++++++++++++ src/frontend/qt_sdl/Platform.cpp | 4 ++-- src/frontend/qt_sdl/main.cpp | 37 +++++++++++++++++++++++++++++++------ 5 files changed, 54 insertions(+), 8 deletions(-) (limited to 'src/frontend/qt_sdl/Platform.cpp') diff --git a/src/SPU.cpp b/src/SPU.cpp index 710533e..1ebfd4c 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -116,6 +116,9 @@ void Reset() void Stop() { memset(OutputBuffer, 0, 2*OutputBufferSize*2); + + OutputReadOffset = 0; + OutputWriteOffset = 0; } void DoSavestate(Savestate* file) diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index d838b63..faa29de 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -65,6 +65,10 @@ int LoadBIOS(); // note: loading a ROM to the NDS slot resets emulation int LoadROM(const char* file, int slot); +// unload the ROM loaded in the specified cart slot +// simulating ejection of the cartridge +void UnloadROM(int slot); + // reset execution of the current ROM int Reset(); diff --git a/src/frontend/Util_ROM.cpp b/src/frontend/Util_ROM.cpp index e13eb2c..ec3186a 100644 --- a/src/frontend/Util_ROM.cpp +++ b/src/frontend/Util_ROM.cpp @@ -202,6 +202,20 @@ int LoadROM(const char* file, int slot) } } +void UnloadROM(int slot) +{ + if (slot == ROMSlot_NDS) + { + // TODO! + } + else if (slot == ROMSlot_GBA) + { + GBACart::Eject(); + } + + ROMPath[slot][0] = '\0'; +} + int Reset() { int res; diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 6a5b466..dd838d7 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -55,7 +55,7 @@ char* EmuDirectory; -void Stop(bool internal); +void emuStop(); namespace Platform @@ -133,7 +133,7 @@ void DeInit() void StopEmu() { - //Stop(true); + emuStop(); } diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index a73362d..67272af 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -115,8 +115,6 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent) connect(this, SIGNAL(windowEmuStop()), mainWindow, SLOT(onEmuStop())); connect(this, SIGNAL(windowEmuPause()), mainWindow->actPause, SLOT(trigger())); connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger())); - - emit windowEmuStop(); } void EmuThread::run() @@ -140,7 +138,6 @@ void EmuThread::run() } Input::Init(); - /*Touching = false;*/ u32 nframes = 0; u32 starttick = SDL_GetTicks(); @@ -376,7 +373,6 @@ void EmuThread::emuPause() EmuRunning = 2; while (EmuStatus != 2); - //emit windowEmuPause(); if (audioDevice) SDL_PauseAudioDevice(audioDevice, 1); } @@ -384,7 +380,6 @@ void EmuThread::emuUnpause() { EmuRunning = PrevEmuStatus; - //emit windowEmuUnpause(); if (audioDevice) SDL_PauseAudioDevice(audioDevice, 0); } @@ -703,6 +698,18 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) panel->setMinimumSize(256, 384); + for (int i = 0; i < 9; i++) + { + actSaveState[i]->setEnabled(false); + actLoadState[i]->setEnabled(false); + } + actUndoStateLoad->setEnabled(false); + + actPause->setEnabled(false); + actReset->setEnabled(false); + actStop->setEnabled(false); + + actSavestateSRAMReloc->setChecked(Config::SavestateRelocSRAM != 0); actScreenRotation[Config::ScreenRotation]->setChecked(true); @@ -1051,7 +1058,10 @@ void MainWindow::onReset() void MainWindow::onStop() { - // + if (!RunningSomething) return; + + emuThread->emuPause(); + NDS::Stop(); } @@ -1168,6 +1178,8 @@ void MainWindow::onEmuStart() void MainWindow::onEmuStop() { + emuThread->emuPause(); + for (int i = 0; i < 9; i++) { actSaveState[i]->setEnabled(false); @@ -1181,6 +1193,19 @@ void MainWindow::onEmuStop() } +void emuStop() +{ + RunningSomething = false; + + Frontend::UnloadROM(Frontend::ROMSlot_NDS); + Frontend::UnloadROM(Frontend::ROMSlot_GBA); + + emit emuThread->windowEmuStop(); + + //OSD::AddMessage(0xFFC040, "Shutdown"); +} + + int main(int argc, char** argv) { -- cgit v1.2.3 From 36f4cdbbbf1904c1a0455bf45d9720f03872e1bd Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 25 May 2020 18:25:50 +0200 Subject: get the OpenGL renderer going. sorta. (also make the blackmagic_II branch obsolete in the process) --- src/CMakeLists.txt | 2 + src/GPU.cpp | 2 + src/GPU.h | 14 + src/GPU2D.cpp | 2 + src/GPU3D.cpp | 2 +- src/GPU3D_OpenGL.cpp | 31 +- src/GPU_OpenGL.cpp | 207 ++++++++++ src/GPU_OpenGL_shaders.h | 867 +++++++++++++++++++++++++++++++++++++++ src/OpenGLSupport.cpp | 14 +- src/OpenGLSupport.h | 30 +- src/frontend/qt_sdl/Platform.cpp | 3 +- src/frontend/qt_sdl/main.cpp | 96 ++++- src/frontend/qt_sdl/main.h | 11 + 13 files changed, 1240 insertions(+), 41 deletions(-) create mode 100644 src/GPU_OpenGL.cpp create mode 100644 src/GPU_OpenGL_shaders.h (limited to 'src/frontend/qt_sdl/Platform.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 245e6a2..56bb3cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,8 @@ add_library(core STATIC FIFO.h GBACart.cpp GPU.cpp + GPU_OpenGL.cpp + GPU_OpenGL_shaders.h GPU2D.cpp GPU3D.cpp GPU3D_OpenGL.cpp diff --git a/src/GPU.cpp b/src/GPU.cpp index 42bfc56..993086e 100644 --- a/src/GPU.cpp +++ b/src/GPU.cpp @@ -985,6 +985,8 @@ void StartScanline(u32 line) GPU2D_A->VBlank(); GPU2D_B->VBlank(); GPU3D::VBlank(); + + if (Accelerated) GLCompositor::RenderFrame(); } else if (VCount == 144) { diff --git a/src/GPU.h b/src/GPU.h index 661a7d9..e85a5b4 100644 --- a/src/GPU.h +++ b/src/GPU.h @@ -422,6 +422,20 @@ void SetDispStat(u32 cpu, u16 val); void SetVCount(u16 val); +namespace GLCompositor +{ + +bool Init(); +void DeInit(); +void Reset(); + +void UpdateDisplaySettings(); + +void RenderFrame(); +void BindOutputTexture(); + +} + } #endif diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp index 1c6cf0c..6f950b7 100644 --- a/src/GPU2D.cpp +++ b/src/GPU2D.cpp @@ -728,6 +728,8 @@ u32 GPU2D::ColorComposite(int i, u32 val1, u32 val2) case 3: return ColorBrightnessDown(val1, EVY); case 4: return ColorBlend5(val1, val2); } + + return val1; } diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 4f146ae..e687e37 100644 --- a/src/GPU3D.cpp +++ b/src/GPU3D.cpp @@ -616,7 +616,7 @@ int InitRenderer(bool hasGL) if (!GLRenderer::Init()) renderer = 0; } - +printf("renderer: %d\n", renderer); if (renderer == 0) SoftRenderer::Init(); Renderer = renderer; diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp index b1bcaa1..dcc4b6b 100644 --- a/src/GPU3D_OpenGL.cpp +++ b/src/GPU3D_OpenGL.cpp @@ -29,6 +29,8 @@ namespace GPU3D namespace GLRenderer { +using namespace OpenGL; + // GL version requirements // * texelFetch: 3.0 (GLSL 1.30) (3.2/1.50 for MS) // * UBO: 3.1 @@ -142,7 +144,7 @@ bool BuildRenderShader(u32 flags, const char* vs, const char* fs) strcpy(&fsbuf[headerlen], kRenderFSCommon); strcpy(&fsbuf[headerlen + fsclen], fs); - bool ret = OpenGL_BuildShaderProgram(vsbuf, fsbuf, RenderShader[flags], shadername); + bool ret = OpenGL::BuildShaderProgram(vsbuf, fsbuf, RenderShader[flags], shadername); delete[] vsbuf; delete[] fsbuf; @@ -158,7 +160,7 @@ bool BuildRenderShader(u32 flags, const char* vs, const char* fs) glBindFragDataLocation(prog, 0, "oColor"); glBindFragDataLocation(prog, 1, "oAttr"); - if (!OpenGL_LinkShaderProgram(RenderShader[flags])) + if (!OpenGL::LinkShaderProgram(RenderShader[flags])) return false; GLint uni_id = glGetUniformBlockIndex(prog, "uConfig"); @@ -202,14 +204,14 @@ bool Init() glClearDepth(1.0); - if (!OpenGL_BuildShaderProgram(kClearVS, kClearFS, ClearShaderPlain, "ClearShader")) + if (!OpenGL::BuildShaderProgram(kClearVS, kClearFS, ClearShaderPlain, "ClearShader")) return false; glBindAttribLocation(ClearShaderPlain[2], 0, "vPosition"); glBindFragDataLocation(ClearShaderPlain[2], 0, "oColor"); glBindFragDataLocation(ClearShaderPlain[2], 1, "oAttr"); - if (!OpenGL_LinkShaderProgram(ClearShaderPlain)) + if (!OpenGL::LinkShaderProgram(ClearShaderPlain)) return false; ClearUniformLoc[0] = glGetUniformLocation(ClearShaderPlain[2], "uColor"); @@ -237,15 +239,15 @@ bool Init() kRenderVS_W, kRenderFS_WSM)) return false; - if (!OpenGL_BuildShaderProgram(kFinalPassVS, kFinalPassEdgeFS, FinalPassEdgeShader, "FinalPassEdgeShader")) + if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassEdgeFS, FinalPassEdgeShader, "FinalPassEdgeShader")) return false; - if (!OpenGL_BuildShaderProgram(kFinalPassVS, kFinalPassFogFS, FinalPassFogShader, "FinalPassFogShader")) + if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassFogFS, FinalPassFogShader, "FinalPassFogShader")) return false; glBindAttribLocation(FinalPassEdgeShader[2], 0, "vPosition"); glBindFragDataLocation(FinalPassEdgeShader[2], 0, "oColor"); - if (!OpenGL_LinkShaderProgram(FinalPassEdgeShader)) + if (!OpenGL::LinkShaderProgram(FinalPassEdgeShader)) return false; uni_id = glGetUniformBlockIndex(FinalPassEdgeShader[2], "uConfig"); @@ -261,7 +263,7 @@ bool Init() glBindAttribLocation(FinalPassFogShader[2], 0, "vPosition"); glBindFragDataLocation(FinalPassFogShader[2], 0, "oColor"); - if (!OpenGL_LinkShaderProgram(FinalPassFogShader)) + if (!OpenGL::LinkShaderProgram(FinalPassFogShader)) return false; uni_id = glGetUniformBlockIndex(FinalPassFogShader[2], "uConfig"); @@ -371,11 +373,19 @@ bool Init() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 1024, 48, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL); + if (!GPU::GLCompositor::Init()) + { + // TODO: clean up things? fail more gracefully?? + return false; + } + return true; } void DeInit() { + GPU::GLCompositor::DeInit(); + glDeleteTextures(1, &TexMemID); glDeleteTextures(1, &TexPalMemID); @@ -392,12 +402,13 @@ void DeInit() for (int i = 0; i < 16; i++) { if (!RenderShader[i][2]) continue; - OpenGL_DeleteShaderProgram(RenderShader[i]); + OpenGL::DeleteShaderProgram(RenderShader[i]); } } void Reset() { + GPU::GLCompositor::Reset(); } void UpdateDisplaySettings() @@ -480,6 +491,8 @@ void UpdateDisplaySettings() //glLineWidth(scale); //glLineWidth(1.5); + + GPU::GLCompositor::UpdateDisplaySettings(); } diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp new file mode 100644 index 0000000..c9d31f1 --- /dev/null +++ b/src/GPU_OpenGL.cpp @@ -0,0 +1,207 @@ +/* + 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 +#include +#include "NDS.h" +#include "GPU.h" +#include "Config.h" +#include "OpenGLSupport.h" +#include "GPU_OpenGL_shaders.h" + +namespace GPU +{ +namespace GLCompositor +{ + +using namespace OpenGL; + +int Scale; +int ScreenH, ScreenW; + +GLuint CompShader[1][3]; +GLuint CompScaleLoc[1]; + +GLuint CompVertexBufferID; +GLuint CompVertexArrayID; +float CompVertices[2 * 3*2 * 2]; // position + +GLuint CompScreenInputTex; +GLuint CompScreenOutputTex; +GLuint CompScreenOutputFB; + + +bool Init() +{ + if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Nearest, CompShader[0], "CompositorShader")) + //if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Linear, CompShader[0], "CompositorShader")) + //if (!OpenGL::BuildShaderProgram(kCompositorVS_xBRZ, kCompositorFS_xBRZ, CompShader[0], "CompositorShader")) + return false; + + for (int i = 0; i < 1; i++) + { + GLint uni_id; + + glBindAttribLocation(CompShader[i][2], 0, "vPosition"); + glBindFragDataLocation(CompShader[i][2], 0, "oColor"); + + if (!OpenGL::LinkShaderProgram(CompShader[i])) + return false; + + CompScaleLoc[i] = glGetUniformLocation(CompShader[i][2], "u3DScale"); + + glUseProgram(CompShader[i][2]); + uni_id = glGetUniformLocation(CompShader[i][2], "ScreenTex"); + glUniform1i(uni_id, 0); + uni_id = glGetUniformLocation(CompShader[i][2], "_3DTex"); + glUniform1i(uni_id, 1); + } + +#define SETVERTEX(i, x, y) \ + CompVertices[2*(i) + 0] = x; \ + CompVertices[2*(i) + 1] = y; + + // top screen + SETVERTEX(0, -1, 1); + SETVERTEX(1, 1, 0); + SETVERTEX(2, 1, 1); + SETVERTEX(3, -1, 1); + SETVERTEX(4, -1, 0); + SETVERTEX(5, 1, 0); + + // bottom screen + SETVERTEX(6, -1, 0); + SETVERTEX(7, 1, -1); + SETVERTEX(8, 1, 0); + SETVERTEX(9, -1, 0); + SETVERTEX(10, -1, -1); + SETVERTEX(11, 1, -1); + +#undef SETVERTEX + + glGenBuffers(1, &CompVertexBufferID); + glBindBuffer(GL_ARRAY_BUFFER, CompVertexBufferID); + glBufferData(GL_ARRAY_BUFFER, sizeof(CompVertices), CompVertices, GL_STATIC_DRAW); + + glGenVertexArrays(1, &CompVertexArrayID); + glBindVertexArray(CompVertexArrayID); + glEnableVertexAttribArray(0); // position + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2*4, (void*)(0)); + + glGenFramebuffers(1, &CompScreenOutputFB); + + glGenTextures(1, &CompScreenInputTex); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, CompScreenInputTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL); + + glGenTextures(1, &CompScreenOutputTex); + glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + return true; +} + +void DeInit() +{ + glDeleteFramebuffers(1, &CompScreenOutputFB); + glDeleteTextures(1, &CompScreenInputTex); + glDeleteTextures(1, &CompScreenOutputTex); + + glDeleteVertexArrays(1, &CompVertexArrayID); + glDeleteBuffers(1, &CompVertexBufferID); + + for (int i = 0; i < 1; i++) + OpenGL::DeleteShaderProgram(CompShader[i]); +} + +void Reset() +{ +} + + +void UpdateDisplaySettings() +{ + int scale = Config::GL_ScaleFactor; + + Scale = scale; + ScreenW = 256 * scale; + ScreenH = 384 * scale; + + glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + GLenum fbassign[] = {GL_COLOR_ATTACHMENT0}; + glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex, 0); + glDrawBuffers(1, fbassign); +} + + +void RenderFrame() +{ + glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + + glViewport(0, 0, ScreenW, ScreenH); + + // TODO: select more shaders (filtering, etc) + OpenGL::UseShaderProgram(CompShader[0]); + glUniform1ui(CompScaleLoc[0], Scale); + + //if (RunningSomething) + { + int frontbuf = GPU::FrontBuffer; + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, CompScreenInputTex); + + if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1]) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256*3 + 1, 192, GL_RGBA_INTEGER, + GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256*3 + 1, 192, GL_RGBA_INTEGER, + GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]); + } + + glActiveTexture(GL_TEXTURE1); + GPU3D::GLRenderer::SetupAccelFrame(); + + glBindBuffer(GL_ARRAY_BUFFER, CompVertexBufferID); + glBindVertexArray(CompVertexArrayID); + glDrawArrays(GL_TRIANGLES, 0, 4*3); + } +} + +void BindOutputTexture() +{ + glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex); +} + +} +} diff --git a/src/GPU_OpenGL_shaders.h b/src/GPU_OpenGL_shaders.h new file mode 100644 index 0000000..ec975ed --- /dev/null +++ b/src/GPU_OpenGL_shaders.h @@ -0,0 +1,867 @@ +/* + 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 GPU_OPENGL_SHADERS_H +#define GPU_OPENGL_SHADERS_H + +const char* kCompositorVS = R"(#version 140 + +in vec2 vPosition; + +smooth out vec2 fTexcoord; + +void main() +{ + vec4 fpos; + fpos.xy = vPosition; + fpos.z = 0.0; + fpos.w = 1.0; + + gl_Position = fpos; + fTexcoord = (vPosition + vec2(1.0, 1.0)) * (vec2(256.0, 384.0) / 2.0); +} +)"; + +const char* kCompositorFS_Nearest = R"(#version 140 + +uniform uint u3DScale; + +uniform usampler2D ScreenTex; +uniform sampler2D _3DTex; + +smooth in vec2 fTexcoord; + +out vec4 oColor; + +void main() +{ + ivec4 pixel = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord), 0)); + + ivec4 mbright = ivec4(texelFetch(ScreenTex, ivec2(256*3, int(fTexcoord.y)), 0)); + int dispmode = mbright.b & 0x3; + + if (dispmode == 1) + { + ivec4 val1 = pixel; + ivec4 val2 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(256,0), 0)); + ivec4 val3 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(512,0), 0)); + + int compmode = val3.a & 0xF; + int eva, evb, evy; + + if (compmode == 4) + { + // 3D on top, blending + + float xpos = val3.r + fract(fTexcoord.x); + float ypos = mod(fTexcoord.y, 192); + ivec4 _3dpix = ivec4(texelFetch(_3DTex, ivec2(vec2(xpos, ypos)*u3DScale), 0).bgra + * vec4(63,63,63,31)); + + if (_3dpix.a > 0) + { + eva = (_3dpix.a & 0x1F) + 1; + evb = 32 - eva; + + val1 = ((_3dpix * eva) + (val1 * evb)) >> 5; + if (eva <= 16) val1 += ivec4(1,1,1,0); + val1 = min(val1, 0x3F); + } + else + val1 = val2; + } + else if (compmode == 1) + { + // 3D on bottom, blending + + float xpos = val3.r + fract(fTexcoord.x); + float ypos = mod(fTexcoord.y, 192); + ivec4 _3dpix = ivec4(texelFetch(_3DTex, ivec2(vec2(xpos, ypos)*u3DScale), 0).bgra + * vec4(63,63,63,31)); + + if (_3dpix.a > 0) + { + eva = val3.g; + evb = val3.b; + + val1 = ((val1 * eva) + (_3dpix * evb)) >> 4; + val1 = min(val1, 0x3F); + } + else + val1 = val2; + } + else if (compmode <= 3) + { + // 3D on top, normal/fade + + float xpos = val3.r + fract(fTexcoord.x); + float ypos = mod(fTexcoord.y, 192); + ivec4 _3dpix = ivec4(texelFetch(_3DTex, ivec2(vec2(xpos, ypos)*u3DScale), 0).bgra + * vec4(63,63,63,31)); + + if (_3dpix.a > 0) + { + evy = val3.g; + + val1 = _3dpix; + if (compmode == 2) val1 += ((ivec4(0x3F,0x3F,0x3F,0) - val1) * evy) >> 4; + else if (compmode == 3) val1 -= (val1 * evy) >> 4; + } + else + val1 = val2; + } + + pixel = val1; + } + + if (dispmode != 0) + { + int brightmode = mbright.g >> 6; + if (brightmode == 1) + { + // up + int evy = mbright.r & 0x1F; + if (evy > 16) evy = 16; + + pixel += ((ivec4(0x3F,0x3F,0x3F,0) - pixel) * evy) >> 4; + } + else if (brightmode == 2) + { + // down + int evy = mbright.r & 0x1F; + if (evy > 16) evy = 16; + + pixel -= (pixel * evy) >> 4; + } + } + + pixel.rgb <<= 2; + pixel.rgb |= (pixel.rgb >> 6); + + // TODO: filters + + oColor = vec4(vec3(pixel.rgb) / 255.0, 1.0); +} +)"; + + + +const char* kCompositorFS_Linear = R"(#version 140 + +uniform uint u3DScale; + +uniform usampler2D ScreenTex; +uniform sampler2D _3DTex; + +smooth in vec2 fTexcoord; + +out vec4 oColor; + +ivec4 Get3DPixel(vec2 pos) +{ + return ivec4(texelFetch(_3DTex, ivec2(pos*u3DScale), 0).bgra + * vec4(63,63,63,31)); +} + +ivec4 GetFullPixel(ivec4 val1, ivec4 val2, ivec4 val3, ivec4 _3dpix) +{ + int compmode = val3.a & 0xF; + int eva, evb, evy; + + if (compmode == 4) + { + // 3D on top, blending + + if (_3dpix.a > 0) + { + eva = (_3dpix.a & 0x1F) + 1; + evb = 32 - eva; + + val1 = ((_3dpix * eva) + (val1 * evb)) >> 5; + if (eva <= 16) val1 += ivec4(1,1,1,0); + val1 = min(val1, 0x3F); + } + else + val1 = val2; + } + else if (compmode == 1) + { + // 3D on bottom, blending + + if (_3dpix.a > 0) + { + eva = val3.g; + evb = val3.b; + + val1 = ((val1 * eva) + (_3dpix * evb)) >> 4; + val1 = min(val1, 0x3F); + } + else + val1 = val2; + } + else if (compmode <= 3) + { + // 3D on top, normal/fade + + if (_3dpix.a > 0) + { + evy = val3.g; + + val1 = _3dpix; + if (compmode == 2) val1 += ((ivec4(0x3F,0x3F,0x3F,0) - val1) * evy) >> 4; + else if (compmode == 3) val1 -= (val1 * evy) >> 4; + } + else + val1 = val2; + } + + return val1; +} + +ivec4 imix(ivec4 a, ivec4 b, float x) +{ + return ivec4(vec4(a)*(1-x) + vec4(b)*x); +} + +void main() +{ + ivec4 pixel = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord), 0)); + + ivec4 mbright = ivec4(texelFetch(ScreenTex, ivec2(256*3, int(fTexcoord.y)), 0)); + int dispmode = mbright.b & 0x3; + + if (dispmode == 1) + { + ivec4 val1 = pixel; + ivec4 val2 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(256,0), 0)); + ivec4 val3 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(512,0), 0)); + + float xfract = fract(fTexcoord.x); + float yfract = fract(fTexcoord.y); + + float xpos = val3.r + xfract; + float ypos = mod(fTexcoord.y, 192); + ivec4 _3dpix = Get3DPixel(vec2(xpos,ypos)); + + ivec4 p00 = GetFullPixel(val1, val2, val3, _3dpix); + + int xdisp = 1 - int(step(255, fTexcoord.x)); + int ydisp = 1 - int(step(191, ypos)); + + ivec4 p01 = GetFullPixel(ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(xdisp+0 ,0), 0)), + ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(xdisp+256,0), 0)), + ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(xdisp+512,0), 0)), + _3dpix); + + ivec4 p10 = GetFullPixel(ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(0+0 ,ydisp), 0)), + ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(0+256,ydisp), 0)), + ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(0+512,ydisp), 0)), + _3dpix); + + ivec4 p11 = GetFullPixel(ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(xdisp+0 ,ydisp), 0)), + ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(xdisp+256,ydisp), 0)), + ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(xdisp+512,ydisp), 0)), + _3dpix); + + ivec4 pa = imix(p00, p01, xfract); + ivec4 pb = imix(p10, p11, xfract); + + pixel = imix(pa, pb, yfract); + } + + if (dispmode != 0) + { + int brightmode = mbright.g >> 6; + if (brightmode == 1) + { + // up + int evy = mbright.r & 0x1F; + if (evy > 16) evy = 16; + + pixel += ((ivec4(0x3F,0x3F,0x3F,0) - pixel) * evy) >> 4; + } + else if (brightmode == 2) + { + // down + int evy = mbright.r & 0x1F; + if (evy > 16) evy = 16; + + pixel -= (pixel * evy) >> 4; + } + } + + pixel.rgb <<= 2; + pixel.rgb |= (pixel.rgb >> 6); + + // TODO: filters + + oColor = vec4(vec3(pixel.rgb) / 255.0, 1.0); +} +)"; + + + + + + +// HUGE TEST ZONE ARRLGD + +const char* kCompositorVS_xBRZ = R"(#version 140 + +#define BLEND_NONE 0 +#define BLEND_NORMAL 1 +#define BLEND_DOMINANT 2 +#define LUMINANCE_WEIGHT 1.0 +#define EQUAL_COLOR_TOLERANCE 30.0/255.0 +#define STEEP_DIRECTION_THRESHOLD 2.2 +#define DOMINANT_DIRECTION_THRESHOLD 3.6 + +#if __VERSION__ >= 130 +#define COMPAT_VARYING out +#define COMPAT_ATTRIBUTE in +#define COMPAT_TEXTURE texture +#else +#define COMPAT_VARYING varying +#define COMPAT_ATTRIBUTE attribute +#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +COMPAT_ATTRIBUTE vec2 vPosition; +COMPAT_VARYING vec4 TEX0; +COMPAT_VARYING vec4 t1; +COMPAT_VARYING vec4 t2; +COMPAT_VARYING vec4 t3; +COMPAT_VARYING vec4 t4; +COMPAT_VARYING vec4 t5; +COMPAT_VARYING vec4 t6; +COMPAT_VARYING vec4 t7; + +uniform COMPAT_PRECISION int FrameDirection; +uniform COMPAT_PRECISION int FrameCount; +uniform COMPAT_PRECISION vec2 OutputSize; +uniform COMPAT_PRECISION vec2 TextureSize; +uniform COMPAT_PRECISION vec2 InputSize; + +// vertex compatibility #defines +#define vTexCoord TEX0.xy +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + +void main() +{ + vec4 fpos; + fpos.xy = vPosition; + fpos.z = 0.0; + fpos.w = 1.0; + + gl_Position = fpos; + vec2 TexCoord = (vPosition + vec2(1.0, 1.0)) * (vec2(256.0, 384.0) / 2.0); + + + //gl_Position = MVPMatrix * VertexCoord; + //COL0 = COLOR; + TEX0.xy = TexCoord.xy; + vec2 ps = vec2(1,1);//vec2(SourceSize.z, SourceSize.w); + float dx = ps.x; + float dy = ps.y; + + // A1 B1 C1 + // A0 A B C C4 + // D0 D E F F4 + // G0 G H I I4 + // G5 H5 I5 + + t1 = vTexCoord.xxxy + vec4( -dx, 0.0, dx,-2.0*dy); // A1 B1 C1 + t2 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, -dy); // A B C + t3 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 0.0); // D E F + t4 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, dy); // G H I + t5 = vTexCoord.xxxy + vec4( -dx, 0.0, dx, 2.0*dy); // G5 H5 I5 + t6 = vTexCoord.xyyy + vec4(-2.0*dx,-dy, 0.0, dy); // A0 D0 G0 + t7 = vTexCoord.xyyy + vec4( 2.0*dx,-dy, 0.0, dy); // C4 F4 I4 +} +)"; + +const char* kCompositorFS_xBRZ = R"(#version 140 + +#define BLEND_NONE 0 +#define BLEND_NORMAL 1 +#define BLEND_DOMINANT 2 +#define LUMINANCE_WEIGHT 1.0 +#define EQUAL_COLOR_TOLERANCE 30.0/255.0 +#define STEEP_DIRECTION_THRESHOLD 2.2 +#define DOMINANT_DIRECTION_THRESHOLD 3.6 + +#if __VERSION__ >= 130 +#define COMPAT_VARYING in +//#define COMPAT_TEXTURE texture +#define FragColor oColor +#else +#define COMPAT_VARYING varying +#define FragColor gl_FragColor +//#define COMPAT_TEXTURE texture2D +#endif + +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; +#endif +#define COMPAT_PRECISION mediump +#else +#define COMPAT_PRECISION +#endif + +uniform uint u3DScale; + +uniform usampler2D ScreenTex; +uniform sampler2D _3DTex; + +smooth in vec2 fTexcoord; + +out vec4 oColor; + +//uniform COMPAT_PRECISION vec2 OutputSize; +//uniform COMPAT_PRECISION vec2 TextureSize; +#define TextureSize vec2(256,384) +//uniform COMPAT_PRECISION vec2 InputSize; +//uniform sampler2D Texture; +#define Texture 1312 +COMPAT_VARYING vec4 TEX0; +COMPAT_VARYING vec4 t1; +COMPAT_VARYING vec4 t2; +COMPAT_VARYING vec4 t3; +COMPAT_VARYING vec4 t4; +COMPAT_VARYING vec4 t5; +COMPAT_VARYING vec4 t6; +COMPAT_VARYING vec4 t7; + +// fragment compatibility #defines +#define Source Texture +#define vTexCoord TEX0.xy + +#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize +#define outsize vec4(OutputSize, 1.0 / OutputSize) + + const float one_sixth = 1.0 / 6.0; + const float two_sixth = 2.0 / 6.0; + const float four_sixth = 4.0 / 6.0; + const float five_sixth = 5.0 / 6.0; + +vec4 Get2DPixel(vec2 texcoord, int level) +{ + ivec4 pixel = ivec4(texelFetch(ScreenTex, ivec2(texcoord) + ivec2(level*256,0), 0)); + + return vec4(pixel) / vec4(63.0, 63.0, 63.0, 31.0); +} + +ivec4 Get3DPixel(vec2 pos) +{ + return ivec4(texelFetch(_3DTex, ivec2(pos*u3DScale), 0).bgra + * vec4(63,63,63,31)); +} + +float reduce(const vec3 color) +{ + return dot(color, vec3(65536.0, 256.0, 1.0)); +} + +float DistYCbCr(const vec3 pixA, const vec3 pixB) +{ + const vec3 w = vec3(0.2627, 0.6780, 0.0593); + const float scaleB = 0.5 / (1.0 - w.b); + const float scaleR = 0.5 / (1.0 - w.r); + vec3 diff = pixA - pixB; + float Y = dot(diff, w); + float Cb = scaleB * (diff.b - Y); + float Cr = scaleR * (diff.r - Y); + + return sqrt( ((LUMINANCE_WEIGHT * Y) * (LUMINANCE_WEIGHT * Y)) + (Cb * Cb) + (Cr * Cr) ); +} + +bool IsPixEqual(const vec3 pixA, const vec3 pixB) +{ + return (DistYCbCr(pixA, pixB) < EQUAL_COLOR_TOLERANCE); +} + +bool IsBlendingNeeded(const ivec4 blend) +{ + return any(notEqual(blend, ivec4(BLEND_NONE))); +} + +//--------------------------------------- +// Input Pixel Mapping: --|21|22|23|-- +// 19|06|07|08|09 +// 18|05|00|01|10 +// 17|04|03|02|11 +// --|15|14|13|-- +// +// Output Pixel Mapping: 20|21|22|23|24|25 +// 19|06|07|08|09|26 +// 18|05|00|01|10|27 +// 17|04|03|02|11|28 +// 16|15|14|13|12|29 +// 35|34|33|32|31|30 + +ivec4 GetFiltered2DPixel(int level) +{ + vec2 f = fract(vTexCoord.xy);// * SourceSize.xy); + + //--------------------------------------- + // Input Pixel Mapping: 20|21|22|23|24 + // 19|06|07|08|09 + // 18|05|00|01|10 + // 17|04|03|02|11 + // 16|15|14|13|12 + + vec3 src[25]; + + src[21] = Get2DPixel(t1.xw, level).rgb; + src[22] = Get2DPixel(t1.yw, level).rgb; + src[23] = Get2DPixel(t1.zw, level).rgb; + src[ 6] = Get2DPixel(t2.xw, level).rgb; + src[ 7] = Get2DPixel(t2.yw, level).rgb; + src[ 8] = Get2DPixel(t2.zw, level).rgb; + src[ 5] = Get2DPixel(t3.xw, level).rgb; + src[ 0] = Get2DPixel(t3.yw, level).rgb; + src[ 1] = Get2DPixel(t3.zw, level).rgb; + src[ 4] = Get2DPixel(t4.xw, level).rgb; + src[ 3] = Get2DPixel(t4.yw, level).rgb; + src[ 2] = Get2DPixel(t4.zw, level).rgb; + src[15] = Get2DPixel(t5.xw, level).rgb; + src[14] = Get2DPixel(t5.yw, level).rgb; + src[13] = Get2DPixel(t5.zw, level).rgb; + src[19] = Get2DPixel(t6.xy, level).rgb; + src[18] = Get2DPixel(t6.xz, level).rgb; + src[17] = Get2DPixel(t6.xw, level).rgb; + src[ 9] = Get2DPixel(t7.xy, level).rgb; + src[10] = Get2DPixel(t7.xz, level).rgb; + src[11] = Get2DPixel(t7.xw, level).rgb; + + float v[9]; + v[0] = reduce(src[0]); + v[1] = reduce(src[1]); + v[2] = reduce(src[2]); + v[3] = reduce(src[3]); + v[4] = reduce(src[4]); + v[5] = reduce(src[5]); + v[6] = reduce(src[6]); + v[7] = reduce(src[7]); + v[8] = reduce(src[8]); + + ivec4 blendResult = ivec4(BLEND_NONE); + + // Preprocess corners + // Pixel Tap Mapping: --|--|--|--|-- + // --|--|07|08|-- + // --|05|00|01|10 + // --|04|03|02|11 + // --|--|14|13|-- + // Corner (1, 1) + if ( ((v[0] == v[1] && v[3] == v[2]) || (v[0] == v[3] && v[1] == v[2])) == false) + { + float dist_03_01 = DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + DistYCbCr(src[14], src[ 2]) + DistYCbCr(src[ 2], src[10]) + (4.0 * DistYCbCr(src[ 3], src[ 1])); + float dist_00_02 = DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[ 3], src[13]) + DistYCbCr(src[ 7], src[ 1]) + DistYCbCr(src[ 1], src[11]) + (4.0 * DistYCbCr(src[ 0], src[ 2])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_03_01) < dist_00_02; + blendResult[2] = ((dist_03_01 < dist_00_02) && (v[0] != v[1]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: --|--|--|--|-- + // --|06|07|--|-- + // 18|05|00|01|-- + // 17|04|03|02|-- + // --|15|14|--|-- + // Corner (0, 1) + if ( ((v[5] == v[0] && v[4] == v[3]) || (v[5] == v[4] && v[0] == v[3])) == false) + { + float dist_04_00 = DistYCbCr(src[17], src[ 5]) + DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[15], src[ 3]) + DistYCbCr(src[ 3], src[ 1]) + (4.0 * DistYCbCr(src[ 4], src[ 0])); + float dist_05_03 = DistYCbCr(src[18], src[ 4]) + DistYCbCr(src[ 4], src[14]) + DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + (4.0 * DistYCbCr(src[ 5], src[ 3])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_03) < dist_04_00; + blendResult[3] = ((dist_04_00 > dist_05_03) && (v[0] != v[5]) && (v[0] != v[3])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: --|--|22|23|-- + // --|06|07|08|09 + // --|05|00|01|10 + // --|--|03|02|-- + // --|--|--|--|-- + // Corner (1, 0) + if ( ((v[7] == v[8] && v[0] == v[1]) || (v[7] == v[0] && v[8] == v[1])) == false) + { + float dist_00_08 = DistYCbCr(src[ 5], src[ 7]) + DistYCbCr(src[ 7], src[23]) + DistYCbCr(src[ 3], src[ 1]) + DistYCbCr(src[ 1], src[ 9]) + (4.0 * DistYCbCr(src[ 0], src[ 8])); + float dist_07_01 = DistYCbCr(src[ 6], src[ 0]) + DistYCbCr(src[ 0], src[ 2]) + DistYCbCr(src[22], src[ 8]) + DistYCbCr(src[ 8], src[10]) + (4.0 * DistYCbCr(src[ 7], src[ 1])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_07_01) < dist_00_08; + blendResult[1] = ((dist_00_08 > dist_07_01) && (v[0] != v[7]) && (v[0] != v[1])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + // Pixel Tap Mapping: --|21|22|--|-- + // 19|06|07|08|-- + // 18|05|00|01|-- + // --|04|03|--|-- + // --|--|--|--|-- + // Corner (0, 0) + if ( ((v[6] == v[7] && v[5] == v[0]) || (v[6] == v[5] && v[7] == v[0])) == false) + { + float dist_05_07 = DistYCbCr(src[18], src[ 6]) + DistYCbCr(src[ 6], src[22]) + DistYCbCr(src[ 4], src[ 0]) + DistYCbCr(src[ 0], src[ 8]) + (4.0 * DistYCbCr(src[ 5], src[ 7])); + float dist_06_00 = DistYCbCr(src[19], src[ 5]) + DistYCbCr(src[ 5], src[ 3]) + DistYCbCr(src[21], src[ 7]) + DistYCbCr(src[ 7], src[ 1]) + (4.0 * DistYCbCr(src[ 6], src[ 0])); + bool dominantGradient = (DOMINANT_DIRECTION_THRESHOLD * dist_05_07) < dist_06_00; + blendResult[0] = ((dist_05_07 < dist_06_00) && (v[0] != v[5]) && (v[0] != v[7])) ? ((dominantGradient) ? BLEND_DOMINANT : BLEND_NORMAL) : BLEND_NONE; + } + + vec3 dst[16]; + dst[ 0] = src[0]; + dst[ 1] = src[0]; + dst[ 2] = src[0]; + dst[ 3] = src[0]; + dst[ 4] = src[0]; + dst[ 5] = src[0]; + dst[ 6] = src[0]; + dst[ 7] = src[0]; + dst[ 8] = src[0]; + dst[ 9] = src[0]; + dst[10] = src[0]; + dst[11] = src[0]; + dst[12] = src[0]; + dst[13] = src[0]; + dst[14] = src[0]; + dst[15] = src[0]; + + // Scale pixel + if (IsBlendingNeeded(blendResult) == true) + { + float dist_01_04 = DistYCbCr(src[1], src[4]); + float dist_03_08 = DistYCbCr(src[3], src[8]); + bool haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[4]) && (v[5] != v[4]); + bool haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[8]) && (v[7] != v[8]); + bool needBlend = (blendResult[2] != BLEND_NONE); + bool doLineBlend = ( blendResult[2] >= BLEND_DOMINANT || + ((blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) || + (blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) || + (IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[0], src[2]) == false) ) == false ); + + vec3 blendPix = ( DistYCbCr(src[0], src[1]) <= DistYCbCr(src[0], src[3]) ) ? src[1] : src[3]; + dst[ 2] = mix(dst[ 2], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[10] = mix(dst[10], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[11] = mix(dst[11], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[12] = mix(dst[12], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[13] = mix(dst[13], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[14] = mix(dst[14], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + + dist_01_04 = DistYCbCr(src[7], src[2]); + dist_03_08 = DistYCbCr(src[1], src[6]); + haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[2]) && (v[3] != v[2]); + haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[6]) && (v[5] != v[6]); + needBlend = (blendResult[1] != BLEND_NONE); + doLineBlend = ( blendResult[1] >= BLEND_DOMINANT || + !((blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) || + (blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) || + (IsPixEqual(src[2], src[1]) && IsPixEqual(src[1], src[8]) && IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && !IsPixEqual(src[0], src[8])) ) ); + + blendPix = ( DistYCbCr(src[0], src[7]) <= DistYCbCr(src[0], src[1]) ) ? src[7] : src[1]; + dst[ 1] = mix(dst[ 1], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[ 7] = mix(dst[ 7], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[ 8] = mix(dst[ 8], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 9] = mix(dst[ 9], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[10] = mix(dst[10], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[11] = mix(dst[11], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + + dist_01_04 = DistYCbCr(src[5], src[8]); + dist_03_08 = DistYCbCr(src[7], src[4]); + haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[8]) && (v[1] != v[8]); + haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[4]) && (v[3] != v[4]); + needBlend = (blendResult[0] != BLEND_NONE); + doLineBlend = ( blendResult[0] >= BLEND_DOMINANT || + !((blendResult[3] != BLEND_NONE && !IsPixEqual(src[0], src[8])) || + (blendResult[1] != BLEND_NONE && !IsPixEqual(src[0], src[4])) || + (IsPixEqual(src[8], src[7]) && IsPixEqual(src[7], src[6]) && IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && !IsPixEqual(src[0], src[6])) ) ); + + blendPix = ( DistYCbCr(src[0], src[5]) <= DistYCbCr(src[0], src[7]) ) ? src[5] : src[7]; + dst[ 0] = mix(dst[ 0], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[15] = mix(dst[15], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[ 4] = mix(dst[ 4], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[ 5] = mix(dst[ 5], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 6] = mix(dst[ 6], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[ 7] = mix(dst[ 7], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 8] = mix(dst[ 8], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[ 9] = mix(dst[ 9], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + + + dist_01_04 = DistYCbCr(src[3], src[6]); + dist_03_08 = DistYCbCr(src[5], src[2]); + haveShallowLine = (STEEP_DIRECTION_THRESHOLD * dist_01_04 <= dist_03_08) && (v[0] != v[6]) && (v[7] != v[6]); + haveSteepLine = (STEEP_DIRECTION_THRESHOLD * dist_03_08 <= dist_01_04) && (v[0] != v[2]) && (v[1] != v[2]); + needBlend = (blendResult[3] != BLEND_NONE); + doLineBlend = ( blendResult[3] >= BLEND_DOMINANT || + !((blendResult[2] != BLEND_NONE && !IsPixEqual(src[0], src[6])) || + (blendResult[0] != BLEND_NONE && !IsPixEqual(src[0], src[2])) || + (IsPixEqual(src[6], src[5]) && IsPixEqual(src[5], src[4]) && IsPixEqual(src[4], src[3]) && IsPixEqual(src[3], src[2]) && !IsPixEqual(src[0], src[4])) ) ); + + blendPix = ( DistYCbCr(src[0], src[3]) <= DistYCbCr(src[0], src[5]) ) ? src[3] : src[5]; + dst[ 3] = mix(dst[ 3], blendPix, (needBlend && doLineBlend) ? ((haveShallowLine) ? ((haveSteepLine) ? 1.0/3.0 : 0.25) : ((haveSteepLine) ? 0.25 : 0.00)) : 0.00); + dst[12] = mix(dst[12], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.25 : 0.00); + dst[13] = mix(dst[13], blendPix, (needBlend && doLineBlend && haveSteepLine) ? 0.75 : 0.00); + dst[14] = mix(dst[14], blendPix, (needBlend) ? ((doLineBlend) ? ((haveSteepLine) ? 1.00 : ((haveShallowLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[15] = mix(dst[15], blendPix, (needBlend) ? ((doLineBlend) ? 1.00 : 0.6848532563) : 0.00); + dst[ 4] = mix(dst[ 4], blendPix, (needBlend) ? ((doLineBlend) ? ((haveShallowLine) ? 1.00 : ((haveSteepLine) ? 0.75 : 0.50)) : 0.08677704501) : 0.00); + dst[ 5] = mix(dst[ 5], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.75 : 0.00); + dst[ 6] = mix(dst[ 6], blendPix, (needBlend && doLineBlend && haveShallowLine) ? 0.25 : 0.00); + } + + vec3 res = mix( mix( mix( mix(dst[ 6], dst[ 7], step(0.25, f.x)), mix(dst[ 8], dst[ 9], step(0.75, f.x)), step(0.50, f.x)), + mix( mix(dst[ 5], dst[ 0], step(0.25, f.x)), mix(dst[ 1], dst[10], step(0.75, f.x)), step(0.50, f.x)), step(0.25, f.y)), + mix( mix( mix(dst[ 4], dst[ 3], step(0.25, f.x)), mix(dst[ 2], dst[11], step(0.75, f.x)), step(0.50, f.x)), + mix( mix(dst[15], dst[14], step(0.25, f.x)), mix(dst[13], dst[12], step(0.75, f.x)), step(0.50, f.x)), step(0.75, f.y)), + step(0.50, f.y)); + + return ivec4(res * vec3(63,63,63), 0); +} + + +void main() +{ + vec2 fTexcoord = vTexCoord.xy; + + ivec4 pixel;// = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord), 0)); + + ivec4 mbright = ivec4(texelFetch(ScreenTex, ivec2(256*3, int(fTexcoord.y)), 0)); + int dispmode = mbright.b & 0x3; + + if (dispmode == 1) + { + ivec4 val1;// = pixel; + //ivec4 val2 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(256,0), 0)); + ivec4 val3 = ivec4(texelFetch(ScreenTex, ivec2(fTexcoord) + ivec2(512,0), 0)); + + int compmode = val3.a & 0xF; + int eva, evb, evy; + + float xpos = val3.r + fract(fTexcoord.x); + float ypos = mod(fTexcoord.y, 192); + ivec4 _3dpix = Get3DPixel(vec2(xpos, ypos)); + + if (compmode == 4) + { + // 3D on top, blending + + if (_3dpix.a > 0) + { + eva = (_3dpix.a & 0x1F) + 1; + if (eva == 32) + { + val1 = _3dpix; + } + else + { + evb = 32 - eva; + + val1 = GetFiltered2DPixel(0); + + val1 = ((_3dpix * eva) + (val1 * evb)) >> 5; + if (eva <= 16) val1 += ivec4(1,1,1,0); + val1 = min(val1, 0x3F); + } + } + else + val1 = GetFiltered2DPixel(1); + } + else if (compmode == 1) + { + // 3D on bottom, blending + + if (_3dpix.a > 0) + { + eva = val3.g; + evb = val3.b; + + val1 = GetFiltered2DPixel(0); + + val1 = ((val1 * eva) + (_3dpix * evb)) >> 4; + val1 = min(val1, 0x3F); + } + else + val1 = GetFiltered2DPixel(1); + } + else if (compmode <= 3) + { + // 3D on top, normal/fade + + if (_3dpix.a > 0) + { + evy = val3.g; + + val1 = _3dpix; + if (compmode == 2) val1 += ((ivec4(0x3F,0x3F,0x3F,0) - val1) * evy) >> 4; + else if (compmode == 3) val1 -= (val1 * evy) >> 4; + } + else + val1 = GetFiltered2DPixel(1); + } + else + val1 = GetFiltered2DPixel(0); + + pixel = val1; + } + else + { + pixel = GetFiltered2DPixel(0); + } + + if (dispmode != 0) + { + int brightmode = mbright.g >> 6; + if (brightmode == 1) + { + // up + int evy = mbright.r & 0x1F; + if (evy > 16) evy = 16; + + pixel += ((ivec4(0x3F,0x3F,0x3F,0) - pixel) * evy) >> 4; + } + else if (brightmode == 2) + { + // down + int evy = mbright.r & 0x1F; + if (evy > 16) evy = 16; + + pixel -= (pixel * evy) >> 4; + } + } + + pixel.rgb <<= 2; + pixel.rgb |= (pixel.rgb >> 6); + + FragColor = vec4(vec3(pixel.rgb) / 255.0, 1.0); +} +)"; + + + + + + +#endif // GPU_OPENGL_SHADERS_H diff --git a/src/OpenGLSupport.cpp b/src/OpenGLSupport.cpp index f91af9b..27b1480 100644 --- a/src/OpenGLSupport.cpp +++ b/src/OpenGLSupport.cpp @@ -19,18 +19,20 @@ #include "OpenGLSupport.h" +namespace OpenGL +{ DO_PROCLIST(DECLPROC); -bool OpenGL_Init() +bool Init() { DO_PROCLIST(LOADPROC); return true; } -bool OpenGL_BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char* name) +bool BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char* name) { int len; int res; @@ -89,7 +91,7 @@ bool OpenGL_BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, cons return true; } -bool OpenGL_LinkShaderProgram(GLuint* ids) +bool LinkShaderProgram(GLuint* ids) { int res; @@ -115,14 +117,16 @@ bool OpenGL_LinkShaderProgram(GLuint* ids) return true; } -void OpenGL_DeleteShaderProgram(GLuint* ids) +void DeleteShaderProgram(GLuint* ids) { glDeleteShader(ids[0]); glDeleteShader(ids[1]); glDeleteProgram(ids[2]); } -void OpenGL_UseShaderProgram(GLuint* ids) +void UseShaderProgram(GLuint* ids) { glUseProgram(ids[2]); } + +} diff --git a/src/OpenGLSupport.h b/src/OpenGLSupport.h index 5f92580..360d215 100644 --- a/src/OpenGLSupport.h +++ b/src/OpenGLSupport.h @@ -21,6 +21,8 @@ #include #include + +// TODO: different includes for each platform #include #include @@ -45,23 +47,11 @@ // if you need more OpenGL functions, add them to the macronator here -// TODO: handle conditionally loading certain functions for different GL versions - -#ifndef __WIN32__ - -#define DO_PROCLIST_1_3(func) -#else -#define DO_PROCLIST_1_3(func) \ +#define DO_PROCLIST(func) \ func(GLACTIVETEXTURE, glActiveTexture); \ func(GLBLENDCOLOR, glBlendColor); \ - -#endif - - -#define DO_PROCLIST(func) \ - DO_PROCLIST_1_3(func) \ \ func(GLGENFRAMEBUFFERS, glGenFramebuffers); \ func(GLDELETEFRAMEBUFFERS, glDeleteFramebuffers); \ @@ -122,14 +112,18 @@ func(GLGETSTRINGI, glGetStringi); \ +namespace OpenGL +{ + DO_PROCLIST(DECLPROC_EXT); +bool Init(); -bool OpenGL_Init(); +bool BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char* name); +bool LinkShaderProgram(GLuint* ids); +void DeleteShaderProgram(GLuint* ids); +void UseShaderProgram(GLuint* ids); -bool OpenGL_BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char* name); -bool OpenGL_LinkShaderProgram(GLuint* ids); -void OpenGL_DeleteShaderProgram(GLuint* ids); -void OpenGL_UseShaderProgram(GLuint* ids); +} #endif // OPENGLSUPPORT_H diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index dd838d7..6b256e0 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -56,6 +56,7 @@ char* EmuDirectory; void emuStop(); +void* oglGetProcAddress(const char* proc); namespace Platform @@ -418,7 +419,7 @@ void Semaphore_Post(void* sema) void* GL_GetProcAddress(const char* proc) { - return NULL;//uiGLGetProcAddress(proc); + return oglGetProcAddress(proc); } diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index bb08a87..096b91c 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -45,6 +45,7 @@ #include "NDS.h" #include "GBACart.h" +#include "OpenGLSupport.h" #include "GPU.h" #include "SPU.h" #include "Wifi.h" @@ -258,6 +259,54 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent) connect(this, SIGNAL(windowEmuPause()), mainWindow->actPause, SLOT(trigger())); connect(this, SIGNAL(windowEmuReset()), mainWindow->actReset, SLOT(trigger())); connect(this, SIGNAL(screenLayoutChange()), mainWindow->panel, SLOT(onScreenLayoutChanged())); + + initOpenGL(); +} + +void EmuThread::initOpenGL() +{ + QOpenGLContext* windowctx = mainWindow->getOGLContext(); + QSurfaceFormat format = windowctx->format(); + + oglSurface = new QOffscreenSurface(); + oglSurface->setFormat(format); + oglSurface->create(); + if (!oglSurface->isValid()) + { + // TODO handle this! + printf("oglSurface shat itself :(\n"); + delete oglSurface; + return; + } + + oglContext = new QOpenGLContext();//oglSurface); + oglContext->setFormat(oglSurface->format()); + oglContext->setShareContext(windowctx); + if (!oglContext->create()) + { + // TODO handle this! + printf("oglContext shat itself :(\n"); + delete oglContext; + delete oglSurface; + return; + } + + oglContext->moveToThread(this); +} + +void deinitOpenGL() +{ + // TODO!! +} + +void* oglGetProcAddress(const char* proc) +{ + return emuThread->oglGetProcAddress(proc); +} + +void* EmuThread::oglGetProcAddress(const char* proc) +{ + return (void*)oglContext->getProcAddress(proc); } void EmuThread::run() @@ -279,7 +328,11 @@ void EmuThread::run() } else*/ { - GPU3D::InitRenderer(false); + //GPU3D::InitRenderer(false); + bool res = oglContext->makeCurrent(oglSurface); + printf("good? %d\n", res); + OpenGL::Init(); + GPU3D::InitRenderer(res); } Input::Init(); @@ -755,6 +808,11 @@ void ScreenPanelGL::initializeGL() { initializeOpenGLFunctions(); + const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string + const GLubyte* version = glGetString(GL_VERSION); // version as a string + printf("OpenGL: renderer: %s\n", renderer); + printf("OpenGL: version: %s\n", version); + glClearColor(0, 0, 0, 1); screenShader = new QOpenGLShaderProgram(this); @@ -828,14 +886,24 @@ void ScreenPanelGL::paintGL() int frontbuf = GPU::FrontBuffer; glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, screenTexture); - if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1]) + if (true) + { + // hardware-accelerated render + GPU::GLCompositor::BindOutputTexture(); + } + else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]); + // regular render + glBindTexture(GL_TEXTURE_2D, screenTexture); + + if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1]) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]); + } } GLint filter = Config::ScreenFilter ? GL_LINEAR : GL_NEAREST; @@ -1141,6 +1209,13 @@ MainWindow::~MainWindow() { } +QOpenGLContext* MainWindow::getOGLContext() +{ + // TODO: check whether we can actually pull this! + QOpenGLWidget* glpanel = (QOpenGLWidget*)panel; + return glpanel->context(); +} + void MainWindow::resizeEvent(QResizeEvent* event) { int w = event->size().width(); @@ -1755,6 +1830,13 @@ int main(int argc, char** argv) } #endif + QSurfaceFormat format; + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + format.setVersion(3, 2); + format.setProfile(QSurfaceFormat::CoreProfile); + QSurfaceFormat::setDefaultFormat(format); + audioSync = SDL_CreateCond(); audioSyncLock = SDL_CreateMutex(); diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index 8a8c041..67c93d0 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,11 @@ class EmuThread : public QThread public: explicit EmuThread(QObject* parent = nullptr); + void initOpenGL(); + void deinitOpenGL(); + + void* oglGetProcAddress(const char* proc); + void changeWindowTitle(char* title); // to be called from the UI thread @@ -67,6 +73,9 @@ private: volatile int EmuStatus; int PrevEmuStatus; int EmuRunning; + + QOffscreenSurface* oglSurface; + QOpenGLContext* oglContext; }; @@ -161,6 +170,8 @@ public: explicit MainWindow(QWidget* parent = nullptr); ~MainWindow(); + QOpenGLContext* getOGLContext(); + protected: void resizeEvent(QResizeEvent* event) override; -- cgit v1.2.3 From a38b20484d72d9d03ac7c807323343c8576c2c35 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 28 May 2020 23:12:21 +0200 Subject: finish the wifi dialog also guess who the idiot is who forgot to add their files --- src/frontend/qt_sdl/Platform.cpp | 22 +++-- src/frontend/qt_sdl/WifiSettingsDialog.cpp | 140 +++++++++++++++++++++++++++++ src/frontend/qt_sdl/WifiSettingsDialog.h | 68 ++++++++++++++ src/frontend/qt_sdl/main.cpp | 19 +++- src/frontend/qt_sdl/main.h | 1 + 5 files changed, 237 insertions(+), 13 deletions(-) create mode 100644 src/frontend/qt_sdl/WifiSettingsDialog.cpp create mode 100644 src/frontend/qt_sdl/WifiSettingsDialog.h (limited to 'src/frontend/qt_sdl/Platform.cpp') diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 6b256e0..edc8d45 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -22,8 +22,8 @@ #include #include "Platform.h" #include "PlatformConfig.h" -//#include "LAN_Socket.h" -//#include "LAN_PCap.h" +#include "LAN_Socket.h" +#include "LAN_PCap.h" #include #ifdef __WIN32__ @@ -559,7 +559,7 @@ int MP_RecvPacket(u8* data, bool block) bool LAN_Init() { - /*if (Config::DirectLAN) + if (Config::DirectLAN) { if (!LAN_PCap::Init(true)) return false; @@ -568,7 +568,7 @@ bool LAN_Init() { if (!LAN_Socket::Init()) return false; - }*/ + } return true; } @@ -580,26 +580,24 @@ void LAN_DeInit() // LAN_PCap::DeInit(); //else // LAN_Socket::DeInit(); - /*LAN_PCap::DeInit(); - LAN_Socket::DeInit();*/ + LAN_PCap::DeInit(); + LAN_Socket::DeInit(); } int LAN_SendPacket(u8* data, int len) { - /*if (Config::DirectLAN) + if (Config::DirectLAN) return LAN_PCap::SendPacket(data, len); else - return LAN_Socket::SendPacket(data, len);*/ - return 0; + return LAN_Socket::SendPacket(data, len); } int LAN_RecvPacket(u8* data) { - /*if (Config::DirectLAN) + if (Config::DirectLAN) return LAN_PCap::RecvPacket(data); else - return LAN_Socket::RecvPacket(data);*/ - return 0; + return LAN_Socket::RecvPacket(data); } diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.cpp b/src/frontend/qt_sdl/WifiSettingsDialog.cpp new file mode 100644 index 0000000..457a78d --- /dev/null +++ b/src/frontend/qt_sdl/WifiSettingsDialog.cpp @@ -0,0 +1,140 @@ +/* + 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 +#include + +#include "types.h" +#include "Platform.h" +#include "Config.h" +#include "PlatformConfig.h" + +#include "LAN_Socket.h" +#include "LAN_PCap.h" +#include "Wifi.h" + +#include "WifiSettingsDialog.h" +#include "ui_WifiSettingsDialog.h" + + +#ifdef __WIN32__ +#define PCAP_NAME "winpcap/npcap" +#else +#define PCAP_NAME "libpcap" +#endif + + +WifiSettingsDialog* WifiSettingsDialog::currentDlg = nullptr; + + +WifiSettingsDialog::WifiSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::WifiSettingsDialog) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); + + LAN_Socket::Init(); + haspcap = LAN_PCap::Init(false); + + ui->cbDirectMode->setText("Direct mode (requires " PCAP_NAME " and ethernet connection)"); + + ui->cbBindAnyAddr->setChecked(Config::SocketBindAnyAddr != 0); + + int sel = 0; + for (int i = 0; i < LAN_PCap::NumAdapters; i++) + { + LAN_PCap::AdapterData* adapter = &LAN_PCap::Adapters[i]; + + ui->cbxDirectAdapter->addItem(QString(adapter->FriendlyName)); + + if (!strncmp(adapter->DeviceName, Config::LANDevice, 128)) + sel = i; + } + ui->cbxDirectAdapter->setCurrentIndex(sel); + + ui->cbDirectMode->setChecked(Config::DirectLAN != 0); + if (!haspcap) ui->cbDirectMode->setEnabled(false); + + updateAdapterControls(); +} + +WifiSettingsDialog::~WifiSettingsDialog() +{ + delete ui; +} + +void WifiSettingsDialog::on_WifiSettingsDialog_accepted() +{ + Config::SocketBindAnyAddr = ui->cbBindAnyAddr->isChecked() ? 1:0; + Config::DirectLAN = ui->cbDirectMode->isChecked() ? 1:0; + + int sel = ui->cbxDirectAdapter->currentIndex(); + if (sel < 0 || sel >= LAN_PCap::NumAdapters) sel = 0; + if (LAN_PCap::NumAdapters < 1) + { + Config::LANDevice[0] = '\0'; + } + else + { + strncpy(Config::LANDevice, LAN_PCap::Adapters[sel].DeviceName, 127); + Config::LANDevice[127] = '\0'; + } + + Config::Save(); + + closeDlg(); +} + +void WifiSettingsDialog::on_WifiSettingsDialog_rejected() +{ + closeDlg(); +} + +void WifiSettingsDialog::on_cbDirectMode_stateChanged(int state) +{ + updateAdapterControls(); +} + +void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel) +{ + if (!haspcap) return; + + if (sel < 0 || sel >= LAN_PCap::NumAdapters) return; + if (LAN_PCap::NumAdapters < 1) return; + + LAN_PCap::AdapterData* adapter = &LAN_PCap::Adapters[sel]; + char tmp[64]; + + sprintf(tmp, "MAC: %02X:%02X:%02X:%02X:%02X:%02X", + adapter->MAC[0], adapter->MAC[1], adapter->MAC[2], + adapter->MAC[3], adapter->MAC[4], adapter->MAC[5]); + ui->lblAdapterMAC->setText(QString(tmp)); + + sprintf(tmp, "IP: %d.%d.%d.%d", + adapter->IP_v4[0], adapter->IP_v4[1], + adapter->IP_v4[2], adapter->IP_v4[3]); + ui->lblAdapterIP->setText(QString(tmp)); +} + +void WifiSettingsDialog::updateAdapterControls() +{ + bool enable = haspcap && ui->cbDirectMode->isChecked(); + + ui->cbxDirectAdapter->setEnabled(enable); + ui->lblAdapterMAC->setEnabled(enable); + ui->lblAdapterIP->setEnabled(enable); +} diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.h b/src/frontend/qt_sdl/WifiSettingsDialog.h new file mode 100644 index 0000000..f8aad1b --- /dev/null +++ b/src/frontend/qt_sdl/WifiSettingsDialog.h @@ -0,0 +1,68 @@ +/* + 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 WIFISETTINGSDIALOG_H +#define WIFISETTINGSDIALOG_H + +#include + +namespace Ui { class WifiSettingsDialog; } +class WifiSettingsDialog; + +class WifiSettingsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit WifiSettingsDialog(QWidget* parent); + ~WifiSettingsDialog(); + + static WifiSettingsDialog* currentDlg; + static WifiSettingsDialog* openDlg(QWidget* parent) + { + if (currentDlg) + { + currentDlg->activateWindow(); + return currentDlg; + } + + currentDlg = new WifiSettingsDialog(parent); + currentDlg->show(); + return currentDlg; + } + static void closeDlg() + { + currentDlg = nullptr; + } + +private slots: + void on_WifiSettingsDialog_accepted(); + void on_WifiSettingsDialog_rejected(); + + void on_cbDirectMode_stateChanged(int state); + void on_cbxDirectAdapter_currentIndexChanged(int sel); + +private: + Ui::WifiSettingsDialog* ui; + + bool haspcap; + + void updateAdapterControls(); +}; + +#endif // WIFISETTINGSDIALOG_H diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index e60a58d..5870d8a 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -1671,7 +1671,24 @@ void MainWindow::onAudioSettingsFinished(int res) void MainWindow::onOpenWifiSettings() { - WifiSettingsDialog::openDlg(this); + WifiSettingsDialog* dlg = WifiSettingsDialog::openDlg(this); + connect(dlg, &WifiSettingsDialog::finished, this, &MainWindow::onWifiSettingsFinished); +} + +void MainWindow::onWifiSettingsFinished(int res) +{ + emuThread->emuPause(); + + if (Wifi::MPInited) + { + Platform::MP_DeInit(); + Platform::MP_Init(); + } + + Platform::LAN_DeInit(); + Platform::LAN_Init(); + + emuThread->emuUnpause(); } void MainWindow::onChangeSavestateSRAMReloc(bool checked) diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index ef51158..279aed8 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -205,6 +205,7 @@ private slots: void onOpenAudioSettings(); void onAudioSettingsFinished(int res); void onOpenWifiSettings(); + void onWifiSettingsFinished(int res); void onChangeSavestateSRAMReloc(bool checked); void onChangeScreenSize(); void onChangeScreenRotation(QAction* act); -- cgit v1.2.3