diff options
| -rw-r--r-- | src/code_80005FD0.c | 31 | ||||
| -rw-r--r-- | src/code_80005FD0.h | 2 | ||||
| -rw-r--r-- | src/enhancements/freecam/freecam.cpp | 6 | ||||
| -rw-r--r-- | src/port/interpolation/FrameInterpolation.cpp | 8 |
4 files changed, 37 insertions, 10 deletions
diff --git a/src/code_80005FD0.c b/src/code_80005FD0.c index 04b6107bc..b0e8210e8 100644 --- a/src/code_80005FD0.c +++ b/src/code_80005FD0.c @@ -41,6 +41,7 @@ #include <stdio.h> #include "port/Game.h" +#include "port/interpolation/FrameInterpolation.h" #include "engine/tracks/Track.h" #include "engine/RaceManager.h" @@ -6550,12 +6551,19 @@ void func_80019760(Camera* camera, UNUSED Player* player, UNUSED s32 arg2, s32 c camera->rot[2] = 0; } -void func_80019890(s32 playerId, s32 cameraId) { +// Starts the cinematic shot selected in D_80164680[cameraId]: dispatches to the +// per-shot setup, which teleports the camera to the shot's opening position. +void camera_start_cinematic_shot(s32 playerId, s32 cameraId) { s32 pathIndex; + f32 prevX, prevY, prevZ, dx, dy, dz; Camera* camera = camera1; camera += cameraId; camera->playerId = playerId; + prevX = camera->pos[0]; + prevY = camera->pos[1]; + prevZ = camera->pos[2]; + D_801646C0[cameraId] = 0; pathIndex = gPathIndexByPlayerId[playerId]; @@ -6614,6 +6622,15 @@ void func_80019890(s32 playerId, s32 cameraId) { if ((s16) D_80164680[cameraId] == 9) { D_80163DD8[cameraId] = (s32) pathIndex; } + + // Flag a camera cut only when the camera teleported to a new shot; + // small moves are continuous tracking updates that should stay smooth. + dx = camera->pos[0] - prevX; + dy = camera->pos[1] - prevY; + dz = camera->pos[2] - prevZ; + if ((dx * dx + dy * dy + dz * dz) > 100.0f * 100.0f) { + FrameInterpolation_DontInterpolateCamera(); + } } void func_80019B50(s32 cameraIndex, u16 arg1) { @@ -6737,11 +6754,11 @@ void func_80019DF4(void) { void func_80019E58(void) { D_80164680[0] = 1; - func_80019890(0, 0); + camera_start_cinematic_shot(0, 0); D_80164670[0] = D_80164678[0]; D_80164678[0] = 1; D_80164680[1] = 9; - func_80019890(0, 1); + camera_start_cinematic_shot(0, 1); D_80164670[1] = D_80164678[1]; D_80164678[1] = 0; } @@ -6866,7 +6883,7 @@ void func_8001A348(s32 cameraId, f32 arg1, s32 arg2) { playerId = cameras[cameraId].playerId; D_80164688[cameraId] = arg1; D_80164680[cameraId] = func_8001A310((s32) gNearestPathPointByCameraId[cameraId], arg2); - func_80019890(playerId, cameraId); + camera_start_cinematic_shot(playerId, cameraId); } void func_8001A3D8(s32 arg0, f32 arg1, s32 arg2) { @@ -6876,7 +6893,7 @@ void func_8001A3D8(s32 arg0, f32 arg1, s32 arg2) { D_80164688[arg0] = arg1; if (arg2 != D_80164680[arg0]) { D_80164680[arg0] = arg2; - func_80019890(playerId, arg0); + camera_start_cinematic_shot(playerId, arg0); } } @@ -6891,7 +6908,7 @@ void func_8001A450(s32 playerId, s32 arg1, s32 arg2) { temp_v0 = func_8001A310(waypoint, (temp_v1 + 1) % 10); if ((temp_v0 != temp_v1) || (arg2 != playerId)) { D_80164680[arg1] = temp_v0; - func_80019890(arg2, arg1); + camera_start_cinematic_shot(arg2, arg1); } } } @@ -6938,7 +6955,7 @@ void func_8001A588(UNUSED u16* localD_80152300, Camera* camera, Player* player, } else { func_8001A124((s32) playerId, cameraIndex); } - func_80019890((s32) playerId, cameraIndex); + camera_start_cinematic_shot((s32) playerId, cameraIndex); } if ((D_80164680[cameraIndex] == 14) || (D_80164680[cameraIndex] == 0)) { diff --git a/src/code_80005FD0.h b/src/code_80005FD0.h index 68560f534..5e3410e03 100644 --- a/src/code_80005FD0.h +++ b/src/code_80005FD0.h @@ -261,7 +261,7 @@ void func_8001933C(Camera*, UNUSED Player*, s32, s32); void func_8001968C(void); void func_8001969C(s32, f32, s32, s16); void func_80019760(Camera*, UNUSED Player*, s32, s32); -void func_80019890(s32, s32); +void camera_start_cinematic_shot(s32, s32); void func_80019B50(s32, u16); void func_80019C50(s32); void func_80019D2C(Camera*, Player*, s32); diff --git a/src/enhancements/freecam/freecam.cpp b/src/enhancements/freecam/freecam.cpp index c5ee60319..07d0f6e51 100644 --- a/src/enhancements/freecam/freecam.cpp +++ b/src/enhancements/freecam/freecam.cpp @@ -236,9 +236,11 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) { if (bFreecamUseController) { if (fController.buttonDepressed & R_TRIG) { fTargetPlayer = true; + FrameInterpolation_DontInterpolateCamera(); } if (fController.buttonDepressed & L_TRIG) { fTargetPlayer = false; + FrameInterpolation_DontInterpolateCamera(); } if (fController.buttonPressed & L_JPAD) { TargetPreviousPlayer = true; @@ -273,6 +275,7 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) { else if (wnd->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) { if (FreecamKeyDown('F')) { fTargetPlayer = !fTargetPlayer; + FrameInterpolation_DontInterpolateCamera(); } if (FreecamKeyDown('N')) { TargetPreviousPlayer = true; @@ -309,6 +312,7 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) { const uint8_t* keystate = SDL_GetKeyboardState(NULL); if (FreecamKeyDown(SDL_SCANCODE_F)) { fTargetPlayer = !fTargetPlayer; + FrameInterpolation_DontInterpolateCamera(); } if (FreecamKeyDown(SDL_SCANCODE_N)) { TargetPreviousPlayer = true; @@ -345,6 +349,7 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) { fRankIndex--; camera->playerId = fRankIndex; gScreenOneCtx->player = &gPlayers[fRankIndex]; + FrameInterpolation_DontInterpolateCamera(); } } @@ -354,6 +359,7 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) { fRankIndex++; camera->playerId = fRankIndex; gScreenOneCtx->player = &gPlayers[fRankIndex]; + FrameInterpolation_DontInterpolateCamera(); } } diff --git a/src/port/interpolation/FrameInterpolation.cpp b/src/port/interpolation/FrameInterpolation.cpp index 981ef3fa6..51d411c95 100644 --- a/src/port/interpolation/FrameInterpolation.cpp +++ b/src/port/interpolation/FrameInterpolation.cpp @@ -253,6 +253,7 @@ bool is_recording; vector<Path*> current_path; uint32_t camera_epoch; uint32_t previous_camera_epoch; +bool frame_had_camera_cut; Recording current_recording; Recording previous_recording; @@ -599,8 +600,10 @@ struct InterpolateCtx { unordered_map<Mtx*, MtxF> FrameInterpolation_Interpolate(float step) { InterpolateCtx ctx; - ctx.step = step; - ctx.w = 1.0f - step; + // On a camera cut, blending the two frames would mix unrelated views; + // snap every sub-frame to the new frame instead (hard cut, like hardware). + ctx.step = frame_had_camera_cut ? 1.0f : step; + ctx.w = 1.0f - ctx.step; ctx.interpolate_branch(&previous_recording.root_path, ¤t_recording.root_path); return ctx.mtx_replacements; } @@ -633,6 +636,7 @@ void FrameInterpolation_StartRecord(void) { } void FrameInterpolation_StopRecord(void) { + frame_had_camera_cut = camera_epoch != previous_camera_epoch; previous_camera_epoch = camera_epoch; is_recording = false; } |
