summaryrefslogtreecommitdiff
path: root/src/engine/camera_interp_skip.c
blob: 0d2f6569c734963219c91934b8a218c5eb428cf3 (plain)
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
110
111
112
113
#ifndef CAMERA_INTERP_SKIP_C
#define CAMERA_INTERP_SKIP_C

#include "global.h"

#define SQXYZ(vec) ((vec.x) * (vec.x) + (vec.y) * (vec.y) + (vec.z) * (vec.z))

void Math_Vec3f_Diff(Vec3f* l, Vec3f* r, Vec3f* dest) {
    dest->x = l->x - r->x;
    dest->y = l->y - r->y;
    dest->z = l->z - r->z;
}

void Math_Vec3f_Sum(Vec3f* l, Vec3f* r, Vec3f* dest) {
    dest->x = l->x + r->x;
    dest->y = l->y + r->y;
    dest->z = l->z + r->z;
}

f32 Math_Vec3f_DistXYZ(Vec3f* a, Vec3f* b) {
    Vec3f diff;
    Math_Vec3f_Diff(b, a, &diff);
    return sqrtf(SQXYZ(diff));
}

bool should_interpolate_perspective(Vec3f* eye, Vec3f* at) {
    static Vec3f prev_eye = { 0, 0, 0 };
    static Vec3f prev_at = { 0, 0, 0 };
    static Vec3f eye_velocity = { 0, 0, 0 };
    static Vec3f at_velocity = { 0, 0, 0 };

    Vec3f predicted_eye;
    Vec3f predicted_at;
    // Predict the new eye and at positions based on the previous velocity and positions.
    Math_Vec3f_Sum(&prev_eye, &eye_velocity, &predicted_eye);
    Math_Vec3f_Sum(&prev_at, &at_velocity, &predicted_at);

    // Calculate the current velocities from the previous and current positions.
    Math_Vec3f_Diff(eye, &prev_eye, &eye_velocity);
    Math_Vec3f_Diff(at, &prev_at, &at_velocity);

    // Compare the predicted positions to the real positions.
    float eye_dist = Math_Vec3f_DistXYZ(&predicted_eye, eye);
    float at_dist = Math_Vec3f_DistXYZ(&predicted_at, at);

    // Compare the velocities of the eye and at positions.
    float velocity_diff = Math_Vec3f_DistXYZ(&eye_velocity, &at_velocity);

    // Update the tracking for the previous positions with the new ones.
    prev_eye = *eye;
    prev_at = *at;

    // These numbers are all picked via testing.

    // If the velocity of both positions was the same, then they're moving together and should interpolate.
    if (velocity_diff <= 3.0f && eye_dist <= 100.0f && at_dist <= 100.0f) {
        return true;
    }

    // If the focus or position are basically the same across frames and the eye didn't move too far then it should
    // probably be interpolated.
    if (at_dist <= 20.0f && eye_dist <= 300.0f) {
        return true;
    }
    if (eye_dist <= 20.0f && at_dist <= 300.0f) {
        return true;
    }

    // Force camera interpolation during the all-range transition
    if (gPlayer[0].state == PLAYERSTATE_START_360) {
        return true;
    }

    // Force camera interpolation during camera shake
    if (gCameraShake > 0 || gCameraShake > 0) {
        return true;
    }

    switch (gCurrentLevel) {
        // For Robot destroy cutscenes
        case LEVEL_SECTOR_Y:
            if (velocity_diff > 100.0f || at_dist > 500.0f || eye_dist > 500.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;

                printf("velocity_diff: %f\n at_dist: %f\n eye_dist: %f\n", velocity_diff, at_dist, eye_dist);
                return false;
            }
            break;

        default:
            if (velocity_diff > 200.0f || at_dist > 150.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;

                printf("velocity_diff: %f\n at_dist: %f\n eye_dist: %f\n", velocity_diff, at_dist, eye_dist);
                return false;
            }
            break;
    }

    return true;
}

#endif