From 9c10ee1d28a45e7373af455f59c5e66235be30ee Mon Sep 17 00:00:00 2001 From: Derek Hensley Date: Sat, 20 Jan 2024 16:04:28 -0800 Subject: [PATCH] Framebuffer filter docs (#1528) * Framebuffer filter docs * PR * Format * Leading 0s --- include/variables.h | 2 +- include/z64vis.h | 87 +++++++++++++++++++++++++++++++ include/z64viscvg.h | 18 ------- include/z64vismono.h | 20 -------- include/z64viszbuf.h | 18 ------- src/code/game.c | 67 ++++++++++++------------ src/code/z_demo.c | 16 +++--- src/code/z_play.c | 10 ++-- src/code/z_viscvg.c | 93 ++++++++++++++++++++++++---------- src/code/z_vismono.c | 52 ++++++++++--------- src/code/z_viszbuf.c | 81 ++++++++++++++++++++++------- tools/disasm/functions.txt | 6 +-- tools/disasm/variables.txt | 12 ++--- tools/sizes/code_functions.csv | 6 +-- 14 files changed, 305 insertions(+), 183 deletions(-) create mode 100644 include/z64vis.h delete mode 100644 include/z64viscvg.h delete mode 100644 include/z64vismono.h delete mode 100644 include/z64viszbuf.h diff --git a/include/variables.h b/include/variables.h index ff1d6690d3..44f56a8d6f 100644 --- a/include/variables.h +++ b/include/variables.h @@ -1432,7 +1432,7 @@ extern void (*sKaleidoScopeUpdateFunc)(PlayState* play); extern void (*sKaleidoScopeDrawFunc)(PlayState* play); extern s32 gTransitionTileState; -extern Color_RGBA8_u32 gVisMonoColor; +extern Color_RGBA8_u32 gPlayVisMonoColor; extern GfxMasterList* gGfxMasterDL; diff --git a/include/z64vis.h b/include/z64vis.h new file mode 100644 index 0000000000..46071a1e9a --- /dev/null +++ b/include/z64vis.h @@ -0,0 +1,87 @@ +#ifndef Z64_VIS_H +#define Z64_VIS_H + +#include "ultra64.h" +#include "color.h" + +typedef enum FramebufferFilterType { + /* 0 */ FB_FILTER_NONE, + /* 1 */ FB_FILTER_CVG_RGB, + /* 2 */ FB_FILTER_CVG_RGB_UNIFORM, + /* 3 */ FB_FILTER_CVG_ONLY, + /* 4 */ FB_FILTER_CVG_RGB_FOG, // Not recommended, easily overflows blender + /* 5 */ FB_FILTER_ZBUF_IA, + /* 6 */ FB_FILTER_ZBUF_RGBA, + /* 7 */ FB_FILTER_MONO +} FramebufferFilterType; + +typedef enum VisScissorType { + /* 0 */ VIS_NO_SETSCISSOR, + /* 1 */ VIS_SETSCISSOR +} VisScissorType; + +typedef struct Vis { + /* 0x0 */ u32 type; + /* 0x4 */ u32 scissorType; + /* 0x8 */ Color_RGBA8_u32 primColor; + /* 0xC */ Color_RGBA8_u32 envColor; +} Vis; // size = 0x10 + + + +/* Cvg: Coverage */ + +#define FB_FILTER_TO_CVG_TYPE(filter) (filter) + +typedef enum VisCvgType { + /* 0 */ VIS_CVG_TYPE_NONE = FB_FILTER_TO_CVG_TYPE(FB_FILTER_NONE), + /* 1 */ VIS_CVG_TYPE_CVG_RGB = FB_FILTER_TO_CVG_TYPE(FB_FILTER_CVG_RGB), + /* 2 */ VIS_CVG_TYPE_CVG_RGB_UNIFORM = FB_FILTER_TO_CVG_TYPE(FB_FILTER_CVG_RGB_UNIFORM), + /* 3 */ VIS_CVG_TYPE_CVG_ONLY = FB_FILTER_TO_CVG_TYPE(FB_FILTER_CVG_ONLY), + /* 4 */ VIS_CVG_TYPE_CVG_RGB_FOG = FB_FILTER_TO_CVG_TYPE(FB_FILTER_CVG_RGB_FOG) +} VisCvgType; + +typedef struct VisCvg { + /* 0x0 */ Vis vis; +} VisCvg; // size = 0x10 + +void VisCvg_Init(VisCvg* this); +void VisCvg_Destroy(VisCvg* this); +void VisCvg_Draw(VisCvg* this, Gfx** gfxP); + + + +/* Mono: Desaturation */ + +// Only one type + +typedef struct VisMono { + /* 0x00 */ Vis vis; + /* 0x10 */ u16* tlut; + /* 0x14 */ Gfx* dList; +} VisMono; // size = 0x18 + +void VisMono_Init(VisMono* this); +void VisMono_Destroy(VisMono* this); +void VisMono_Draw(VisMono* this, Gfx** gfxP); + + + +/* ZBuf: Z-Buffer */ + +#define FB_FILTER_TO_ZBUF_TYPE(filter) ((filter) - FB_FILTER_ZBUF_IA) + +typedef enum VisZBufType { + /* 0 */ VIS_ZBUF_TYPE_IA = FB_FILTER_TO_ZBUF_TYPE(FB_FILTER_ZBUF_IA), + /* 1 */ VIS_ZBUF_TYPE_RGBA = FB_FILTER_TO_ZBUF_TYPE(FB_FILTER_ZBUF_RGBA) +} VisZBufType; + +typedef struct VisZBuf { + /* 0x0 */ Vis vis; +} VisZBuf; // size = 0x10 + +void VisZBuf_Init(VisZBuf* this); +void VisZBuf_Destroy(VisZBuf* this); +void VisZBuf_Draw(VisZBuf* this, Gfx** gfxP, void* zbuffer); + +#endif diff --git a/include/z64viscvg.h b/include/z64viscvg.h deleted file mode 100644 index 354cf2a141..0000000000 --- a/include/z64viscvg.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef Z64_VISCVG_H -#define Z64_VISCVG_H - -#include "ultra64.h" -#include "color.h" - -typedef struct VisCvg { - /* 0x0 */ u32 type; - /* 0x4 */ u32 setScissor; - /* 0x8 */ Color_RGBA8_u32 color; - /* 0xC */ Color_RGBA8 envColor; -} VisCvg; // size = 0x10 - -void VisCvg_Init(VisCvg* this); -void VisCvg_Destroy(VisCvg* this); -void VisCvg_Draw(VisCvg* this, Gfx** gfxp); - -#endif diff --git a/include/z64vismono.h b/include/z64vismono.h deleted file mode 100644 index 9965034a8c..0000000000 --- a/include/z64vismono.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef Z64_VISMONO_H -#define Z64_VISMONO_H - -#include "ultra64.h" -#include "color.h" - -typedef struct VisMono { - /* 0x00 */ u32 unk_00; - /* 0x04 */ u32 setScissor; - /* 0x08 */ Color_RGBA8_u32 primColor; - /* 0x0C */ Color_RGBA8_u32 envColor; - /* 0x10 */ u16* tlut; - /* 0x14 */ Gfx* dList; -} VisMono; // size = 0x18 - -void VisMono_Init(VisMono* this); -void VisMono_Destroy(VisMono* this); -void VisMono_Draw(VisMono* this, Gfx** gfxp); - -#endif diff --git a/include/z64viszbuf.h b/include/z64viszbuf.h deleted file mode 100644 index ea68b34ceb..0000000000 --- a/include/z64viszbuf.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef Z64_VISZBUF_H -#define Z64_VISZBUF_H - -#include "ultra64.h" -#include "color.h" - -typedef struct VisZbuf { - /* 0x0 */ u32 useRgba; - /* 0x4 */ u32 setScissor; - /* 0x8 */ Color_RGBA8_u32 primColor; - /* 0xC */ Color_RGBA8_u32 envColor; -} VisZbuf; // size = 0x10 - -void VisZbuf_Init(VisZbuf* this); -void VisZbuf_Destroy(VisZbuf* this); -void VisZbuf_Draw(VisZbuf* this, Gfx** gfxP, void* zbuffer); - -#endif diff --git a/src/code/game.c b/src/code/game.c index 0179062f45..908a0c315a 100644 --- a/src/code/game.c +++ b/src/code/game.c @@ -7,9 +7,7 @@ #include "z64rumble.h" #include "z64speed_meter.h" #include "z64vimode.h" -#include "z64viscvg.h" -#include "z64vismono.h" -#include "z64viszbuf.h" +#include "z64vis.h" #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" #include "debug.h" @@ -20,7 +18,7 @@ f32 gFramerateDivisorThird = 1.0f / 3.0f; SpeedMeter sGameSpeedMeter; VisCvg sGameVisCvg; -VisZbuf sGameVisZbuf; +VisZBuf sGameVisZBuf; VisMono sGameVisMono; ViMode sGameViMode; @@ -40,34 +38,37 @@ void GameState_SetFramerateDivisor(GameState* gameState, s32 divisor) { void GameState_SetFBFilter(Gfx** gfxP, void* zbuffer) { Gfx* gfx = *gfxP; - if ((R_FB_FILTER_TYPE > 0) && (R_FB_FILTER_TYPE < 5)) { - sGameVisCvg.type = R_FB_FILTER_TYPE; - sGameVisCvg.color.r = R_FB_FILTER_PRIM_COLOR(0); - sGameVisCvg.color.g = R_FB_FILTER_PRIM_COLOR(1); - sGameVisCvg.color.b = R_FB_FILTER_PRIM_COLOR(2); - sGameVisCvg.color.a = R_FB_FILTER_A; + if ((R_FB_FILTER_TYPE >= FB_FILTER_CVG_RGB) && (R_FB_FILTER_TYPE <= FB_FILTER_CVG_RGB_FOG)) { + // Visualize coverage + sGameVisCvg.vis.type = FB_FILTER_TO_CVG_TYPE(R_FB_FILTER_TYPE); + sGameVisCvg.vis.primColor.r = R_FB_FILTER_PRIM_COLOR(0); + sGameVisCvg.vis.primColor.g = R_FB_FILTER_PRIM_COLOR(1); + sGameVisCvg.vis.primColor.b = R_FB_FILTER_PRIM_COLOR(2); + sGameVisCvg.vis.primColor.a = R_FB_FILTER_A; VisCvg_Draw(&sGameVisCvg, &gfx); - } else if ((R_FB_FILTER_TYPE == 5) || (R_FB_FILTER_TYPE == 6)) { - sGameVisZbuf.useRgba = (R_FB_FILTER_TYPE == 6); - sGameVisZbuf.primColor.r = R_FB_FILTER_PRIM_COLOR(0); - sGameVisZbuf.primColor.g = R_FB_FILTER_PRIM_COLOR(1); - sGameVisZbuf.primColor.b = R_FB_FILTER_PRIM_COLOR(2); - sGameVisZbuf.primColor.a = R_FB_FILTER_A; - sGameVisZbuf.envColor.r = R_FB_FILTER_ENV_COLOR(0); - sGameVisZbuf.envColor.g = R_FB_FILTER_ENV_COLOR(1); - sGameVisZbuf.envColor.b = R_FB_FILTER_ENV_COLOR(2); - sGameVisZbuf.envColor.a = R_FB_FILTER_A; - VisZbuf_Draw(&sGameVisZbuf, &gfx, zbuffer); - } else if (R_FB_FILTER_TYPE == 7) { - sGameVisMono.unk_00 = 0; - sGameVisMono.primColor.r = R_FB_FILTER_PRIM_COLOR(0); - sGameVisMono.primColor.g = R_FB_FILTER_PRIM_COLOR(1); - sGameVisMono.primColor.b = R_FB_FILTER_PRIM_COLOR(2); - sGameVisMono.primColor.a = R_FB_FILTER_A; - sGameVisMono.envColor.r = R_FB_FILTER_ENV_COLOR(0); - sGameVisMono.envColor.g = R_FB_FILTER_ENV_COLOR(1); - sGameVisMono.envColor.b = R_FB_FILTER_ENV_COLOR(2); - sGameVisMono.envColor.a = R_FB_FILTER_A; + } else if ((R_FB_FILTER_TYPE == FB_FILTER_ZBUF_IA) || (R_FB_FILTER_TYPE == FB_FILTER_ZBUF_RGBA)) { + // Visualize z-buffer + sGameVisZBuf.vis.type = (R_FB_FILTER_TYPE == FB_FILTER_ZBUF_RGBA); + sGameVisZBuf.vis.primColor.r = R_FB_FILTER_PRIM_COLOR(0); + sGameVisZBuf.vis.primColor.g = R_FB_FILTER_PRIM_COLOR(1); + sGameVisZBuf.vis.primColor.b = R_FB_FILTER_PRIM_COLOR(2); + sGameVisZBuf.vis.primColor.a = R_FB_FILTER_A; + sGameVisZBuf.vis.envColor.r = R_FB_FILTER_ENV_COLOR(0); + sGameVisZBuf.vis.envColor.g = R_FB_FILTER_ENV_COLOR(1); + sGameVisZBuf.vis.envColor.b = R_FB_FILTER_ENV_COLOR(2); + sGameVisZBuf.vis.envColor.a = R_FB_FILTER_A; + VisZBuf_Draw(&sGameVisZBuf, &gfx, zbuffer); + } else if (R_FB_FILTER_TYPE == FB_FILTER_MONO) { + // Monochrome filter + sGameVisMono.vis.type = 0; + sGameVisMono.vis.primColor.r = R_FB_FILTER_PRIM_COLOR(0); + sGameVisMono.vis.primColor.g = R_FB_FILTER_PRIM_COLOR(1); + sGameVisMono.vis.primColor.b = R_FB_FILTER_PRIM_COLOR(2); + sGameVisMono.vis.primColor.a = R_FB_FILTER_A; + sGameVisMono.vis.envColor.r = R_FB_FILTER_ENV_COLOR(0); + sGameVisMono.vis.envColor.g = R_FB_FILTER_ENV_COLOR(1); + sGameVisMono.vis.envColor.b = R_FB_FILTER_ENV_COLOR(2); + sGameVisMono.vis.envColor.a = R_FB_FILTER_A; VisMono_Draw(&sGameVisMono, &gfx); } @@ -222,7 +223,7 @@ void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* g init(gameState); VisCvg_Init(&sGameVisCvg); - VisZbuf_Init(&sGameVisZbuf); + VisZBuf_Init(&sGameVisZBuf); VisMono_Init(&sGameVisMono); ViMode_Init(&sGameViMode); SpeedMeter_Init(&sGameSpeedMeter); @@ -243,7 +244,7 @@ void GameState_Destroy(GameState* gameState) { Rumble_Destroy(); SpeedMeter_Destroy(&sGameSpeedMeter); VisCvg_Destroy(&sGameVisCvg); - VisZbuf_Destroy(&sGameVisZbuf); + VisZBuf_Destroy(&sGameVisZBuf); VisMono_Destroy(&sGameVisMono); ViMode_Destroy(&sGameViMode); THA_Destroy(&gameState->tha); diff --git a/src/code/z_demo.c b/src/code/z_demo.c index 985b3c240c..e9264ec847 100644 --- a/src/code/z_demo.c +++ b/src/code/z_demo.c @@ -219,17 +219,17 @@ void CutsceneCmd_Misc(PlayState* play, CutsceneContext* csCtx, CsCmdMisc* cmd) { break; case CS_MISC_VISMONO_BLACK_AND_WHITE: - gVisMonoColor.r = 255; - gVisMonoColor.g = 255; - gVisMonoColor.b = 255; - gVisMonoColor.a = 255 * lerp; + gPlayVisMonoColor.r = 255; + gPlayVisMonoColor.g = 255; + gPlayVisMonoColor.b = 255; + gPlayVisMonoColor.a = 255 * lerp; break; case CS_MISC_VISMONO_SEPIA: - gVisMonoColor.r = 255; - gVisMonoColor.g = 180; - gVisMonoColor.b = 100; - gVisMonoColor.a = 255 * lerp; + gPlayVisMonoColor.r = 255; + gPlayVisMonoColor.g = 180; + gPlayVisMonoColor.b = 100; + gPlayVisMonoColor.a = 255 * lerp; break; case CS_MISC_HIDE_ROOM: diff --git a/src/code/z_play.c b/src/code/z_play.c index 38a9ede2aa..12357f59a2 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -2,7 +2,7 @@ #include "regs.h" #include "functions.h" #include "z64malloc.h" -#include "z64vismono.h" +#include "z64vis.h" #include "z64visfbuf.h" // Variables are put before most headers as a hacky way to bypass bss reordering @@ -11,7 +11,7 @@ Input D_801F6C18; TransitionTile sTransitionTile; s32 gTransitionTileState; VisMono sPlayVisMono; -Color_RGBA8_u32 gVisMonoColor; +Color_RGBA8_u32 gPlayVisMonoColor; VisFbuf sPlayVisFbuf; VisFbuf* sPlayVisFbufInstance; BombersNotebook sBombersNotebook; @@ -1232,8 +1232,8 @@ void Play_DrawMain(PlayState* this) { TransitionFade_Draw(&this->unk_18E48, &sp218); - if (gVisMonoColor.a != 0) { - sPlayVisMono.primColor.rgba = gVisMonoColor.rgba; + if (gPlayVisMonoColor.a != 0) { + sPlayVisMono.vis.primColor.rgba = gPlayVisMonoColor.rgba; VisMono_Draw(&sPlayVisMono, &sp218); } @@ -2301,7 +2301,7 @@ void Play_Init(GameState* thisx) { TransitionFade_Start(&this->unk_18E48); VisMono_Init(&sPlayVisMono); - gVisMonoColor.a = 0; + gPlayVisMonoColor.a = 0; sPlayVisFbufInstance = &sPlayVisFbuf; VisFbuf_Init(sPlayVisFbufInstance); sPlayVisFbufInstance->lodProportion = 0.0f; diff --git a/src/code/z_viscvg.c b/src/code/z_viscvg.c index 1821805ee8..739af628fd 100644 --- a/src/code/z_viscvg.c +++ b/src/code/z_viscvg.c @@ -1,14 +1,43 @@ +/** + * @file z_viscvg.c + * + * This file implements full-screen frame buffer effects involving the visualization of Coverage in various ways. + * + * Coverage is roughly how much of a pixel is covered by a primitive; the final coverage for a frame is stored in the + * color image alpha component where it is used for antialiasing, see PreRender.c and ยง15 of the programming manual for + * details. + * + * To understand this file, it is helpful to remember that A_MEM is essentially synonymous with coverage, and that + * `GBL_c1/2(p, a, m, b)` usually represents the RDP blender calculation `(p * a + m * b)`. + * Note the division step that is often included in the blender calculation is omitted; the division is skipped if + * force blending (FORCE_BL) is set, which is the case for all render modes used in this file. + * + * Coverage is full when not on an edge, while on an edge it is usually lower. Since coverage is treated as an alpha + * value, edges of primitives where coverage is lower will show up darker than primitive interiors in all of the + * available modes. + * + * Coverage is abbreviated to "cvg"; "FB RGB" ("framebuffer red/green/blue") is the color the pixel originally had + * before the filter is applied. + */ +#include "z64vis.h" #include "global.h" -#include "z64viscvg.h" -Gfx D_801C5DD0[] = { +/** + * Draws only coverage: does not retain any of the original pixel RGB, primColor is used as background color. + */ +Gfx sCoverageOnlyDL[] = { gsDPSetOtherMode(G_AD_PATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_CONV | G_TF_POINT | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PRIM | G_RM_VISCVG | G_RM_VISCVG2), gsSPBranchList(D_0E000000.fillRect), }; -Gfx D_801C5DE0[] = { +/** + * Draws fog + coverage * RGB of pixels + * + * @bug This easily overflows the blender because the fog value is added to the coverage value. + */ +Gfx sCoverageRGBFogDL[] = { gsDPSetOtherMode(G_AD_PATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_CONV | G_TF_POINT | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PRIM | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | @@ -17,7 +46,10 @@ Gfx D_801C5DE0[] = { gsSPBranchList(D_0E000000.fillRect), }; -Gfx D_801C5DF0[] = { +/** + * Draws coverage and RGB of pixels + */ +Gfx sCoverageRGBDL[] = { gsDPSetOtherMode(G_AD_PATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_CONV | G_TF_POINT | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PRIM | IM_RD | CVG_DST_CLAMP | ZMODE_OPA | FORCE_BL | @@ -26,7 +58,14 @@ Gfx D_801C5DF0[] = { gsSPBranchList(D_0E000000.fillRect), }; -Gfx D_801C5E00[] = { +/** + * Two stage filtering: + * + * 1. Apply a uniform color filter by transparently blending primColor with original frame. The "cloud surface" + * RenderMode is used to preserve the coverage for the second stage. + * 2. Second half is the same as `sCoverageRGBDL`'s, i.e. (RGB from stage 1) * cvg + */ +Gfx sCoverageRGBUniformDL[] = { gsDPSetCombineMode(G_CC_PRIMITIVE, G_CC_PRIMITIVE), gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_DISABLE | G_CK_NONE | G_TC_CONV | G_TF_POINT | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, @@ -41,45 +80,45 @@ Gfx D_801C5E00[] = { }; void VisCvg_Init(VisCvg* this) { - this->type = 0; - this->setScissor = false; - this->color.r = 255; - this->color.g = 255; - this->color.b = 255; - this->color.a = 255; + this->vis.type = VIS_CVG_TYPE_NONE; + this->vis.scissorType = VIS_NO_SETSCISSOR; + this->vis.primColor.r = 255; + this->vis.primColor.g = 255; + this->vis.primColor.b = 255; + this->vis.primColor.a = 255; } void VisCvg_Destroy(VisCvg* this) { } -void VisCvg_Draw(VisCvg* this, Gfx** gfxp) { - Gfx* gfx = *gfxp; +void VisCvg_Draw(VisCvg* this, Gfx** gfxP) { + Gfx* gfx = *gfxP; gDPPipeSync(gfx++); gDPSetPrimDepth(gfx++, -1, -1); - if (this->setScissor == true) { + if (this->vis.scissorType == VIS_SETSCISSOR) { gSPDisplayList(gfx++, D_0E000000.setScissor); } - switch (this->type) { - case 1: - gSPDisplayList(gfx++, D_801C5DF0); + switch (this->vis.type) { + case VIS_CVG_TYPE_CVG_RGB: + gSPDisplayList(gfx++, sCoverageRGBDL); break; - case 2: - gDPSetColor(gfx++, G_SETPRIMCOLOR, this->color.rgba); - gSPDisplayList(gfx++, D_801C5E00); + case VIS_CVG_TYPE_CVG_RGB_UNIFORM: + gDPSetColor(gfx++, G_SETPRIMCOLOR, this->vis.primColor.rgba); + gSPDisplayList(gfx++, sCoverageRGBUniformDL); break; - case 3: - gDPSetColor(gfx++, G_SETBLENDCOLOR, this->color.rgba); - gSPDisplayList(gfx++, D_801C5DD0); + case VIS_CVG_TYPE_CVG_ONLY: + gDPSetColor(gfx++, G_SETBLENDCOLOR, this->vis.primColor.rgba); + gSPDisplayList(gfx++, sCoverageOnlyDL); break; - case 4: - gDPSetColor(gfx++, G_SETFOGCOLOR, this->color.rgba); - gSPDisplayList(gfx++, D_801C5DE0); + case VIS_CVG_TYPE_CVG_RGB_FOG: + gDPSetColor(gfx++, G_SETFOGCOLOR, this->vis.primColor.rgba); + gSPDisplayList(gfx++, sCoverageRGBFogDL); break; default: @@ -87,5 +126,5 @@ void VisCvg_Draw(VisCvg* this, Gfx** gfxp) { } gDPPipeSync(gfx++); - *gfxp = gfx; + *gfxP = gfx; } diff --git a/src/code/z_vismono.c b/src/code/z_vismono.c index d4c462fc47..5e4330786e 100644 --- a/src/code/z_vismono.c +++ b/src/code/z_vismono.c @@ -1,16 +1,20 @@ -/* - * File: z_vismono.c - * Description: Color frame buffer effect to desaturate the colors. +/** + * @file z_vismono.c + * + * This file implements a full-screen framebuffer effect for desaturating the contents of the framebuffer image. + * + * Broadly, this effect is achieved by reinterpreting the contents of the RGBA16 color image as indices into an IA16 + * color palette that converts each color into the desaturated equivalent. More precise details can be found in inline + * comments. */ - +#include "z64vis.h" #include "global.h" -#include "z64vismono.h" #include "libc64/malloc.h" // 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)) +// the half of TMEM dedicated to color-indexed data. +#define VISMONO_CFBFRAG_HEIGHT ((TMEM_SIZE / 2) / (SCREEN_WIDTH * G_IM_SIZ_16b_BYTES)) // Maximum size of the dlist written by `VisMono_DesaturateDList`. // `VisMono_DesaturateDList` consistently uses `VISMONO_DLSIZE - 2` double words, so this can be 2 less. @@ -26,16 +30,16 @@ 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; + this->vis.type = 0; + this->vis.scissorType = VIS_NO_SETSCISSOR; + this->vis.primColor.r = 255; + this->vis.primColor.g = 255; + this->vis.primColor.b = 255; + this->vis.primColor.a = 255; + this->vis.envColor.r = 0; + this->vis.envColor.g = 0; + this->vis.envColor.b = 0; + this->vis.envColor.a = 0; } void VisMono_Destroy(VisMono* this) { @@ -95,6 +99,8 @@ Gfx* VisMono_DesaturateDList(Gfx* gfx) { // 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 + // Note the palette index for this tile has also been incremented from 0 to 1, however the palette index is + // ignored for CI8 texture sampling. 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); @@ -129,8 +135,8 @@ Gfx* VisMono_DesaturateDList(Gfx* gfx) { return gfx; } -void VisMono_Draw(VisMono* this, Gfx** gfxp) { - Gfx* gfx = *gfxp; +void VisMono_Draw(VisMono* this, Gfx** gfxP) { + Gfx* gfx = *gfxP; u16* tlut; Gfx* dList; Gfx* dListEnd; @@ -151,12 +157,12 @@ void VisMono_Draw(VisMono* this, Gfx** gfxp) { gDPPipeSync(gfx++); - if (this->setScissor == true) { + if (this->vis.scissorType == VIS_SETSCISSOR) { gSPDisplayList(gfx++, D_0E000000.setScissor); } - gDPSetColor(gfx++, G_SETPRIMCOLOR, this->primColor.rgba); - gDPSetColor(gfx++, G_SETENVCOLOR, this->envColor.rgba); + gDPSetColor(gfx++, G_SETPRIMCOLOR, this->vis.primColor.rgba); + gDPSetColor(gfx++, G_SETENVCOLOR, this->vis.envColor.rgba); gDPLoadTLUT_pal256(gfx++, tlut); @@ -164,7 +170,7 @@ void VisMono_Draw(VisMono* this, Gfx** gfxp) { gDPPipeSync(gfx++); - *gfxp = gfx; + *gfxP = gfx; } void VisMono_DrawOld(VisMono* this) { diff --git a/src/code/z_viszbuf.c b/src/code/z_viszbuf.c index 17c734cb07..86fb644749 100644 --- a/src/code/z_viszbuf.c +++ b/src/code/z_viszbuf.c @@ -1,55 +1,100 @@ +/** + * @file z_viszbuf.c + * + * This file implements a full-screen framebuffer effect for visualizing the z-buffer (AKA depth buffer), using either + * cycling RGBA or a single fading color. + * + * This is done by reading the z-buffer as if it were a color image, the format of which is specified by the selected + * vis type: + * - VIS_ZBUF_TYPE_IA : Produces a monotonic fade from primColor to envColor as depth increases. + * - VIS_ZBUF_TYPE_RGBA : Produces vibrant almost-periodic-looking bands. + * + * In both cases this occurs because of the format the depth information takes: it is 18-bit, and is a nonnegative + * floating-point number with + * bbb mmmmmmmmmmm dd|dd + * exponent mantissa dz value (only first 16 bits visible to CPU, the least significant 2 bits of dz are ignored) + * + * Reading z-buffer as IA16: + * bbbmmmmm mmmmmmdd + * iiiiiiii aaaaaaaa + * + * Since floating-point numbers of this format have the same ordering as their binary/hex representation, increasing + * the depth also increases the intensity in the IA16 representation and hence the interpolation parameter used to + * combine primColor and envColor. The alpha is ignored by the RenderMode. + * + * Reading z-buffer as RGBA16: + * bbbmm mmmmm mmmmd d + * rrrrr ggggg bbbbb a + * + * The red increases monotonically with the depth. The significant visible oscillation is the green component, because + * it rolls over every time the second-most-significant bit of the mantissa increments. The blue component oscillates + * too rapidly to be particularly visible (it rolls over when the 7th-most-significant bit increments). The alpha is + * again ignored by the RenderMode. + */ +#include "z64vis.h" #include "global.h" -#include "z64viszbuf.h" #include "sys_cfb.h" #include "libc/stdbool.h" +// Height of the fragments the z-buffer is split into. +// It is the maximum amount of lines such that all rgba16 SCREEN_WIDTH-long lines fit into TMEM. #define VISZBUF_ZBUFFRAG_HEIGHT (TMEM_SIZE / (gCfbWidth * G_IM_SIZ_16b_BYTES)) -void VisZbuf_Init(VisZbuf* this) { - this->useRgba = false; - 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 = 255; +/** + * Initialise to IA type with white and black as default colors. + */ +void VisZBuf_Init(VisZBuf* this) { + this->vis.type = VIS_ZBUF_TYPE_IA; + this->vis.scissorType = VIS_NO_SETSCISSOR; + this->vis.primColor.r = 255; + this->vis.primColor.g = 255; + this->vis.primColor.b = 255; + this->vis.primColor.a = 255; + this->vis.envColor.r = 0; + this->vis.envColor.g = 0; + this->vis.envColor.b = 0; + this->vis.envColor.a = 255; } -void VisZbuf_Destroy(VisZbuf* this) { +void VisZBuf_Destroy(VisZBuf* this) { } -void VisZbuf_Draw(VisZbuf* this, Gfx** gfxP, void* zbuffer) { +void VisZBuf_Draw(VisZBuf* this, Gfx** gfxP, void* zbuffer) { Gfx* gfx = *gfxP; s32 height = VISZBUF_ZBUFFRAG_HEIGHT; s32 y; - s32 fmt = !this->useRgba ? G_IM_FMT_IA : G_IM_FMT_RGBA; + s32 fmt = (this->vis.type == VIS_ZBUF_TYPE_IA) ? G_IM_FMT_IA : G_IM_FMT_RGBA; if (zbuffer == NULL) { return; } gDPPipeSync(gfx++); - if (this->setScissor == true) { + if (this->vis.scissorType == VIS_SETSCISSOR) { gSPDisplayList(gfx++, D_0E000000.setScissor); } + // No palette so can use all of TMEM. + // G_RM_OPA_SURF discards all information previously in the pixel, and the current alpha, leaving only the color + // from this filter. gDPSetOtherMode(gfx++, G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PRIM | G_RM_OPA_SURF | G_RM_OPA_SURF2); + + // LERP between primColor and envColor in 1-cycle mode using the z-buffer value. gDPSetCombineLERP(gfx++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT); - gDPSetColor(gfx++, G_SETPRIMCOLOR, this->primColor.rgba); - gDPSetColor(gfx++, G_SETENVCOLOR, this->envColor.rgba); + gDPSetColor(gfx++, G_SETPRIMCOLOR, this->vis.primColor.rgba); + gDPSetColor(gfx++, G_SETENVCOLOR, this->vis.envColor.rgba); for (y = 0; y < (gCfbHeight - height) + 1; y += height) { + // Load a few lines of the z-buffer, as many as can fit in TMEM at once. gDPLoadTextureTile(gfx++, zbuffer, fmt, G_IM_SIZ_16b, gCfbWidth, 0, 0, y, gCfbWidth - 1, (y + height) - 1, 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); + // Overwrite them with the calculated colors. gSPTextureRectangle(gfx++, 0, y << 2, gCfbWidth << 2, (y + height) << 2, G_TX_RENDERTILE, 0, y << 5, 1 << 10, 1 << 10); } diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index e3f55e876e..20a297f379 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -2775,9 +2775,9 @@ 0x80141C34:("VisMono_DesaturateDList",), 0x80141E60:("VisMono_Draw",), 0x8014204C:("VisMono_DrawOld",), - 0x801420C0:("VisZbuf_Init",), - 0x801420F4:("VisZbuf_Destroy",), - 0x80142100:("VisZbuf_Draw",), + 0x801420C0:("VisZBuf_Init",), + 0x801420F4:("VisZBuf_Destroy",), + 0x80142100:("VisZBuf_Draw",), 0x80142440:("Skybox_CalculateFace128",), 0x80143148:("Skybox_Calculate128",), 0x801431E8:("Skybox_Setup",), diff --git a/tools/disasm/variables.txt b/tools/disasm/variables.txt index b2bf6393d0..d2e29913b7 100644 --- a/tools/disasm/variables.txt +++ b/tools/disasm/variables.txt @@ -1897,10 +1897,10 @@ 0x801C5D60:("gShadowMaterialDL","UNK_TYPE1","",0x1), 0x801C5D80:("gShadowModelDL","UNK_TYPE1","",0x1), 0x801C5DB0:("gOneVec3f","UNK_TYPE1","",0x1), - 0x801C5DD0:("D_801C5DD0","UNK_TYPE1","",0x1), - 0x801C5DE0:("D_801C5DE0","UNK_TYPE1","",0x1), - 0x801C5DF0:("D_801C5DF0","UNK_TYPE1","",0x1), - 0x801C5E00:("D_801C5E00","UNK_TYPE1","",0x1), + 0x801C5DD0:("sCoverageOnlyDL","UNK_TYPE1","",0x1), + 0x801C5DE0:("sCoverageRGBFogDL","UNK_TYPE1","",0x1), + 0x801C5DF0:("sCoverageRGBDL","UNK_TYPE1","",0x1), + 0x801C5E00:("sCoverageRGBUniformDL","UNK_TYPE1","",0x1), 0x801C5E30:("sSkybox128TexOffsets","UNK_TYPE1","",0x1), 0x801C5E48:("sSkybox128VtxBufIndices","UNK_TYPE2","",0x2), 0x801C5E88:("sSkybox128TexSCoords","UNK_TYPE4","",0x4), @@ -3973,7 +3973,7 @@ 0x801F6C30:("sTransitionTile","TransitionTile","",0xE0), 0x801F6D10:("gTransitionTileState","UNK_TYPE4","",0x4), 0x801F6D18:("sPlayVisMono","VisMono","",0x18), - 0x801F6D30:("gVisMonoColor","Color_RGBA8","",0x4), + 0x801F6D30:("gPlayVisMonoColor","Color_RGBA8","",0x4), 0x801F6D38:("sPlayVisFbuf","UNK_TYPE1","",0x1), 0x801F6D4C:("sPlayVisFbufInstance","UNK_TYPE4","",0x4), 0x801F6D50:("sBombersNotebook","UNK_TYPE1","",0x1), @@ -3985,7 +3985,7 @@ 0x801F6FE8:("sSlowlyStack","u8","[4096]",0x1000), 0x801F7FF0:("sGameSpeedMeter","SpeedMeter","", 0x20), 0x801F8010:("sGameVisCvg","VisCvg","",0x10), - 0x801F8020:("sGameVisZbuf","VisZbuf","",0x10), + 0x801F8020:("sGameVisZBuf","VisZBuf","",0x10), 0x801F8030:("sGameVisMono","VisMono","",0x18), 0x801F8048:("sGameViMode","ViMode","",0x88), 0x801F80D0:("sGraphFaultAddrConvClient","FaultAddrConvClient","",0xc), diff --git a/tools/sizes/code_functions.csv b/tools/sizes/code_functions.csv index 6084b14eba..97c7fbae20 100644 --- a/tools/sizes/code_functions.csv +++ b/tools/sizes/code_functions.csv @@ -2289,9 +2289,9 @@ asm/non_matchings/code/z_vismono/VisMono_DesaturateTLUT.s,VisMono_DesaturateTLUT 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/VisMono_DrawOld.s,VisMono_DrawOld,0x8014204C,0x1D -asm/non_matchings/code/z_viszbuf/VisZbuf_Init.s,VisZbuf_Init,0x801420C0,0xD -asm/non_matchings/code/z_viszbuf/VisZbuf_Destroy.s,VisZbuf_Destroy,0x801420F4,0x3 -asm/non_matchings/code/z_viszbuf/VisZbuf_Draw.s,VisZbuf_Draw,0x80142100,0xD0 +asm/non_matchings/code/z_viszbuf/VisZBuf_Init.s,VisZBuf_Init,0x801420C0,0xD +asm/non_matchings/code/z_viszbuf/VisZBuf_Destroy.s,VisZBuf_Destroy,0x801420F4,0x3 +asm/non_matchings/code/z_viszbuf/VisZBuf_Draw.s,VisZBuf_Draw,0x80142100,0xD0 asm/non_matchings/code/z_vr_box/Skybox_CalculateFace128.s,Skybox_CalculateFace128,0x80142440,0x342 asm/non_matchings/code/z_vr_box/Skybox_Calculate128.s,Skybox_Calculate128,0x80143148,0x28 asm/non_matchings/code/z_vr_box/Skybox_Setup.s,Skybox_Setup,0x801431E8,0x4F