Add patch for skipping camera interpolation during non-gameplay segments. (#6)

* Add patch for skipping camera interpolation during non-gameplay segments.

* Fix ignore interpolation patches. Add skip for zoombox.
This commit is contained in:
Darío
2025-12-20 14:41:47 -03:00
committed by GitHub
parent b3886866b9
commit 498002a425
8 changed files with 153 additions and 41 deletions
+112 -17
View File
@@ -1,6 +1,7 @@
#include "patches.h"
#include "transform_ids.h"
#include "core1/core1.h"
#include "core2/nc/camera.h"
s32 cur_perspective_projection_transform_id = 0;
s32 backup_perspective_projection_transform_id = 0;
@@ -13,7 +14,11 @@ void reset_projection_ids() {
cur_ortho_projection_transform_id = 0;
}
bool perspective_interpolation_skipped = FALSE;
bool skip_perspective_interpolation = FALSE;
bool perspective_interpolation_skipped() {
return skip_perspective_interpolation;
}
s32 getGameMode(void);
@@ -75,20 +80,26 @@ RECOMP_PATCH void viewport_setRenderPerspectiveMatrix(Gfx **gfx, Mtx **mtx, f32
gEXSetViewMatrixFloat((*gfx)++, view->m);
// @recomp If a perspective projection transform ID is set, apply it as the projection matrix group. Otherwise, use auto as the projection matrix group.
if (all_interpolation_skipped()) {
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
}
else if (cur_perspective_projection_transform_id != 0) {
// 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;
bool skip_interpolation = all_interpolation_skipped() || perspective_interpolation_skipped();
if (cur_perspective_projection_transform_id != 0) {
if (skip_interpolation) {
gEXMatrixGroupSkipAll((*gfx)++, cur_perspective_projection_transform_id, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
}
else {
// 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);
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 if (skip_interpolation) {
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
}
else {
gEXMatrixGroupSimpleNormal((*gfx)++, G_EX_ID_AUTO, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
@@ -116,11 +127,16 @@ RECOMP_PATCH void viewport_setRenderViewportAndOrthoMatrix(Gfx **gfx, Mtx **mtx)
gEXSetViewMatrixFloat((*gfx)++, identity_matrix);
// @recomp If an ortho projection transform ID is set, apply it as the projection matrix group. Otherwise, use auto as the projection matrix group.
if (all_interpolation_skipped()) {
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
if (cur_ortho_projection_transform_id != 0) {
if (all_interpolation_skipped()) {
gEXMatrixGroupSkipAll((*gfx)++, cur_ortho_projection_transform_id, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
}
else {
gEXMatrixGroupSimpleNormal((*gfx)++, cur_ortho_projection_transform_id, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
}
}
else if (cur_ortho_projection_transform_id != 0) {
gEXMatrixGroupSimpleNormal((*gfx)++, cur_ortho_projection_transform_id, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
else if (all_interpolation_skipped()) {
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
}
else {
gEXMatrixGroupSimpleNormal((*gfx)++, G_EX_ID_AUTO, G_EX_NOPUSH, G_MTX_PROJECTION, G_EX_EDIT_NONE);
@@ -168,3 +184,82 @@ RECOMP_PATCH void viewport_restoreState(void) {
cur_perspective_projection_transform_id = backup_perspective_projection_transform_id;
cur_ortho_projection_transform_id = backup_ortho_projection_transform_id;
}
extern s32 ncCameraType;
extern u8 D_8037D8C5;
extern u8 D_8037D8C6;
void ncDynamicCamera_update(void);
void ncStaticCamera_update(void);
void ncRandomCamera_update(void);
void func_802BB4D8(f32 position[3], f32 rotation[3]);
void func_802BEFB0(void);
void func_802BBA84(void);
// @recomp Patched to detect camera type changes or sudden camera movements and skip perspective interpolation when they happen.
RECOMP_PATCH void ncCamera_update(void) {
f32 vpPos[3];
f32 vpRot[3];
s32 camType;
camType = ncCameraType;
if (!D_8037D8C5 && !D_8037D8C6) {
camType = 0;
}
switch (camType) {
case CAMERA_TYPE_2_DYNAMIC://dynamic viewport position
ncDynamicCamera_update();
break;
case CAMERA_TYPE_3_STATIC://set viewport to static location
ncStaticCamera_update();
break;
case CAMERA_TYPE_4_RANDOM: //set viewport to random location
ncRandomCamera_update();
break;
}
viewport_getPosition_vec3f(vpPos);
viewport_getRotation_vec3f(vpRot);
func_802BB4D8(vpPos, vpRot);
viewport_setPosition_vec3f(vpPos);
viewport_setRotation_vec3f(vpRot);
// @recomp Detect camera type changes or sudden camera movements.
static s32 camTypePrev = 0;
static f32 vpPosPrev[3] = {};
static f32 vpPosVel[3] = {};
f32 vpPosDelta[3];
ml_vec3f_diff_copy(vpPosDelta, vpPos, vpPosPrev);
if (camType != camTypePrev) {
// Always skip perspective interpolation on camera type changes.
skip_perspective_interpolation = TRUE;
}
else if (camType == CAMERA_TYPE_2_DYNAMIC) {
// Never skip interpolation during controllable gameplay.
skip_perspective_interpolation = FALSE;
}
else {
// Check for sudden position differences. They must be within an arbitrary threshold o
// the projected position from using the previous frame's velocity.
f32 vpPosProjected[3];
ml_vec3f_add(vpPosProjected, vpPosPrev, vpPosVel);
f32 distToProjected = ml_vec3f_distance(vpPos, vpPosProjected);
const f32 SkipThreshold = 100.0f;
if (distToProjected > SkipThreshold) {
ml_vec3f_clear(vpPosVel);
skip_perspective_interpolation = TRUE;
}
else {
ml_vec3f_copy(vpPosVel, vpPosDelta);
skip_perspective_interpolation = FALSE;
}
}
camTypePrev = camType;
ml_vec3f_copy(vpPosPrev, vpPos);
viewport_update();
func_802BEFB0();
func_802BBA84();
}
+1 -1
View File
@@ -132,7 +132,7 @@ RECOMP_PATCH void __particleEmitter_drawOnPass(ParticleEmitter *this, Gfx **gfx,
func_80344C2C(this->unk0_16);
// @recomp Get the particle's ID and use it to set a matrix group for this particle.
u32 transform_id = NORMAL_PARTICLE_TRANSFORM_ID_START + get_particle_id(iPtr);
gEXMatrixGroupDecomposedNormal((*gfx)++, transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
gEXMatrixGroupDecomposedNormal((*gfx)++, transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
if(this->draw_mode & PART_EMIT_ROTATABLE){
func_80344720(this->unk34, (s32)iPtr->frame, 0, position, flat_rotation, scale, gfx, mtx);
+4
View File
@@ -50,6 +50,9 @@ void osWriteBackDCacheAll(void);
)
#endif
#define gEXMatrixGroupSkipAll(cmd, id, push, proj, edit) \
gEXMatrixGroup(cmd, id, G_EX_INTERPOLATE_SIMPLE, push, proj, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_ORDER_LINEAR, edit, G_EX_ASPECT_AUTO, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP)
#define gEXMatrixGroupSimpleNormal(cmd, id, push, proj, edit) \
gEXMatrixGroup(cmd, id, G_EX_INTERPOLATE_SIMPLE, push, proj, 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, edit, G_EX_ASPECT_AUTO, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_AUTO)
@@ -82,5 +85,6 @@ void set_additional_model_scale(f32 x, f32 y, f32 z);
void set_frustum_checks_enabled(int enabled);
void set_all_interpolation_skipped(bool skipped);
bool all_interpolation_skipped();
bool perspective_interpolation_skipped();
#endif
+4 -1
View File
@@ -291,14 +291,17 @@ RECOMP_PATCH void func_803163A8(GcZoombox *this, Gfx **gfx, Mtx **mtx) {
anctrl_drawSetup(this->anim_ctrl, sp50, 1);
}
// @recomp Set the model transform ID.
// @recomp Set the model transform ID. Skip interpolation when the camera does a cut.
u32 prev_transform_id = cur_drawn_model_transform_id;
s32 prev_skip = cur_drawn_model_transform_id_skip_interpolation;
cur_drawn_model_transform_id = ZOOMBOX_TRANSFORM_ID_START + this->portrait_id;
cur_drawn_model_transform_id_skip_interpolation = perspective_interpolation_skipped();
modelRender_draw(gfx, mtx, sp50, sp5C, this->unk198 * sp34, sp38, this->model);
// @recomp Reset the model transform ID.
cur_drawn_model_transform_id = prev_transform_id;
cur_drawn_model_transform_id_skip_interpolation = prev_skip;
}
// @recomp Patched to set the zoombox portrait's model and ortho projection transform IDs.
+10 -6
View File
@@ -92,12 +92,16 @@ RECOMP_PATCH void func_8032D510(Cube *cube, Gfx **gfx, Mtx **mtx, Vtx **vtx){
// @recomp Set the matrix group before drawing the sprite.
// Skip interpolation on vertices to account for vertex lists changing between frames of the sprite.
// Also skip interpolation on scale to account for the scale inverting when sprites are mirrored.
// TODO track this matrix for skipping interpolation when camera interpolation is skipped.
gEXMatrixGroupDecomposed((*gfx)++, base_transform_id, G_EX_PUSH, G_MTX_MODELVIEW,
G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE,
G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE,
G_EX_ORDER_LINEAR, G_EX_EDIT_ALLOW, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_AUTO);
if (perspective_interpolation_skipped()) {
gEXMatrixGroupSkipAll((*gfx)++, base_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
}
else {
gEXMatrixGroupDecomposed((*gfx)++, base_transform_id, G_EX_PUSH, G_MTX_MODELVIEW,
G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE,
G_EX_COMPONENT_INTERPOLATE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE,
G_EX_ORDER_LINEAR, G_EX_EDIT_NONE, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_AUTO);
}
// @recomp Also set the model render transform ID before drawing the sprite. This won't have any effect
// in the unmodified game, but will allow transform tagging for mods that draw models in place of sprites.
cur_drawn_model_transform_id = base_transform_id;
+3 -2
View File
@@ -198,12 +198,13 @@ RECOMP_PATCH bool func_802F989C(Gfx **gfx, Mtx **mtx, f32 arg2[3]) {
// @recomp Set a matrix group before drawing the snow particle. If the interpolation skip bit is enabled as the snow particle was just
// created, do not interpolate and clear the bit instead.
s32 snowIndex = (struct struct_4D_s *)(arg2)-D_80369280->unk1C;
u32 snowId = SNOW_TRANSFORM_ID_START + snowIDArray[snowIndex];
if (snowIDArray[snowIndex] & SNOW_SKIP_INTERPOLATION_MASK) {
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
gEXMatrixGroupSkipAll((*gfx)++, snowId, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
snowIDArray[snowIndex] ^= SNOW_SKIP_INTERPOLATION_MASK;
}
else {
gEXMatrixGroupSimpleNormal((*gfx)++, SNOW_TRANSFORM_ID_START + snowIDArray[snowIndex], G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
gEXMatrixGroupSimpleNormal((*gfx)++, snowId, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
}
gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
+1
View File
@@ -72,6 +72,7 @@ void reset_projection_ids();
extern s32 cur_drawn_model_is_map;
extern s32 cur_drawn_model_transform_id;
extern s32 cur_drawn_model_transform_id_skip_interpolation;
extern s32 cur_perspective_projection_transform_id;
extern s32 cur_ortho_projection_transform_id;
+18 -14
View File
@@ -29,6 +29,7 @@ void set_additional_model_scale(f32 x, f32 y, f32 z) {
s32 cur_drawn_model_is_map = FALSE;
s32 cur_drawn_model_transform_id = 0;
s32 cur_drawn_model_transform_id_skip_interpolation = FALSE;
Mtx identity_fixed_mtx = {{
{
@@ -92,11 +93,7 @@ void func_802E6BD0(BKModelUnk28List *arg0, BKVertexList *arg1, AnimMtxList *mtx_
void assetCache_free(void *arg0);
void set_model_matrix_group(Gfx **gfx, void *geo_list, u32 bone_index) {
if (skip_all_interpolation || cur_drawn_model_transform_id == -1) {
// @recomp Skip interpolation if all interpolation is currently skipped or the transform id is -1.
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
}
else if (cur_drawn_model_transform_id != 0) {
if (cur_drawn_model_transform_id != 0) {
u32 group_id;
// Pick a group ID based on whether this is a map or not.
if (cur_drawn_model_is_map) {
@@ -107,11 +104,18 @@ void set_model_matrix_group(Gfx **gfx, void *geo_list, u32 bone_index) {
// Other models use a group ID determined by the bone index.
group_id = cur_drawn_model_transform_id + bone_index;
}
// @recomp Tag the matrix.
// gEXMatrixGroupSimpleNormal((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
gEXMatrixGroupSimpleVerts((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
// gEXMatrixGroupDecomposedNormal((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
// gEXMatrixGroupDecomposedVerts((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
if (skip_all_interpolation || cur_drawn_model_transform_id_skip_interpolation) {
// @recomp Skip interpolation if all interpolation is currently skipped or the transform was specified to be skipped.
gEXMatrixGroupSkipAll((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
}
else {
// @recomp Tag the matrix.
gEXMatrixGroupSimpleVerts((*gfx)++, group_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
}
}
else if (skip_all_interpolation) {
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
}
}
@@ -639,12 +643,12 @@ RECOMP_PATCH BKModelBin *modelRender_draw(Gfx **gfx, Mtx **mtx, f32 position[3],
gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
// @recomp Create a matrix group if a transform id is set.
if (skip_all_interpolation || cur_drawn_model_transform_id == -1) {
// @recomp Skip interpolation if all interpolation is currently skipped or the transform id is -1.
gEXMatrixGroupNoInterpolate((*gfx)++, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
if (skip_all_interpolation || cur_drawn_model_transform_id_skip_interpolation) {
// @recomp Skip interpolation if all interpolation is currently skipped or the transform was specified to be skipped.
gEXMatrixGroupSkipAll((*gfx)++, cur_drawn_model_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
}
else if (cur_drawn_model_transform_id != 0) {
gEXMatrixGroupDecomposedVerts((*gfx)++, cur_drawn_model_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW);
gEXMatrixGroupDecomposedVerts((*gfx)++, cur_drawn_model_transform_id, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE);
}
modelRenderScale = scale;