summaryrefslogtreecommitdiff
path: root/src/code
diff options
context:
space:
mode:
authorDerek Hensley <hensley.derek58@gmail.com>2024-01-20 16:04:28 -0800
committerGitHub <noreply@github.com>2024-01-20 21:04:28 -0300
commit9c10ee1d28a45e7373af455f59c5e66235be30ee (patch)
tree39c583393035f81600ca0e023d5eb0dcfa9284d5 /src/code
parent665353f3446db43d0efe0e9c6a9c80d16684da7a (diff)
Framebuffer filter docs (#1528)
* Framebuffer filter docs * PR * Format * Leading 0s
Diffstat (limited to 'src/code')
-rw-r--r--src/code/game.c67
-rw-r--r--src/code/z_demo.c16
-rw-r--r--src/code/z_play.c10
-rw-r--r--src/code/z_viscvg.c93
-rw-r--r--src/code/z_vismono.c52
-rw-r--r--src/code/z_viszbuf.c81
6 files changed, 205 insertions, 114 deletions
diff --git a/src/code/game.c b/src/code/game.c
index 0179062f4..908a0c315 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 985b3c240..e9264ec84 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 38a9ede2a..12357f59a 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 1821805ee..739af628f 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 d4c462fc4..5e4330786 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 17c734cb0..86fb64474 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);
}