From 4e54904e6bdcdc61e39cfd7ace0897baaf0f0a1f Mon Sep 17 00:00:00 2001 From: bluisblu <53455507+bluisblu@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:41:36 -0400 Subject: [PATCH 1/4] Add offset comments to some rw structs --- include/rwsdk/rwplcore.h | 74 ++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/include/rwsdk/rwplcore.h b/include/rwsdk/rwplcore.h index bfa8af8b9..495b4dc3c 100644 --- a/include/rwsdk/rwplcore.h +++ b/include/rwsdk/rwplcore.h @@ -500,13 +500,13 @@ struct RwMemoryFunctions struct RwFreeList { - RwUInt32 entrySize; - RwUInt32 entriesPerBlock; - RwUInt32 heapSize; - RwUInt32 alignment; - RwLinkList blockList; - RwUInt32 flags; - RwLLLink link; + RwUInt32 entrySize; // 0x0 + RwUInt32 entriesPerBlock; // 0x4 + RwUInt32 heapSize; // 0x8 + RwUInt32 alignment; // 0xC + RwLinkList blockList; // 0x10 + RwUInt32 flags; // 0x18 + RwLLLink link; // 0x1C }; typedef void (*RwFreeListCallBack)(void* pMem, void* pData); @@ -1131,20 +1131,20 @@ typedef RwBool (*RwIm3DRenderIndexedPrimitiveFunction)(RwPrimitiveType primtype, struct RwDevice { - RwReal gammaCorrection; - RwSystemFunc fpSystem; - RwReal zBufferNear; - RwReal zBufferFar; - RwRenderStateSetFunction fpRenderStateSet; - RwRenderStateGetFunction fpRenderStateGet; - RwIm2DRenderLineFunction fpIm2DRenderLine; - RwIm2DRenderTriangleFunction fpIm2DRenderTriangle; - RwIm2DRenderPrimitiveFunction fpIm2DRenderPrimitive; - RwIm2DRenderIndexedPrimitiveFunction fpIm2DRenderIndexedPrimitive; - RwIm3DRenderLineFunction fpIm3DRenderLine; - RwIm3DRenderTriangleFunction fpIm3DRenderTriangle; - RwIm3DRenderPrimitiveFunction fpIm3DRenderPrimitive; - RwIm3DRenderIndexedPrimitiveFunction fpIm3DRenderIndexedPrimitive; + RwReal gammaCorrection; // 0x0 + RwSystemFunc fpSystem; // 0x4 + RwReal zBufferNear; // 0x8 + RwReal zBufferFar; // 0xC + RwRenderStateSetFunction fpRenderStateSet; // 0x10 + RwRenderStateGetFunction fpRenderStateGet; // 0x14 + RwIm2DRenderLineFunction fpIm2DRenderLine; // 0x18 + RwIm2DRenderTriangleFunction fpIm2DRenderTriangle; // 0x1C + RwIm2DRenderPrimitiveFunction fpIm2DRenderPrimitive; // 0x20 + RwIm2DRenderIndexedPrimitiveFunction fpIm2DRenderIndexedPrimitive; // 0x24 + RwIm3DRenderLineFunction fpIm3DRenderLine; // 0x28 + RwIm3DRenderTriangleFunction fpIm3DRenderTriangle; // 0x2C + RwIm3DRenderPrimitiveFunction fpIm3DRenderPrimitive; // 0x30 + RwIm3DRenderIndexedPrimitiveFunction fpIm3DRenderIndexedPrimitive; // 0x34 }; struct RwMetrics @@ -1202,22 +1202,22 @@ enum RwEngineStatus struct RwGlobals { - void* curCamera; - void* curWorld; - RwUInt16 renderFrame; - RwUInt16 lightFrame; - RwUInt16 pad[2]; - RwDevice dOpenDevice; - RwStandardFunc stdFunc[29]; - RwLinkList dirtyFrameList; - RwFileFunctions fileFuncs; - RwStringFunctions stringFuncs; - RwMemoryFunctions memoryFuncs; - RwMemoryAllocFn memoryAlloc; - RwMemoryFreeFn memoryFree; - RwMetrics* metrics; - RwEngineStatus engineStatus; - RwUInt32 resArenaInitSize; + void* curCamera; // 0x0 + void* curWorld; // 0x4 + RwUInt16 renderFrame; // 0x8 + RwUInt16 lightFrame; // 0xA + RwUInt16 pad[2]; // 0xC + RwDevice dOpenDevice; // 0x10 + RwStandardFunc stdFunc[29]; // 0x48 + RwLinkList dirtyFrameList; // 0xBC + RwFileFunctions fileFuncs; // 0xC4 + RwStringFunctions stringFuncs; // 0xF0 + RwMemoryFunctions memoryFuncs; // 0x134 + RwMemoryAllocFn memoryAlloc; // 0x144 + RwMemoryFreeFn memoryFree; // 0x148 + RwMetrics* metrics; // 0x14C + RwEngineStatus engineStatus; // 0x150 + RwUInt32 resArenaInitSize; // 0x154 }; typedef struct RwResEntry; From a7522e690122df4ee17f48d2c94b7def22b2f4e0 Mon Sep 17 00:00:00 2001 From: bluisblu <53455507+bluisblu@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:28:34 -0400 Subject: [PATCH 2/4] iSystem 99% --- configure.py | 2 +- src/SB/Core/gc/iSystem.cpp | 645 +++++++++++++++++++++++++++++++++---- src/SB/Core/gc/iSystem.h | 19 ++ src/SB/Core/gc/iTime.h | 4 +- 4 files changed, 605 insertions(+), 65 deletions(-) diff --git a/configure.py b/configure.py index 86acf5752..50824ddae 100644 --- a/configure.py +++ b/configure.py @@ -543,7 +543,7 @@ def MatchingFor(*versions): Object(NonMatching, "SB/Core/gc/isavegame.cpp"), Object(NonMatching, "SB/Core/gc/iScrFX.cpp"), Object(NonMatching, "SB/Core/gc/iSnd.cpp"), - Object(NonMatching, "SB/Core/gc/iSystem.cpp"), + Object(NonMatching, "SB/Core/gc/iSystem.cpp", extra_cflags=["-sym on"]), Object(Matching, "SB/Core/gc/iTime.cpp"), Object(NonMatching, "SB/Core/gc/ngcrad3d.c"), Object(Matching, "SB/Game/zNPCGoals.cpp"), diff --git a/src/SB/Core/gc/iSystem.cpp b/src/SB/Core/gc/iSystem.cpp index b8ef79e05..c5692fcf9 100644 --- a/src/SB/Core/gc/iSystem.cpp +++ b/src/SB/Core/gc/iSystem.cpp @@ -1,42 +1,29 @@ #include "iSystem.h" -#include "dolphin/dvd/dvd.h" -#include "dolphin/gx/GXFrameBuffer.h" -#include "dolphin/gx/GXManage.h" -#include "dolphin/gx/GXStruct.h" -#include "dolphin/hio.h" -#include "dolphin/os/OSError.h" -#include "dolphin/vi.h" -#include "rpcollis.h" -#include "rphanim.h" +#include + +#include + #include "rpmatfx.h" #include "rpptank.h" #include "rpskin.h" #include "rpusrdat.h" -#include "rpworld.h" -#include "rwplcore.h" -#include "xBase.h" -#include "xFX.h" -#include "xShadow.h" -#include "xstransvc.h" -#include -#include - -#include #include "xDebug.h" -#include "xMath.h" #include "xSnd.h" -#include "xPad.h" -#include "xMemMgr.h" +#include "xFX.h" +#include "xShadow.h" +#include "xstransvc.h" #include "iMemMgr.h" #include "iSystem.h" -#include "iFile.h" #include "iFMV.h" -#include "iTime.h" #include "iTRC.h" +// .bss +static RwMemoryFunctions MemoryFunctions; + +// .comm struct { GXRenderModeObj* renderMode; @@ -45,16 +32,23 @@ struct } deviceConfig; RwVideoMode sVideoMode; +// .sbss GXDrawSyncCallback old_dsc; U16 last_error; OSContext* last_context; -U32 size; U32 add; +U32 size; S32 gEmergencyMemLevel; + +// .sdata void* bad_val = (void*)0x81abcaa0; U32 test_alloc_val = 0x210A; +static S32 rwID_DOLPHINDEVICEMODULE = 0x430; -static RwMemoryFunctions MemoryFunctions; +static RwTexture* TextureRead(const RwChar* name, const RwChar* maskName); +static void* _rwDolphinFSOpen(void*, int, int); +static void* _rwDolphinFSClose(void*, int, int); +static S32 DolphinInstallFileSystem(); static const char* __deadstripped() { @@ -217,38 +211,35 @@ static U32 RWAttachPlugins() { if (!RpWorldPluginAttach()) { - return true; + return TRUE; } if (!RpCollisionPluginAttach()) { - return true; + return TRUE; } if (!RpSkinPluginAttach()) { - return true; + return TRUE; } if (!RpHAnimPluginAttach()) { - return true; + return TRUE; } if (!RpMatFXPluginAttach()) { - return true; + return TRUE; } if (!RpUserDataPluginAttach()) { - return true; + return TRUE; } if (!RpPTankPluginAttach()) { - return true; + return TRUE; } - return false; + return FALSE; } -static S32 DolphinInstallFileSystem(); -static RwTexture* TextureRead(const RwChar* name, const RwChar* maskName); - static S32 RenderWareInit() { RwMemoryFunctions* memoryFns = psGetMemoryFunctions(); @@ -280,7 +271,7 @@ static S32 RenderWareInit() return TRUE; } RwTextureSetReadCallBack(TextureRead); - RwRenderStateSet((RwRenderState)0x14, (void*)0x2); // RwRenderState 0x14 isn't defined?? + RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLBACK); xShadowInit(); xFXInit(); RwTextureSetMipmapping(TRUE); @@ -314,7 +305,7 @@ static RwTexture* TextureRead(const RwChar* name, const RwChar* maskName) if (asset->raster != NULL && asset->raster->depth < 8) { RwGameCubeRasterExt* ext = - (RwGameCubeRasterExt*)((U32)asset->raster + _RwGameCubeRasterExtOffset); + RWPLUGINOFFSET(RwGameCubeRasterExt, asset->raster, _RwGameCubeRasterExtOffset); if (ext == NULL || ext->unk_c != 14) { asset = NULL; @@ -336,7 +327,7 @@ void null_func() } extern "C" { -void mem_null(U32 param_1, U32 param_2) +static void mem_null(U32 param_1, U32 param_2) { add = param_1; size = param_2; @@ -368,7 +359,7 @@ void free(void* __ptr) } } -void _rwDolphinHeapFree(void* __ptr) +static void _rwDolphinHeapFree(void* __ptr) { if (__ptr == bad_val) { @@ -392,7 +383,8 @@ void _rwDolphinHeapFree(void* __ptr) } } -void* _rwDolphinHeapAlloc(u32 size) +// non-matching: sda scheduling +static void* _rwDolphinHeapAlloc(u32 size) { static u32 alloc_num = 0; U32 alloc = (U32)malloc(size + 0x20); @@ -425,6 +417,473 @@ void* _rwDolphinHeapAlloc(u32 size) return (void*)alloc; } +static void* _rwDolphinHeapCalloc(u32 p1, u32 p2) +{ + void* __s = _rwDolphinHeapAlloc(p1 * p2); + if (__s != NULL) + { + memset(__s, 0, p1 * p2); + } + return __s; +} + +static void* _rwDolphinHeapRealloc(void* p1, u32 p2) +{ + u32 __n; + void* __dest; + + if (p1 != NULL) + __n = *(u32*)((u8*)p1 - 0x20); + else + __n = 0; + + if (p2 < __n) + return p1; + + __dest = _rwDolphinHeapAlloc(p2); + if (__dest != NULL) + { + if (__n < p2) + memcpy(__dest, p1, __n); + else + memcpy(__dest, p1, p2); + _rwDolphinHeapFree(p1); + } + return __dest; +} + +S32 DolphinInitMemorySystem(RwMemoryFunctions* memoryFuncs) +{ + memoryFuncs->rwmalloc = _rwDolphinHeapAlloc; + memoryFuncs->rwcalloc = _rwDolphinHeapCalloc; + memoryFuncs->rwrealloc = _rwDolphinHeapRealloc; + memoryFuncs->rwfree = _rwDolphinHeapFree; + + return 1; +} + +static S32 dlAccessToMode(const char* mode) +{ + char c; + S32 ret = 0; + + if (mode == 0) + { + return 0; + } + + c = mode[0]; + + if (c == 'r' && (mode[1] == '\0' || (mode[1] == 'b' && mode[2] == '\0'))) + { + ret = 1; + } + else if (c == 'w' && (mode[1] == '\0' || (mode[1] == 'b' && mode[2] == '\0'))) + { + ret = 0xe; + } + else if (c == 'a' && (mode[1] == '\0' || (mode[1] == 'b' && mode[2] == '\0'))) + { + ret = 6; + } + else if (c == 'r' && mode[1] == '+' && (mode[2] == '\0' || (mode[2] == 'b' && mode[3] == '\0'))) + { + ret = 3; + } + else if (c == 'w' && mode[1] == '+' && (mode[2] == '\0' || (mode[2] == 'b' && mode[3] == '\0'))) + { + ret = 0xf; + } + else if (c == 'a' && mode[1] == '+' && (mode[2] == '\0' || (mode[2] == 'b' && mode[3] == '\0'))) + { + ret = 7; + } + + return ret; +} + +// both need to be after alloc_num from _rwDolphinHeapAlloc +static S32 FSOpenFiles; +struct RwModuleInfo +{ + s32 globalsOffset; + s32 numInstances; +}; +static RwModuleInfo FSModuleInfo; // Type only exists in PS2 dwarf, symbol only exists on GC + +void* dlFopen(const char* name, const char* access) +{ + U32 mode = dlAccessToMode(access); + if (mode == 0) + { + return NULL; + } + + dlFile* fp = (dlFile*)RwEngineInstance->memoryAlloc( + RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset)->unk_2C); + if (fp == NULL) + { + return NULL; + } + + fp->accessMode = 0; + if (mode == 1) + { + fp->accessMode = 1; + } + + if (fp->accessMode == 0) + { + RwEngineInstance->memoryFree( + RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset)->unk_2C, + fp); + return NULL; + } + + if (DVDOpen(name, &fp->fileInfo) == 0) + { + RwEngineInstance->memoryFree( + RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset)->unk_2C, + fp); + return NULL; + } + + fp->SOF = fp->fileInfo.length; + fp->POS = 0; + fp->bufferPos = DLFILE_BUF_SIZE; + FSOpenFiles++; + return fp; +} + +static S32 dlFclose(void* fptr) +{ + dlFile* fp = (dlFile*)fptr; + + if (fp != NULL && FSOpenFiles != 0 && DVDClose(&fp->fileInfo) != 0) + { + RwEngineInstance->memoryFree( + RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset)->unk_2C, + fp); + + FSOpenFiles--; + return 0; + } + return -1; +} + +static RwBool dlFexist(const char* name) +{ + void* fp; + + fp = ((void* (*)(const char*, const char*))((void**)RwOsGetFileInterface())[1])(name, "r"); + + if (fp != 0) + { + ((void (*)(void*))((void**)RwOsGetFileInterface())[2])(fp); + return true; + } + + return false; +} + +// non-matching: r25/r26/r27 register issue +static size_t dlFread(void* addr, size_t size, size_t count, void* fptr) +{ + S32 pos2; + S32 posTmp; + S32 bytesRead = 0; + S32 readSize; + U32 buffered; + U32 uVar1; + dlFile* fp = (dlFile*)fptr; + U32 numBytesToRead = size * count; + + if ((U32)(fp->POS + numBytesToRead) > fp->SOF) + { + numBytesToRead = fp->SOF - fp->POS; + } + if (fp->bufferPos < DLFILE_BUF_SIZE) + { + if (numBytesToRead > bytesRead) + { + buffered = DLFILE_BUF_SIZE - fp->bufferPos; + if (numBytesToRead < buffered) + { + buffered = numBytesToRead; + } + bytesRead = buffered; + memcpy(addr, fp->readBuffer + fp->bufferPos, buffered); + addr = (char*)addr + buffered; + fp->bufferPos += buffered; + fp->POS += buffered; + } + } + uVar1 = numBytesToRead - bytesRead; + if (uVar1 != 0) + { + if (uVar1 >= DLFILE_BUF_SIZE) + { + if (!((U32)addr & 0x1f) && !(uVar1 & 0x1f)) + { + uVar1 = DVDReadPrio(&fp->fileInfo, addr, uVar1, fp->POS, 2); + if ((S32)uVar1 < 0) + { + uVar1 = 0; + } + } + else + { + numBytesToRead -= bytesRead; + uVar1 = 0; + posTmp = fp->POS; + S32 loopCount = (S32)numBytesToRead / DLFILE_BUF_SIZE + 1; + while (loopCount-- != 0) + { + pos2 = fp->POS; + readSize = DLFILE_BUF_SIZE; + pos2 += uVar1; + if ((S32)(fp->SOF - pos2) <= DLFILE_BUF_SIZE) + { + readSize = (fp->SOF - pos2); + } + if (DVDReadPrio(&fp->fileInfo, fp->readBuffer, ((U32)readSize + 0x1f) & ~0x1f, + posTmp, 2) == -1) + { + return bytesRead + uVar1; + } + if ((S32)numBytesToRead >= readSize) + { + memcpy(addr, fp->readBuffer, readSize); + numBytesToRead -= readSize; + uVar1 += readSize; + posTmp += readSize; + addr = (char*)addr + readSize; + } + else + { + memcpy(addr, fp->readBuffer, numBytesToRead); + fp->bufferPos = numBytesToRead; + uVar1 += numBytesToRead; + posTmp += numBytesToRead; + } + } + } + } + else + { + buffered = ((U32)(fp->SOF - fp->POS) + 0x1f) & ~0x1f; + if ((S32)buffered > DLFILE_BUF_SIZE) + { + buffered = DLFILE_BUF_SIZE; + } + if (DVDReadPrio(&fp->fileInfo, fp->readBuffer, buffered, fp->POS, 2) == -1) + { + return bytesRead; + } + memcpy(addr, fp->readBuffer, uVar1); + fp->bufferPos = uVar1; + } + bytesRead += uVar1; + fp->POS += uVar1; + } + return bytesRead / size; +} + +static size_t dlFwrite(const void* addr, size_t size, size_t count, void* fptr) +{ + return 0; +} + +static S32 dlFseek(void* fptr, long offset, int origin) +{ + S32 oldFPos = ((dlFile*)fptr)->POS; + dlFile* fp = (dlFile*)fptr; + S32 bufStart; + + switch (origin) + { + case 1: + { + fp->POS = oldFPos + offset; + if ((S32)(fp->bufferPos + offset) >= 0 && (fp->bufferPos + offset) <= DLFILE_BUF_SIZE && + fp->POS <= fp->SOF) + { + fp->bufferPos += offset; + return 0; + } + break; + } + case 2: + { + S32 delta = (fp->POS = fp->SOF + offset) - oldFPos; + if ((S32)(fp->bufferPos + delta) >= 0 && (fp->bufferPos + delta) <= DLFILE_BUF_SIZE && + fp->POS <= fp->SOF) + { + fp->bufferPos += delta; + return 0; + } + break; + } + case 0: + { + fp->POS = offset; + S32 delta = offset - oldFPos; + if ((S32)(fp->bufferPos + delta) >= 0 && (fp->bufferPos + delta) <= DLFILE_BUF_SIZE && + fp->POS <= fp->SOF) + { + fp->bufferPos += delta; + return 0; + } + break; + } + default: + { + return -1; + } + } + + if (fp->POS > fp->SOF) + { + fp->POS = oldFPos; + return -1; + } + + bufStart = (fp->POS / (U32)DLFILE_BUF_SIZE) * DLFILE_BUF_SIZE; + + if (DVDReadPrio(&fp->fileInfo, fp->readBuffer, + (fp->SOF - bufStart <= DLFILE_BUF_SIZE) ? (fp->SOF - bufStart + 31) & ~31 : + DLFILE_BUF_SIZE, + bufStart, 2) == -1) + { + fp->POS = oldFPos; + return -1; + } + + fp->bufferPos = fp->POS - bufStart; + return 0; +} + +// non-matching: mr, subi, and li scheduling at the start +static char* dlFgets(char* buffer, S32 maxLen, void* fptr) +{ + dlFile* fp = (dlFile*)fptr; + S32 i; + S32 numBytesRead; + i = 0; + numBytesRead = dlFread(buffer, 1, maxLen - 1, fp); + if (numBytesRead == 0) + return NULL; + while (i < numBytesRead) + { + if (buffer[i] == '\n') + { + i++; + buffer[i] = '\0'; + i -= numBytesRead; + dlFseek(fp, i, 1); + return buffer; + } + if (buffer[i] == '\r') + { + if ((i < numBytesRead - 1) && (buffer[i + 1] == '\n')) + { + memcpy(&buffer[i], &buffer[i + 1], (numBytesRead - i) - 1); + numBytesRead--; + } + else + { + i++; + } + } + else + { + i++; + } + } + if ((numBytesRead < maxLen) && (fp->POS == fp->SOF)) + { + buffer[numBytesRead] = '\0'; + } + return buffer; +} + +static S32 dlFputs(const char* buffer, void* fptr) +{ + return -1; +} + +static S32 dlFeof(void* fptr) +{ + dlFile* fp = (dlFile*)fptr; + return fp->POS >= fp->SOF; +} + +static S32 dlFflush(void*) +{ + return 0; +} + +static S32 dlFtell(void* fptr) +{ + dlFile* fp = (dlFile*)fptr; + return fp->POS; +} + +static void* _rwDolphinFSOpen(void* param_1, int param_2, int param_3) +{ + FSModuleInfo.globalsOffset = param_2; + + RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset)->unk_2C = + RwFreeListCreate(sizeof(dlFile), 5, 0x20); + + if (RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset)->unk_2C == + NULL) + { + return NULL; + } + + RwFileFunctions* funcs = RwOsGetFileInterface(); + RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset)->fileFuncs = + *funcs; + + funcs->rwfexist = dlFexist; + funcs->rwfopen = dlFopen; + funcs->rwfclose = dlFclose; + funcs->rwfread = dlFread; + funcs->rwfwrite = dlFwrite; + funcs->rwfgets = dlFgets; + funcs->rwfputs = dlFputs; + funcs->rwfeof = dlFeof; + funcs->rwfseek = dlFseek; + funcs->rwfflush = dlFflush; + funcs->rwftell = dlFtell; + + FSModuleInfo.numInstances++; + + return param_1; +} + +static void* _rwDolphinFSClose(void* param_1, int param_2, int param_3) +{ + RwFileFunctions* osFileInterface = RwOsGetFileInterface(); + *osFileInterface = + (RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset))->fileFuncs; + RwFreeListDestroy( + (RWPLUGINOFFSET(dlFSUnkGlobals, RwEngineInstance, FSModuleInfo.globalsOffset))->unk_2C); + + FSModuleInfo.numInstances--; + + return param_1; +} + +static S32 DolphinInstallFileSystem() +{ + DVDInit(); + RwUInt32 plugin = + RwEngineRegisterPlugin(0x30, rwID_DOLPHINDEVICEMODULE, _rwDolphinFSOpen, _rwDolphinFSClose); + return plugin >> 0x1f ^ 1; +} + S32 iGetMinute() { OSTime ticks = OSGetTime(); @@ -457,36 +916,98 @@ S32 iGetMonth() return td.mon + 1; } -// Template for future use. TODO -char* iGetCurrFormattedDate(char* input) +char* months[] = { "January ", "February ", "March ", "April ", "May ", "June ", + "July ", "August ", "September ", "October ", "November ", "December " }; + +char* dotw[] = { + "Sunday ", "Monday ", "Tuesday ", "Wednesday ", "Thursday ", "Friday ", "Saturday " +}; + +U32 iGetCurrFormattedDate(char* str) { - return NULL; + char* start = str; + OSTime ticks = OSGetTime(); + OSCalendarTime td; + + OSTicksToCalendarTime(ticks, &td); + + strcpy(str, dotw[td.wday]); + strcat(str, months[td.mon]); + str += strlen(str); + + if (td.mday >= 10) + { + str[0] = (td.mday / 10) + '0'; + str++; + } + + str[0] = (td.mday % 10) + '0'; + str[1] = ','; + str[2] = ' '; + str[3] = (td.year / 1000) + '0'; + str[4] = ((td.year / 100) % 10) + '0'; + str[5] = ((td.year / 10) % 100) + '0'; + str[6] = (td.year % 10) + '0'; + str += 7; + *str++ = '\0'; + + return str - start; } -// WIP. -char* iGetCurrFormattedTime(char* input) +U32 iGetCurrFormattedTime(char* str) { + char* start = str; + S32 am = 0; + OSTime ticks = OSGetTime(); OSCalendarTime td; OSTicksToCalendarTime(ticks, &td); - bool pm = false; - // STUFF. - char* ret = input; - // STUFF. - if (pm) + + if (td.hour < 12) { - ret[8] = 'P'; - ret[9] = '.'; - ret[10] = 'M'; - ret[11] = '.'; + am = 1; } else { - ret[8] = 'A'; - ret[9] = '.'; - ret[10] = 'M'; - ret[11] = '.'; + td.hour -= 12; + } + + if (td.hour == 0) + td.hour = 12; + + if (td.hour >= 10) + { + str[0] = (td.hour / 10) + '0'; + str++; } - ret[12] = '\0'; - return ret + (0xd - (S32)input); + + str[0] = (td.hour % 10) + '0'; + str[1] = ':'; + str[2] = (td.min / 10) + '0'; + str[3] = (td.min % 10) + '0'; + str[4] = ':'; + str[5] = (td.sec / 10) + '0'; + str[6] = (td.sec % 10) + '0'; + str[7] = ' '; + + if (am) + { + str[8] = 'A'; + str[9] = '.'; + str[10] = 'M'; + str[11] = '.'; + str += 12; + } + else + { + str[8] = 'P'; + str[9] = '.'; + str[10] = 'M'; + str[11] = '.'; + str += 12; + } + + *str++ = '\0'; + + return str - start; } diff --git a/src/SB/Core/gc/iSystem.h b/src/SB/Core/gc/iSystem.h index 881f99963..14a5a1b1f 100644 --- a/src/SB/Core/gc/iSystem.h +++ b/src/SB/Core/gc/iSystem.h @@ -1,6 +1,7 @@ #ifndef ISYSTEM_H #define ISYSTEM_H +#include "rwplcore.h" #include #include @@ -9,6 +10,24 @@ void* malloc(U32 __size); void free(void* __ptr); } +#define DLFILE_BUF_SIZE 0x2800 + +struct dlFile // fabricated based on skyFile dwarf +{ + U8 readBuffer[DLFILE_BUF_SIZE]; // 0x00 + DVDFileInfo fileInfo; // 0x2800 + S32 POS; // 0x283C + U32 SOF; // 0x2840 + U32 bufferPos; // 0x2844 + S32 accessMode; // 0x2848 +}; + +struct dlFSUnkGlobals // entirely fabricated +{ + RwFileFunctions fileFuncs; // 0x00 + RwFreeList* unk_2C; // 0x2C +}; + void iVSync(); #define GET_MAKER_CODE() (*((U32*)0x80000004)) diff --git a/src/SB/Core/gc/iTime.h b/src/SB/Core/gc/iTime.h index e73b7483f..d2e03a4bf 100644 --- a/src/SB/Core/gc/iTime.h +++ b/src/SB/Core/gc/iTime.h @@ -22,8 +22,8 @@ S32 iGetMinute(); S32 iGetHour(); S32 iGetDay(); S32 iGetMonth(); -char* iGetCurrFormattedDate(char* input); -char* iGetCurrFormattedTime(char* input); +U32 iGetCurrFormattedDate(char* input); +U32 iGetCurrFormattedTime(char* input); void iTimeInit(); void iTimeExit(); iTime iTimeGet(); From c8fdb8a6225e9671e47895b311303dd097a44d4f Mon Sep 17 00:00:00 2001 From: bluisblu <53455507+bluisblu@users.noreply.github.com> Date: Thu, 2 Jul 2026 12:50:38 -0400 Subject: [PATCH 3/4] Less hardcoded date/time getters (thanks Cuyler) --- src/SB/Core/gc/iSystem.cpp | 59 +++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/SB/Core/gc/iSystem.cpp b/src/SB/Core/gc/iSystem.cpp index c5692fcf9..2c737a9fa 100644 --- a/src/SB/Core/gc/iSystem.cpp +++ b/src/SB/Core/gc/iSystem.cpp @@ -937,18 +937,16 @@ U32 iGetCurrFormattedDate(char* str) if (td.mday >= 10) { - str[0] = (td.mday / 10) + '0'; - str++; - } - - str[0] = (td.mday % 10) + '0'; - str[1] = ','; - str[2] = ' '; - str[3] = (td.year / 1000) + '0'; - str[4] = ((td.year / 100) % 10) + '0'; - str[5] = ((td.year / 10) % 100) + '0'; - str[6] = (td.year % 10) + '0'; - str += 7; + *str++ = (td.mday / 10) + '0'; + } + + *str++ = (td.mday % 10) + '0'; + *str++ = ','; + *str++ = ' '; + *str++ = (td.year / 1000) + '0'; + *str++ = ((td.year / 100) % 10) + '0'; + *str++ = ((td.year / 10) % 100) + '0'; + *str++ = (td.year % 10) + '0'; *str++ = '\0'; return str - start; @@ -977,34 +975,31 @@ U32 iGetCurrFormattedTime(char* str) if (td.hour >= 10) { - str[0] = (td.hour / 10) + '0'; - str++; + *str++ = (td.hour / 10) + '0'; } - str[0] = (td.hour % 10) + '0'; - str[1] = ':'; - str[2] = (td.min / 10) + '0'; - str[3] = (td.min % 10) + '0'; - str[4] = ':'; - str[5] = (td.sec / 10) + '0'; - str[6] = (td.sec % 10) + '0'; - str[7] = ' '; + *str++ = (td.hour % 10) + '0'; + *str++ = ':'; + *str++ = (td.min / 10) + '0'; + *str++ = (td.min % 10) + '0'; + *str++ = ':'; + *str++ = (td.sec / 10) + '0'; + *str++ = (td.sec % 10) + '0'; + *str++ = ' '; if (am) { - str[8] = 'A'; - str[9] = '.'; - str[10] = 'M'; - str[11] = '.'; - str += 12; + *str++ = 'A'; + *str++ = '.'; + *str++ = 'M'; + *str++ = '.'; } else { - str[8] = 'P'; - str[9] = '.'; - str[10] = 'M'; - str[11] = '.'; - str += 12; + *str++ = 'P'; + *str++ = '.'; + *str++ = 'M'; + *str++ = '.'; } *str++ = '\0'; From fabd4abc59c5afe74fe322bb26e636f4494b4fd0 Mon Sep 17 00:00:00 2001 From: bluisblu <53455507+bluisblu@users.noreply.github.com> Date: Sun, 19 Jul 2026 16:18:24 -0400 Subject: [PATCH 4/4] xCM progress --- src/SB/Core/x/xCM.cpp | 241 ++++++++++++++++++++++++++++++++++++++--- src/SB/Core/x/xCM.h | 113 ++++++++++--------- src/SB/Core/x/xColor.h | 8 ++ 3 files changed, 289 insertions(+), 73 deletions(-) diff --git a/src/SB/Core/x/xCM.cpp b/src/SB/Core/x/xCM.cpp index c4a8984cb..58b9970b2 100644 --- a/src/SB/Core/x/xCM.cpp +++ b/src/SB/Core/x/xCM.cpp @@ -1,14 +1,41 @@ #include "xCM.h" #include "xEvent.h" +#include "xFont.h" +#include "xstransvc.h" +#include "xDebug.h" +#include "xVec3.h" +#include +#include #include -volatile static F32 credits_time; +// TODO: find and move to appropriate header +U32 Im2DRenderQuad(F32 x0, F32 y0, F32 x1, F32 y1, F32 z, F32 alpha, F32 uv_offset); + +void __deadstripped_rodata() +{ + const xVec3 dead0 = {}; + const xVec3 dead1 = {}; + const xVec3 dead2 = {}; + const xVec3 dead3 = {}; + const U8 dead4[0x28] = {}; + const U8 dead5[0x28] = {}; + const U8 dead6[0x28] = {}; + const U8 dead7[0x28] = {}; + const U8 dead8[0x28] = {}; + const U8 dead9[0x28] = {}; + const U8 dead10[0x28] = {}; +} + +static const basic_rect screen_bounds = { 0.0f, 0.0f, 1.0f, 1.0f }; +static const basic_rect default_adjust = { 0.0f, 0.0f, 1.0f, 1.0f }; + +F32 dtscale = 1.0f; + +static F32 credits_time = 10000.0f; static xCreditsData* credits_data; static U32 credits_parentID; -F32 dtscale; - static void xCMprep(xCreditsData* data) { /* @@ -27,41 +54,41 @@ static void xCMprep(xCreditsData* data) return; } - xCMcredits* cp = (xCMcredits *)(&hdr[1]); - while ((int)cp - (int)data < hdr->total_size) + xCMcredits* cp = (xCMcredits*)(&hdr[1]); + while ((S32)cp - (S32)data < hdr->total_size) { xCMpreset* pp = (xCMpreset*)(&cp[1]); xCMhunk* hp = (xCMhunk*)(&pp[cp->num_presets]); - for ( ; (int)hp - (int)cp < cp->credits_size; hp = (xCMhunk*)((int)hp + hp->hunk_size)) + for (; (S32)hp - (S32)cp < cp->credits_size; hp = (xCMhunk*)((S32)hp + hp->hunk_size)) { switch (pp[hp->preset].align) { - case 0: - case 1: - case 2: - case 3: + case 0: + case 1: + case 2: + case 3: if (hdr->state == 0) { if (hp->text1 != NULL) { - hp->text1 -= (int)data; + hp->text1 -= (S32)data; } if (hp->text2 != NULL) { - hp->text2 -= (int)data; + hp->text2 -= (S32)data; } } else { if (hp->text1 != NULL) { - hp->text1 += (int)data; + hp->text1 += (S32)data; } if (hp->text2 != NULL) { - hp->text2 += (int)data; + hp->text2 += (S32)data; } } break; @@ -73,12 +100,196 @@ static void xCMprep(xCreditsData* data) hdr->state = hdr->state == 0 ? 1 : 0; } +static iColor_tag xCMcolor_scale(iColor_tag color, F32 t) +{ + F64 r = (F64)color.r; + F64 g = (F64)color.g; + F64 b = (F64)color.b; + F64 a = (F64)color.a * (F64)t; + + iColor_tag ret; + xColorInit(&ret, (U8)r, (U8)g, (U8)b, (U8)a); + return ret; +} + +void __deadstripped_strings(xCMpreset* preset) +{ + switch (preset->align) + { + // TODO: Assign correct cases to these and make an enum/defines out of it + default: + { + xprintf("CM_ALIGN_CENTER"); + xprintf("CM_ALIGN_LEFT"); + xprintf("CM_ALIGN_RIGHT"); + xprintf("CM_ALIGN_INNER"); + xprintf("CM_ALIGN_TEXTURE"); + } + } +} + +static U32 xCMrender(F32 time, xCreditsData* data) +{ + if (data == NULL || ((xCMheader*)data)->magic != 0xBEEEEEEF) + return 0; + + xCMheader* hdr = (xCMheader*)data; + if (hdr->state == 1) + xCMprep(data); + + char* dp = (char*)data; + + xprintf("credits time %6.2f\n", time); + + xCMhunk* hp; + xCMcredits* cp = (xCMcredits*)(dp + sizeof(xCMheader)); + while ((U32)((char*)cp - dp) < hdr->total_size) + { + xCMpreset* pp = (xCMpreset*)((char*)cp + sizeof(xCMcredits)); + hp = (xCMhunk*)((char*)pp + cp->num_presets * sizeof(xCMpreset)); + + for (; (U32)((char*)hp - (char*)cp) < cp->credits_size; + hp = (xCMhunk*)((char*)hp + hp->hunk_size)) + { + if (time >= hp->t0 && time <= hp->t1) + { + F32 t = (time - hp->t0) / (hp->t1 - hp->t0); + xCMpreset* preset = &pp[hp->preset]; + + F32 yScroll = t * (cp->out.y - cp->in.y) + cp->in.y; + + F32 a; + if (t < cp->fin.start || t > cp->fout.end) + a = 0.0f; + else if (t >= cp->fin.start && t <= cp->fin.end) + a = (t - cp->fin.start) / (cp->fin.end - cp->fin.start); + else if (t >= cp->fout.start && t <= cp->fout.end) + a = (cp->fout.end - t) / (cp->fout.end - cp->fout.start); + else + a = 1.0f; + + switch (preset->align) + { + case 4: + { + xCMtexture* tex = (xCMtexture*)&preset->box[0]; + if (tex->texture == NULL) + tex->texture = (RwTexture*)xSTFindAsset(tex->assetID, NULL); + if (tex->texture != NULL) + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, tex->texture->raster); + + F32 x0 = 640.0f * tex->x; + F32 y0 = 480.0f * tex->y; + F32 x1 = 640.0f * (tex->x + tex->w); + F32 y1 = 480.0f * (tex->y + tex->h); + Im2DRenderQuad(x0, y0, x1, y1, 0.0f, 1000000.0f, 0.5f); + xprintf("tex %6.2f,%6.2f - %6.2f,%6.2f\n", x0, y0, x1, y1); + break; + } + case 0: + { + xCMtextbox* box = &preset->box[0]; + + basic_rect bounds = { 0.0f, 0.0f, 0.0f, 0.0f }; + bounds.x = 0.5f * (1.0f - box->box.x); + bounds.y = yScroll; + bounds.w = box->box.x; + bounds.h = box->box.y; + + iColor_tag scaled = xCMcolor_scale(box->color, a); + + xtextbox tb = + xtextbox::create(xfont::create(box->font, NSCREENX(box->char_size.x), + NSCREENY(box->char_size.y), + box->char_spacing.x, scaled, screen_bounds), + bounds, 2, 0.0f, 0.0f, 0.0f, 0.0f); + tb.set_text(hp->text1); + tb.render(true); + break; + } + case 1: + case 2: + case 3: + { + xCMtextbox* box0 = &preset->box[0]; + xCMtextbox* box1 = &preset->box[1]; + + F32 x0 = 0.5f * (1.0f - box0->box.x - preset->innerspace - box1->box.x); + + U32 alignL, alignR; + if (preset->align == 1) + { + alignL = 0; + alignR = 0; + } + else if (preset->align == 2) + { + alignL = 1; + alignR = 1; + } + else + { + alignL = 1; + alignR = 0; + } + + // Scoped because of multiple bounds in dwarf + { + iColor_tag scaled0 = xCMcolor_scale(box0->color, a); + basic_rect bounds = { 0.0f, 0.0f, 0.0f, 0.0f }; + bounds.x = x0; + bounds.y = yScroll; + bounds.w = box0->box.x; + bounds.h = box0->box.y; + + xtextbox tb = xtextbox::create( + xfont::create(box0->font, NSCREENX(box0->char_size.x), + NSCREENY(box0->char_size.y), box0->char_spacing.x, + scaled0, screen_bounds), + bounds, alignL, 0.0f, 0.0f, 0.0f, 0.0f); + tb.set_text(hp->text1); + tb.render(true); + } + + F32 x1 = x0 + box0->box.x + preset->innerspace; + + { + iColor_tag scaled1 = xCMcolor_scale(box1->color, a); + basic_rect bounds = { 0.0f, 0.0f, 0.0f, 0.0f }; + bounds.x = x1; + bounds.y = yScroll; + bounds.w = box1->box.x; + bounds.h = box1->box.y; + + xtextbox tb = xtextbox::create( + xfont::create(box1->font, NSCREENX(box1->char_size.x), + NSCREENY(box1->char_size.y), box1->char_spacing.x, + scaled1, screen_bounds), + bounds, alignR, 0.0f, 0.0f, 0.0f, 0.0f); + tb.set_text(hp->text2); + tb.render(true); + } + break; + } + default: + break; + } + } + } + cp = (xCMcredits*)hp; + } + + if (time >= 0.0f && time <= hdr->total_time) + return 1; + return 0; +} + void xCMupdate(F32 time) { if (credits_data != 0) { credits_time += (time * dtscale); - if (credits_time >= *(F32*)((int)&credits_data->dummy + 0x10)) + if (credits_time >= *(F32*)((S32)&credits_data->dummy + 0x10)) { xCMstop(); } diff --git a/src/SB/Core/x/xCM.h b/src/SB/Core/x/xCM.h index e0ceb582a..a136991d5 100644 --- a/src/SB/Core/x/xCM.h +++ b/src/SB/Core/x/xCM.h @@ -10,87 +10,84 @@ struct xCreditsData U32 dummy; }; -class xCMheader +struct xCMheader { - // total size: 0x18 -public: - unsigned int magic; // offset 0x0, size 0x4 - unsigned int version; // offset 0x4, size 0x4 - unsigned int crdID; // offset 0x8, size 0x4 - unsigned int state; // offset 0xC, size 0x4 - float total_time; // offset 0x10, size 0x4 - unsigned int total_size; // offset 0x14, size 0x4 + U32 magic; // 0x0 + U32 version; // 0x4 + U32 crdID; // 0x8 + U32 state; // 0xC + F32 total_time; // 0x10 + U32 total_size; // 0x14 }; -class sxy +struct sxy { - // total size: 0x8 -public: - float x; // offset 0x0, size 0x4 - float y; // offset 0x4, size 0x4 + F32 x; // 0x0 + F32 y; // 0x4 }; -class fade +struct fade { - // total size: 0x8 -public: - float start; // offset 0x0, size 0x4 - float end; // offset 0x4, size 0x4 + F32 start; // 0x0 + F32 end; // 0x4 }; -class xCMtextbox +struct xCMtextbox { - // total size: 0x20 -public: - unsigned int font; // offset 0x0, size 0x4 - class iColor_tag color; // offset 0x4, size 0x4 - class sxy char_size; // offset 0x8, size 0x8 - class sxy char_spacing; // offset 0x10, size 0x8 - class sxy box; // offset 0x18, size 0x8 + U32 font; // 0x0 + iColor_tag color; // 0x4 + sxy char_size; // 0x8 + sxy char_spacing; // 0x10 + sxy box; // 0x18 }; -class xCMpreset +struct xCMtexture { - // total size: 0x4C -public: - unsigned short num; // offset 0x0, size 0x2 - unsigned short align; // offset 0x2, size 0x2 - float delay; // offset 0x4, size 0x4 - float innerspace; // offset 0x8, size 0x4 - class xCMtextbox box[2]; // offset 0xC, size 0x40 + U32 assetID; // 0x0 + iColor_tag color; // 0x4 + F32 x; // 0x8 + F32 y; // 0xC + F32 w; // 0x10 + F32 h; // 0x14 + RwTexture* texture; // 0x18 + U32 pad; // 0x1C }; -class xCMhunk +struct xCMpreset { - // total size: 0x18 -public: - unsigned int hunk_size; // offset 0x0, size 0x4 - unsigned int preset; // offset 0x4, size 0x4 - float t0; // offset 0x8, size 0x4 - float t1; // offset 0xC, size 0x4 - char * text1; // offset 0x10, size 0x4 - char * text2; // offset 0x14, size 0x4 + U16 num; // 0x0 + U16 align; // 0x2 + F32 delay; // 0x4 + F32 innerspace; // 0x8 + xCMtextbox box[2]; // 0xC }; -class xCMcredits +struct xCMhunk { - // total size: 0x38 -public: - unsigned int credits_size; // offset 0x0, size 0x4 - float len; // offset 0x4, size 0x4 - unsigned int flags; // offset 0x8, size 0x4 - sxy in; // offset 0xC, size 0x8 - sxy out; // offset 0x14, size 0x8 - float scroll_rate; // offset 0x1C, size 0x4 - float lifetime; // offset 0x20, size 0x4 - fade fin; // offset 0x24, size 0x8 - fade fout; // offset 0x2C, size 0x8 - unsigned int num_presets; // offset 0x34, size 0x4 + U32 hunk_size; // 0x0 + U32 preset; // 0x4 + F32 t0; // 0x8 + F32 t1; // 0xC + char* text1; // 0x10 + char* text2; // 0x14 +}; + +struct xCMcredits +{ + U32 credits_size; // 0x0 + F32 len; // 0x4 + U32 flags; // 0x8 + sxy in; // 0xC + sxy out; // 0x14 + F32 scroll_rate; // 0x1C + F32 lifetime; // 0x20 + fade fin; // 0x24 + fade fout; // 0x2C + U32 num_presets; // 0x34 }; void xCMupdate(F32 dt); void xCMrender(); -void xCMrender(F32 time, xCreditsData* data); void xCMstart(xCreditsData* data, F32, xBase* parent); void xCMstop(); diff --git a/src/SB/Core/x/xColor.h b/src/SB/Core/x/xColor.h index fcd3ef124..991586e91 100644 --- a/src/SB/Core/x/xColor.h +++ b/src/SB/Core/x/xColor.h @@ -20,4 +20,12 @@ extern const iColor_tag g_PINK; iColor_tag xColorFromRGBA(U8 r, U8 g, U8 b, U8 a); +inline void xColorInit(iColor_tag* ret, U8 r, U8 g, U8 b, U8 a) +{ + ret->r = r; + ret->g = g; + ret->b = b; + ret->a = a; +} + #endif