Port over decomp updates for vis* and reimplement vismono fb (#4533)

* Port over decomp updates for vis*

* move vismono framebuffer handling to file
This commit is contained in:
Archez 2024-11-09 12:51:31 -05:00 committed by GitHub
parent 2603b97366
commit f12a2bbbb7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 593 additions and 335 deletions

View File

@ -1419,18 +1419,6 @@ void ViMode_Init(ViMode* viMode);
void ViMode_Destroy(ViMode* viMode); void ViMode_Destroy(ViMode* viMode);
void ViMode_ConfigureFeatures(ViMode* viMode, s32 viFeatures); void ViMode_ConfigureFeatures(ViMode* viMode, s32 viFeatures);
void ViMode_Update(ViMode* viMode, Input* input); void ViMode_Update(ViMode* viMode, Input* input);
void func_800ACE70(struct_801664F0* this);
void func_800ACE90(struct_801664F0* this);
void func_800ACE98(struct_801664F0* this, Gfx** gfxp);
void VisMono_Init(VisMono* this);
void VisMono_Destroy(VisMono* this);
void VisMono_UpdateTexture(VisMono* this, u16* tex);
Gfx* VisMono_DrawTexture(VisMono* this, Gfx* gfx);
void VisMono_Draw(VisMono* this, Gfx** gfxp);
void VisMono_DrawOld(VisMono* this);
void func_800AD920(struct_80166500* this);
void func_800AD950(struct_80166500* this);
void func_800AD958(struct_80166500* this, Gfx** gfxp);
void Skybox_Init(GameState* state, SkyboxContext* skyboxCtx, s16 skyboxId); void Skybox_Init(GameState* state, SkyboxContext* skyboxCtx, s16 skyboxId);
Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z); Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z);
void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId, s16 blend, f32 x, f32 y, f32 z); void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId, s16 blend, f32 x, f32 y, f32 z);

9
soh/include/gfx.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef GFX_H
#define GFX_H
// Texture memory size, 4 KiB
#define TMEM_SIZE 0x1000
// Upstream TODO: Rest of this file
#endif

View File

@ -299,6 +299,10 @@ extern GraphicsContext* __gfxCtx;
#define BGCHECK_POS_ERROR_CHECK(vec3f) BgCheck_PosErrorCheck(vec3f, __FILE__, __LINE__) #define BGCHECK_POS_ERROR_CHECK(vec3f) BgCheck_PosErrorCheck(vec3f, __FILE__, __LINE__)
#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1) #define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1)
// Upstream TODO: Bring back decomp file/line macro use in src (but ignore the args for our needs)
#define SYSTEM_ARENA_MALLOC(size, file, line) SystemArena_MallocDebug(size, __FILE__, __LINE__)
#define SYSTEM_ARENA_FREE(ptr, file, line) SystemArena_FreeDebug(ptr, __FILE__, __LINE__)
// #endregion // #endregion
#define DPAD_ITEM(button) ((gSaveContext.buttonStatus[(button) + 5] != BTN_DISABLED) \ #define DPAD_ITEM(button) ((gSaveContext.buttonStatus[(button) + 5] != BTN_DISABLED) \

View File

@ -203,7 +203,7 @@ extern "C"
extern f32 gBossMarkScale; extern f32 gBossMarkScale;
extern PauseMapMarksData* gLoadedPauseMarkDataTable; extern PauseMapMarksData* gLoadedPauseMarkDataTable;
extern s32 gTrnsnUnkState; extern s32 gTrnsnUnkState;
extern Color_RGBA8_u32 D_801614B0; extern Color_RGBA8_u32 gVisMonoColor;
extern PreNmiBuff* gAppNmiBufferPtr; extern PreNmiBuff* gAppNmiBufferPtr;
extern SchedContext gSchedContext; extern SchedContext gSchedContext;
extern PadMgr gPadMgr; extern PadMgr gPadMgr;

View File

