diff --git a/lib/rt64 b/lib/rt64 index 482b9c9..8cced1f 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 482b9c9e48e97627b374a997dc8e21116af712e7 +Subproject commit 8cced1f560a5513595b0d32335ac36244b82a411 diff --git a/patches/camera_transform_tagging.c b/patches/camera_transform_tagging.c index 0224dd4..d93b5a0 100644 --- a/patches/camera_transform_tagging.c +++ b/patches/camera_transform_tagging.c @@ -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; diff --git a/patches/particle_transform_tagging.c b/patches/particle_transform_tagging.c index 11a19b7..165ebc4 100644 --- a/patches/particle_transform_tagging.c +++ b/patches/particle_transform_tagging.c @@ -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); - 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 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); diff --git a/patches/patches.h b/patches/patches.h index 2d9b051..0a38df9 100644 --- a/patches/patches.h +++ b/patches/patches.h @@ -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 diff --git a/patches/sky_transform_tagging.c b/patches/sky_transform_tagging.c index c1b1d92..a33a375 100644 --- a/patches/sky_transform_tagging.c +++ b/patches/sky_transform_tagging.c @@ -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. - 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); + // @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); diff --git a/patches/ui_patches.c b/patches/ui_patches.c index 49b7629..f4f37b8 100644 --- a/patches/ui_patches.c +++ b/patches/ui_patches.c @@ -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++); diff --git a/ultramodern/events.cpp b/ultramodern/events.cpp index ed7da59..b6ecb7f 100644 --- a/ultramodern/events.cpp +++ b/ultramodern/events.cpp @@ -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: