mirror of
https://github.com/perfect-dark-pc-port/perfect_dark.git
synced 2026-10-23 15:52:41 +02:00
port: mod: add a dumb replacement system for individual textures and animations
This commit is contained in:
1 parent
75b0d2dd29
commit
8a342a0698
7 files changed
+195
-6
No files matched your search
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
#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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user