From d1b75e4c4b9fa365b9ba39e431734c150bfc9f40 Mon Sep 17 00:00:00 2001 From: Tom Overton Date: Sat, 18 Jun 2022 18:46:41 -0700 Subject: [PATCH] VisMono OK and documented (#829) * VisMono OK and documented * Add some more parentheses * Fix functions.h * Respond to hansldm's review --- include/PR/gbi.h | 1 + include/functions.h | 12 +- include/variables.h | 2 +- include/z64.h | 6 +- src/code/game.c | 6 +- src/code/z_rcp.c | 8 +- src/code/z_vismono.c | 177 +++++++++++++++++- .../fbdemos/ovl_fbdemo_wipe5/z_fbdemo_wipe5.c | 2 +- tools/disasm/functions.txt | 10 +- tools/sizes/code_functions.csv | 10 +- 10 files changed, 200 insertions(+), 34 deletions(-) diff --git a/include/PR/gbi.h b/include/PR/gbi.h index 8e5aefe8e..34ec8af31 100644 --- a/include/PR/gbi.h +++ b/include/PR/gbi.h @@ -216,6 +216,7 @@ #define GPACK_RGBA5551(r, g, b, a) ((((r)<<8) & 0xf800) | \ (((g)<<3) & 0x7c0) | \ (((b)>>2) & 0x3e) | ((a) & 0x1)) +#define GPACK_IA16(i, a) (((i) << 8) | (a)) #define GPACK_ZDZ(z, dz) ((z) << 2 | (dz)) /* diff --git a/include/functions.h b/include/functions.h index a29024850..1f19f5da4 100644 --- a/include/functions.h +++ b/include/functions.h @@ -2534,12 +2534,12 @@ void func_80140E80(void* param_1); // void func_8014151C(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5, UNK_TYPE4 param_6); // void func_80141678(UNK_TYPE1 param_1, UNK_TYPE1 param_2, UNK_TYPE1 param_3, UNK_TYPE1 param_4, UNK_TYPE4 param_5); // void func_80141778(void); -void func_801418B0(void* arg0); -void func_80141900(void* arg0); -// void func_80141924(void); -// void func_80141C34(void); -void VisMono_Draw(void* arg0, Gfx** gfx, u32 arg2); -// void func_8014204C(void); +void VisMono_Init(VisMono* this); +void VisMono_Destroy(VisMono* this); +// void VisMono_DesaturateTLUT(u16* tlut); +// void VisMono_DesaturateDList(Gfx* gfx); +void VisMono_Draw(VisMono* this, Gfx** gfxp); +// void VisMono_DrawOld(VisMono* this); void func_801420C0(void* arg0); void func_801420F4(void* arg0); void func_80142100(void* arg0, Gfx** gfx, u32 arg2); diff --git a/include/variables.h b/include/variables.h index c37938555..e8f8d5a3e 100644 --- a/include/variables.h +++ b/include/variables.h @@ -3562,7 +3562,7 @@ extern u16 gFramebuffer0[SCREEN_HEIGHT][SCREEN_WIDTH]; // other segments extern GfxMasterList D_0E000000; extern Mtx D_01000000; -extern UNK_TYPE D_0F000000; +extern u16 D_0F000000[]; #endif diff --git a/include/z64.h b/include/z64.h index 7f1dfd701..5852b9212 100644 --- a/include/z64.h +++ b/include/z64.h @@ -1404,10 +1404,10 @@ typedef struct { typedef struct { /* 0x00 */ u32 unk_00; /* 0x04 */ u32 setScissor; - /* 0x08 */ Color_RGBA8 primColor; - /* 0x0C */ Color_RGBA8 envColor; + /* 0x08 */ Color_RGBA8_u32 primColor; + /* 0x0C */ Color_RGBA8_u32 envColor; /* 0x10 */ u16* tlut; - /* 0x14 */ Gfx* monoDl; + /* 0x14 */ Gfx* dList; } VisMono; // size = 0x18 typedef struct DebugDispObject { diff --git a/src/code/game.c b/src/code/game.c index 2713be299..6f796bc12 100644 --- a/src/code/game.c +++ b/src/code/game.c @@ -52,7 +52,7 @@ void GameState_SetFBFilter(Gfx** gfx, u32 arg1) { sMonoColors.envColor.g = R_FB_FILTER_ENV_COLOR(1); sMonoColors.envColor.b = R_FB_FILTER_ENV_COLOR(2); sMonoColors.envColor.a = R_FB_FILTER_A; - VisMono_Draw(&sMonoColors, &dlist, arg1); + VisMono_Draw(&sMonoColors, &dlist); } } } @@ -213,7 +213,7 @@ void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* g func_80140CE0(&D_801F8010); func_801420C0(&D_801F8020); - func_801418B0(&sMonoColors); + VisMono_Init(&sMonoColors); func_80140898(&D_801F8048); func_801773A0(&D_801F7FF0); func_8013ED9C(); @@ -235,7 +235,7 @@ void GameState_Destroy(GameState* gameState) { func_801773C4(&D_801F7FF0); func_80140D04(&D_801F8010); func_801420F4(&D_801F8020); - func_80141900(&sMonoColors); + VisMono_Destroy(&sMonoColors); func_80140900(&D_801F8048); THA_Dt(&gameState->heap); GameAlloc_Cleanup(&gameState->alloc); diff --git a/src/code/z_rcp.c b/src/code/z_rcp.c index f4ffd43c1..1d13be316 100644 --- a/src/code/z_rcp.c +++ b/src/code/z_rcp.c @@ -1239,11 +1239,11 @@ void func_8012CF0C(GraphicsContext* gfxCtx, s32 clearFb, s32 clearZb, u8 r, u8 g gSPDisplayList(&masterGfx[0], D_0E000000.syncSegments); gSPDisplayList(&masterGfx[1], sFillSetupDL); - gDPSetColorImage(&masterGfx[2], G_IM_FMT_RGBA, G_IM_SIZ_16b, D_801FBBCC, &D_0F000000); + gDPSetColorImage(&masterGfx[2], G_IM_FMT_RGBA, G_IM_SIZ_16b, D_801FBBCC, D_0F000000); if (zbuffer != NULL) { gDPSetDepthImage(&masterGfx[3], zbuffer); } else { - gDPSetDepthImage(&masterGfx[3], &D_0F000000); + gDPSetDepthImage(&masterGfx[3], D_0F000000); } gSPEndDisplayList(&masterGfx[4]); @@ -1267,7 +1267,7 @@ void func_8012CF0C(GraphicsContext* gfxCtx, s32 clearFb, s32 clearZb, u8 r, u8 g gDPSetRenderMode(&masterGfx[3], G_RM_NOOP, G_RM_NOOP2); gDPSetFillColor(&masterGfx[4], (GPACK_RGBA5551(255, 255, 240, 0) << 16) | GPACK_RGBA5551(255, 255, 240, 0)); gSPDisplayList(&masterGfx[5], D_0E000000.clearFillRect); - gDPSetColorImage(&masterGfx[6], G_IM_FMT_RGBA, G_IM_SIZ_16b, D_801FBBCC, &D_0F000000); + gDPSetColorImage(&masterGfx[6], G_IM_FMT_RGBA, G_IM_SIZ_16b, D_801FBBCC, D_0F000000); gSPEndDisplayList(&masterGfx[7]); } @@ -1275,7 +1275,7 @@ void func_8012CF0C(GraphicsContext* gfxCtx, s32 clearFb, s32 clearZb, u8 r, u8 g masterGfx = gGfxMasterDL->clearFrameBuffer; - gDPSetColorImage(&masterGfx[0], G_IM_FMT_RGBA, G_IM_SIZ_16b, D_801FBBCC, &D_0F000000); + gDPSetColorImage(&masterGfx[0], G_IM_FMT_RGBA, G_IM_SIZ_16b, D_801FBBCC, D_0F000000); gDPSetCycleType(&masterGfx[1], G_CYC_FILL); gDPSetRenderMode(&masterGfx[2], G_RM_NOOP, G_RM_NOOP2); gDPSetFillColor(&masterGfx[3], (GPACK_RGBA5551(r, g, b, 1) << 16) | GPACK_RGBA5551(r, g, b, 1)); diff --git a/src/code/z_vismono.c b/src/code/z_vismono.c index 6c0d1ef22..b28ed2aa6 100644 --- a/src/code/z_vismono.c +++ b/src/code/z_vismono.c @@ -1,14 +1,179 @@ +/* + * File: z_vismono.c + * Description: Color frame buffer effect to desaturate the colors. + */ + #include "global.h" #include "system_malloc.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/z_vismono/func_801418B0.s") +// Height of the fragments the color frame buffer (CFB) is split into. +// It is the maximum amount of lines such that all rgba16 SCREEN_WIDTH-long lines fit into +// the half of tmem (0x800 bytes) dedicated to color-indexed data. +#define VISMONO_CFBFRAG_HEIGHT (0x800 / (SCREEN_WIDTH * G_IM_SIZ_16b_BYTES)) -#pragma GLOBAL_ASM("asm/non_matchings/code/z_vismono/func_80141900.s") +// Maximum size of the dlist written by `VisMono_DesaturateDList`. +// `VisMono_DesaturateDList` consistently uses `VISMONO_DLSIZE - 2` double words, so this can be 2 less. +#define VISMONO_DLSIZE (3 + SCREEN_HEIGHT / VISMONO_CFBFRAG_HEIGHT * (7 + 2 + 2 + 3) + 2 + 2) -#pragma GLOBAL_ASM("asm/non_matchings/code/z_vismono/func_80141924.s") +// How much each color component contributes to the desaturated result. +// These coefficients are close to what the YUV color space defines Y (luminance) as: +// https://en.wikipedia.org/wiki/YUV#Conversion_to/from_RGB +#define VISMONO_FAC_RED 2 +#define VISMONO_FAC_GREEN 4 +#define VISMONO_FAC_BLUE 1 +#define VISMONO_FAC_NORM (0x1F * VISMONO_FAC_RED + 0x1F * VISMONO_FAC_GREEN + 0x1F * VISMONO_FAC_BLUE) -#pragma GLOBAL_ASM("asm/non_matchings/code/z_vismono/func_80141C34.s") +void VisMono_Init(VisMono* this) { + bzero(this, sizeof(VisMono)); + this->unk_00 = 0; + this->setScissor = false; + this->primColor.r = 255; + this->primColor.g = 255; + this->primColor.b = 255; + this->primColor.a = 255; + this->envColor.r = 0; + this->envColor.g = 0; + this->envColor.b = 0; + this->envColor.a = 0; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_vismono/VisMono_Draw.s") +void VisMono_Destroy(VisMono* this) { + SystemArena_Free(this->dList); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_vismono/func_8014204C.s") +void VisMono_DesaturateTLUT(u16* tlut) { + s32 i; + + for (i = 0; i < 256; i++) { + // `tlut[i]` is a IA16 color + // `i` corresponds to either byte of a RGBA16 color RRRR_RGGG GGBB_BBBA from the color frame buffer + + // The high byte I (intensity) corresponds to `i` being interpreted as the high byte RRRR_RGGG + // I = (RRRRR * FAC_RED + GGG00 * FAC_GREEN) * (255 / FAC_NORM) + + // The low byte A (alpha) corresponds to `i` being interpreted as the low byte GGBB_BBBA + // A = (000GG * FAC_GREEN + BBBBB * FAC_BLUE) * (255 / FAC_NORM) + + // Note: I + A = (RRRRR * FAC_RED + GGGGG * FAC_GREEN + BBBBB * FAC_BLUE) * (255 / FAC_NORM) + + tlut[i] = GPACK_IA16( + (((i >> 3) & 0x1F) * VISMONO_FAC_RED + ((i << 2) & 0x1F) * VISMONO_FAC_GREEN) * 255 / VISMONO_FAC_NORM, + (((i >> 6) & 0x1F) * VISMONO_FAC_GREEN + ((i >> 1) & 0x1F) * VISMONO_FAC_BLUE) * 255 / VISMONO_FAC_NORM); + } +} + +Gfx* VisMono_DesaturateDList(Gfx* gfx) { + s32 y; + s32 height = VISMONO_CFBFRAG_HEIGHT; + u16* cfbFrag = D_0F000000; + + gDPPipeSync(gfx++); + // `G_TT_IA16`: use color-indexed images, and IA16 palettes + gDPSetOtherMode(gfx++, + G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_IA16 | G_TL_TILE | + G_TD_CLAMP | G_TP_NONE | G_CYC_2CYCLE | G_PM_1PRIMITIVE, + G_AC_NONE | G_ZS_PRIM | GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) | G_RM_CLD_SURF2); + // First color cycle sums texel 1 alpha and texel 0 color + // By using IA16 palettes, this means summing A (from the IA16 color texel 1 maps to) + // with I (from the IA16 color texel 0 maps to) + gDPSetCombineLERP(gfx++, 1, 0, TEXEL1_ALPHA, TEXEL0, 0, 0, 0, 1, PRIMITIVE, ENVIRONMENT, COMBINED, ENVIRONMENT, 0, + 0, 0, PRIMITIVE); + + for (y = 0; y <= SCREEN_HEIGHT - height; y += height) { + // Load a few lines of the color frame buffer + gDPLoadTextureBlock(gfx++, cfbFrag, G_IM_FMT_CI, G_IM_SIZ_8b, SCREEN_WIDTH * 2, height, 0, + G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD); + + // Set texel 0 to be a CI8 image with width `SCREEN_WIDTH * 2` and height `VISMONO_CFBFRAG_HEIGHT` + // Its position in texture image space is shifted along +S by 2 + gDPSetTile(gfx++, G_IM_FMT_CI, G_IM_SIZ_8b, SCREEN_WIDTH * 2 * G_IM_SIZ_8b_LINE_BYTES / 8, 0x0, G_TX_RENDERTILE, + 0, G_TX_NOMIRROR | G_TX_CLAMP, 0, 0, G_TX_NOMIRROR | G_TX_CLAMP, 0, 0); + gDPSetTileSize(gfx++, G_TX_RENDERTILE, 2 << 2, 0, (SCREEN_WIDTH * 2 + 1) << 2, + (VISMONO_CFBFRAG_HEIGHT - 1) << 2); + + // Set texel 1 to be a CI8 image with width `SCREEN_WIDTH * 2` and height `VISMONO_CFBFRAG_HEIGHT` + // Its position in texture image space is shifted along +S by 1 + gDPSetTile(gfx++, G_IM_FMT_CI, G_IM_SIZ_8b, SCREEN_WIDTH * 2 * G_IM_SIZ_8b_LINE_BYTES / 8, 0x0, 1, 1, + G_TX_NOMIRROR | G_TX_CLAMP, 0, 0, G_TX_NOMIRROR | G_TX_CLAMP, 0, 0); + gDPSetTileSize(gfx++, 1, 1 << 2, 0, (SCREEN_WIDTH * 2) << 2, (VISMONO_CFBFRAG_HEIGHT - 1) << 2); + + // Draw a `SCREEN_WIDTH` wide, `height` high rectangle. + // Texture coordinate T (vertical) starts at 0 and changes by one each line (dtdy = 1) + // Texture coordinate S (horizontal) starts at 2 and changes by two each column (dsdx = 2) + + // Because texel 0 is shifted by 2 and texel 1 only by 1 along +S, + // a pixel at S coordinates s = 2+2*n will look at the 2*n-th byte of texel 0 and the 2*n+1-th byte of texel 1. + // (in "s = 2+2*n" the first "2" is the starting S coordinate and the second "2" is the dsdx value) + + // The 2*n-th byte of texel 0 is the high byte of the n-th RGBA16 color of the color frame buffer. + // The 2*n+1-th byte of texel 1 is the low byte of the n-th RGBA16 color of the color frame buffer. + + // With the TLUT computed by `VisMono_DesaturateTLUT`: + // The 2*n-th byte of texel 0 maps to a IA16 color where the high byte I (intensity) corresponds to + // the high byte of the n-th RGBA16 color of the color frame buffer. + // The 2*n+1-th byte of texel 1 maps to a IA16 color where the low byte A (alpha) corresponds to + // the low byte of the n-th RGBA16 color of the color frame buffer. + + // Since the combiner is in part set up to sum texel 0 color (I, intensity) with texel 1 alpha (A, alpha), + // the resulting color in the drawn rectangle is a desaturated color as defined by the `VISMONO_FAC_*` values. + + gSPTextureRectangle(gfx++, 0, y << 2, SCREEN_WIDTH << 2, (y + height) << 2, G_TX_RENDERTILE, 2 << 5, 0, 2 << 10, + 1 << 10); + cfbFrag += SCREEN_WIDTH * height; + } + + gDPPipeSync(gfx++); + gSPEndDisplayList(gfx++); + return gfx; +} + +void VisMono_Draw(VisMono* this, Gfx** gfxp) { + Gfx* gfx = *gfxp; + u16* tlut; + Gfx* dList; + Gfx* dListEnd; + + if (this->tlut) { + tlut = this->tlut; + } else { + tlut = Graph_DlistAlloc(&gfx, 256 * G_IM_SIZ_16b_BYTES); + VisMono_DesaturateTLUT(tlut); + } + + if (this->dList) { + dList = this->dList; + } else { + dList = Graph_DlistAlloc(&gfx, VISMONO_DLSIZE * sizeof(Gfx)); + dListEnd = VisMono_DesaturateDList(dList); + } + + gDPPipeSync(gfx++); + + if (this->setScissor == true) { + gSPDisplayList(gfx++, D_0E000000.setScissor); + } + + gDPSetColor(gfx++, G_SETPRIMCOLOR, this->primColor.rgba); + gDPSetColor(gfx++, G_SETENVCOLOR, this->envColor.rgba); + + gDPLoadTLUT_pal256(gfx++, tlut); + + gSPDisplayList(gfx++, dList); + + gDPPipeSync(gfx++); + + *gfxp = gfx; +} + +void VisMono_DrawOld(VisMono* this) { + if (this->tlut == NULL) { + this->tlut = SystemArena_Malloc(256 * G_IM_SIZ_16b_BYTES); + VisMono_DesaturateTLUT(this->tlut); + } + + if (this->dList == NULL) { + this->dList = SystemArena_Malloc(VISMONO_DLSIZE * sizeof(Gfx)); + VisMono_DesaturateDList(this->dList); + } +} diff --git a/src/overlays/fbdemos/ovl_fbdemo_wipe5/z_fbdemo_wipe5.c b/src/overlays/fbdemos/ovl_fbdemo_wipe5/z_fbdemo_wipe5.c index 4c27fe134..87f5638ac 100644 --- a/src/overlays/fbdemos/ovl_fbdemo_wipe5/z_fbdemo_wipe5.c +++ b/src/overlays/fbdemos/ovl_fbdemo_wipe5/z_fbdemo_wipe5.c @@ -31,7 +31,7 @@ const TransitionInit TransitionWipe5_InitVars = { #endif -extern UNK_TYPE D_0F000000; +extern u16 D_0F000000[]; #pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_fbdemo_wipe5/TransitionWipe5_Start.s") diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index 5989a3114..a0eae0028 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -2769,12 +2769,12 @@ 0x8014151C:("func_8014151C",), 0x80141678:("func_80141678",), 0x80141778:("func_80141778",), - 0x801418B0:("func_801418B0",), - 0x80141900:("func_80141900",), - 0x80141924:("func_80141924",), - 0x80141C34:("func_80141C34",), + 0x801418B0:("VisMono_Init",), + 0x80141900:("VisMono_Destroy",), + 0x80141924:("VisMono_DesaturateTLUT",), + 0x80141C34:("VisMono_DesaturateDList",), 0x80141E60:("VisMono_Draw",), - 0x8014204C:("func_8014204C",), + 0x8014204C:("VisMono_DrawOld",), 0x801420C0:("func_801420C0",), 0x801420F4:("func_801420F4",), 0x80142100:("func_80142100",), diff --git a/tools/sizes/code_functions.csv b/tools/sizes/code_functions.csv index 5b7c0d71d..bb57bb8a8 100644 --- a/tools/sizes/code_functions.csv +++ b/tools/sizes/code_functions.csv @@ -2283,12 +2283,12 @@ asm/non_matchings/code/code_80140E80/func_80141200.s,func_80141200,0x80141200,0x asm/non_matchings/code/code_80140E80/func_8014151C.s,func_8014151C,0x8014151C,0x57 asm/non_matchings/code/code_80140E80/func_80141678.s,func_80141678,0x80141678,0x40 asm/non_matchings/code/code_80140E80/func_80141778.s,func_80141778,0x80141778,0x4E -asm/non_matchings/code/z_vismono/func_801418B0.s,func_801418B0,0x801418B0,0x14 -asm/non_matchings/code/z_vismono/func_80141900.s,func_80141900,0x80141900,0x9 -asm/non_matchings/code/z_vismono/func_80141924.s,func_80141924,0x80141924,0xC4 -asm/non_matchings/code/z_vismono/func_80141C34.s,func_80141C34,0x80141C34,0x8B +asm/non_matchings/code/z_vismono/VisMono_Init.s,VisMono_Init,0x801418B0,0x14 +asm/non_matchings/code/z_vismono/VisMono_Destroy.s,VisMono_Destroy,0x80141900,0x9 +asm/non_matchings/code/z_vismono/VisMono_DesaturateTLUT.s,VisMono_DesaturateTLUT,0x80141924,0xC4 +asm/non_matchings/code/z_vismono/VisMono_DesaturateDList.s,VisMono_DesaturateDList,0x80141C34,0x8B asm/non_matchings/code/z_vismono/VisMono_Draw.s,VisMono_Draw,0x80141E60,0x7B -asm/non_matchings/code/z_vismono/func_8014204C.s,func_8014204C,0x8014204C,0x1D +asm/non_matchings/code/z_vismono/VisMono_DrawOld.s,VisMono_DrawOld,0x8014204C,0x1D asm/non_matchings/code/code_801420C0/func_801420C0.s,func_801420C0,0x801420C0,0xD asm/non_matchings/code/code_801420C0/func_801420F4.s,func_801420F4,0x801420F4,0x3 asm/non_matchings/code/code_801420C0/func_80142100.s,func_80142100,0x80142100,0xD0