diff --git a/CMakeLists.txt b/CMakeLists.txt index eab45515a0..6438155549 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,10 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON) +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + set(DAWN_USE_WAYLAND ON CACHE BOOL "Enable support for Wayland surface" FORCE) +endif () +set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE) add_subdirectory(extern/aurora EXCLUDE_FROM_ALL) option(DUSK_BUILD_WARNINGS "If off, compiler warnings will be suppressed") @@ -80,7 +84,7 @@ target_include_directories(game_debug PUBLIC extern ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include build/${DUSK_TP_VERSION}/include) -target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os) +target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) add_library(game SHARED ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${SSYSTEM_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} ${DOLPHIN_FILES}) diff --git a/README.md b/README.md index c94758e7eb..53a726fac7 100644 --- a/README.md +++ b/README.md @@ -62,4 +62,9 @@ cmake -B build/dusk -GNinja ninja -C build/dusk ``` -After building the executable, extract the original game files to a folder named `data` in the same folder as the executable. +#### Running +Pass the disc image as a positional argument. Supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, GCZ +```sh +build/dusk/dusk /path/to/game.rvz +``` +If no path is specified, Dusk defaults to `game.iso` in the current working directory. diff --git a/extern/aurora b/extern/aurora index 2b4bac1b9e..45ed0aa9d2 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 2b4bac1b9e193627e1266ac991b8e9ea941b841d +Subproject commit 45ed0aa9d29c4e87c8a4da67225c81370e366518 diff --git a/files.cmake b/files.cmake index 8ab894658e..d2f452738c 100644 --- a/files.cmake +++ b/files.cmake @@ -1335,7 +1335,6 @@ set(DUSK_FILES src/dusk/extras.cpp src/dusk/globals.cpp #src/dusk/m_Do_ext_dusk.cpp - src/dusk/dvd_emu.cpp src/dusk/imgui/imgui.hpp src/dusk/imgui/processes.cpp src/dusk/imgui/camera.cpp diff --git a/include/dusk/dvd_emu.h b/include/dusk/dvd_emu.h deleted file mode 100644 index 8366b2b37b..0000000000 --- a/include/dusk/dvd_emu.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef DOLPHIN_DVD_EMU_H -#define DOLPHIN_DVD_EMU_H - -#include "dolphin/types.h" -#include - -// PC-Emulation der DVD-Funktionen -namespace DvdEmu { - -// Basis-Pfad zum Datenordner (relativ zur .exe) -void setBasePath(const char* path); -const char* getBasePath(); - -// Konvertiert GameCube-Pfad zu PC-Pfad -// z.B. "/res/Object/LogoUs.arc" -> "C:/Games/Dusk/data/res/Object/LogoUs.arc" -std::string convertPath(const char* gcPath); - -// Prüft ob Datei existiert -bool fileExists(const char* gcPath); - -// Lädt Datei komplett in Speicher -// Gibt Pointer zurück, Größe wird in outSize geschrieben -// Caller muss Speicher mit free() freigeben -void* loadFile(const char* gcPath, u32* outSize, void* heap = nullptr); - -// Lädt Datei in vorhandenen Buffer -// Gibt gelesene Bytes zurück -u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offset = 0); - -// Datei-Größe abfragen -u32 getFileSize(const char* gcPath); - -} // namespace DvdEmu - -// Ersatz für DVDConvertPathToEntrynum -// Gibt einen "Fake" Entry-Number zurück (Hash des Pfads) oder -1 wenn nicht gefunden -s32 DVDConvertPathToEntrynum_Emu(const char* path); - -// Speichert Pfad für Entry-Number (für späteres Laden) -void DVDRegisterPath(s32 entryNum, const char* path); - -// Holt Pfad für Entry-Number -const char* DVDGetPathForEntry(s32 entryNum); - -#endif // DOLPHIN_DVD_EMU_H diff --git a/libs/JSystem/include/JSystem/JKernel/JKRHeap.h b/libs/JSystem/include/JSystem/JKernel/JKRHeap.h index 7eaff3f448..e8da75a0a7 100644 --- a/libs/JSystem/include/JSystem/JKernel/JKRHeap.h +++ b/libs/JSystem/include/JSystem/JKernel/JKRHeap.h @@ -240,7 +240,7 @@ inline void* operator new[](size_t, JKRHeapToken, void* where) { #define JKR_NEW new (JKRHeapToken::Dummy) #define JKR_NEW_ARGS(...) new (JKRHeapToken::Dummy, __VA_ARGS__ ) #define JKR_DELETE(expr) jkrDelete(expr) -#define JKR_DELETE_ARRAY(expr) delete[] (expr) +#define JKR_DELETE_ARRAY(expr) jkrDeleteArray(expr) #define JKR_HEAP_TOKEN , JKRHeapToken::Dummy #define JKR_HEAP_TOKEN_PARAM , JKRHeapToken #else @@ -261,7 +261,7 @@ void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, int alignment); void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment); void operator delete(void* ptr JKR_HEAP_TOKEN_PARAM); -void operator delete[](void* ptr); +void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM); #if TARGET_PC template @@ -281,6 +281,10 @@ inline void jkrDelete(void* ptr) { operator delete(ptr, JKRHeapToken::Dummy); } + +static void jkrDeleteArray(void* ptr) { + operator delete[](ptr, JKRHeapToken::Dummy); +} #endif void JKRDefaultMemoryErrorRoutine(void* heap, u32 size, int alignment); diff --git a/libs/JSystem/src/J2DGraph/J2DScreen.cpp b/libs/JSystem/src/J2DGraph/J2DScreen.cpp index a03b6a7f76..104bf95e33 100644 --- a/libs/JSystem/src/J2DGraph/J2DScreen.cpp +++ b/libs/JSystem/src/J2DGraph/J2DScreen.cpp @@ -38,7 +38,7 @@ void J2DScreen::clean() { mFontRes = NULL; if (mNameTable != NULL) { - JKR_DELETE_ARRAY(mNameTable->getResNameTable()); + JKR_DELETE_ARRAY(const_cast(mNameTable->getResNameTable())); JKR_DELETE(mNameTable); mNameTable = NULL; } diff --git a/libs/JSystem/src/JGadget/binary.cpp b/libs/JSystem/src/JGadget/binary.cpp index a249565981..62d4661360 100644 --- a/libs/JSystem/src/JGadget/binary.cpp +++ b/libs/JSystem/src/JGadget/binary.cpp @@ -3,7 +3,8 @@ #include "JSystem/JGadget/binary.h" #include "JSystem/JGadget/define.h" #include "global.h" -#include +#include +#include #include "global.h" diff --git a/libs/JSystem/src/JKernel/JKRHeap.cpp b/libs/JSystem/src/JKernel/JKRHeap.cpp index e5767d6ebb..17ab6aae19 100644 --- a/libs/JSystem/src/JKernel/JKRHeap.cpp +++ b/libs/JSystem/src/JKernel/JKRHeap.cpp @@ -593,14 +593,6 @@ void* operator new[](size_t size) { return JKRHeap::alloc(size, 4, NULL); } #else -void* operator new[](size_t size) { - return fallback_alloc(size, 0, false); -} - -void* operator new[](std::size_t size, const std::nothrow_t&) noexcept { - return fallback_alloc(size, 0, false); -} - void* operator new[](size_t size JKR_HEAP_TOKEN_PARAM) { void* mem = JKRHeap::alloc(size, alignof(max_align_t), NULL); if (mem == NULL) { @@ -654,7 +646,7 @@ void operator delete[](void* ptr) { JKRHeap::free(ptr, NULL); } #else -void operator delete[](void* ptr) { +void operator delete[](void* ptr JKR_HEAP_TOKEN_PARAM) { if (ptr == NULL) return; JKRHeap* heap = JKRHeap::findFromRoot(ptr); diff --git a/src/dusk/dvd_emu.cpp b/src/dusk/dvd_emu.cpp deleted file mode 100644 index 70ae9d3ddd..0000000000 --- a/src/dusk/dvd_emu.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include "dusk/dvd_emu.h" -#include -#include -#include -#include -#include "dolphin/os.h" -#include "dusk/logging.h" - -#ifdef _WIN32 -#include -#include -#define PATH_SEP '\\' -#else -#include -#include -#define PATH_SEP '/' -#endif - -namespace { -s32 g_nextEntryNum = 1; - -// Lazy-init to avoid crash during DLL static initialization -std::string& g_basePath() { - static std::string instance = "data"; - return instance; -} - -std::unordered_map& getEntryPaths() { - static std::unordered_map instance; - return instance; -} -} // namespace - -namespace DvdEmu { - -void setBasePath(const char* path) { -#ifdef _WIN32 - char exePath[MAX_PATH]; - GetModuleFileNameA(NULL, exePath, MAX_PATH); - - // Get the directory of the .exe - char* lastSlash = strrchr(exePath, '\\'); - if (lastSlash) { - *lastSlash = '\0'; - } - - // exeDir + "/" + path - g_basePath() = exePath; - g_basePath() += PATH_SEP; - g_basePath() += path; -#else - g_basePath() = path; -#endif - - DuskLog.debug("[DvdEmu] Base path set to: %s\n", g_basePath().c_str()); -} - -const char* getBasePath() { - return g_basePath().c_str(); -} - -std::string convertPath(const char* gcPath) { - std::string result = g_basePath(); - - // Skip leading slashes - const char* p = gcPath; - while (*p == '/' || *p == '\\') - p++; - - result += PATH_SEP; - - // Append path, converting slashes - while (*p) { - if (*p == '/' || *p == '\\') { - result += PATH_SEP; - } else { - result += *p; - } - p++; - } - - return result; -} - -bool fileExists(const char* gcPath) { - std::string fullPath = convertPath(gcPath); - -#ifdef _WIN32 - DWORD attrib = GetFileAttributesA(fullPath.c_str()); - bool exists = (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY)); -#else - struct stat st; - bool exists = (stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode)); -#endif - - if (exists) { - DuskLog.info("[DvdEmu] FOUND: {}", gcPath); - } else { - DuskLog.warn("[DvdEmu] MISSING: {}", gcPath); - } - - return exists; -} - -u32 getFileSize(const char* gcPath) { - std::string fullPath = convertPath(gcPath); - FILE* f = fopen(fullPath.c_str(), "rb"); - if (!f) - return 0; - - fseek(f, 0, SEEK_END); - u32 size = (u32)ftell(f); - fclose(f); - return size; -} - -void* loadFile(const char* gcPath, u32* outSize, void* heap) { - std::string fullPath = convertPath(gcPath); - - DuskLog.debug("[DvdEmu] Loading request: '{}'", gcPath); - - FILE* f = fopen(fullPath.c_str(), "rb"); - if (!f) { - DuskLog.error("[DvdEmu] Failed to open file at physical path: {}", fullPath.c_str()); - if (outSize) - *outSize = 0; - return nullptr; - } - - fseek(f, 0, SEEK_END); - u32 size = (u32)ftell(f); - fseek(f, 0, SEEK_SET); - - // Allocate with 32-byte alignment (matching GameCube) - void* data; -#ifdef _WIN32 - data = _aligned_malloc(size, 32); -#else - data = aligned_alloc(32, (size + 31) & ~31); -#endif - - if (!data) { - DuskLog.fatal("[DvdEmu] Failed to allocate {} bytes for {}", size, gcPath); - fclose(f); - if (outSize) - *outSize = 0; - return nullptr; - } - - u32 bytesRead = (u32)fread(data, 1, size, f); - fclose(f); - - if (bytesRead != size) { - DuskLog.fatal("[DvdEmu] Read error: expected {}, got {} for {}", size, bytesRead, - gcPath); - } - - if (outSize) - *outSize = bytesRead; - - DuskLog.info("[DvdEmu] Loaded {} ({} bytes)", gcPath, bytesRead); - return data; -} - -u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offset) { - std::string fullPath = convertPath(gcPath); - - FILE* f = fopen(fullPath.c_str(), "rb"); - if (!f) { - DuskLog.error("[DvdEmu] Failed to open file for buffer load: {}", fullPath.c_str()); - return 0; - } - - if (offset > 0) { - fseek(f, offset, SEEK_SET); - } - - u32 bytesRead = (u32)fread(buffer, 1, bufferSize, f); - fclose(f); - - return bytesRead; -} - -} // namespace DvdEmu - -// Entry-Number System (emulates DVD's entry system) - -s32 DVDConvertPathToEntrynum_Emu(const char* path) { - if (!DvdEmu::fileExists(path)) { - printf("[DVD] Error: File not found for entrynum conversion: %s\n", path); - return -1; - } - - // Check if already registered - for (const auto& pair : getEntryPaths()) { - if (pair.second == path) { - return pair.first; - } - } - - // Assign new entry number - s32 entryNum = g_nextEntryNum++; - getEntryPaths()[entryNum] = path; - - return entryNum; -} - -void DVDRegisterPath(s32 entryNum, const char* path) { - getEntryPaths()[entryNum] = path; -} - -const char* DVDGetPathForEntry(s32 entryNum) { - auto it = getEntryPaths().find(entryNum); - if (it != getEntryPaths().end()) { - return it->second.c_str(); - } - return nullptr; -} diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 55e22fbea3..5109eed144 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include @@ -1169,123 +1168,6 @@ void AIStopDMA(void) { STUB_LOG(); } -#pragma mark DVD -#include -s32 DVDCancel(volatile DVDCommandBlock* block) { - STUB_LOG(); - return 0; -} -s32 DVDCancel(DVDCommandBlock* block) { - STUB_LOG(); - return 0; -} -BOOL DVDChangeDir(const char* dirName) { - STUB_LOG(); - return TRUE; -} -BOOL DVDCheckDisk(void) { - STUB_LOG(); - return TRUE; -} -BOOL DVDClose(DVDFileInfo* fileInfo) { - STUB_LOG(); - return TRUE; -} -int DVDCloseDir(DVDDir* dir) { - STUB_LOG(); - return 0; -} -s32 DVDConvertPathToEntrynum(const char* pathPtr) { - return DVDConvertPathToEntrynum_Emu(pathPtr); -} -BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo) { - const char* path = DVDGetPathForEntry(entrynum); - if (!path) { - OSReport("[DVD] DVDFastOpen: no path for entry %d\n", entrynum); - return FALSE; - } - u32 fileSize = DvdEmu::getFileSize(path); - if (fileSize == 0) { - OSReport("[DVD] DVDFastOpen: file not found or empty for entry %d (%s)\n", entrynum, path); - return FALSE; - } - // Repurpose startAddr to store entrynum for later DVDReadPrio lookups - fileInfo->startAddr = (u32)entrynum; - fileInfo->length = fileSize; - fileInfo->callback = NULL; - fileInfo->cb.state = 0; - return TRUE; -} -s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block) { - STUB_LOG(); - return 0; -} -DVDDiskID* DVDGetCurrentDiskID(void) { - STUB_LOG(); - return NULL; -} -s32 DVDGetDriveStatus(void) { - STUB_LOG(); - return 0; -} -void DVDInit(void) { - STUB_LOG(); -} -BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) { - s32 entryNum = DVDConvertPathToEntrynum(fileName); - if (entryNum < 0) { - OSReport("[DVD] DVDOpen: file not found: %s\n", fileName); - return FALSE; - } - return DVDFastOpen(entryNum, fileInfo); -} -int DVDOpenDir(const char* dirName, DVDDir* dir) { - STUB_LOG(); - return 0; -} -BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, - DVDCallback callback, s32 prio) { - // Synchronous read, then invoke callback with result - s32 entryNum = (s32)fileInfo->startAddr; - const char* path = DVDGetPathForEntry(entryNum); - if (!path) { - OSReport("[DVD] DVDReadAsyncPrio: no path for entry %d\n", entryNum); - if (callback) callback(-1, fileInfo); - return FALSE; - } - u32 bytesRead = DvdEmu::loadFileToBuffer(path, addr, (u32)length, (u32)offset); - if (callback) { - callback((s32)bytesRead, fileInfo); - } - return TRUE; -} -int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent) { - STUB_LOG(); - return 0; -} -s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) { - s32 entryNum = (s32)fileInfo->startAddr; - const char* path = DVDGetPathForEntry(entryNum); - if (!path) { - OSReport("[DVD] DVDReadPrio: no path for entry %d\n", entryNum); - return -1; - } - u32 bytesRead = DvdEmu::loadFileToBuffer(path, addr, (u32)length, (u32)offset); - return (s32)bytesRead; -} - -void DVDReadAbsAsyncForBS(void* a, struct bb2struct* b, int c, int d, void (*e)()) { - STUB_LOG(); -} - -void DVDReadDiskID(void* a, DVDDiskID* b, void (*c)()) { - STUB_LOG(); -} - -void DVDReset() { - STUB_LOG(); -} - #pragma mark GX #include diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index f0c1ba115d..27be20aa2e 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -44,13 +44,14 @@ #include #include #include "SSystem/SComponent/c_API.h" -#include "dusk/dvd_emu.h" #include "dusk/dusk.h" #include "dusk/logging.h" #include #include #include +#include +#include #include "cxxopts.hpp" @@ -67,7 +68,7 @@ const int audioHeapSize = 0x14D800; #endif // ========================================================================= -// LOAD_COPYDATE - PC Version using DvdEmu +// LOAD_COPYDATE - PC Version // ========================================================================= #define COPYDATE_PATH "/str/Final/Release/COPYDATE" @@ -75,33 +76,26 @@ s32 LOAD_COPYDATE(void*) { char buffer[32]; memset(buffer, 0, sizeof(buffer)); - u32 size = 0; - void* data = DvdEmu::loadFile(COPYDATE_PATH, &size, nullptr); + DVDFileInfo fi; + if (DVDOpen(COPYDATE_PATH, &fi)) { + u32 readLen = (fi.length < sizeof(buffer) - 1) ? fi.length : sizeof(buffer) - 1; + // DVDReadPrio requires 32-byte aligned buffer and length rounded up to 32 + u32 alignedLen = (readLen + 31) & ~31; + alignas(32) char readBuf[64]; + DVDReadPrio(&fi, readBuf, alignedLen, 0, 2); + DVDClose(&fi); - // Fallback: Try root if not found - if (!data) { - data = DvdEmu::loadFile("/COPYDATE", &size, nullptr); - } - - if (data) { - u32 copyLen = (size < sizeof(buffer) - 1) ? size : sizeof(buffer) - 1; - memcpy(buffer, data, copyLen); - buffer[copyLen] = '\0'; - -#ifdef _WIN32 - _aligned_free(data); -#else - free(data); -#endif + memcpy(buffer, readBuf, readLen); + buffer[readLen] = '\0'; } else { strcpy(buffer, "PC PORT BUILD"); - OSReport("Warning: COPYDATE file not found at %s\n", COPYDATE_PATH); + DuskLog.warn("COPYDATE file not found at {}", COPYDATE_PATH); } memcpy(mDoMain::COPYDATE_STRING, buffer, sizeof(mDoMain::COPYDATE_STRING) - 1); mDoMain::COPYDATE_STRING[sizeof(mDoMain::COPYDATE_STRING) - 1] = '\0'; - OS_REPORT("\x1b[36mCOPYDATE=[%s]\n\x1b[m", mDoMain::COPYDATE_STRING); + DuskLog.info("COPYDATE=[{}]", mDoMain::COPYDATE_STRING); return 1; } @@ -203,8 +197,11 @@ int game_main(int argc, char* argv[]) { arg_options.add_options() ("l,log-level", "Log level from " + std::to_string(AuroraLogLevel::LOG_DEBUG) + " to " + std::to_string(AuroraLogLevel::LOG_FATAL), cxxopts::value()->default_value("0")) - ("h,help", "Print usage"); + ("h,help", "Print usage") + ("dvd", "Path to DVD image file", cxxopts::value()->default_value("game.iso")); + arg_options.parse_positional({"dvd"}); + arg_options.positional_help(""); arg_options.allow_unrecognised_options(); parsed_arg_options = arg_options.parse(argc, argv); @@ -234,10 +231,13 @@ int game_main(int argc, char* argv[]) { auroraInfo = aurora_initialize(argc, argv, &config); - OSInit(); + const auto& dvd_path = parsed_arg_options["dvd"].as(); + DuskLog.info("Loading DVD image: {}", dvd_path); + if (!aurora_dvd_open(dvd_path.c_str())) { + DuskLog.fatal("Failed to open DVD image: {}", dvd_path); + } - // 3. Init DVD Emulation - DvdEmu::setBasePath("data"); + OSInit(); mDoMain::sPowerOnTime = OSGetTime();