port: mod: add a dumb replacement system for individual textures and animations

This commit is contained in:
fgsfds committed 2023-09-27 23:42:47 +02:00
1 parent 75b0d2dd29
commit 8a342a0698
7 files changed
+190 -1

No files matched your search

+1
View File
@@ -14,6 +14,7 @@ s32 fsPathIsAbsolute(const char *path);
s32 fsPathIsCwdRelative(const char *path);
void *fsFileLoad(const char *name, u32 *outSize);
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize);
s32 fsFileSize(const char *name);
FILE *fsFileOpenWrite(const char *name);
+7
View File
@@ -5,6 +5,13 @@
#define MOD_CONFIG_FNAME "modconfig.txt"
struct animtableentry;
s32 modConfigLoad(const char *path);
s32 modTextureLoad(u16 num, void *dst, u32 dstSize);
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim);
void *modAnimationLoadData(u16 num);
#endif
+31
View File
@@ -184,6 +184,37 @@ const char *fsGetModDir(void)
return modDir[0] ? modDir : NULL;
}
s32 fsFileLoadTo(const char *name, void *dst, u32 dstSize)
{
const char *fullName = fsFullPath(name);
FILE *f = fopen(fullName, "rb");
if (!f) {
return -1;
}
fseek(f, 0, SEEK_END);
const s32 size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size < 0) {
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: empty file or invalid size (%d): %s", size, fullName);
fclose(f);
return -1;
}
if ((u32)size > dstSize) {
sysLogPrintf(LOG_ERROR, "fsFileLoadTo: file too big for buffer (%u > %u): %s", size, dstSize, fullName);
fclose(f);
return -1;
}
fread(dst, 1, size, f);
fclose(f);
return size;
}
void *fsFileLoad(const char *name, u32 *outSize)
{
const char *fullName = fsFullPath(name);
+102
View File
@@ -10,6 +10,9 @@
#include "data.h"
#include "game/stagetable.h"
#define MOD_TEXTURES_DIR "textures"
#define MOD_ANIMATIONS_DIR "animations"
extern struct stagemusic g_StageTracks[];
extern struct stageallocation g_StageAllocations8Mb[];
@@ -42,6 +45,13 @@ extern struct stageallocation g_StageAllocations8Mb[];
} \
v = strUnquote(token);
#define PARSE_INT(sec, name, v, min, max, ret) \
p = modConfigParseIntValue(p, token, &v); \
if (!p || v < (min) || v > (max)) { \
sysLogPrintf(LOG_ERROR, "mod: %s: invalid " name " value: %s", sec, token); \
return ret; \
}
static inline char *modConfigParseFileValue(char *p, char *token, s32 *filenum)
{
p = strParseToken(p, token, NULL);
@@ -404,3 +414,95 @@ s32 modConfigLoad(const char *fname)
sysMemFree(data);
return success;
}
s32 modTextureLoad(u16 num, void *dst, u32 dstSize)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_TEXTURES_DIR "/") >= 0);
}
if (!dirExists) {
return -1;
}
char path[FS_MAXPATH + 1];
snprintf(path, sizeof(path), MOD_TEXTURES_DIR "/%04x.bin", num);
const s32 ret = fsFileLoadTo(path, dst, dstSize);
if (ret > 0) {
sysLogPrintf(LOG_NOTE, "mod: loaded external texture %04x", num);
}
return ret;
}
void *modAnimationLoadData(u16 num)
{
char path[FS_MAXPATH + 1];
// load the animation data
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.bin", num);
void *data = fsFileLoad(path, NULL);
if (!data) {
sysFatalError("External animation %04x has no data file.\nEnsure that it is placed at %s or delete the descriptor.", num, path);
}
return data;
}
s32 modAnimationLoadDescriptor(u16 num, struct animtableentry *anim)
{
static s32 dirExists = -1;
if (dirExists < 0) {
dirExists = (fsFileSize(MOD_ANIMATIONS_DIR "/") >= 0);
}
if (!dirExists) {
return false;
}
char path[FS_MAXPATH + 1];
// load the descriptor, if any
snprintf(path, sizeof(path), MOD_ANIMATIONS_DIR "/%04x.txt", num);
if (fsFileSize(path) <= 0) {
return false;
}
char *desc = fsFileLoad(path, NULL);
if (!desc) {
return false;
}
// parse the descriptor
char token[UTIL_MAX_TOKEN + 1] = { 0 };
char *p = strParseToken(desc, token, NULL);
s32 tmp = 0;
while (p && token[0]) {
if (!strcmp(token, "numframes")) {
PARSE_INT(path, "numframes", tmp, 0, 0xFFFF, false);
anim->numframes = tmp;
} else if (!strcmp(token, "bytesperframe")) {
PARSE_INT(path, "bytesperframe", tmp, 0, 0xFFFF, false);
anim->bytesperframe = tmp;
} else if (!strcmp(token, "headerlen")) {
PARSE_INT(path, "headerlen", tmp, 0, 0xFFFF, false);
anim->headerlen = tmp;
} else if (!strcmp(token, "framelen")) {
PARSE_INT(path, "framelen", tmp, 0, 0xFF, false);
anim->framelen = tmp;
} else if (!strcmp(token, "flags")) {
PARSE_INT(path, "flags", tmp, 0, 0xFF, false);
anim->flags = tmp;
} else {
sysLogPrintf(LOG_ERROR, "mod: %s: invalid key: %s", path, token);
return false;
}
p = strParseToken(p, token, NULL);
}
sysMemFree(desc);
sysLogPrintf(LOG_NOTE, "mod: loaded external animation %04x", num);
return true;
}
+8
View File
@@ -12,6 +12,7 @@
#include "game/texdecompress.h"
#include "preprocess.h"
#include "romdata.h"
#include "mod.h"
#include "system.h"
static inline f32 swapF32(f32 x) { *(u32 *)&x = PD_BE32(*(u32 *)&x); return x; }
@@ -1011,18 +1012,25 @@ void preprocessAnimations(u8 *data, u32 size)
// set the anim table pointers as well
extern u8 *_animationsTableRomStart;
extern u8 *_animationsTableRomEnd;
// the animation table is at the end of the segment
u32 *animtbl = (void *)(data + size - 0x38a0);
_animationsTableRomStart = (u8 *)animtbl;
_animationsTableRomEnd = data + size;
PD_SWAP_VAL(*animtbl);
const u32 count = *animtbl++;
struct animtableentry *anim = (struct animtableentry *)animtbl;
for (u32 i = 0; i < count; ++i, ++anim) {
PD_SWAP_VAL(anim->numframes);
PD_SWAP_VAL(anim->bytesperframe);
PD_SWAP_VAL(anim->headerlen);
PD_SWAP_VAL(anim->data);
// if an external replacement exists, replace the table entry and mark the offset
if (modAnimationLoadDescriptor(i, anim) > 0) {
anim->data = 0xffffffff;
}
}
}
+11 -1
View File
@@ -10,6 +10,9 @@
#include "lib/rzip.h"
#include "data.h"
#include "types.h"
#ifndef PLATFORM_N64
#include "mod.h"
#endif
struct texture *g_Textures;
u32 var800aabc4;
@@ -2256,12 +2259,19 @@ void texLoad(texnum_t *updateword, struct texpool *pool, bool unusedarg)
return;
}
#ifndef PLATFORM_N64
// try to load external replacement if present
if (modTextureLoad(g_TexNumToLoad, alignedcompbuffer, 4096) > 0) {
compptr = alignedcompbuffer;
} else
#endif
{
// Copy the compressed texture to RAM
dmaExec(alignedcompbuffer,
(romptr_t) REF_SEG _texturesdataSegmentRomStart + (thisoffset & 0xfffffff8),
((u32) (nextoffset - thisoffset) + 0x1f) >> 4 << 4);
compptr = (u8 *) alignedcompbuffer + (thisoffset & 7);
}
thisoffset = 0;
hasloddata = (*compptr & 0x80) >> 7;
iszlib = (*compptr & 0x40) >> 6;
+30
View File
@@ -12,6 +12,9 @@
#include "lib/libc/ll.h"
#include "data.h"
#include "types.h"
#ifndef PLATFORM_N64
#include "mod.h"
#endif
#define ANIM_HEADER_CACHE_SIZE 40
#define ANIM_FRAME_CACHE_SIZE 32
@@ -39,6 +42,10 @@ s32 g_AnimMaxHeaderLength = 608;
bool g_AnimHostEnabled = false;
u8 *g_AnimHostSegment = NULL;
#ifndef PLATFORM_N64
u8 **g_AnimReplacements;
#endif
extern u8 EXT_SEG _animationsTableRomStart;
extern u8 EXT_SEG _animationsTableRomEnd;
@@ -81,6 +88,10 @@ void animsInit(void)
g_AnimHeaderBytes = mempAlloc(ALIGN64(ANIM_HEADER_CACHE_SIZE * sizeof(*g_AnimHeaderBytes)), MEMPOOL_PERMANENT);
g_AnimHeaderAnimNums = mempAlloc(ALIGN64(ANIM_HEADER_CACHE_SIZE * sizeof(*g_AnimHeaderAnimNums)), MEMPOOL_PERMANENT);
g_AnimHeaderBirths = mempAlloc(ALIGN64(ANIM_HEADER_CACHE_SIZE * sizeof(*g_AnimHeaderBirths)), MEMPOOL_PERMANENT);
#ifndef PLATFORM_N64
g_AnimReplacements = mempAlloc(ALIGN64(g_NumAnimations * sizeof(u8 *)), MEMPOOL_PERMANENT);
bzero(g_AnimReplacements, g_NumAnimations * sizeof(u8 *));
#endif
animsInitTables();
@@ -305,6 +316,16 @@ u8 animLoadFrame(s16 animnum, s32 framenum)
if (g_Anims[animnum].bytesperframe) {
offset = g_Anims[animnum].bytesperframe * loadframenum + (g_Anims[animnum].data + g_Anims[animnum].headerlen);
#ifndef PLATFORM_N64
if (g_Anims[animnum].data == 0xffffffff) {
// load external replacement (this will fatal error if there's no data)
if (!g_AnimReplacements[animnum]) {
g_AnimReplacements[animnum] = modAnimationLoadData(animnum);
}
offset = g_Anims[animnum].bytesperframe * loadframenum + g_Anims[animnum].headerlen;
g_AnimFrameBytes[slot] = g_AnimReplacements[animnum] + offset;
} else
#endif
g_AnimFrameBytes[slot] = animDma(&g_AnimFrameByteSlots[slot * g_AnimMaxBytesPerFrame], offset, g_Anims[animnum].bytesperframe);
} else {
g_AnimFrameBytes[slot] = &g_AnimFrameByteSlots[slot * g_AnimMaxBytesPerFrame];
@@ -355,6 +376,15 @@ void animLoadHeader(s16 animnum)
tmp = g_Anims[animnum].headerlen;
#ifndef PLATFORM_N64
if (g_Anims[animnum].data == 0xffffffff) {
// load external replacement (this will fatal error if there's no data)
if (!g_AnimReplacements[animnum]) {
g_AnimReplacements[animnum] = modAnimationLoadData(animnum);
}
g_AnimHeaderBytes[slot] = g_AnimReplacements[animnum];
} else
#endif
g_AnimHeaderBytes[slot] = animDma(&g_AnimHeaderByteSlots[slot * g_AnimMaxHeaderLength], g_Anims[animnum].data, tmp);
g_AnimToHeaderSlot[animnum] = slot;
g_AnimHeaderAnimNums[slot] = animnum;