motion blur v2

Co-authored-by: Tharo <17233964+Thar0@users.noreply.github.com>
This commit is contained in:
Yanis42
2024-04-15 01:46:17 +02:00
parent eafdc5db94
commit 915cd9b4b2
12 changed files with 377 additions and 0 deletions

View File

@@ -46,6 +46,7 @@ Most discussions happen on our [Discord Server](https://discord.gg/brETAakcXr),
List of every HackerOoT contributors, from most recent to oldest contribution:
- Thar0
- recardo-7
- HailToDodongo
- CrashOverride95

View File

@@ -65,4 +65,9 @@
*/
#define ENABLE_DMA_PRINTF false
/**
* Enable motion blur debug
*/
#define ENABLE_MOTION_BLUR_DEBUG false
#endif

View File

@@ -103,4 +103,9 @@
*/
#define MM_N64_BOOT_LOGO false
/*
* Motion Blur
*/
#define ENABLE_MOTION_BLUR true
#endif

View File

@@ -48,6 +48,7 @@
#undef ENABLE_DEBUG_SAVE
#undef MAP_SELECT_ON_FILE_1
#undef ENABLE_DEBUG_HEAP
#undef ENABLE_MOTION_BLUR_DEBUG
#define SHOW_CS_INFOS false
#define SHOW_INPUT_DISPLAY false
@@ -67,6 +68,7 @@
#define ENABLE_DEBUG_SAVE false
#define MAP_SELECT_ON_FILE_1 false
#define ENABLE_DEBUG_HEAP false
#define ENABLE_MOTION_BLUR_DEBUG false
#endif
@@ -151,6 +153,7 @@
#undef ENABLE_MSG_DEBUGGER
#undef ENABLE_DEBUG_SAVE
#undef MAP_SELECT_ON_FILE_1
#undef ENABLE_MOTION_BLUR_DEBUG
#define DETERMINISTIC_BUILD false
#define SKIP_N64_BOOT_LOGO true
@@ -175,6 +178,7 @@
#define ENABLE_MSG_DEBUGGER false
#define ENABLE_DEBUG_SAVE false
#define MAP_SELECT_ON_FILE_1 true
#define ENABLE_MOTION_BLUR_DEBUG false
#endif
/**
@@ -186,6 +190,15 @@
#define IS_DEBUG OOT_DEBUG
#endif
/**
* Game
*/
#define IS_MOTION_BLUR_ENABLED (ENABLE_HACKEROOT && ENABLE_MOTION_BLUR)
/**
* Debug
*/
// General features
#define IS_DEBUG_HEAP_ENABLED (IS_DEBUG && ENABLE_DEBUG_HEAP)
#define IS_NO_CLIP_ENABLED (IS_DEBUG && ENABLE_NO_CLIP)

View File

@@ -1975,4 +1975,16 @@ void TitleSetup_Destroy(GameState* thisx);
void FileSelect_Init(GameState* thisx);
void FileSelect_Destroy(GameState* thisx);
#if ENABLE_MOTION_BLUR
void Play_DrawMotionBlur(PlayState* this);
void Play_InitMotionBlur(PlayState* this);
void Play_DestroyMotionBlur(void);
void Play_SetMotionBlurAlpha(u32 alpha);
void Play_EnableMotionBlur(u32 alpha);
void Play_DisableMotionBlur(void);
void Play_SetMotionBlurPriorityAlpha(u32 alpha);
void Play_EnableMotionBlurPriority(u32 alpha);
void Play_DisableMotionBlurPriority(void);
#endif
#endif

View File

@@ -357,4 +357,9 @@ typedef enum {
#define R_VI_CUR_ADDI_SCAN_LINES HREG(83)
#define R_VI_CUR_Y_SCALE_MODE HREG(84)
#define R_MOTION_BLUR_ALPHA SREG(90)
#define R_MOTION_BLUR_PRIORITY_ALPHA SREG(92)
#define R_MOTION_BLUR_PRIORITY_ENABLED SREG(93)
#define R_MOTION_BLUR_ENABLED SREG(95)
#endif

View File

@@ -2,6 +2,7 @@
#define Z64CUTSCENE_H
#include "ultra64.h"
#include "config.h"
typedef union CutsceneData {
s32 i;
@@ -147,6 +148,7 @@ typedef enum {
/* 0x008F */ CS_CMD_ACTOR_CUE_9_0,
/* 0x0090 */ CS_CMD_ACTOR_CUE_0_17,
/* 0x03E8 */ CS_CMD_DESTINATION = 0x03E8,
/* 0x03E9 */ CS_CMD_MOTION_BLUR,
/* 0xFFFF */ CS_CMD_END = 0xFFFF
} CutsceneCmd;
@@ -510,6 +512,22 @@ typedef struct {
/* 0x20 */ CutsceneCameraPoint* camEyePoints;
/* 0x24 */ CsCmdActorCue* playerCue;
/* 0x28 */ CsCmdActorCue* actorCues[10]; // "npcdemopnt"
/* 0x38 */ u16 originalBlurAlpha;
} CutsceneContext; // size = 0x50
typedef union {
struct {
/* 0x0 */ u16 type;
/* 0x2 */ u16 alpha;
/* 0x4 */ u16 startFrame;
/* 0x6 */ u16 endFrame;
};
s32 _words[2];
} CsCmdMotionBlur; // size = 0x8
typedef enum {
/* 1 */ CS_MOTION_BLUR_ENABLE = 1,
/* 2 */ CS_MOTION_BLUR_DISABLE
} CsMotionBlurType;
#endif

View File

@@ -266,6 +266,30 @@
#define CS_DESTINATION(destination, startFrame, endFrame) \
CS_CMD_DESTINATION, 1, CMD_HH(destination, startFrame), CMD_HH(endFrame, endFrame)
/**
* Declares a list of `CS_MOTION_BLUR` entries
*/
#define CS_MOTION_BLUR_LIST(entries) \
CS_CMD_MOTION_BLUR, CMD_W(entries)
#define CS_MOTION_BLUR(type, alpha, startFrame, endFrame) \
CMD_HH(type, alpha), CMD_HH(startFrame, endFrame)
/**
* Enables motion blur
* ``alpha`` is how visible the motion blur is, MM uses 180 for every instance of motion blur.
* Note: this can happen gradually
*/
#define CS_MOTION_BLUR_ENABLE(startFrame, endFrame, alpha) \
CS_MOTION_BLUR(CS_MOTION_BLUR_ENABLE, alpha, startFrame, endFrame)
/**
* Disables motion blur
* Note: this can happen gradually
*/
#define CS_MOTION_BLUR_DISABLE(startFrame, endFrame) \
CS_MOTION_BLUR(CS_MOTION_BLUR_DISABLE, 0, startFrame, endFrame)
/**
* Marks the end of a cutscene script.
*/

View File

@@ -815,3 +815,81 @@ void PreRender_ApplyFilters(PreRender* this) {
}
}
}
#if ENABLE_MOTION_BLUR
void PreRender_MotionBlurImpl(PreRender* this, Gfx** gfxp, void* buf, void* bufSave, s32 envR, s32 envG, s32 envB, s32 envA) {
Gfx* gfx = *gfxp;
uObjBg* bg;
gDPPipeSync(gfx++);
if (envA == 255) {
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_1CYCLE | G_PM_NPRIMITIVE,
G_AC_NONE | G_ZS_PRIM | G_RM_OPA_SURF | G_RM_OPA_SURF2);
} else {
gDPSetOtherMode(gfx++,
G_AD_NOISE | G_CD_NOISE | 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_CLD_SURF | G_RM_CLD_SURF2);
}
gDPSetEnvColor(gfx++, envR, envG, envB, envA);
gDPSetCombineLERP(gfx++, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0,
ENVIRONMENT);
gDPSetColorImage(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_16b, this->width, bufSave);
gDPSetScissor(gfx++, G_SC_NON_INTERLACE, 0, 0, this->width, this->height);
// Setup BG Obj
bg = Gfx_Alloc(&gfx, sizeof(uObjBg));
bg->s.imageX = 0;
bg->s.imageW = this->width * 4 + 1;
bg->s.frameX = 0;
bg->s.imageY = 0;
bg->s.imageH = this->height * 4 + 1;
bg->s.frameY = 0;
bg->s.imagePtr = buf;
bg->s.imageLoad = G_BGLT_LOADTILE;
bg->s.imageFmt = G_IM_FMT_RGBA;
bg->s.imageSiz = G_IM_SIZ_16b;
bg->s.imagePal = 0;
bg->s.imageFlip = 0;
bg->s.frameW = this->width * 4;
bg->s.frameH = this->height * 4;
bg->s.scaleW = 1024;
bg->s.scaleH = 1024;
bg->s.imageYorig = bg->s.imageY;
// Load S2DEX
gSPLoadUcodeL(gfx++, gspS2DEX2d_fifo);
gDPPipeSync(gfx++);
gSPObjRenderMode(gfx++, G_OBJRM_ANTIALIAS | G_OBJRM_BILERP);
gSPBgRect1Cyc(gfx++, bg);
gDPPipeSync(gfx++);
// Reload F3DZEX
gSPLoadUcodeEx(gfx++, SysUcode_GetUCode(), SysUcode_GetUCodeData(), 0x800);
gDPPipeSync(gfx++);
gDPSetColorImage(gfx++, G_IM_FMT_RGBA, G_IM_SIZ_16b, this->width, this->fbuf);
*gfxp = gfx;
}
// TODO this could do with a better name but whatever
void PreRender_MotionBlurOpaque(PreRender* this, Gfx** gfxP) {
if (this->fbuf != NULL && this->fbufSave != NULL) {
PreRender_MotionBlurImpl(this, gfxP, this->fbuf, this->fbufSave, 255, 255, 255, 255);
}
}
void PreRender_MotionBlur(PreRender* this, Gfx** gfxP, s32 alpha) {
PreRender_MotionBlurImpl(this, gfxP, this->fbufSave, this->fbuf, 255, 255, 255, alpha);
}
#endif

View File

@@ -35,6 +35,10 @@ UCodeInfo D_8012D248[3] = {
{ UCODE_S2DEX, gspS2DEX2d_fifoTextStart },
};
#if ENABLE_MOTION_BLUR
u16 (*gWorkBuf)[SCREEN_WIDTH * SCREEN_HEIGHT]; // pointer-to-array, array itself is allocated (see below)
#endif
void Graph_FaultClient(void) {
void* nextFb = osViGetNextFramebuffer();
void* newFb = (SysCfb_GetFbPtr(0) != nextFb) ? SysCfb_GetFbPtr(0) : SysCfb_GetFbPtr(1);
@@ -459,6 +463,11 @@ void Graph_ThreadEntry(void* arg0) {
GameStateOverlay* nextOvl = &gGameStateOverlayTable[GAMESTATE_SETUP];
GameStateOverlay* ovl;
#if ENABLE_MOTION_BLUR
gWorkBuf = SYSTEM_ARENA_MALLOC(sizeof(*gWorkBuf) + 64 - 1, __FILE__, __LINE__);
gWorkBuf = (void*)ALIGN64((u32)gWorkBuf);
#endif
PRINTF("グラフィックスレッド実行開始\n"); // "Start graphic thread execution"
Graph_Init(&gfxCtx);

View File

@@ -1,6 +1,7 @@
#include "global.h"
#include "quake.h"
#include "z64camera.h"
#include "config.h"
#include "assets/scenes/indoors/tokinoma/tokinoma_scene.h"
#include "assets/scenes/overworld/spot00/spot00_scene.h"
@@ -30,6 +31,7 @@
#include "assets/scenes/misc/hakaana_ouke/hakaana_ouke_scene.h"
u16 sCurTextId = 0;
u16 sCurOcarinaAction = 0;
@@ -1776,6 +1778,37 @@ void CutsceneCmd_Text(PlayState* play, CutsceneContext* csCtx, CsCmdText* cmd) {
}
}
void CutsceneCmd_MotionBlur(PlayState* play, CutsceneContext* csCtx, CsCmdMotionBlur* cmd) {
if (ENABLE_MOTION_BLUR) {
if ((csCtx->curFrame >= cmd->startFrame) && (cmd->endFrame >= csCtx->curFrame)) {
f32 lerp = Environment_LerpWeight(cmd->endFrame, cmd->startFrame, csCtx->curFrame);
if (ENABLE_MOTION_BLUR_DEBUG) {
PRINTF("[HackerOoT:INFO]: originalBlurAlpha: 0x%X, lerp: %f\n", play->csCtx.originalBlurAlpha, lerp);
}
if (cmd->type == CS_MOTION_BLUR_ENABLE) {
if (csCtx->originalBlurAlpha == 0) {
csCtx->originalBlurAlpha = cmd->alpha;
}
Play_EnableMotionBlur(lerp * cmd->alpha);
} else if (cmd->type == CS_MOTION_BLUR_DISABLE) {
if (lerp >= 0.9f) {
Play_DisableMotionBlur();
csCtx->originalBlurAlpha = 0;
} else {
Play_SetMotionBlurAlpha((1.0f - lerp) * csCtx->originalBlurAlpha);
}
}
}
} else if (ENABLE_MOTION_BLUR_DEBUG) {
PRINTF("[HackerOoT:INFO]: Warning: Motion Blur is disabled\ntype: %d, startFrame: %d, endFrame: %d, curFrame: %d\n",
cmd->type, cmd->startFrame, cmd->endFrame, csCtx->curFrame
);
}
}
void Cutscene_ProcessScript(PlayState* play, CutsceneContext* csCtx, u8* script) {
s16 i;
s32 totalEntries;
@@ -2196,6 +2229,18 @@ void Cutscene_ProcessScript(PlayState* play, CutsceneContext* csCtx, u8* script)
script += sizeof(CsCmdTransition);
break;
case CS_CMD_MOTION_BLUR:
if (ENABLE_MOTION_BLUR) {
MemCpy(&cmdEntries, script, sizeof(cmdEntries));
script += sizeof(cmdEntries);
for (j = 0; j < cmdEntries; j++) {
CutsceneCmd_MotionBlur(play, csCtx, (CsCmdMotionBlur*)script);
script += sizeof(CsCmdMotionBlur);
}
}
break;
default:
MemCpy(&cmdEntries, script, 4);
script += sizeof(cmdEntries);

View File

@@ -190,6 +190,10 @@ void Play_Destroy(GameState* thisx) {
this->state.gfxCtx->callback = NULL;
this->state.gfxCtx->callbackParam = NULL;
#if ENABLE_MOTION_BLUR
Play_DestroyMotionBlur();
#endif
SREG(91) = 0;
R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_OFF;
@@ -358,6 +362,10 @@ void Play_Init(GameState* thisx) {
KaleidoScopeCall_Init(this);
Interface_Init(this);
#if ENABLE_MOTION_BLUR
Play_InitMotionBlur(this);
#endif
if (gSaveContext.nextDayTime != NEXT_TIME_NONE) {
if (gSaveContext.nextDayTime == NEXT_TIME_DAY) {
gSaveContext.save.totalDays++;
@@ -1050,6 +1058,26 @@ skip:
PLAY_LOG(3816);
Environment_Update(this, &this->envCtx, &this->lightCtx, &this->pauseCtx, &this->msgCtx, &this->gameOverCtx,
this->state.gfxCtx);
if (ENABLE_MOTION_BLUR && ENABLE_MOTION_BLUR_DEBUG) {
// motion blur testing controls
if (CHECK_BTN_ALL(this->state.input[0].press.button, BTN_DUP)) {
R_MOTION_BLUR_ENABLED ^= 1;
}
if (R_MOTION_BLUR_ENABLED != 0) {
if (CHECK_BTN_ALL(this->state.input[0].cur.button, BTN_DRIGHT)) {
R_MOTION_BLUR_ALPHA++;
if (R_MOTION_BLUR_ALPHA > 255) {
R_MOTION_BLUR_ALPHA = 255;
}
} else if (CHECK_BTN_ALL(this->state.input[0].cur.button, BTN_DLEFT)) {
R_MOTION_BLUR_ALPHA--;
if (R_MOTION_BLUR_ALPHA < 0) {
R_MOTION_BLUR_ALPHA = 0;
}
}
}
}
}
void Play_DrawOverlayElements(PlayState* this) {
@@ -1068,6 +1096,109 @@ void Play_DrawOverlayElements(PlayState* this) {
}
}
#if ENABLE_MOTION_BLUR
void PreRender_MotionBlurOpaque(PreRender* this, Gfx** gfxP);
void PreRender_MotionBlur(PreRender* this, Gfx** gfxp, s32 alpha);
extern u16 (*gWorkBuf)[SCREEN_WIDTH * SCREEN_HEIGHT];
static u8 sMotionBlurStatus;
typedef enum {
/* 0 */ MOTION_BLUR_OFF,
/* 1 */ MOTION_BLUR_SETUP,
/* 2 */ MOTION_BLUR_PROCESS
} MotionBlurStatus;
void Play_DrawMotionBlur(PlayState* this) {
GraphicsContext* gfxCtx = this->state.gfxCtx;
s32 alpha;
Gfx* gfx;
Gfx* gfxHead;
if (R_MOTION_BLUR_PRIORITY_ENABLED) {
alpha = R_MOTION_BLUR_PRIORITY_ALPHA;
if (sMotionBlurStatus == MOTION_BLUR_OFF) {
sMotionBlurStatus = MOTION_BLUR_SETUP;
}
} else if (R_MOTION_BLUR_ENABLED) {
alpha = R_MOTION_BLUR_ALPHA;
if (sMotionBlurStatus == MOTION_BLUR_OFF) {
sMotionBlurStatus = MOTION_BLUR_SETUP;
}
} else {
alpha = 0;
sMotionBlurStatus = MOTION_BLUR_OFF;
}
if (sMotionBlurStatus != MOTION_BLUR_OFF) {
OPEN_DISPS(gfxCtx, __FILE__, __LINE__);
gfxHead = POLY_OPA_DISP;
gfx = Gfx_Open(gfxHead);
gSPDisplayList(OVERLAY_DISP++, gfx);
this->pauseBgPreRender.fbuf = gfxCtx->curFrameBuffer;
this->pauseBgPreRender.fbufSave = (u16*)gWorkBuf;
if (sMotionBlurStatus == MOTION_BLUR_PROCESS) {
PreRender_MotionBlur(&this->pauseBgPreRender, &gfx, alpha);
} else {
sMotionBlurStatus = MOTION_BLUR_PROCESS;
}
PreRender_MotionBlurOpaque(&this->pauseBgPreRender, &gfx);
gSPEndDisplayList(gfx++);
Gfx_Close(gfxHead, gfx);
POLY_OPA_DISP = gfx;
CLOSE_DISPS(gfxCtx, __FILE__, __LINE__);
}
}
void Play_InitMotionBlur(PlayState* this) {
R_MOTION_BLUR_ENABLED = false;
R_MOTION_BLUR_PRIORITY_ENABLED = false;
sMotionBlurStatus = MOTION_BLUR_OFF;
this->csCtx.originalBlurAlpha = R_MOTION_BLUR_ALPHA = 0;
}
void Play_DestroyMotionBlur(void) {
R_MOTION_BLUR_ENABLED = false;
R_MOTION_BLUR_PRIORITY_ENABLED = false;
sMotionBlurStatus = MOTION_BLUR_OFF;
}
void Play_SetMotionBlurAlpha(u32 alpha) {
R_MOTION_BLUR_ALPHA = alpha;
}
void Play_EnableMotionBlur(u32 alpha) {
R_MOTION_BLUR_ALPHA = alpha;
R_MOTION_BLUR_ENABLED = true;
}
void Play_DisableMotionBlur(void) {
R_MOTION_BLUR_ENABLED = false;
}
void Play_SetMotionBlurPriorityAlpha(u32 alpha) {
R_MOTION_BLUR_PRIORITY_ALPHA = alpha;
}
void Play_EnableMotionBlurPriority(u32 alpha) {
R_MOTION_BLUR_PRIORITY_ALPHA = alpha;
R_MOTION_BLUR_PRIORITY_ENABLED = true;
}
void Play_DisableMotionBlurPriority(void) {
R_MOTION_BLUR_PRIORITY_ENABLED = false;
}
#endif
void Play_Draw(PlayState* this) {
GraphicsContext* gfxCtx = this->state.gfxCtx;
Lights* sp228;
@@ -1177,6 +1308,10 @@ void Play_Draw(PlayState* this) {
R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_OFF;
}
#if ENABLE_MOTION_BLUR
Play_DrawMotionBlur(this);
#endif
if (R_PAUSE_BG_PRERENDER_STATE == PAUSE_BG_PRERENDER_READY) {
Gfx* gfxP = POLY_OPA_DISP;
@@ -1326,6 +1461,33 @@ void Play_Draw(PlayState* this) {
}
Play_Draw_skip:
if (ENABLE_MOTION_BLUR && ENABLE_MOTION_BLUR_DEBUG) {
// motion blur testing display
GfxPrint printer;
Gfx* gfxRef;
Gfx* gfx;
gfxRef = POLY_OPA_DISP;
gfx = Gfx_Open(POLY_OPA_DISP);
gSPDisplayList(OVERLAY_DISP++, gfx);
GfxPrint_Init(&printer);
GfxPrint_Open(&printer, gfx);
GfxPrint_SetColor(&printer, 255, 255, 55, 32);
GfxPrint_SetPos(&printer, 6, 18);
GfxPrint_Printf(&printer, "Motion Blur Enabled: %x", R_MOTION_BLUR_ENABLED);
GfxPrint_SetPos(&printer, 6, 20);
GfxPrint_Printf(&printer, "Motion Blur Alpha: %x", R_MOTION_BLUR_ALPHA);
gfx = GfxPrint_Close(&printer);
GfxPrint_Destroy(&printer);
gSPEndDisplayList(gfx++);
Gfx_Close(gfxRef, gfx);
POLY_OPA_DISP = gfx;
}
if (this->view.unk_124 != 0) {
Camera_Update(GET_ACTIVE_CAM(this));