Fixed camera interpolation double skips, made the skybox skip interpolation with the camera, fixed particles getting incorrectly matched

This commit is contained in:
Mr-Wiseguy 2024-03-27 18:47:15 -04:00
parent 447689afd5
commit d1d00e164c
7 changed files with 114 additions and 16 deletions

@ -1 +1 @@
Subproject commit 482b9c9e48e97627b374a997dc8e21116af712e7
Subproject commit 8cced1f560a5513595b0d32335ac36244b82a411

View File

@ -10,6 +10,20 @@ static bool camera_ignore_tracking = false;
static bool in_kaleido = false;
static bool prev_in_kaleido = false;
static bool camera_skipped = false;
void set_camera_skipped(bool skipped) {
camera_skipped = skipped;
}
void clear_camera_skipped() {
camera_skipped = false;
}
bool camera_was_skipped() {
return camera_skipped;
}
void camera_pre_play_update(PlayState* play) {
}
@ -126,15 +140,13 @@ bool should_interpolate_perspective(Vec3f* eye, Vec3f* at) {
return true;
}
if (velocity_diff > 50.0f) {
return false;
}
if (at_dist > 50.0f) {
return false;
}
if (eye_dist > 300.0f) {
if (velocity_diff > 50.0f || at_dist > 50.0f || eye_dist > 300.0f) {
eye_velocity.x = 0.0f;
eye_velocity.y = 0.0f;
eye_velocity.z = 0.0f;
at_velocity.x = 0.0f;
at_velocity.y = 0.0f;
at_velocity.z = 0.0f;
return false;
}
@ -194,6 +206,9 @@ void View_Apply(View* view, s32 mask) {
G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_LINEAR);
}
// Record whether the camera was skipped for later use.
set_camera_skipped(!interpolate_camera);
camera_interpolation_forced = false;
camera_skip_interpolation_forced = false;

View File

