diff --git a/src/code/PreRender.c b/src/code/PreRender.c index ddf6b473ea..d240f6c80e 100644 --- a/src/code/PreRender.c +++ b/src/code/PreRender.c @@ -431,7 +431,8 @@ void PreRender_RestoreZBuffer(PreRender* this, Gfx** gfxP) { /** * Draws a full-screen image to the current framebuffer, that sources the rgb channel from `this->fbufSave` and - * the alpha channel from `this->cvgSave` modulated by environment color. + * the alpha channel from `this->cvgSave` modulated by environment color. The alpha channel becomes the framebuffer's + * coverage content. */ void func_800C213C(PreRender* this, Gfx** gfxP) { Gfx* gfx; @@ -450,6 +451,7 @@ void func_800C213C(PreRender* this, Gfx** gfxP) { gDPSetEnvColor(gfx++, 255, 255, 255, 32); // Effectively disable blending in both cycles. It's 2-cycle so that TEXEL1 can be used to point to a different // texture tile. + // CVG_X_ALPHA in this mode transfers combined alpha to coverage. gDPSetOtherMode(gfx++, G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_2CYCLE | G_PM_NPRIMITIVE, @@ -460,7 +462,12 @@ void func_800C213C(PreRender* this, Gfx** gfxP) { // Set up the color combiner: first cycle: TEXEL0, TEXEL1 + ENVIRONMENT; second cycle: G_CC_PASS2 gDPSetCombineLERP(gfx++, 0, 0, 0, TEXEL0, 1, 0, TEXEL1, ENVIRONMENT, 0, 0, 0, COMBINED, 0, 0, 0, COMBINED); - nRows = 4; + // The first 0xA00 bytes of TMEM are reserved for framebuffer data (TEXEL0, RGBA16) + // The last 0x500 bytes of the remaining 0x600 bytes of TMEM is for coverage data (TEXEL1, I8) + // In total it needs to simultaneously fit + // SCREEN_WIDTH * (RGBA16 pixel + I8 pixel) = SCREEN_WIDTH * (2 bytes + 1 byte) +#define FB_ROWS (TMEM_SIZE / (3 * SCREEN_WIDTH)) + nRows = FB_ROWS; rowsRemaining = this->height; curRow = 0; @@ -486,9 +493,9 @@ void func_800C213C(PreRender* this, Gfx** gfxP) { rtile = rtile; // Fake match? // Load the coverage line - gDPLoadMultiTile(gfx++, this->cvgSave, 0x0160, rtile, G_IM_FMT_I, G_IM_SIZ_8b, this->width, this->height, - uls, ult, lrs, lrt, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, - G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPLoadMultiTile(gfx++, this->cvgSave, (TMEM_SIZE - SCREEN_WIDTH * FB_ROWS) / 8, rtile, G_IM_FMT_I, + G_IM_SIZ_8b, this->width, this->height, uls, ult, lrs, lrt, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); rtile = rtile; // Fake match? @@ -500,6 +507,7 @@ void func_800C213C(PreRender* this, Gfx** gfxP) { curRow += nRows; rowsRemaining -= nRows; } +#undef FB_ROWS gDPPipeSync(gfx++); *gfxP = gfx; diff --git a/src/code/z_actor.c b/src/code/z_actor.c index ce2b883b03..109bc4acbd 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -2709,6 +2709,14 @@ void Actor_DrawLensActors(PlayState* play, s32 numInvisibleActors, Actor** invis // the z-buffer will later only allow drawing inside the lens circle } else { // Update the z-buffer but not the color frame buffer + // The render mode here sets the following modes for framebuffer and z-buffer access: + // - Framebuffer reads & writes + // - Z-Buffer writes only, value from primitive Z + // - Framebuffer coverage is unchanged + // Since the goal is to mask the z-buffer, there are two options: + // - Set the FB to the ZB and render a texture over it + // - Read and write the FB without changes to its contents, since ZB writes only happen when FB writes happen + // Here the second option is used. gDPSetOtherMode(POLY_XLU_DISP++, G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, @@ -4512,7 +4520,7 @@ Gfx* func_80034B54(GraphicsContext* gfxCtx) { displayList = displayListHead = GRAPH_ALLOC(gfxCtx, 2 * sizeof(Gfx)); - gDPSetRenderMode(displayListHead++, G_RM_FOG_SHADE_A, Z_UPD | G_RM_AA_ZB_XLU_SURF2); + gDPSetRenderMode(displayListHead++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2 | Z_UPD); gSPEndDisplayList(displayListHead++); @@ -4710,8 +4718,7 @@ Vec3f D_80116268 = { 0.0f, -1.5f, 0.0f }; Vec3f D_80116274 = { 0.0f, -0.2f, 0.0f }; Gfx D_80116280[] = { - gsDPSetRenderMode(G_RM_FOG_SHADE_A, AA_EN | Z_CMP | Z_UPD | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_XLU | - FORCE_BL | GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2 | Z_UPD), gsDPSetAlphaCompare(G_AC_THRESHOLD), gsSPEndDisplayList(), }; diff --git a/src/code/z_rcp.c b/src/code/z_rcp.c index 657bd9e560..76cc6c467c 100644 --- a/src/code/z_rcp.c +++ b/src/code/z_rcp.c @@ -223,6 +223,9 @@ Gfx sSetupDL[SETUPDL_MAX][6] = { gsDPPipeSync(), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), gsDPSetCombineMode(G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM), + // This render mode uses CVG_X_ALPHA to transfer texture alpha to coverage, but the coverage written to the + // framebuffer is always full. It also doesn't write depth, but uses an opaque Z mode. It's hard to say what + // the intention was here. gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_PERSP | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_NONE | G_ZS_PIXEL | AA_EN | Z_CMP | IM_RD | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | @@ -723,9 +726,7 @@ Gfx sSetupDL[SETUPDL_MAX][6] = { gsDPSetCombineMode(G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM), gsDPSetOtherMode(G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, - G_AC_THRESHOLD | G_ZS_PIXEL | Z_UPD | IM_RD | CVG_DST_SAVE | ZMODE_OPA | FORCE_BL | - GBL_c1(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) | - GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)), + G_AC_THRESHOLD | G_ZS_PIXEL | G_RM_CLD_SURF | G_RM_CLD_SURF2 | Z_UPD), gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_SHADING_SMOOTH), gsSPEndDisplayList(), }, @@ -756,6 +757,8 @@ Gfx sSetupDL[SETUPDL_MAX][6] = { gsDPPipeSync(), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), + // This render mode is a non-AA texture edge mode that writes full coverage to the framebuffer for all pixels. + // The c2 render mode would be G_RM_PASS2 if it were defined. gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_PERSP | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_THRESHOLD | G_ZS_PIXEL | Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | @@ -768,6 +771,7 @@ Gfx sSetupDL[SETUPDL_MAX][6] = { gsDPPipeSync(), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), gsDPSetCombineMode(G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM), + // Same as SETUPDL_66 gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_PERSP | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_THRESHOLD | G_ZS_PIXEL | Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | @@ -780,6 +784,7 @@ Gfx sSetupDL[SETUPDL_MAX][6] = { gsDPPipeSync(), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA), + // This render mode would be RM_ZB_SUB_SURF if it were defined. gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_PERSP | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_THRESHOLD | G_ZS_PIXEL | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | @@ -793,6 +798,7 @@ Gfx sSetupDL[SETUPDL_MAX][6] = { gsDPPipeSync(), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), gsDPSetCombineMode(G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM), + // This render mode would be RM_ZB_SUB_SURF if it were defined. gsDPSetOtherMode(G_AD_NOTPATTERN | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE | G_TD_CLAMP | G_TP_PERSP | G_CYC_1CYCLE | G_PM_NPRIMITIVE, G_AC_THRESHOLD | G_ZS_PIXEL | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | ZMODE_OPA | CVG_X_ALPHA | diff --git a/src/code/z_room.c b/src/code/z_room.c index 29f23ebe0e..ebcb9de743 100644 --- a/src/code/z_room.c +++ b/src/code/z_room.c @@ -348,13 +348,17 @@ void Room_DrawBackground2D(Gfx** gfxP, void* tex, void* tlut, u16 width, u16 hei gDPSetOtherMode(gfx++, tlutMode | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_COPY | G_PM_NPRIMITIVE, G_AC_THRESHOLD | G_ZS_PIXEL | G_RM_NOOP | G_RM_NOOP2); gSPBgRectCopy(gfx++, bg); - } else { bg->s.frameW = width * (1 << 2); bg->s.frameH = height * (1 << 2); bg->s.scaleW = 1 << 10; bg->s.scaleH = 1 << 10; bg->s.imageYorig = bg->b.imageY; + // The render mode used here is like TEX_EDGE modes except it doesn't blend against memcolor, it instead blends + // against the current blend color which is 0 here. Since this is in 1-Cycle mode, AA_EN is set, and FORCE_BL + // is unset, blending only occurs on partially covered edge pixels. However the image is specified in + // whole-pixel units so no partially covered edges arise in rendering, the odd blending formula is not used. + // If there were edge pixels, the alpha value sent to the blender would be the coverage value. gDPSetOtherMode(gfx++, tlutMode | G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TL_TILE | G_TD_CLAMP | G_TP_NONE | G_CYC_1CYCLE | G_PM_NPRIMITIVE, diff --git a/src/overlays/actors/ovl_En_Box/z_en_box.c b/src/overlays/actors/ovl_En_Box/z_en_box.c index adb65c23c8..f7bd70c824 100644 --- a/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -605,9 +605,7 @@ Gfx* func_809CA4A0(GraphicsContext* gfxCtx) { ASSERT(dListHead != NULL, "gfxp != NULL", "../z_en_box.c", 1546); dList = dListHead; - gDPSetRenderMode(dListHead++, G_RM_FOG_SHADE_A, - AA_EN | Z_CMP | Z_UPD | IM_RD | CLR_ON_CVG | CVG_DST_WRAP | ZMODE_XLU | FORCE_BL | - GBL_c2(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA)); + gDPSetRenderMode(dListHead++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2 | Z_UPD); gSPEndDisplayList(dListHead++); return dList;