@ -25,12 +25,14 @@
#include "z64skin.h" #include "z64skin.h"
#include "z64transition.h" #include "z64transition.h"
#include "z64interface.h" #include "z64interface.h"
#include "z64vis.h"
#include "alignment.h" #include "alignment.h"
#include "sequence.h" #include "sequence.h"
#include "sfx.h" #include "sfx.h"
#include <libultraship/color.h> #include <libultraship/color.h>
#include "ichain.h" #include "ichain.h"
#include "regs.h" #include "regs.h"
#include "gfx.h"
#if defined(__LP64__) #if defined(__LP64__)
#define _SOH64 #define _SOH64
@ -2225,31 +2227,6 @@ typedef struct {
/* 0x0084 */ u32 unk_84; /* 0x0084 */ u32 unk_84;
} ViMode; } ViMode;
// Vis...
typedef struct {
/* 0x00 */ u32 type;
/* 0x04 */ u32 setScissor;
/* 0x08 */ Color_RGBA8_u32 color;
/* 0x0C */ Color_RGBA8_u32 envColor;
} struct_801664F0; // size = 0x10
typedef struct {
/* 0x00 */ u32 unk_00;
/* 0x04 */ u32 setScissor;
/* 0x08 */ Color_RGBA8_u32 primColor;
/* 0x0C */ Color_RGBA8_u32 envColor;
/* 0x10 */ u16* tlut;
/* 0x14 */ Gfx* monoDl;
} VisMono; // size = 0x18
// Vis...
typedef struct {
/* 0x00 */ u32 useRgba;
/* 0x04 */ u32 setScissor;
/* 0x08 */ Color_RGBA8_u32 primColor;
/* 0x08 */ Color_RGBA8_u32 envColor;
} struct_80166500; // size = 0x10
typedef struct { typedef struct {
/* 0x000 */ u8 rumbleEnable[4]; /* 0x000 */ u8 rumbleEnable[4];
/* 0x004 */ u8 unk_04[0x40]; /* 0x004 */ u8 unk_04[0x40];

101
soh/include/z64vis.h Normal file
View File

@ -0,0 +1,101 @@
#ifndef Z64_VIS_H
#define Z64_VIS_H
// #include "ultra64.h"
// #include "color.h"
#include <libultraship/libultra.h>
#ifdef __cplusplus
#define this thisx
extern "C"
{
#endif
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 {
/* 0x00 */ u32 type;
/* 0x04 */ u32 scissorType;
/* 0x08 */ Color_RGBA8_u32 primColor;
/* 0x0C */ 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 {
/* 0x00 */ 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 {
/* 0x00 */ Vis vis;
} VisZBuf; // size = 0x10
void VisZBuf_Init(VisZBuf* this);
void VisZBuf_Destroy(VisZBuf* this);
void VisZBuf_Draw(VisZBuf* this, Gfx** gfxP);
#ifdef __cplusplus
#undef this
}
#endif
#endif

View File

@ -23,6 +23,10 @@ u16 gAudioSEFlagSwapSource[64];
u16 gAudioSEFlagSwapTarget[64]; u16 gAudioSEFlagSwapTarget[64];
u8 gAudioSEFlagSwapMode[64]; u8 gAudioSEFlagSwapMode[64];
// Zbuffer and Color framebuffer
u16 D_0E000000[SCREEN_WIDTH * SCREEN_HEIGHT];
u16 D_0F000000[SCREEN_WIDTH * SCREEN_HEIGHT];
u8 osAppNmiBuffer[2048]; u8 osAppNmiBuffer[2048];
f32 qNaN0x10000 = 0x7F810000; f32 qNaN0x10000 = 0x7F810000;

View File

@ -1,97 +0,0 @@
#include "global.h"
// Note : This file is related to z_vismono, the original name was probably z_vis<something before "mono"
// alphabetically>
Gfx D_8012AC00[] = {
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),
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsDPPipeSync(),
gsDPSetBlendColor(0, 0, 0, 8),
gsSPEndDisplayList(),
};
Gfx D_8012AC28[] = {
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 |
GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_A_MEM) |
GBL_c2(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_A_MEM)),
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsSPEndDisplayList(),
};
Gfx D_8012AC40[] = {
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 |
GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM) |
GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM)),
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsSPEndDisplayList(),
};
Gfx D_8012AC58[] = {
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,
G_AC_NONE | G_ZS_PRIM | G_RM_CLD_SURF | G_RM_CLD_SURF2),
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
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 |
GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM) |
GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM)),
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsSPEndDisplayList(),
};
// Init
void func_800ACE70(struct_801664F0* this) {
this->type = 0;
this->setScissor = false;
this->color.r = 255;
this->color.g = 255;
this->color.b = 255;
this->color.a = 255;
}
// Destroy
void func_800ACE90(struct_801664F0* this) {
}
// Draw
void func_800ACE98(struct_801664F0* this, Gfx** gfxp) {
Gfx* gfx = *gfxp;
gDPPipeSync(gfx++);
gDPSetPrimDepth(gfx++, -1, -1);
if (this->setScissor == true) {
gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
switch (this->type) {
case 1:
gSPDisplayList(gfx++, D_8012AC40);
break;
case 2:
gDPSetColor(gfx++, G_SETPRIMCOLOR, this->color.rgba);
gSPDisplayList(gfx++, D_8012AC58);
break;
case 3:
gDPSetColor(gfx++, G_SETBLENDCOLOR, this->color.rgba);
gSPDisplayList(gfx++, D_8012AC00);
break;
case 4:
gDPSetColor(gfx++, G_SETFOGCOLOR, this->color.rgba);
gSPDisplayList(gfx++, D_8012AC28);
break;
}
gDPPipeSync(gfx++);
*gfxp = gfx;
}

View File

@ -1,64 +0,0 @@
#include "global.h"
// Note : This file is related to z_vismono, the original name was probably z_vis<something after "mono" alphabetically>
// z-buffer
extern u16 D_0E000000[];
// Init
void func_800AD920(struct_80166500* 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.a = 255;
this->envColor.r = 0;
this->envColor.g = 0;
this->envColor.b = 0;
}
// Destroy
void func_800AD950(struct_80166500* this) {
}
// Draw
void func_800AD958(struct_80166500* this, Gfx** gfxp) {
Gfx* gfx = *gfxp;
// OTRTODO
#if 0
u16* tex = D_0E000000;
s32 fmt = this->useRgba == false ? G_IM_FMT_IA : G_IM_FMT_RGBA;
s32 y;
s32 height = 6;
gDPPipeSync(gfx++);
if (this->setScissor == true) {
gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
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);
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);
for (y = 0; y <= SCREEN_HEIGHT - height; y += height) {
gDPLoadTextureBlock(gfx++, tex, fmt, G_IM_SIZ_16b, SCREEN_WIDTH, 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);
gSPTextureRectangle(gfx++, 0, (y) << 2, (SCREEN_WIDTH << 2), (y + height) << 2, G_TX_RENDERTILE, 0, 0,
(1 << 10), (1 << 10));
tex += SCREEN_WIDTH * height;
}
gDPPipeSync(gfx++);
*gfxp = gfx;
#endif
}

