1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
#include "2s2h/GameInteractor/GameInteractor.h"
#include "2s2h/ShipInit.hpp"
#include "CameraUtils.h"
#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h"
extern "C" {
#include "macros.h"
#include "functions.h"
extern PlayState* gPlayState;
extern SaveContext gSaveContext;
extern CameraSetting sCameraSettings[];
}
// This function should check for outstanding conditions which the distance check would falsly flag
// as something we do not want to interpolate. This mostly applies to general play for now
bool Camera_ShouldOverrideInterpolationCheck(Camera* camera) {
switch (sCameraSettings[camera->setting].cameraModes[camera->mode].funcId) {
case CAM_FUNC_BATTLE0:
case CAM_FUNC_BATTLE1:
case CAM_FUNC_BATTLE2:
case CAM_FUNC_BATTLE3:
case CAM_FUNC_BATTLE4:
case CAM_FUNC_PARALLEL0:
case CAM_FUNC_PARALLEL1:
case CAM_FUNC_PARALLEL2:
case CAM_FUNC_PARALLEL3:
case CAM_FUNC_PARALLEL4:
return true;
}
return false;
}
// This function checks whether there is too large a distance or change in angle between the expected
// position camera and the actual position of the camera. If there is, then we should not interpolate
bool Camera_ShouldInterpolateDist(Camera* camera) {
// Account for changes in position, pitch and yaw. Roll is rarely used so not currently handled
// `Velocity` is measured as the change across the previous frame
static f32 lastYaw = 0.0f;
static f32 lastYawVelocity = 0.0f;
static f32 lastPitch = 0.0f;
static f32 lastPitchVelocity = 0.0f;
static Vec3f lastEye = { 0.0f, 0.0f, 0.0f };
static Vec3f lastEyeVelocity = { 0.0f, 0.0f, 0.0f };
Vec3f* eye = &camera->eye;
Vec3f* at = &camera->at;
Vec3f eyeVelo;
bool shouldInterpolate = true;
VecGeo eyeGeo = OLib_Vec3fDiffToVecGeo(at, eye);
Vec3f expectedEye;
// Calculate Current
f32 yaw = BINANG_TO_DEG(eyeGeo.yaw);
if (yaw > 360.0f) {
yaw -= 360.0f;
} else if (yaw < 0.0f) {
yaw += 360.0f;
}
f32 yawVelocity = yaw - lastYaw;
f32 pitch = BINANG_TO_DEG(eyeGeo.pitch);
f32 pitchVelocity = pitch - lastPitch;
Math_Vec3f_Diff(eye, &lastEye, &eyeVelo);
// Update static variables.
lastYaw = yaw;
lastYawVelocity = yawVelocity;
lastPitch = pitch;
lastPitchVelocity = pitchVelocity;
lastEye = *eye;
lastEyeVelocity = eyeVelo;
if (Camera_ShouldOverrideInterpolationCheck(camera)) {
return true;
}
// Calculate Expected
f32 expectedYaw = lastYaw + lastYawVelocity;
if (expectedYaw > 360.0f) {
expectedYaw -= 360.0f;
} else if (expectedYaw < 0.0f) {
expectedYaw += 360.0f;
}
f32 expectedPitch = CLAMP(lastPitch + lastPitchVelocity, -180.0f, 180.0f);
Math_Vec3f_Sum(&lastEye, &lastEyeVelocity, &expectedEye);
// Check if changes are too great
f32 diffYaw = fabsf(yaw - expectedYaw);
f32 diffPitch = fabsf(pitch - expectedPitch);
f32 diffDistEye = Math_Vec3f_DistXYZ(eye, &expectedEye);
if ((diffYaw > 90.0f && diffYaw < 270.0f) || diffPitch > 60.0f || diffDistEye > 200.0f) {
shouldInterpolate = false;
}
// If we aren't interpolating, then reset velocities as they are inaccurate to the camera's current movement
if (!shouldInterpolate) {
lastYawVelocity = 0.0f;
lastPitchVelocity = 0.0f;
lastEyeVelocity = { 0.0f, 0.0f, 0.0f };
}
return shouldInterpolate;
}
void RegisterCameraInterpolationFixes() {
COND_HOOK(AfterCameraUpdate, true,
[](Camera* camera) { FrameInterpolation_ShouldInterpolateFrame(Camera_ShouldInterpolateDist(camera)); });
}
static RegisterShipInitFunc initFunc(RegisterCameraInterpolationFixes, {});
|