Fix: Write framebuffer data to CPU for Deku bubble (#236)

* use framebuffer data for deku bubble

* review feedback
This commit is contained in:
Archez
2024-05-22 09:05:03 -05:00
committed by Garrett Cox
parent ecf0f2a06f
commit 0916ba52f5
4 changed files with 73 additions and 36 deletions
+45 -4
View File
@@ -10,8 +10,8 @@ s32 gBlurFrameBuffer = -1;
// i.e. the VisMono and VisFbuf effects
s32 gReusableFrameBuffer = -1;
// Picto box buffer is unscaled at 320x240
s32 gPictoBoxFrameBuffer = -1;
// N64 resolution sized buffer (320x240), used by picto box and deku bubble
s32 gN64ResFrameBuffer = -1;
void FB_CreateFramebuffers(void) {
if (gPauseFrameBuffer == -1) {
@@ -26,8 +26,8 @@ void FB_CreateFramebuffers(void) {
gReusableFrameBuffer = gfx_create_framebuffer(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT, true);
}
if (gPictoBoxFrameBuffer == -1) {
gPictoBoxFrameBuffer = gfx_create_framebuffer(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT, false);
if (gN64ResFrameBuffer == -1) {
gN64ResFrameBuffer = gfx_create_framebuffer(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT, false);
}
}
@@ -65,6 +65,47 @@ void FB_CopyToFramebuffer(Gfx** gfxp, s32 fb_src, s32 fb_dest, u8 oncePerFrame,
*gfxp = gfx;
}
/**
* Copies a 4:3 slice of the current framebuffer scaled down to 320x240 to a CPU buffer address.
* The buffer output will be in RGBA16 format.
* Specify the byteswap flag to force the buffer data to be written as BigEndian, which is
* required if the buffer is being used as a texture in F3D.
*/
void FB_WriteFramebufferSliceToCPU(Gfx** gfxp, void* buffer, u8 byteSwap) {
Gfx* gfx = *gfxp;
FB_CopyToFramebuffer(&gfx, 0, gReusableFrameBuffer, false, NULL);
// Set the N64 resolution framebuffer as the draw target (320x240)
gsSPSetFB(gfx++, gN64ResFrameBuffer);
int16_t s0 = 0, t0 = 0;
int16_t s1 = OTRGetGameRenderWidth();
int16_t t1 = OTRGetGameRenderHeight();
float aspectRatio = OTRGetAspectRatio();
float fourByThree = 4.0f / 3.0f;
// Adjust the texture coordinates so that only a 4:3 region from the center is drawn
// to the N64 resolution buffer. Currently ratios smaller than 4:3 will just stretch to fill.
if (aspectRatio > fourByThree) {
int16_t adjustedWidth = OTRGetGameRenderWidth() / (aspectRatio / fourByThree);
s0 = (OTRGetCurrentWidth() - adjustedWidth) / 2;
s1 -= s0;
}
gDPSetTextureImageFB(gfx++, 0, 0, 0, gReusableFrameBuffer);
gDPImageRectangle(gfx++, 0 << 2, 0 << 2, s0, t0, SCREEN_WIDTH << 2, SCREEN_HEIGHT << 2, s1, t1, G_TX_RENDERTILE,
OTRGetGameRenderWidth(), OTRGetGameRenderHeight());
// Read the final N64 framebuffer back as rgba16 into the CPU-side buffer
gDPReadFB(gfx++, gN64ResFrameBuffer, buffer, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, byteSwap);
gsSPResetFB(gfx++);
*gfxp = gfx;
}
/**
* Draws the texture data from the specified frame buffer as a full screen image
*/
+2 -1
View File
@@ -6,10 +6,11 @@
extern s32 gPauseFrameBuffer;
extern s32 gBlurFrameBuffer;
extern s32 gReusableFrameBuffer;
extern s32 gPictoBoxFrameBuffer;
extern s32 gN64ResFrameBuffer;
void FB_CreateFramebuffers(void);
void FB_CopyToFramebuffer(Gfx** gfxp, s32 fb_src, s32 fb_dest, u8 oncePerFrame, u8* hasCopied);
void FB_WriteFramebufferSliceToCPU(Gfx** gfxp, void* buffer, u8 byteSwap);
void FB_DrawFromFramebuffer(Gfx** gfxp, s32 fb, u8 alpha);
void FB_DrawFromFramebufferScaled(Gfx** gfxp, s32 fb, u8 alpha, float scaleX, float scaleY);
+2 -31
View File
@@ -1476,37 +1476,8 @@ void Play_DrawMain(PlayState* this) {
// this->pauseBgPreRender.cvgSave = this->unk_18E58;
this->pauseBgPreRender.cvgSave = NULL;
// #region 2S2H [Port] Custom handling for picto box capture
// Copy to our reusable buffer first
FB_CopyToFramebuffer(&sp74, 0, gReusableFrameBuffer, false, NULL);
// Set the picto framebuffer as the draw target (320x240)
gsSPSetFB(sp74++, gPictoBoxFrameBuffer);
int16_t s0 = 0, t0 = 0;
int16_t s1 = OTRGetGameRenderWidth();
int16_t t1 = OTRGetGameRenderHeight();
float aspectRatio = OTRGetAspectRatio();
float fourByThree = 4.0f / 3.0f;
// Adjsut the texture coordinates so that only a 4:3 region from the center is drawn
// to the picto buffer. Currently ratios smaller than 4:3 will just stretch to fill.
if (aspectRatio > fourByThree) {
int16_t adjustedWidth = OTRGetGameRenderWidth() / (aspectRatio / fourByThree);
s0 = (OTRGetCurrentWidth() - adjustedWidth) / 2;
s1 -= s0;
}
gDPSetTextureImageFB(sp74++, 0, 0, 0, gReusableFrameBuffer);
gDPImageRectangle(sp74++, 0 << 2, 0 << 2, s0, t0, SCREEN_WIDTH << 2, SCREEN_HEIGHT << 2, s1, t1,
G_TX_RENDERTILE, OTRGetGameRenderWidth(), OTRGetGameRenderHeight());
// Read the picto box framebuffer back as a rgba16 buffer
gDPReadFB(sp74++, gPictoBoxFrameBuffer, this->pauseBgPreRender.fbufSave, 0, 0, SCREEN_WIDTH,
SCREEN_HEIGHT, false);
gsSPResetFB(sp74++);
// #region 2S2H [Port] Custom handling for picto box capture to CPU
FB_WriteFramebufferSliceToCPU(&sp74, this->pauseBgPreRender.fbufSave, false);
// #endregion
} else {
gTransitionTileState = TRANS_TILE_PROCESS;
@@ -8,6 +8,8 @@
#include "overlays/effects/ovl_Effect_Ss_Sbn/z_eff_ss_sbn.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "2s2h/framebuffer_effects.h"
#define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20)
#define THIS ((EnArrow*)thisx)
@@ -672,6 +674,17 @@ void EnArrow_Draw(Actor* thisx, PlayState* play) {
if (this->actor.speed == 0.0f) {
func_800B8118(&this->actor, play, 0);
// #region 2S2H [Port] Capture framebuffer to current frame, byteswaped, so that it will
// be read from seg 0x0F in gameplay_keep_DL_06F380
Gfx* gfx = POLY_XLU_DISP;
FB_WriteFramebufferSliceToCPU(&gfx, play->state.gfxCtx->curFrameBuffer, true);
POLY_XLU_DISP = gfx;
// Only a portion of the buffer is used as a texture, so we need to invalidate by the same offset
// Offset derived from ((ult * width + uls) * 2), with values taken from the DL directly
gSPInvalidateTexCache(POLY_XLU_DISP++,
(uintptr_t)(play->state.gfxCtx->curFrameBuffer) + ((104 * 320 + 144) * 2));
// #endregion
gSPDisplayList(POLY_XLU_DISP++, gameplay_keep_DL_06F380);
gDPSetRenderMode(POLY_XLU_DISP++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_SURF2);
gDPSetCombineLERP(POLY_XLU_DISP++, TEXEL1, 0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0,
@@ -686,6 +699,17 @@ void EnArrow_Draw(Actor* thisx, PlayState* play) {
} else {
func_800B8050(&this->actor, play, 0);
// #region 2S2H [Port] Capture framebuffer to current frame, byteswaped, so that it will
// be read from seg 0x0F in gameplay_keep_DL_06F380
Gfx* gfx = POLY_OPA_DISP;
FB_WriteFramebufferSliceToCPU(&gfx, play->state.gfxCtx->curFrameBuffer, true);
POLY_OPA_DISP = gfx;
// Only a portion of the buffer is used as a texture, so we need to invalidate by the same offset
// Offset derived from ((ult * width + uls) * 2), with values taken from the DL directly
gSPInvalidateTexCache(POLY_OPA_DISP++,
(uintptr_t)(play->state.gfxCtx->curFrameBuffer) + ((104 * 320 + 144) * 2));
// #endregion
gSPDisplayList(POLY_OPA_DISP++, gameplay_keep_DL_06F380);
gDPSetCombineLERP(POLY_OPA_DISP++, TEXEL1, 0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0,
COMBINED, 0, PRIMITIVE, 0, 0, 0, 0, COMBINED);