mirror of
https://github.com/BanjoRecomp/BanjoRecomp
synced 2026-06-03 18:06:09 -04:00
Add level model hotpatch for intro scene to fix gap in widescreen
Co-authored-by: Reonu <15913880+Reonu@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
#include "patches.h"
|
||||
#include "misc_funcs.h"
|
||||
#include "functions.h"
|
||||
#include "bk_api.h"
|
||||
#include "object_extension_funcs.h"
|
||||
|
||||
extern ActorMarker *D_8036E7C8;
|
||||
extern u8 D_80383428[0x1C];
|
||||
|
||||
typedef struct {
|
||||
s16 map_id; //enum map_e
|
||||
s16 opa_model_id; //enum asset_e level_model_id
|
||||
s16 xlu_model_id; //enum asset_e level2_model_id
|
||||
s16 unk6[3]; // min bounds (for cubes?)
|
||||
s16 unkC[3]; // max bounds (for cubes?)
|
||||
// u8 pad12[0x2];
|
||||
f32 scale;
|
||||
}MapModelDescription;
|
||||
|
||||
extern struct {
|
||||
void *unk0;
|
||||
void *unk4;
|
||||
BKCollisionList *collision_opa;
|
||||
BKCollisionList *collision_xlu;
|
||||
BKModel *model_opa;
|
||||
BKModel *model_xlu;
|
||||
BKModelBin *model_bin_opa;
|
||||
BKModelBin *model_bin_xlu;
|
||||
s32 unk20;
|
||||
struct5Bs *unk24;
|
||||
MapModelDescription *description;
|
||||
u8 env_red;
|
||||
u8 env_green;
|
||||
u8 env_blue;
|
||||
f32 scale;
|
||||
}mapModel;
|
||||
|
||||
BKGfxList *model_getDisplayList(BKModelBin *arg0);
|
||||
|
||||
|
||||
#define INTRO_OPA_DL_LENGTH 97
|
||||
#define INTRO_OPA_DL_GRASS_PATCH_INDEX 63
|
||||
#define INTRO_OPA_DL_WALL_PATCH_INDEX 84
|
||||
#define INTRO_OPA_DL_HASH 0xA912614C535FA0BBULL
|
||||
|
||||
Vtx intro_grass_extension_verts[3] = {
|
||||
{{ {-1262, 20, 1040}, 0, {214, 522}, {51, 190, 133, 255} }},
|
||||
{{ {-10, 20, 5107}, 0, {3108, -10083}, {0, 13, 169, 255} }},
|
||||
{{ {-10, 20, 1372}, 0, {3360, -211}, {51, 190, 133, 255} }},
|
||||
};
|
||||
|
||||
Gfx intro_grass_extension_dl[] = {
|
||||
// Copy of the replaced command.
|
||||
gsSP1Triangle(31, 28, 29, 0),
|
||||
// New commands.
|
||||
gsSPVertex(intro_grass_extension_verts + 0, 3, 0),
|
||||
gsSP1Triangle(0, 1, 2, 0),
|
||||
gsSPEndDisplayList(),
|
||||
};
|
||||
|
||||
Vtx intro_wall_extension_verts[4] = {
|
||||
{{ {-1262, 20, 1040}, 0, {-31, 33}, {51, 190, 133, 255} }},
|
||||
{{ {-1262, 1004, 1040}, 0, {-60, 1950}, {255, 255, 255, 255} }},
|
||||
{{ {189, 1004, 4315}, 0, {-7416, 1801}, {255, 255, 255, 255} }},
|
||||
{{ {189, 20, 4315}, 0, {-7387, -116}, {51, 190, 133, 255} }},
|
||||
};
|
||||
|
||||
Gfx intro_wall_extension_dl[] = {
|
||||
// Copy of the replaced command.
|
||||
gsSP1Triangle(22, 24, 21, 0),
|
||||
// New commands.
|
||||
gsSPVertex(intro_wall_extension_verts + 0, 4, 0),
|
||||
gsSP2Triangles(0, 1, 2, 0, 0, 2, 3, 0),
|
||||
gsSPEndDisplayList(),
|
||||
};
|
||||
|
||||
void hotpatch_intro_opa_map_model(BKModelBin* model_bin) {
|
||||
BKGfxList *gfx_list = model_getDisplayList(model_bin);
|
||||
Gfx* dl = &gfx_list->list[0];
|
||||
|
||||
// Hash the displaylist of the model to make sure it's unmodified. This will prevent the hotpatch from
|
||||
// affecting mods.
|
||||
u64 hash = recomp_xxh3(dl, INTRO_OPA_DL_LENGTH * sizeof(Gfx));
|
||||
if (hash != INTRO_OPA_DL_HASH) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Patch a call to the new displaylist after the grass material.
|
||||
gSPDisplayList(&dl[INTRO_OPA_DL_GRASS_PATCH_INDEX], intro_grass_extension_dl);
|
||||
|
||||
// Patch a call to the new displaylist after the wall material.
|
||||
gSPDisplayList(&dl[INTRO_OPA_DL_WALL_PATCH_INDEX], intro_wall_extension_dl);
|
||||
}
|
||||
|
||||
// @recomp Patched to act as a point to run code when a new map is loaded.
|
||||
// This includes:
|
||||
// * Resetting all extended marker data and skip interpolation for the next frame.
|
||||
// * Hotpatching the map model for the title cutscene to fix ultrawide effects.
|
||||
RECOMP_PATCH void func_803329AC(void){
|
||||
s32 i;
|
||||
|
||||
D_8036E7C8 = (ActorMarker *)malloc(0xE0*sizeof(ActorMarker));
|
||||
|
||||
for( i = 0; i < 0x1C; i++){
|
||||
D_80383428[i] = 0;
|
||||
}
|
||||
|
||||
for(i =0; i<0xE0; i++){
|
||||
D_8036E7C8[i].unk5C = 0;
|
||||
}
|
||||
|
||||
// @recomp Run any new code on map load.
|
||||
|
||||
// @recomp If the current map's model is ASSET_149D_MODEL_CS_START_NINTENDO_OPA,
|
||||
// hotpatch it to fill in some regions for widescreen.
|
||||
if (mapModel.description->opa_model_id == ASSET_149D_MODEL_CS_START_NINTENDO_OPA) {
|
||||
hotpatch_intro_opa_map_model(mapModel.model_bin_opa);
|
||||
}
|
||||
|
||||
// @recomp Reset all actor data and skip interpolation for the next frame.
|
||||
// Interpolation is skipped as the next frame will potentially reuse IDs from the previous frame,
|
||||
// as the marker ID tracking gets reset here.
|
||||
recomp_clear_all_object_data(EXTENSION_TYPE_MARKER);
|
||||
set_all_interpolation_skipped(TRUE);
|
||||
}
|
||||
@@ -15,27 +15,6 @@ extern u8 D_80383428[0x1C];
|
||||
void func_8032F3D4(s32 arg0[3], ActorMarker *marker, s32 arg2);
|
||||
ActorMarker * func_80332A60(void);
|
||||
|
||||
// @recomp Patched to reset all extended marker data and skip interpolation for the next frame.
|
||||
RECOMP_PATCH void func_803329AC(void){
|
||||
s32 i;
|
||||
|
||||
D_8036E7C8 = (ActorMarker *)malloc(0xE0*sizeof(ActorMarker));
|
||||
|
||||
for( i = 0; i < 0x1C; i++){
|
||||
D_80383428[i] = 0;
|
||||
}
|
||||
|
||||
for(i =0; i<0xE0; i++){
|
||||
D_8036E7C8[i].unk5C = 0;
|
||||
}
|
||||
|
||||
// @recomp Reset all actor data and skip interpolation for the next frame.
|
||||
// Interpolation is skipped as the next frame will potentially reuse IDs from the previous frame,
|
||||
// as the marker ID tracking gets reset here.
|
||||
recomp_clear_all_object_data(EXTENSION_TYPE_MARKER);
|
||||
set_all_interpolation_skipped(TRUE);
|
||||
}
|
||||
|
||||
// @recomp Patched to create extension data for the marker.
|
||||
RECOMP_PATCH ActorMarker * marker_init(s32 *pos, MarkerDrawFunc draw_func, int arg2, int marker_id, int arg4){
|
||||
ActorMarker * marker = func_80332A60();
|
||||
|
||||
@@ -7,5 +7,6 @@ DECLARE_FUNC(void, recomp_load_overlays, u32 rom, void* ram, u32 size);
|
||||
DECLARE_FUNC(void, recomp_puts, const char* data, u32 size);
|
||||
DECLARE_FUNC(void, recomp_exit);
|
||||
DECLARE_FUNC(void, recomp_error, const char* str);
|
||||
DECLARE_FUNC(u64, recomp_xxh3, void* data, u32 size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,3 +36,4 @@ osPiStartDma_recomp = 0x8F00007C;
|
||||
recomp_abort = 0x8F000080;
|
||||
recomp_get_target_aspect_ratio = 0x8F000084;
|
||||
osExQueueDisplaylistEvent_recomp = 0x8F000088;
|
||||
recomp_xxh3 = 0x8F00008C;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "../patches/sound.h"
|
||||
#include "ultramodern/ultramodern.hpp"
|
||||
#include "ultramodern/config.hpp"
|
||||
#include "../lib/N64ModernRuntime/thirdparty/xxHash/xxh3.h"
|
||||
|
||||
extern "C" void recomp_update_inputs(uint8_t* rdram, recomp_context* ctx) {
|
||||
recomp::poll_inputs();
|
||||
@@ -219,3 +220,20 @@ extern "C" void recomp_abort(uint8_t* rdram, recomp_context* ctx) {
|
||||
assert(false);
|
||||
ultramodern::error_handling::quick_exit(__FILE__, __LINE__, __FUNCTION__);
|
||||
}
|
||||
|
||||
extern "C" void recomp_xxh3(uint8_t* rdram, recomp_context* ctx) {
|
||||
PTR(void) data = _arg<0, PTR(void)>(rdram, ctx);
|
||||
u32 size = _arg<1, u32>(rdram, ctx);
|
||||
XXH3_state_t xxh3;
|
||||
XXH3_64bits_reset(&xxh3);
|
||||
|
||||
// Hash 1 byte at a time to account for byteswapping.
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
XXH3_64bits_update(&xxh3, TO_PTR(u8, data + i), 1);
|
||||
}
|
||||
|
||||
uint64_t ret = XXH3_64bits_digest(&xxh3);
|
||||
|
||||
ctx->r2 = (int32_t)(ret >> 32);
|
||||
ctx->r3 = (int32_t)(ret >> 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user