diff --git a/lib/rt64 b/lib/rt64 index 7242637..2fb9bd8 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 7242637a73e00d12dcdb36851045d7f657fea7fc +Subproject commit 2fb9bd809b169e12a97f8ab58438c6ca84ef70fd diff --git a/patches/camera_transform_tagging.c b/patches/camera_transform_tagging.c index ec3133e..3ef5477 100644 --- a/patches/camera_transform_tagging.c +++ b/patches/camera_transform_tagging.c @@ -13,6 +13,10 @@ void reset_projection_ids() { cur_ortho_projection_transform_id = 0; } +bool perspective_interpolation_skipped = FALSE; + +s32 getGameMode(void); + extern f32 sViewportFOVy; extern f32 sViewportAspect; extern f32 sViewportNear; @@ -69,7 +73,16 @@ RECOMP_PATCH void viewport_setRenderPerspectiveMatrix(Gfx **gfx, Mtx **mtx, f32 gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE); } else if (cur_perspective_projection_transform_id != 0) { - gEXMatrixGroupSimpleNormal((*gfx)++, cur_perspective_projection_transform_id, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE); + // Force the projection to not adjust itself for a wider aspect ratio when it's being rendered for the Bottles' bonus puzzle or the Mumbo photo. + u16 aspect = G_EX_ASPECT_AUTO; + bool inPictureGameMode = (getGameMode() == GAME_MODE_8_BOTTLES_BONUS) || (getGameMode() == GAME_MODE_A_SNS_PICTURE); + bool isGameplayTransformId = (cur_perspective_projection_transform_id == PROJECTION_GAMEPLAY_TRANSFORM_ID); + bool isTransitionTransformId = (cur_perspective_projection_transform_id == PROJECTION_TRANSITION_TRANSFORM_ID); + if (inPictureGameMode && (isGameplayTransformId || isTransitionTransformId)) { + aspect = G_EX_ASPECT_STRETCH; + } + + gEXMatrixGroup((*gfx)++, cur_perspective_projection_transform_id, G_EX_INTERPOLATE_SIMPLE, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_LINEAR, G_EX_EDIT_NONE, aspect, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_AUTO); } else { gEXMatrixGroupSimpleNormal((*gfx)++, G_EX_ID_AUTO, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE); diff --git a/patches/picture_patches.c b/patches/picture_patches.c new file mode 100644 index 0000000..a223981 --- /dev/null +++ b/patches/picture_patches.c @@ -0,0 +1,204 @@ +#include "patches.h" +#include "transform_ids.h" +#include "functions.h" + +#define TILE_SIZE 32 +#define TILE_COUNT_X 5 +#define TILE_COUNT_Y 4 +#define IMAGE_WIDTH (TILE_SIZE * TILE_COUNT_X) +#define IMAGE_HEIGHT (TILE_SIZE * TILE_COUNT_Y) +#define FROM_XZ 0 +#define FROM_YZ 1 + +extern f32 D_80368250; +extern f32 D_80368360[3]; +extern f32 D_8037DFF0[3]; +extern BKModelBin *D_8037DEA8; +extern BKModelBin *D_8037DFE8; +extern BKModelBin *chBottleBonusBookselfModelBin; +extern ActorMarker *D_8037E000; + +extern s32 getGameMode(void); +extern s16 *func_8030C704(void); +extern void chBottlesBonus_func_802DD080(Gfx **gfx, Mtx **mtx); +extern Actor *func_802DF160(Gfx **gfx, Mtx **mtx, Vtx **vtx); +extern void actor_postdrawMethod(ActorMarker *); +extern void chBottlesBonusCursor_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx); +extern void chBottlesBonus_func_802DD158(Gfx **gfx, Mtx **mtx); +extern BKGfxList *model_getDisplayList(BKModelBin *arg0); + +void patch_picture_model(BKModelBin *model_bin, s32 min_xy, s32 max_xy, s32 min_z, s32 max_z, u32 from) { + // Use pad0 to indicate if the model's been patched already. + if (model_bin->pad0[0] == 0xBA) { + return; + } + + model_bin->pad0[0] = 0xBA; + + BKGfxList *gfx_list = model_getDisplayList(model_bin); + Vtx *vtx_list = model_getVtxList(model_bin)->vtx_18; + Gfx *cur_gfx = &gfx_list->list[0]; + Gfx *end_gfx = (Gfx *)((char *)model_bin + model_bin->vtx_list_offset_10); + bool in_framebuffer_tile = FALSE; + while (cur_gfx < end_gfx) { + if (cur_gfx->words.w0 >> 24 == G_SETTIMG) { + in_framebuffer_tile = cur_gfx->words.w1 == 0x04000000; + if (in_framebuffer_tile) { + // Patch the settimg and the 6 commands after it, replacing with a load of the framebuffer texture. + Gfx* g = cur_gfx; + Gfx* ng = cur_gfx + 1; + u8 fmt = (ng->words.w0 >> 21) & 0x7; + gDPLoadTextureTile(g++, 0x04000000, fmt, G_IM_SIZ_16b, 160, 128, 0, 0, 160 - 1, 128 - 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); + } + } + else if (cur_gfx->words.w0 >> 24 == G_VTX) { + // Patch vertices. Get the loaded vertex count for this command. + u32 cur_vtx_count = (cur_gfx->words.w0 >> 10) & 0b111111; + + // Get the vertex address, converting from a segmented address if necessary. + Vtx *cur_vtx; + if (cur_gfx->words.w1 >> 24 == 0x01) { + cur_vtx = (Vtx *)(SEGMENT_OFFSET(cur_gfx->words.w1) + (char *)vtx_list); + } + else { + // Not a segmented address (should never happen, but may help with compatibility for future mods). + cur_vtx = (Vtx *)cur_gfx->words.w1; + } + + if (in_framebuffer_tile) { + if (from == FROM_YZ) { + for (u32 i = 0; i < cur_vtx_count; i++) { + float xy_frac = (cur_vtx[i].v.ob[1] - (float)min_xy) / (max_xy - min_xy); + float z_frac = (cur_vtx[i].v.ob[2] - (float)min_z) / (max_z - min_z); + cur_vtx[i].v.tc[0] = z_frac * 160.0f * 64.0f; + cur_vtx[i].v.tc[1] = (1.0f - xy_frac) * 128.0f * 64.0f; + } + } + else if (from == FROM_XZ) { + for (u32 i = 0; i < cur_vtx_count; i++) { + float xy_frac = (cur_vtx[i].v.ob[0] - (float)min_xy) / (max_xy - min_xy); + float z_frac = (cur_vtx[i].v.ob[2] - (float)min_z) / (max_z - min_z); + cur_vtx[i].v.tc[0] = xy_frac * 160.0f * 64.0f; + cur_vtx[i].v.tc[1] = (1.0f - z_frac) * 128.0f * 64.0f; + } + } + } + + for (u32 i = 0; i < cur_vtx_count; i++) { + if (cur_vtx[i].v.ob[0] == 568) { + cur_vtx[i].v.ob[0] = 567; + } + } + } + + cur_gfx++; + } +} + +// @recomp Patches the model for the puzzle to fix the seams. +RECOMP_PATCH Actor *chBottlesBonus_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *sp6C; + f32 sp60[3]; + f32 sp54[3]; + void *sp50; + + sp6C = marker_getActor(marker); + sp50 = func_8030C704(); //grabs frame as texture? + if ((sp50 == NULL) || (getGameMode() != GAME_MODE_8_BOTTLES_BONUS)) + return sp6C; + + chBottlesBonus_func_802DD080(gfx, mtx); + { sp60[0] = 0.0f; sp60[1] = 0.0f; sp60[2] = 0.0f; }; + { sp54[0] = 0.0f; sp54[1] = 0.0f; sp54[2] = 0.0f; }; + modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); + modelRender_draw(gfx, mtx, sp60, NULL, 1.0f, sp54, chBottleBonusBookselfModelBin); + modelRender_draw(gfx, mtx, sp60, NULL, 1.0f, sp54, D_8037DEA8); + + gDPSetTextureFilter((*gfx)++, G_TF_POINT); + gDPSetColorDither((*gfx)++, G_CD_DISABLE); + func_802DF160(gfx, mtx, vtx); + func_80253190(gfx); + + gDPSetTextureFilter((*gfx)++, G_TF_POINT); + gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp50)); + modelRender_preDraw((GenFunction_1)actor_predrawMethod, (s32)sp6C); + modelRender_postDraw((GenFunction_1)actor_postdrawMethod, (s32)marker); + + // @recomp Load and patch the puzzle model. + BKModelBin *model_bin = marker_loadModelBin(marker); + patch_picture_model(model_bin, 260, 398, -273, -100, FROM_YZ); + + modelRender_draw(gfx, mtx, sp60, NULL, D_80368250, sp54, model_bin); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + gDPSetColorDither((*gfx)++, G_CD_MAGICSQ); + chBottlesBonusCursor_draw(gfx, mtx, vtx); + chBottlesBonus_func_802DD158(gfx, mtx); + return sp6C; +} + +// @recomp Patches the model for the background picture to fix the seams. +RECOMP_PATCH Actor *func_802DF160(Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *this; + void *sp38; + + this = marker_getActor(D_8037E000); + sp38 = func_8030C704(); + modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); + gDPSetTextureFilter((*gfx)++, G_TF_POINT); + gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp38)); + modelRender_preDraw((GenFunction_1)actor_predrawMethod, (s32)this); + modelRender_postDraw((GenFunction_1)actor_postdrawMethod, (s32)D_8037E000); + + // @recomp Load and patch the picture model. + BKModelBin *model_bin = marker_loadModelBin(D_8037E000); + patch_picture_model(model_bin, 262, 397, -273, -100, FROM_YZ); + + modelRender_draw(gfx, mtx, &D_80368360, NULL, 1.0f, NULL, model_bin); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + return this; +} + +// @recomp Patches the model for the photo to fix the seams. +RECOMP_PATCH Actor *func_802DEC00(ActorMarker *marker, Gfx **gfx, Mtx **mtx, Vtx **vtx) { + Actor *this; + f32 sp58[3]; + f32 sp4C[3]; + void *sp48; + + + this = marker_getActor(marker); + sp48 = func_8030C704(); + + if ((sp48 == 0) || (getGameMode() != GAME_MODE_A_SNS_PICTURE)) + return this; + + chBottlesBonus_func_802DD080(gfx, mtx); + sp58[0] = 0.0f; + sp58[1] = 0.0f; + sp58[2] = 50.0f; + + sp4C[0] = 0.0f; + sp4C[1] = 0.0f; + sp4C[2] = 0.0f; + + D_8037DFF0[0] = 0.0f; + D_8037DFF0[1] = 270.0f; + D_8037DFF0[2] = 0.0f; + modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); + modelRender_draw(gfx, mtx, sp58, NULL, 1.0f, sp4C, D_8037DFE8); + gDPSetColorDither((*gfx)++, G_CD_DISABLE); + func_80253190(gfx); + gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp48)); + modelRender_preDraw((GenFunction_1)actor_predrawMethod, (s32)this); + modelRender_postDraw((GenFunction_1)actor_postdrawMethod, (s32)marker); + + // @recomp Load and patch the photo model. + BKModelBin *model_bin = marker_loadModelBin(marker); + patch_picture_model(model_bin, -55, -5, -6, 34, FROM_XZ); + + modelRender_draw(gfx, mtx, this->position, NULL, 4.5f, sp4C, model_bin); + gDPSetTextureFilter((*gfx)++, G_TF_BILERP); + gDPSetColorDither((*gfx)++, G_CD_MAGICSQ); + chBottlesBonus_func_802DD158(gfx, mtx); + return this; +} \ No newline at end of file diff --git a/patches/transition_patches.c b/patches/transition_patches.c index 47f1867..8d47228 100644 --- a/patches/transition_patches.c +++ b/patches/transition_patches.c @@ -293,9 +293,13 @@ RECOMP_PATCH void gctransition_draw(Gfx **gdl, Mtx **mptr, Vtx **vptr){ modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL); } - // @recomp Calculate the ratio between the original aspect ratio and the current aspect ratio. + // @recomp Calculate the ratio between the original aspect ratio and the current aspect ratio, except when in picture mode. float original_aspect = (float)DEFAULT_FRAMEBUFFER_WIDTH / DEFAULT_FRAMEBUFFER_HEIGHT; float cur_aspect = recomp_get_target_aspect_ratio(original_aspect); + if (getGameMode() == GAME_MODE_A_SNS_PICTURE) { + cur_aspect = original_aspect; + } + float aspect_ratio_ratio = cur_aspect / original_aspect; // @recomp Determine what scaling to use based on the transition type.