View File

@ -6,9 +6,9 @@
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
SpeedMeter D_801664D0; SpeedMeter D_801664D0;
struct_801664F0 D_801664F0; VisCvg sVisCvg;
struct_80166500 D_80166500; VisZBuf sVisZBuf;
VisMono sMonoColors; VisMono sVisMono;
ViMode sViMode; ViMode sViMode;
FaultClient sGameFaultClient; FaultClient sGameFaultClient;
u16 sLastButtonPressed; u16 sLastButtonPressed;
@ -31,41 +31,43 @@ void GameState_FaultPrint(void) {
} }
} }
void GameState_SetFBFilter(Gfx** gfx) { void GameState_SetFBFilter(Gfx** gfxP) {
Gfx* gfxP; Gfx* gfx = *gfxP;
gfxP = *gfx;
if ((R_FB_FILTER_TYPE > 0) && (R_FB_FILTER_TYPE < 5)) { if ((R_FB_FILTER_TYPE >= FB_FILTER_CVG_RGB) && (R_FB_FILTER_TYPE <= FB_FILTER_CVG_RGB_FOG)) {
D_801664F0.type = R_FB_FILTER_TYPE; // Visualize coverage
D_801664F0.color.r = R_FB_FILTER_PRIM_COLOR(0); sVisCvg.vis.type = FB_FILTER_TO_CVG_TYPE(R_FB_FILTER_TYPE);
D_801664F0.color.g = R_FB_FILTER_PRIM_COLOR(1); sVisCvg.vis.primColor.r = R_FB_FILTER_PRIM_COLOR(0);
D_801664F0.color.b = R_FB_FILTER_PRIM_COLOR(2); sVisCvg.vis.primColor.g = R_FB_FILTER_PRIM_COLOR(1);
D_801664F0.color.a = R_FB_FILTER_A; sVisCvg.vis.primColor.b = R_FB_FILTER_PRIM_COLOR(2);
func_800ACE98(&D_801664F0, &gfxP); sVisCvg.vis.primColor.a = R_FB_FILTER_A;
} else if ((R_FB_FILTER_TYPE == 5) || (R_FB_FILTER_TYPE == 6)) { VisCvg_Draw(&sVisCvg, &gfx);
D_80166500.useRgba = (R_FB_FILTER_TYPE == 6); } else if ((R_FB_FILTER_TYPE == FB_FILTER_ZBUF_IA) || (R_FB_FILTER_TYPE == FB_FILTER_ZBUF_RGBA)) {
D_80166500.primColor.r = R_FB_FILTER_PRIM_COLOR(0); // Visualize z-buffer
D_80166500.primColor.g = R_FB_FILTER_PRIM_COLOR(1); sVisZBuf.vis.type = (R_FB_FILTER_TYPE == FB_FILTER_ZBUF_RGBA);
D_80166500.primColor.b = R_FB_FILTER_PRIM_COLOR(2); sVisZBuf.vis.primColor.r = R_FB_FILTER_PRIM_COLOR(0);
D_80166500.primColor.a = R_FB_FILTER_A; sVisZBuf.vis.primColor.g = R_FB_FILTER_PRIM_COLOR(1);
D_80166500.envColor.r = R_FB_FILTER_ENV_COLOR(0); sVisZBuf.vis.primColor.b = R_FB_FILTER_PRIM_COLOR(2);
D_80166500.envColor.g = R_FB_FILTER_ENV_COLOR(1); sVisZBuf.vis.primColor.a = R_FB_FILTER_A;
D_80166500.envColor.b = R_FB_FILTER_ENV_COLOR(2); sVisZBuf.vis.envColor.r = R_FB_FILTER_ENV_COLOR(0);
D_80166500.envColor.a = R_FB_FILTER_A; sVisZBuf.vis.envColor.g = R_FB_FILTER_ENV_COLOR(1);
func_800AD958(&D_80166500, &gfxP); sVisZBuf.vis.envColor.b = R_FB_FILTER_ENV_COLOR(2);
} else if (R_FB_FILTER_TYPE == 7) { sVisZBuf.vis.envColor.a = R_FB_FILTER_A;
sMonoColors.unk_00 = 0; VisZBuf_Draw(&sVisZBuf, &gfx);
sMonoColors.primColor.r = R_FB_FILTER_PRIM_COLOR(0); } else if (R_FB_FILTER_TYPE == FB_FILTER_MONO) {
sMonoColors.primColor.g = R_FB_FILTER_PRIM_COLOR(1); // Monochrome filter
sMonoColors.primColor.b = R_FB_FILTER_PRIM_COLOR(2); sVisMono.vis.type = 0;
sMonoColors.primColor.a = R_FB_FILTER_A; sVisMono.vis.primColor.r = R_FB_FILTER_PRIM_COLOR(0);
sMonoColors.envColor.r = R_FB_FILTER_ENV_COLOR(0); sVisMono.vis.primColor.g = R_FB_FILTER_PRIM_COLOR(1);
sMonoColors.envColor.g = R_FB_FILTER_ENV_COLOR(1); sVisMono.vis.primColor.b = R_FB_FILTER_PRIM_COLOR(2);
sMonoColors.envColor.b = R_FB_FILTER_ENV_COLOR(2); sVisMono.vis.primColor.a = R_FB_FILTER_A;
sMonoColors.envColor.a = R_FB_FILTER_A; sVisMono.vis.envColor.r = R_FB_FILTER_ENV_COLOR(0);
VisMono_Draw(&sMonoColors, &gfxP); sVisMono.vis.envColor.g = R_FB_FILTER_ENV_COLOR(1);
sVisMono.vis.envColor.b = R_FB_FILTER_ENV_COLOR(2);
sVisMono.vis.envColor.a = R_FB_FILTER_A;
VisMono_Draw(&sVisMono, &gfx);
} }
*gfx = gfxP; *gfxP = gfx;
} }
void func_800C4344(GameState* gameState) { void func_800C4344(GameState* gameState) {
@ -420,9 +422,9 @@ void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* g
startTime = endTime; startTime = endTime;
LOG_CHECK_NULL_POINTER("this->cleanup", gameState->destroy); LOG_CHECK_NULL_POINTER("this->cleanup", gameState->destroy);
func_800ACE70(&D_801664F0); VisCvg_Init(&sVisCvg);
func_800AD920(&D_80166500); VisZBuf_Init(&sVisZBuf);
VisMono_Init(&sMonoColors); VisMono_Init(&sVisMono);
if (SREG(48) == 0) { if (SREG(48) == 0) {
ViMode_Init(&sViMode); ViMode_Init(&sViMode);
} }
@ -450,9 +452,9 @@ void GameState_Destroy(GameState* gameState) {
} }
func_800AA0F0(); func_800AA0F0();
SpeedMeter_Destroy(&D_801664D0); SpeedMeter_Destroy(&D_801664D0);
func_800ACE90(&D_801664F0); VisCvg_Destroy(&sVisCvg);
func_800AD950(&D_80166500); VisZBuf_Destroy(&sVisZBuf);
VisMono_Destroy(&sMonoColors); VisMono_Destroy(&sVisMono);
if (SREG(48) == 0) { if (SREG(48) == 0) {
ViMode_Destroy(&sViMode); ViMode_Destroy(&sViMode);
} }

View File

@ -350,16 +350,16 @@ void func_80064824(PlayState* play, CutsceneContext* csCtx, CsCmdBase* cmd) {
Flags_SetEventChkInf(EVENTCHKINF_RAISED_LAKE_HYLIA_WATER); Flags_SetEventChkInf(EVENTCHKINF_RAISED_LAKE_HYLIA_WATER);
break; break;
case 22: case 22:
D_801614B0.r = 255; gVisMonoColor.r = 255;
D_801614B0.g = 255; gVisMonoColor.g = 255;
D_801614B0.b = 255; gVisMonoColor.b = 255;
D_801614B0.a = 255; gVisMonoColor.a = 255;
break; break;
case 23: case 23:
D_801614B0.r = 255; gVisMonoColor.r = 255;
D_801614B0.g = 180; gVisMonoColor.g = 180;
D_801614B0.b = 100; gVisMonoColor.b = 100;
D_801614B0.a = 255.0f * temp; gVisMonoColor.a = 255.0f * temp;
break; break;
case 24: case 24:
play->roomCtx.curRoom.segment = NULL; play->roomCtx.curRoom.segment = NULL;

View File

@ -21,7 +21,7 @@
TransitionUnk sTrnsnUnk; TransitionUnk sTrnsnUnk;
s32 gTrnsnUnkState; s32 gTrnsnUnkState;
VisMono gPlayVisMono; VisMono gPlayVisMono;
Color_RGBA8_u32 D_801614B0; Color_RGBA8_u32 gVisMonoColor;
FaultClient D_801614B8; FaultClient D_801614B8;
@ -567,7 +567,7 @@ void Play_Init(GameState* thisx) {
TransitionFade_SetColor(&play->transitionFade, RGBA8(160, 160, 160, 255)); TransitionFade_SetColor(&play->transitionFade, RGBA8(160, 160, 160, 255));
TransitionFade_Start(&play->transitionFade); TransitionFade_Start(&play->transitionFade);
VisMono_Init(&gPlayVisMono); VisMono_Init(&gPlayVisMono);
D_801614B0.a = 0; gVisMonoColor.a = 0;
Flags_UnsetAllEnv(play); Flags_UnsetAllEnv(play);
osSyncPrintf("ZELDA ALLOC SIZE=%x\n", THA_GetSize(&play->state.tha)); osSyncPrintf("ZELDA ALLOC SIZE=%x\n", THA_GetSize(&play->state.tha));
@ -1422,11 +1422,9 @@ void Play_Draw(PlayState* play) {
TransitionFade_Draw(&play->transitionFade, &gfxP); TransitionFade_Draw(&play->transitionFade, &gfxP);
if (D_801614B0.a > 0) { if (gVisMonoColor.a > 0) {
// gPlayVisMono.vis.primColor.rgba = D_801614B0.rgba; gPlayVisMono.vis.primColor.rgba = gVisMonoColor.rgba;
// VisMono_Draw(&gPlayVisMono, &gfxP); VisMono_Draw(&gPlayVisMono, &gfxP);
gDPSetGrayscaleColor(gfxP++, D_801614B0.r, D_801614B0.g, D_801614B0.b, D_801614B0.a);
gSPGrayscale(gfxP++, true);
} }
gSPEndDisplayList(gfxP++); gSPEndDisplayList(gfxP++);
@ -1610,7 +1608,7 @@ void Play_Draw(PlayState* play) {
play->unk_121C7 = 2; play->unk_121C7 = 2;
SREG(33) |= 1; SREG(33) |= 1;
// 2S2H [Port] Continue to render the post world for pausing to avoid flashing the HUD // SOH [Port] Continue to render the post world for pausing to avoid flashing the HUD
if (gTrnsnUnkState == 2) { if (gTrnsnUnkState == 2) {
goto Play_Draw_skip; goto Play_Draw_skip;
} }

145
soh/src/code/z_viscvg.c Normal file
View File

@ -0,0 +1,145 @@
/**
* @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 "global.h"
/**
* 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),
// (blendColor RGB) * (cvg)
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsDPPipeSync(),
gsDPSetBlendColor(0, 0, 0, 8),
gsSPEndDisplayList(),
};
/**
* 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 |
GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_A_MEM) |
GBL_c2(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_A_MEM)),
// (fog RGB) * (fog alpha) + (FB RGB) * (cvg)
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsSPEndDisplayList(),
};
/**
* 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 |
GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM) |
GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM)),
// (FB RGB) * (cvg)
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsSPEndDisplayList(),
};
/**
* 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,
G_AC_NONE | G_ZS_PRIM | G_RM_CLD_SURF | G_RM_CLD_SURF2),
// stage 1 color = (primColor RGB) * (primColor Alpha) + (FB RGB) * (1 - primColor Alpha)
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
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 |
GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM) |
GBL_c2(G_BL_CLR_IN, G_BL_0, G_BL_CLR_MEM, G_BL_A_MEM)),
// final color = (stage 1 RGB) * (cvg)
gsDPFillRectangle(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1),
gsSPEndDisplayList(),
};
void VisCvg_Init(VisCvg* this) {
this->vis.type = FB_FILTER_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;
gDPPipeSync(gfx++);
gDPSetPrimDepth(gfx++, 0xFFFF, 0xFFFF);
if (this->vis.scissorType == VIS_SETSCISSOR) {
gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
switch (this->vis.type) {
case FB_FILTER_CVG_RGB:
gSPDisplayList(gfx++, sCoverageRGBDL);
break;
case FB_FILTER_CVG_RGB_UNIFORM:
// Set primitive color for uniform color filter in custom RenderMode
gDPSetColor(gfx++, G_SETPRIMCOLOR, this->vis.primColor.rgba);
gSPDisplayList(gfx++, sCoverageRGBUniformDL);
break;
case FB_FILTER_CVG_ONLY:
// Set background color for G_RM_VISCVG
gDPSetColor(gfx++, G_SETBLENDCOLOR, this->vis.primColor.rgba);
gSPDisplayList(gfx++, sCoverageOnlyDL);
break;
case FB_FILTER_CVG_RGB_FOG:
// Set fog color for custom RenderMode, needs to be close to 0 to not overflow
gDPSetColor(gfx++, G_SETFOGCOLOR, this->vis.primColor.rgba);
gSPDisplayList(gfx++, sCoverageRGBFogDL);
break;
default:
break;
}
gDPPipeSync(gfx++);
*gfxP = gfx;
}

View File

@ -1,137 +1,218 @@
/**
* @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 "global.h" #include "global.h"
#include <string.h>
#include <string.h> // memset
#include <assert.h> #include <assert.h>
#include "soh/framebuffer_effects.h"
// (Note: 80 = SCREEN_HEIGHT/3, see VisMono_DrawTexture) // Upstream TODO: Replace these ones they are served from other headers
// This may not have been kept up-to-date with the code, 1+1+1+80*(7+2+2+3)+1+1 makes more sense #define ASSERT(cond, msg, file, line) assert(cond)
#define DLSIZE (1 + 3 + 1 + 1 + 80 * (7 + 2 + 2 + 3) + 1) #define GPACK_IA16(i, a) (((i) << 8) | (a))
// framebuffer // 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 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.
#define VISMONO_DLSIZE (3 + SCREEN_HEIGHT / VISMONO_CFBFRAG_HEIGHT * (7 + 2 + 2 + 3) + 2 + 2)
// 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)
// color framebuffer
extern u16 D_0F000000[]; extern u16 D_0F000000[];
void VisMono_Init(VisMono* this) { void VisMono_Init(VisMono* this) {
memset(this, 0, sizeof(VisMono)); memset(this, 0, sizeof(VisMono));
this->unk_00 = 0; this->vis.type = 0;
this->setScissor = false; this->vis.scissorType = VIS_NO_SETSCISSOR;
this->primColor.r = 255; this->vis.primColor.r = 255;
this->primColor.g = 255; this->vis.primColor.g = 255;
this->primColor.b = 255; this->vis.primColor.b = 255;
this->primColor.a = 255; this->vis.primColor.a = 255;
this->envColor.r = 0; this->vis.envColor.r = 0;
this->envColor.g = 0; this->vis.envColor.g = 0;
this->envColor.b = 0; this->vis.envColor.b = 0;
this->envColor.a = 0; this->vis.envColor.a = 0;
} }
void VisMono_Destroy(VisMono* this) { void VisMono_Destroy(VisMono* this) {
SYSTEM_ARENA_FREE_DEBUG(this->monoDl); SYSTEM_ARENA_FREE(this->dList, "../z_vismono.c", 137);
} }
void VisMono_UpdateTexture(VisMono* this, u16* tex) { void VisMono_DesaturateTLUT(VisMono* this, u16* tlut) {
s32 i; s32 i;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
tex[i] = ((((i >> 3 & 0x1F) * 2 + (i << 2 & 0x1F) * 4) * 0xFF / 0xD9) << 8) | // `tlut[i]` is a IA16 color
(((i >> 6 & 0x1F) * 4 + (i >> 1 & 0x1F)) * 0xFF / 0xD9); // `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_DrawTexture(VisMono* this, Gfx* gfx) Gfx* VisMono_DesaturateDList(VisMono* this, Gfx* gfx) {
{
// OTRTODO
#if 1
s32 y; s32 y;
s32 height = 3; s32 height = VISMONO_CFBFRAG_HEIGHT;
//u16* tex = D_0F000000; u16* cfbFrag = D_0F000000;
u16* tex = SEG_ADDR(0xF, 0);
gDPPipeSync(gfx++); gDPPipeSync(gfx++);
// `G_TT_IA16`: use color-indexed images, and IA16 palettes
gDPSetOtherMode(gfx++, gDPSetOtherMode(gfx++,
G_AD_DISABLE | G_CD_DISABLE | G_CK_NONE | G_TC_FILT | G_TF_POINT | G_TT_IA16 | G_TL_TILE | 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_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); G_AC_NONE | G_ZS_PRIM | G_RM_PASS | 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, gDPSetCombineLERP(gfx++, 1, 0, TEXEL1_ALPHA, TEXEL0, 0, 0, 0, 1, PRIMITIVE, ENVIRONMENT, COMBINED, ENVIRONMENT, 0,
0, 0, PRIMITIVE); 0, 0, PRIMITIVE);
for (y = 0; y <= SCREEN_HEIGHT - height; y += height) { for (y = 0; y <= SCREEN_HEIGHT - height; y += height) {
gDPLoadTextureBlock(gfx++, tex, G_IM_FMT_CI, G_IM_SIZ_8b, SCREEN_WIDTH * 2, height, 0, // 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_NOMIRROR | G_TX_CLAMP, G_TX_NOMIRROR | G_TX_CLAMP, G_TX_NOMASK, G_TX_NOMASK,
G_TX_NOLOD, G_TX_NOLOD); G_TX_NOLOD, G_TX_NOLOD);
gDPSetTile(gfx++, G_IM_FMT_CI, G_IM_SIZ_8b, 80, 0x0, G_TX_RENDERTILE, 0, G_TX_NOMIRROR | G_TX_CLAMP, 0, 0, // Set texel 0 to be a CI8 image with width `SCREEN_WIDTH * 2` and height `VISMONO_CFBFRAG_HEIGHT`
G_TX_NOMIRROR | G_TX_CLAMP, 0, 0); // Its position in texture image space is shifted along +S by 2
gDPSetTileSize(gfx++, G_TX_RENDERTILE, (2 << 2), 0, ((SCREEN_WIDTH * 2 + 1) << 2), (2 << 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);
gDPSetTile(gfx++, G_IM_FMT_CI, G_IM_SIZ_8b, 80, 0x0, 1, 1, G_TX_NOMIRROR | G_TX_CLAMP, 0, 0, // Set texel 1 to be a CI8 image with width `SCREEN_WIDTH * 2` and height `VISMONO_CFBFRAG_HEIGHT`
G_TX_NOMIRROR | G_TX_CLAMP, 0, 0); // Its position in texture image space is shifted along +S by 1
gDPSetTileSize(gfx++, 1, (1 << 2), 0, ((SCREEN_WIDTH * 2) << 2), (2 << 2)); // 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);
gSPTextureRectangle(gfx++, 0, y << 2, (SCREEN_WIDTH << 2), (y + height) << 2, G_TX_RENDERTILE, 2 << 5, 0, // Draw a `SCREEN_WIDTH` wide, `height` high rectangle.
2 << 10, 1 << 10); // Texture coordinate T (vertical) starts at 0 and changes by one each line (dtdy = 1)
tex += SCREEN_WIDTH * height; // 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++); gDPPipeSync(gfx++);
gSPEndDisplayList(gfx++); gSPEndDisplayList(gfx++);
#endif
return gfx; return gfx;
} }
void VisMono_Draw(VisMono* this, Gfx** gfxp) { void VisMono_Draw(VisMono* this, Gfx** gfxP) {
Gfx* gfx = *gfxp; Gfx* gfx = *gfxP;
u16* tlut; u16* tlut;
Gfx* monoDL; Gfx* dList;
Gfx* glistpEnd; Gfx* dListEnd;
// SOH [Port] Implement VisMono by performing a framebuffer copy and redraw with an active
// grayscale command to set the mono color
FB_CopyToFramebuffer(&gfx, 0, gReusableFrameBuffer, false, NULL);
gDPSetGrayscaleColor(gfx++, this->vis.primColor.r, this->vis.primColor.g, this->vis.primColor.b,
this->vis.primColor.a);
gSPGrayscale(gfx++, true);
FB_DrawFromFramebuffer(&gfx, gReusableFrameBuffer, 255);
gSPGrayscale(gfx++, false);
#if 0
if (this->tlut) { if (this->tlut) {
tlut = this->tlut; tlut = this->tlut;
} else { } else {
tlut = Graph_DlistAlloc(&gfx, 256 * sizeof(u16)); tlut = Graph_DlistAlloc(&gfx, 256 * G_IM_SIZ_16b_BYTES);
VisMono_UpdateTexture(this, tlut); VisMono_DesaturateTLUT(this, tlut);
} }
if (this->monoDl) { if (this->dList) {
monoDL = this->monoDl; dList = this->dList;
} else { } else {
monoDL = Graph_DlistAlloc(&gfx, DLSIZE * sizeof(Gfx)); dList = Graph_DlistAlloc(&gfx, VISMONO_DLSIZE * sizeof(Gfx));
glistpEnd = VisMono_DrawTexture(this, monoDL); dListEnd = VisMono_DesaturateDList(this, dList);
if (!(glistpEnd <= monoDL + DLSIZE)) { if (!(dListEnd <= dList + VISMONO_DLSIZE)) {
LOG_ADDRESS("glistp_end", glistpEnd); LOG_ADDRESS("glistp_end", dListEnd);
LOG_ADDRESS("mono_dl", monoDL); LOG_ADDRESS("mono_dl", dList);
LOG_ADDRESS("mono_dl + (1+3+1+1+80*(7+2+2+3)+1)", monoDL + DLSIZE); LOG_ADDRESS("mono_dl + (1+3+1+1+80*(7+2+2+3)+1)", dList + VISMONO_DLSIZE);
LOG_ADDRESS("(1+3+1+1+80*(7+2+2+3)+1)", DLSIZE); LOG_ADDRESS("(1+3+1+1+80*(7+2+2+3)+1)", VISMONO_DLSIZE);
} }
assert(glistpEnd <= monoDL + DLSIZE); ASSERT(dListEnd <= dList + VISMONO_DLSIZE, "glistp_end <= mono_dl + DLSIZE", "../z_vismono.c", 262);
} }
gDPPipeSync(gfx++); gDPPipeSync(gfx++);
if (this->setScissor == true) {
if (this->vis.scissorType == VIS_SETSCISSOR) {
gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
} }
gDPSetColor(gfx++, G_SETPRIMCOLOR, this->primColor.rgba); gDPSetColor(gfx++, G_SETPRIMCOLOR, this->vis.primColor.rgba);
gDPSetColor(gfx++, G_SETENVCOLOR, this->envColor.rgba); gDPSetColor(gfx++, G_SETENVCOLOR, this->vis.envColor.rgba);
gDPLoadTLUT_pal256(gfx++, tlut); gDPLoadTLUT_pal256(gfx++, tlut);
gSPDisplayList(gfx++, monoDL); gSPDisplayList(gfx++, dList);
gDPPipeSync(gfx++);
*gfxp = gfx; gDPPipeSync(gfx++);
#endif
*gfxP = gfx;
} }
void VisMono_DrawOld(VisMono* this) { void VisMono_DrawOld(VisMono* this) {
Gfx* glistpEnd; Gfx* dListEnd;
if (!this->tlut) { if (this->tlut == NULL) {
this->tlut = SYSTEM_ARENA_MALLOC_DEBUG(256 * sizeof(u16)); this->tlut = SYSTEM_ARENA_MALLOC(256 * G_IM_SIZ_16b_BYTES, "../z_vismono.c", 283);
VisMono_UpdateTexture(this, this->tlut); VisMono_DesaturateTLUT(this, this->tlut);
} }
if (!this->monoDl) { if (this->dList == NULL) {
this->monoDl = SYSTEM_ARENA_MALLOC_DEBUG(DLSIZE * sizeof(Gfx)); this->dList = SYSTEM_ARENA_MALLOC(VISMONO_DLSIZE * sizeof(Gfx), "../z_vismono.c", 289);
glistpEnd = VisMono_DrawTexture(this, this->monoDl); dListEnd = VisMono_DesaturateDList(this, this->dList);
assert(glistpEnd <= this->monoDl + DLSIZE); ASSERT(dListEnd <= this->dList + VISMONO_DLSIZE, "glistp_end <= this->mono_dl + DLSIZE", "../z_vismono.c", 292);
} }
} }

116
soh/src/code/z_viszbuf.c Normal file
View File

@ -0,0 +1,116 @@
/**
* @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 "global.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 / (SCREEN_WIDTH * G_IM_SIZ_16b_BYTES))
// z-buffer
extern u16 D_0E000000[];
/**
* 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;
// clang-format off
this->vis.envColor.r = 0; \
this->vis.envColor.g = 0; \
this->vis.envColor.b = 0; \
this->vis.envColor.a = 255;
// clang-format on
}
void VisZBuf_Destroy(VisZBuf* this) {
}
void VisZBuf_Draw(VisZBuf* this, Gfx** gfxP) {
Gfx* gfx = *gfxP;
s32 pad;
u16* zbufFrag = D_0E000000;
s32 fmt;
s32 y;
s32 height;
if (this->vis.type == VIS_ZBUF_TYPE_IA) {
fmt = G_IM_FMT_IA;
} else { // VIS_ZBUF_TYPE_RGBA
fmt = G_IM_FMT_RGBA;
}
height = VISZBUF_ZBUFFRAG_HEIGHT;
gDPPipeSync(gfx++);
// Scissoring is only required if the scissor has not been set prior.
if (this->vis.scissorType == VIS_SETSCISSOR) {
gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
// 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->vis.primColor.rgba);
gDPSetColor(gfx++, G_SETENVCOLOR, this->vis.envColor.rgba);
for (y = 0; y <= SCREEN_HEIGHT - height; y += height) {
// Load a few lines of the z-buffer, as many as can fit in TMEM at once.
gDPLoadTextureBlock(gfx++, zbufFrag, fmt, G_IM_SIZ_16b, SCREEN_WIDTH, 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);
// Overwrite them with the calculated colors.
gSPTextureRectangle(gfx++, 0, y << 2, SCREEN_WIDTH << 2, (y + height) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10,
1 << 10);
zbufFrag += SCREEN_WIDTH * height;
}
gDPPipeSync(gfx++);
*gfxP = gfx;
}

View File

@ -196,10 +196,10 @@ void BgHaka_Draw(Actor* thisx, PlayState* play) {
play->envCtx.adjLight1Color[0] = newColor.r; play->envCtx.adjLight1Color[0] = newColor.r;
play->envCtx.adjLight1Color[1] = newColor.g; play->envCtx.adjLight1Color[1] = newColor.g;
play->envCtx.adjLight1Color[2] = newColor.b; play->envCtx.adjLight1Color[2] = newColor.b;
D_801614B0.r = newColor.r; gVisMonoColor.r = newColor.r;
D_801614B0.g = newColor.g; gVisMonoColor.g = newColor.g;
D_801614B0.b = newColor.b; gVisMonoColor.b = newColor.b;
D_801614B0.a = 255; gVisMonoColor.a = 255;
gDPSetGrayscaleColor(POLY_OPA_DISP++, newColor.r, newColor.g, newColor.b, 255); gDPSetGrayscaleColor(POLY_OPA_DISP++, newColor.r, newColor.g, newColor.b, 255);
gSPGrayscale(POLY_OPA_DISP++, true); gSPGrayscale(POLY_OPA_DISP++, true);
} }

View File

@ -84,8 +84,6 @@ void EndTitle_DrawFull(Actor* thisx, PlayState* play) {
} }
OVERLAY_DISP = Gfx_SetupDL_64(OVERLAY_DISP); OVERLAY_DISP = Gfx_SetupDL_64(OVERLAY_DISP);
if (D_801614B0.a > 0)
gSPGrayscale(OVERLAY_DISP++, false);
gDPSetTextureLUT(OVERLAY_DISP++, G_TT_NONE); gDPSetTextureLUT(OVERLAY_DISP++, G_TT_NONE);
gDPSetEnvColor(OVERLAY_DISP++, 255, 120, 30, 0); gDPSetEnvColor(OVERLAY_DISP++, 255, 120, 30, 0);
gDPSetRenderMode(OVERLAY_DISP++, G_RM_PASS, G_RM_XLU_SURF2); gDPSetRenderMode(OVERLAY_DISP++, G_RM_PASS, G_RM_XLU_SURF2);
@ -110,8 +108,6 @@ void EndTitle_DrawFull(Actor* thisx, PlayState* play) {
G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 0, 0, 0, 0); G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 0, 0, 0, 0);
gSPTextureRectangle(OVERLAY_DISP++, 104 << 2, 177 << 2, 216 << 2, 192 << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, gSPTextureRectangle(OVERLAY_DISP++, 104 << 2, 177 << 2, 216 << 2, 192 << 2, G_TX_RENDERTILE, 0, 0, 1 << 10,
1 << 10); 1 << 10);
if (D_801614B0.a > 0)
gSPGrayscale(OVERLAY_DISP++, true);
CLOSE_DISPS(play->state.gfxCtx); CLOSE_DISPS(play->state.gfxCtx);
} }

View File

@ -293,8 +293,6 @@ void Title_Init(GameState* thisx) {
//ResourceMgr_LoadDirectory("nintendo_rogo_static*"); //ResourceMgr_LoadDirectory("nintendo_rogo_static*");
// Disable vismono
D_801614B0.a = 0;
R_UPDATE_RATE = 1; R_UPDATE_RATE = 1;
Matrix_Init(&this->state); Matrix_Init(&this->state);
View_Init(&this->view, this->state.gfxCtx); View_Init(&this->view, this->state.gfxCtx);