@ -3,14 +3,83 @@
extern EffectSsInfo sEffectSsInfo;
#define MAX_PARTICLES 256
u8 particle_reset_list[MAX_PARTICLES];
// @recomp Patched to track that the particle has been reset.
void EffectSS_ResetEntry(EffectSs* particle) {
u32 i;
particle->type = EFFECT_SS_MAX;
particle->accel.x = particle->accel.y = particle->accel.z = 0;
particle->velocity.x = particle->velocity.y = particle->velocity.z = 0;
particle->vec.x = particle->vec.y = particle->vec.z = 0;
particle->pos.x = particle->pos.y = particle->pos.z = 0;
particle->life = -1;
particle->flags = 0;
particle->priority = 128;
particle->draw = NULL;
particle->update = NULL;
particle->gfx = NULL;
particle->actor = NULL;
for (i = 0; i < ARRAY_COUNT(particle->regs); i++) {
particle->regs[i] = 0;
}
// @recomp Get this particle's index and mark it as being reset.
u32 particle_index = particle - &sEffectSsInfo.dataTable[0];
if (particle_index >= sEffectSsInfo.size) {
recomp_crash("Invalid particle was reset!\n");
}
particle_reset_list[particle_index] = true;
}
// @recomp Check numEntries to be sure enough space has been allocated for tracking particle statuses.
void EffectSS_Init(PlayState* play, s32 numEntries) {
u32 i;
EffectSs* effectsSs;
EffectSsOverlay* overlay;
// @recomp Perform the numEntries check.
if (numEntries > MAX_PARTICLES) {
recomp_crash("Particle reset list too small!\n");
}
sEffectSsInfo.dataTable = (EffectSs*)THA_AllocTailAlign16(&play->state.tha, numEntries * sizeof(EffectSs));
sEffectSsInfo.searchIndex = 0;
sEffectSsInfo.size = numEntries;
for (effectsSs = &sEffectSsInfo.dataTable[0]; effectsSs < &sEffectSsInfo.dataTable[sEffectSsInfo.size];
effectsSs++) {
EffectSS_ResetEntry(effectsSs);
}
overlay = &gParticleOverlayTable[0];
for (i = 0; i < EFFECT_SS_MAX; i++) {
overlay->loadedRamAddr = NULL;
overlay++;
}
}
// @recomp Add transform tags to particles
void EffectSS_DrawParticle(PlayState* play, s32 index) {
EffectSs* entry = &sEffectSsInfo.dataTable[index];
OPEN_DISPS(play->state.gfxCtx);
// @recomp If this particle was just reset then skip interpolation.
if (particle_reset_list[index]) {
gEXMatrixGroupDecomposed(POLY_OPA_DISP++, PARTICLE_TRANSFORM_ID_START + index, G_EX_PUSH, G_MTX_MODELVIEW, 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);
gEXMatrixGroupDecomposed(POLY_XLU_DISP++, PARTICLE_TRANSFORM_ID_START + index, G_EX_PUSH, G_MTX_MODELVIEW, 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);
}
else {
gEXMatrixGroupDecomposed(POLY_OPA_DISP++, PARTICLE_TRANSFORM_ID_START + index, G_EX_PUSH, G_MTX_MODELVIEW, 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);
gEXMatrixGroupDecomposed(POLY_XLU_DISP++, PARTICLE_TRANSFORM_ID_START + index, G_EX_PUSH, G_MTX_MODELVIEW, 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);
}
// @recomp Clear this particle's reset state.
particle_reset_list[index] = false;
if (entry->draw != NULL) {
entry->draw(play, index, entry);

View File

@ -48,4 +48,10 @@ void draw_dpad_icons(PlayState* play);
void View_ApplyInterpolate(View* view, s32 mask, bool reset_interpolation_state);
void set_camera_skipped(bool skipped);
void clear_camera_skipped();
bool camera_was_skipped();
void recomp_crash(const char* err);
#endif

View File

@ -30,9 +30,15 @@ void Skybox_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId
gSPMatrix(POLY_OPA_DISP++, sSkyboxDrawMatrix, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
// @recomp Tag the skybox's matrix.
// @recomp Tag the skybox's matrix, skipping interpolation if the camera's interpolation was also skipped.
if (camera_was_skipped()) {
gEXMatrixGroupDecomposed(POLY_OPA_DISP++, SKYBOX_TRANSFORM_ID_START, G_EX_PUSH, G_MTX_MODELVIEW,
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_INTERPOLATE, G_EX_ORDER_LINEAR);
}
else {
gEXMatrixGroupDecomposed(POLY_OPA_DISP++, SKYBOX_TRANSFORM_ID_START, G_EX_PUSH, G_MTX_MODELVIEW,
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);
}
gDPSetColorDither(POLY_OPA_DISP++, G_CD_MAGICSQ);
gDPSetTextureFilter(POLY_OPA_DISP++, G_TF_BILERP);

View File

@ -97,6 +97,9 @@ void Graph_ExecuteAndDraw(GraphicsContext* gfxCtx, GameState* gameState) {
// @recomp Send the current framerate to RT64, including any extra VI interrupt periods.
gEXSetRefreshRate(POLY_OPA_DISP++, 60 / (gameState->framerateDivisor + extra_vis));
// @recomp Clear the camera skip state.
clear_camera_skipped();
gSPEndDisplayList(WORK_DISP++);
gSPEndDisplayList(POLY_OPA_DISP++);
gSPEndDisplayList(POLY_XLU_DISP++);

View File

@ -274,7 +274,6 @@ uint32_t ultramodern::get_target_framerate(uint32_t original) {
switch (graphics_config.rr_option) {
case RT64::UserConfiguration::RefreshRate::Original:
case RT64::UserConfiguration::RefreshRate::OriginalDelay:
default:
return original;
case RT64::UserConfiguration::RefreshRate::Manual: