DRA LoadPendingGfx (#683)

Decompiles the function `LoadPendingGfx` and add comments to document
its behaviour. That allowed me to understand and refactor
`func_800EAF28`, which is now called `LoadGfxAsync`. I was able to
document a previously unknown structure and discover the struct type of
`entityGfxs`, now renamed as `gfxBanks`.
This commit is contained in:
Luciano Ciccariello 2023-10-13 04:55:23 +01:00 committed by GitHub
parent c6feebd92a
commit bae6b09fd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 153 additions and 74 deletions

View File

@ -46,10 +46,10 @@ segments:
- [0x3BD08, rodata] # jtbl_800DBD08
- [0x3BD60, .rodata, 47BB8]
- [0x3BE60, .rodata, save_mgr]
- [0x3C11C, rodata] # jtbl_800DC11C
- [0x3C15C, rodata] # jtbl_800DC15C
- [0x3C19C, rodata]
- [0x3C1AC, rodata] # jtbl_800DC1AC
- [0x3C11C, rodata] # func_800EA7CC
- [0x3C15C, rodata] # DecompressData
- [0x3C19C, .rodata, 4A538]
- [0x3C1AC, rodata] # RenderPrimitives
- [0x3C204, .rodata, collider]
- [0x3C404, .rodata, demo]
- [0x3C488, .rodata, 5087C] # func_800F0940

View File

@ -62,7 +62,7 @@ segments:
- [0x3BEE0, .rodata, save_mgr]
- [0x3C1A8, rodata] # func_800EA7CC
- [0x3C1E8, rodata] # DecompressData
- [0x3C228, rodata]
- [0x3C228, .rodata, 4A538]
- [0x3C238, rodata] # RenderPrimitives
- [0x3C290, .rodata, collider]
- [0x3C490, .rodata, demo]

View File

@ -57,7 +57,7 @@ D_800A3194 = 0x800A31A4;
D_800A37D8 = 0x800A37E8;
g_JosephsCloak = 0x800A37EC;
D_800A3B4C = 0x800A3B5C;
D_800A3B5C = 0x800A3B6C;
g_GfxSharedBank = 0x800A3B6C;
D_800A3BB8 = 0x800A3BC8;
g_StagesLba = 0x800A3C50;
g_SubwpnDefs = 0x800A4A10;
@ -252,12 +252,11 @@ func_800EA720 = 0x800EADD8;
func_800EA7CC = 0x800EAE84;
func_800EAD7C = 0x800EB434;
func_800EAEA4 = 0x800EB55C;
func_800EAEEC = 0x800EB5A4;
func_800EAF28 = 0x800EB5E0;
ResetPendingGfxLoad = 0x800EB5A4;
LoadGfxAsync = 0x800EB5E0;
DecompressWriteNibble = 0x800EB680;
DecompressReadNibble = 0x800EB6F4;
DecompressData = 0x800EB750;
func_800EB314 = 0x800EB9CC;
LoadEquipIcon = 0x800EBBEC;
func_800EB6B4 = 0x800EBD6C;
func_800EB720 = 0x800EBDD8;

View File

@ -672,7 +672,7 @@ g_api_SetSpeedX = 0x8003C7C8;
g_api_GetFreeDraEntity = 0x8003C7CC;
g_api_GetEquipProperties = 0x8003C7D0;
g_api_func_800EA5E4 = 0x8003C7D4;
g_api_func_800EAF28 = 0x8003C7D8;
g_api_LoadGfxAsync = 0x8003C7D8;
g_api_PlaySfx = 0x8003C7DC;
g_api_func_800EDB58 = 0x8003C7E0;
g_api_func_800EA538 = 0x8003C7E4;
@ -900,7 +900,7 @@ g_Player_unk78 = 0x80072F98;
g_Player_unk7A = 0x80072F9A;
g_Player_unk7C = 0x80072F9C;
g_Player_unk7E = 0x80072F9E;
D_80072FA0 = 0x80072FA0;
g_GfxLoad = 0x80072FA0;
g_GameStep = 0x80073060;
D_80073064 = 0x80073064;
g_EvSwCardEnd = 0x80073068;

View File

@ -92,6 +92,7 @@ D_800A3B10 = 0x800A3B10;
D_800A3B24 = 0x800A3B24;
D_800A3B38 = 0x800A3B38;
D_800A3B4C = 0x800A3B4C;
g_GfxSharedBank = 0x800A3B5C;
g_StagesLba = 0x800A3C40;
g_SubwpnDefs = 0x800A4A00;
g_EquipDefs = 0x800A4B04;
@ -672,7 +673,6 @@ jpt_800E7E3C = 0x800DBD88;
D_800DBFFC = 0x800DBFFC; // ignore:true
jpt_800EA8C0 = 0x800DC1A8;
jpt_800EB120 = 0x800DC1E8;
aOver08x04x = 0x800DC228; // type:asciz
jpt_800EE2FC = 0x800DC238;
aWindowColorSet = 0x800DC5FC; // type:asciz
jpt_800F8150 = 0x800DC68C;
@ -791,6 +791,7 @@ MemcardWriteFile = 0x800E96E8;
MemcardClose = 0x800E9804;
StoreSaveData = 0x800E9C14;
MakeMemcardPath = 0x800EA48C;
LoadGfxAsync = 0x800EAF28;
DecompressWriteNibble = 0x800EAFC8;
DecompressReadNibble = 0x800EB03C;
DecompressData = 0x800EB098;

View File

@ -633,7 +633,7 @@ g_api_SetSpeedX = 0x8003C7C8;
g_api_GetFreeDraEntity = 0x8003C7CC;
g_api_GetEquipProperties = 0x8003C7D0;
g_api_func_800EA5E4 = 0x8003C7D4;
g_api_func_800EAF28 = 0x8003C7D8;
g_api_LoadGfxAsync = 0x8003C7D8;
g_api_PlaySfx = 0x8003C7DC;
g_api_func_800EDB58 = 0x8003C7E0;
g_api_func_800EA538 = 0x8003C7E4;
@ -804,6 +804,7 @@ g_Player_unk78 = 0x80072F98;
g_Player_unk7A = 0x80072F9A;
g_Player_unk7C = 0x80072F9C;
g_Player_unk7E = 0x80072F9E;
g_GfxLoad = 0x80072FA0;
g_GameStep = 0x80073060;
g_EvSwCardEnd = 0x80073068;
g_EvSwCardErr = 0x8007306C;

View File

@ -303,6 +303,14 @@ typedef enum {
STAGE_MEMORYCARD = 0xFF,
} Stages;
typedef enum {
GFX_BANK_NONE,
GFX_BANK_4BPP,
GFX_BANK_8BPP,
GFX_BANK_16BPP,
GFX_BANK_COMPRESSED,
} GfxBankKind;
typedef enum {
// Clean-up and reset all the gameplay related memory
Play_Reset = 0,
@ -639,6 +647,25 @@ typedef struct {
/* 0x20 */ u32 env;
} GpuUsage;
typedef struct {
/* 0x00 */ u32 xy;
/* 0x04 */ u32 wh;
/* 0x08 */ void* data;
} GfxEntry; // size=0xC
typedef struct {
GfxBankKind kind;
GfxEntry entries[0];
} GfxBank;
typedef struct {
/* 0x0 */ GfxEntry* next;
/* 0x4 */ u16 kind;
/* 0x6 */ s16 unk6;
/* 0x8 */ s16 unk8;
/* 0xA */ s16 unkA;
} GfxLoad; // size=0xC
typedef enum {
ITEM_S_SWORD,
ITEM_SWORD,
@ -896,7 +923,7 @@ typedef struct {
/* 8003C78C */ UnkStructClut** cluts;
/* 8003C790 */ void* unk1C; // related to entity layout
/* 8003C794 */ RoomDef* tileLayers;
/* 8003C798 */ void** entityGfxs;
/* 8003C798 */ GfxBank** gfxBanks;
/* 8003C79C */ void (*unk28)(void);
/* 8003C7A0 */ void (*unk2c)(void); // similar to Update
/* 8003C7A4 */ void* unk30;
@ -1081,7 +1108,7 @@ typedef struct {
/* 8003C7D0 */ void (*GetEquipProperties)(
s32 handId, Equipment* res, s32 equipId);
/* 8003C7D4 */ s32 (*func_800EA5E4)(u32);
/* 8003C7D8 */ void (*func_800EAF28)(s32);
/* 8003C7D8 */ void (*LoadGfxAsync)(s32 gfxId);
/* 8003C7DC */ void (*PlaySfx)(s32 sfxId);
/* 8003C7E0 */ s16 (*func_800EDB58)(s32, s32);
/* 8003C7E4 */ void (*func_800EA538)(s32 arg0);
@ -1152,7 +1179,7 @@ extern Entity* (*g_api_GetFreeDraEntity)(s16 start, s16 end);
extern void (*g_api_GetEquipProperties)(
s32 handId, Equipment* res, s32 equipId);
extern s32 (*g_api_func_800EA5E4)(u32);
extern void (*g_api_func_800EAF28)(s32);
extern void (*g_api_LoadGfxAsync)(s32);
extern void (*g_api_PlaySfx)(s32 sfxId);
extern s16 (*g_api_func_800EDB58)(s32, s32);
extern void (*g_api_func_800EA538)(s32 arg0);
@ -1448,7 +1475,7 @@ extern u32 D_80070BCC;
extern PlayerState g_Player;
extern u16 g_Player_D_80072EF6; // TODO merge with g_Player
extern unkstruct_80072FA0 D_80072FA0[0x10];
extern GfxLoad g_GfxLoad[0x10];
extern u32 g_GameStep;
extern s32 D_80073064;
extern Event g_EvSwCardEnd; // 80073068

View File

@ -12,14 +12,6 @@ typedef struct {
/* 0x4 */ s32 y;
} Point32; // size = 0x8
typedef struct {
/* 0x0 */ u16* unk0;
/* 0x4 */ u16 unk4;
/* 0x6 */ s16 unk6;
/* 0x8 */ s16 unk8;
/* 0xA */ s16 unkA;
} unkstruct_80072FA0; // size = 0xC
typedef struct {
/* 0x00 */ u16* fg;
/* 0x04 */ u16* bg;

View File

@ -21,7 +21,7 @@ void UpdateGame(void);
void func_800E7BB8(void);
void SetupEvents(void);
void func_800EA7CC(void);
void func_800EB314(void);
void LoadPendingGfx(void);
void RenderEntities(void);
void InitRenderer(void);
void RenderTilemap(void);
@ -851,7 +851,7 @@ loop_5:
func_800EDAE4();
DestroyEntities(0);
func_800EA538(0);
func_800EAEEC();
ResetPendingGfxLoad();
D_801362B4 = 0x20;
g_DebugCurPal = 0x200;
g_DebugEnabled = 0;
@ -919,7 +919,7 @@ loop_5:
#endif
VSync(D_8003C73C);
GsClearVcount();
func_800EB314();
LoadPendingGfx();
ReadPads();
#if defined(VERSION_US)
if ((g_pads->pressed & PAD_RESETCOMBO) == PAD_RESETCOMBO) {
@ -1135,7 +1135,7 @@ void HandleTitle(void) {
ResetEntityArray();
DestroyEntities(0);
func_800EA538(0);
func_800EAEEC();
ResetPendingGfxLoad();
SetStageDisplayBuffer();
g_StageId = STAGE_SEL;
if (g_UseDisk) {

View File

@ -193,7 +193,7 @@ void HandleEnding(void) {
case 0:
DestroyEntities(0);
func_800EA538(0);
func_800EAEEC();
ResetPendingGfxLoad();
DestroyAllPrimitives();
func_800EDAE4();
HideAllBackgroundLayers();

View File

@ -144,39 +144,39 @@ void func_800EAEA4(void) {
}
}
void func_800EAEEC(void) {
unkstruct_80072FA0* ptr = D_80072FA0;
void ResetPendingGfxLoad(void) {
GfxLoad* gfxLoad = g_GfxLoad;
s32 i;
for (i = 0; i < 16; i++, ptr++) {
ptr->unk4 = 0;
for (i = 0; i < LEN(g_GfxLoad); i++, gfxLoad++) {
gfxLoad->kind = GFX_BANK_NONE;
}
func_800EAEA4();
}
void func_800EAF28(s32 arg0) {
s32 temp_v1;
s32 i;
s32 new_var;
u16* var_a1;
unkstruct_80072FA0* var_a0;
void LoadGfxAsync(s32 gfxId) {
// Schedule the load of new graphics into the video RAM in the very next
// frame by LoadPendingGfx. A maximum amount of 16 transfers can be chained.
if (arg0 & ANIMSET_OVL_FLAG) {
var_a1 = g_api.o.entityGfxs[arg0 & 0x7FFF];
s32 i;
GfxBank* gfxBank;
GfxLoad* gfxLoad;
if (gfxId & ANIMSET_OVL_FLAG) {
gfxBank = g_api.o.gfxBanks[gfxId & 0x7FFF];
} else {
var_a1 = D_800A3B5C[arg0];
gfxBank = g_GfxSharedBank[gfxId];
}
temp_v1 = *(s32*)var_a1;
if (temp_v1 != 0 && temp_v1 != (new_var = -1)) {
for (i = 0; i < 0x10; i++) {
var_a0 = &D_80072FA0[i];
if (var_a0->unk4 == 0) {
var_a0->unk4 = var_a1[0];
var_a0->unk6 = 0;
var_a0->unk8 = 0;
var_a0->unk0 = var_a1 + 2;
if (gfxBank->kind != GFX_BANK_NONE && gfxBank->kind != -1) {
for (i = 0; i < LEN(g_GfxLoad); i++) {
gfxLoad = &g_GfxLoad[i];
if (gfxLoad->kind == GFX_BANK_NONE) {
gfxLoad->kind = gfxBank->kind;
gfxLoad->unk6 = 0;
gfxLoad->unk8 = 0;
gfxLoad->next = gfxBank->entries;
break;
}
}
@ -318,7 +318,66 @@ s32 DecompressData(u8* dst, u8* src) {
}
#endif
INCLUDE_ASM("dra/nonmatchings/4A538", func_800EB314);
void LoadPendingGfx(void) {
// Called every frame, it continuously checks if there is any new graphics
// to transfer from RAM to Video RAM. Compressed graphics are loaded as
// 128x128 images into a 256x256 tpage (hence the `j < 4`). Each pending
// GFX load contains a descriptor to instruct this function in which area
// of the Video RAM the texture will be transferred to.
char buf[0x100];
s32 i;
s32 j;
u32 xy;
u32 wh;
u8* src;
u8* src2;
u8* dst;
s32 over;
GfxLoad* gfxLoad;
GfxEntry* gfxEntry;
j = 0;
gfxLoad = g_GfxLoad;
for (i = 0; i < LEN(g_GfxLoad); i++, gfxLoad++) {
switch (gfxLoad->kind) {
case GFX_BANK_NONE:
break;
case GFX_BANK_4BPP:
case GFX_BANK_8BPP:
case GFX_BANK_16BPP:
for (gfxEntry = gfxLoad->next; gfxEntry->xy != -1; gfxEntry++) {
xy = gfxEntry->xy;
wh = gfxEntry->wh;
src2 = gfxEntry->data;
LoadTPage(src2, gfxLoad->kind - 1, 0, xy >> 0x10, (u16)xy,
wh >> 0x10, (u16)wh);
}
gfxLoad->kind = GFX_BANK_NONE;
break;
case GFX_BANK_COMPRESSED:
gfxEntry = gfxLoad->next;
for (; j < 4; j++) {
dst = g_Pix[j];
xy = gfxEntry->xy;
wh = gfxEntry->wh;
src = gfxEntry->data;
over = DecompressData(dst, src);
if (over) {
sprintf(buf, "over:%08x(%04x)", src, over);
DebugInputWait(buf);
}
LoadTPage(dst, 0, 0, xy >> 0x10, (u16)xy, wh >> 0x10, (u16)wh);
gfxLoad->next = ++gfxEntry;
if (gfxEntry->xy == -1) {
gfxLoad->kind = GFX_BANK_NONE;
break;
}
}
break;
}
}
}
void func_800EB4F8(PixPattern* pix, s32 bitDepth, s32 x, s32 y) {
LoadTPage(pix + 1, bitDepth, 0, x, y, (int)pix->w, (int)pix->h);
@ -368,11 +427,11 @@ void func_800EB6B4(void) {
}
bool func_800EB720(void) {
unkstruct_80072FA0* temp = D_80072FA0;
GfxLoad* temp = g_GfxLoad;
s32 i;
for (i = 0; i < 16; i++) {
if (temp[i].unk4 != 0) {
if (temp[i].kind != 0) {
return true;
}
}

View File

@ -49,10 +49,10 @@ void func_800F298C(void) {
func_800F14CC();
LoadRoomLayer(D_801375BC.def->tileLayoutId);
if (D_8003C708.flags & 0x20) {
func_800EAF28(3);
LoadGfxAsync(ANIMSET_DRA(3));
}
if (D_8003C708.flags & 0x40) {
func_800EAF28(4);
LoadGfxAsync(ANIMSET_DRA(4));
}
D_80097910 = g_StagesLba[g_StageId].unk18;
if (g_StageId == STAGE_NO3 && D_8003C730 == 0) {
@ -71,7 +71,7 @@ void func_800F298C(void) {
func_800EA5E4(D_801375BC.def->tilesetId + 0x7fff | 0x4000);
}
if (D_801375BC.def->objGfxId != 0) {
func_800EAF28(D_801375BC.def->objGfxId + 0x7fff);
LoadGfxAsync(D_801375BC.def->objGfxId + 0x7fff);
D_80097904 = D_801375BC.def->objGfxId + 0x7fff;
} else {
D_80097904 = 0;
@ -500,7 +500,7 @@ void func_800F298C(void) {
PLAYER.posX.i.hi = D_801375C0 + g_Camera.posX.i.hi;
PLAYER.posY.i.hi = D_801375C4 + g_Camera.posY.i.hi;
if (D_8003C708.flags & 0x60) {
func_800EAF28(1);
LoadGfxAsync(ANIMSET_DRA(1));
}
func_800EA538(2);
if (D_801375BC.def->tilesetId != 0) {
@ -508,7 +508,7 @@ void func_800F298C(void) {
(D_801375BC.def->tilesetId + 0x7FFF) | 0x4000);
}
if (D_801375BC.def->objGfxId != 0) {
func_800EAF28(D_801375BC.def->objGfxId + 0x7FFF);
LoadGfxAsync(D_801375BC.def->objGfxId + 0x7FFF);
D_80097904 = D_801375BC.def->objGfxId + 0x7FFF;
} else {
D_80097904 = 0;
@ -518,10 +518,10 @@ void func_800F298C(void) {
PLAYER.posX.i.hi = (u8)PLAYER.posX.i.hi;
LoadRoomLayer(D_801375BC.def->tileLayoutId);
if (D_8003C708.flags & 0x20) {
func_800EAF28(3);
LoadGfxAsync(ANIMSET_DRA(3));
}
if (D_8003C708.flags & 0x40) {
func_800EAF28(4);
LoadGfxAsync(ANIMSET_DRA(4));
}
g_CurrentRoom.x =
((D_801375BC.def - 1)->tileLayoutId - g_CurrentRoom.left)

View File

@ -386,7 +386,7 @@ extern s32 D_800A3194[];
extern Unkstruct_801092E8 D_800A37D8;
extern JosephsCloak g_JosephsCloak;
extern Lba g_StagesLba[];
extern u32* D_800A3B5C[];
extern GfxBank** g_GfxSharedBank[];
extern UnkStructClut* D_800A3BB8[];
extern SubweaponDef g_SubwpnDefs[];
extern SpellDef g_SpellDefs[];
@ -811,7 +811,7 @@ void MemcardInfoInit(void);
s32 func_800EA5E4(u32);
void func_800EA538(s32);
void func_800EAD7C(void);
void func_800EAEEC(void);
void ResetPendingGfxLoad(void);
void LoadEquipIcon(s32 equipIcon, s32 palette, s32 index);
bool func_800EB720(void);
void HideAllBackgroundLayers(void);

View File

@ -72,7 +72,7 @@ void HandleGameOver(void) {
}
DestroyEntities(0);
func_800EA538(0);
func_800EAEEC();
ResetPendingGfxLoad();
DestroyAllPrimitives();
func_800EDAE4();
HideAllBackgroundLayers();

View File

@ -19,7 +19,7 @@ void func_800E4970(void) {
DestroyAllPrimitives();
func_800EA538(0);
HideAllBackgroundLayers();
func_800EAEEC();
ResetPendingGfxLoad();
func_800EDAE4();
PlaySfx(SET_UNK_12);
PlaySfx(SET_UNK_0B);
@ -85,8 +85,8 @@ void HandlePlay(void) {
g_GameStep++;
break;
case Play_Init:
func_800EAF28(ANIMSET_DRA(1));
func_800EAF28(ANIMSET_OVL(0));
LoadGfxAsync(ANIMSET_DRA(1));
LoadGfxAsync(ANIMSET_OVL(0));
func_800EA5E4(ANIMSET_OVL(0));
g_GameStep++;
break;
@ -124,7 +124,7 @@ void HandlePlay(void) {
g_GpuBuffers[0].draw.isbg = 0;
HideAllBackgroundLayers();
func_800EA538(1);
func_800EAEEC();
ResetPendingGfxLoad();
DestroyEntities(0);
DestroyAllPrimitives();
func_800EDAE4();

View File

@ -376,10 +376,10 @@ void func_801B60D4(void) {
D_801D6B24 = 0;
D_801BD030 = 0;
g_Entities[8].params = D_800978B4 - 1;
g_api.func_800EA5E4(0x16);
g_api.func_800EA5E4(0);
g_api.func_800EA5E4(0x8005);
g_api.func_800EAF28(0x8000);
g_api.func_800EA5E4(ANIMSET_DRA(0x16));
g_api.func_800EA5E4(ANIMSET_DRA(0));
g_api.func_800EA5E4(ANIMSET_OVL(5));
g_api.LoadGfxAsync(ANIMSET_OVL(0));
D_8003C9A4++;
break;
@ -429,7 +429,7 @@ void func_801B60D4(void) {
break;
case 6:
g_api.func_800EA5E4(0);
g_api.func_800EA5E4(ANIMSET_DRA(0));
D_8003C9A4++;
break;