summaryrefslogtreecommitdiffstats
path: root/game/client/entity/player_look.cc
blob: 715475bddac5db0e9b89bdf4ea00c9a8c8f1777f (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include "client/pch.hh"

#include "client/entity/player_look.hh"

#include "core/config/boolean.hh"
#include "core/config/number.hh"

#include "core/io/config_map.hh"

#include "core/math/angles.hh"

#include "shared/entity/head.hh"

#include "shared/world/dimension.hh"

#include "client/config/gamepad_axis.hh"
#include "client/config/gamepad_button.hh"
#include "client/config/keybind.hh"

#include "client/gui/settings.hh"

#include "client/io/gamepad.hh"
#include "client/io/glfw.hh"

#include "client/const.hh"
#include "client/globals.hh"
#include "client/session.hh"

constexpr static float PITCH_MIN = -1.0f * math::radians(90.0f);
constexpr static float PITCH_MAX = +1.0f * math::radians(90.0f);

// Mouse options
static config::Boolean mouse_raw_input(true);
static config::Unsigned mouse_sensitivity(25U, 1U, 100U);

// Gamepad options
static config::Float gamepad_fastlook_factor(1.5f, 1.0f, 5.0f);
static config::Unsigned gamepad_accel_pitch(15U, 1U, 100U);
static config::Unsigned gamepad_accel_yaw(25U, 1U, 100U);

// Gamepad axes
static config::GamepadAxis axis_pitch(GLFW_GAMEPAD_AXIS_LEFT_Y, false);
static config::GamepadAxis axis_yaw(GLFW_GAMEPAD_AXIS_LEFT_X, false);

// Gamepad buttons
static config::GamepadButton button_fastlook(GLFW_GAMEPAD_BUTTON_LEFT_THUMB);

static bool fastlook_enabled;
static glm::fvec2 last_cursor;

static void add_angles(float pitch, float yaw)
{
    if(session::is_ingame()) {
        auto& head = globals::dimension->entities.get<entity::Head>(globals::player);

        head.angles[0] += pitch;
        head.angles[1] += yaw;
        head.angles[0] = math::clamp(head.angles[0], PITCH_MIN, PITCH_MAX);
        head.angles = math::wrap_180(head.angles);

        // Client-side head angles are not interpolated;
        // Re-assigning the previous state after the current
        // state has been already modified is certainly a way
        // to circumvent the interpolation applied to anything with a head
        globals::dimension->entities.emplace_or_replace<entity::client::HeadPrev>(globals::player, head);
    }
}

static void on_glfw_cursor_pos(const io::GlfwCursorPosEvent& event)
{
    if(io::gamepad::available && io::gamepad::active.get_value()) {
        // The player is assumed to be using
        // a gamepad instead of mouse and keyboard
        last_cursor = event.pos;
        return;
    }

    if(globals::gui_screen || !session::is_ingame()) {
        // UI is visible or we're not in-game
        last_cursor = event.pos;
        return;
    }

    auto dx = -0.01f * static_cast<float>(mouse_sensitivity.get_value()) * math::radians(event.pos.x - last_cursor.x);
    auto dy = -0.01f * static_cast<float>(mouse_sensitivity.get_value()) * math::radians(event.pos.y - last_cursor.y);
    add_angles(dy, dx);

    last_cursor = event.pos;
}

static void on_gamepad_button(const io::GamepadButtonEvent& event)
{
    if(button_fastlook.equals(event.button)) {
        fastlook_enabled = event.action == GLFW_PRESS;
    }
}

void entity::player_look::init(void)
{
    globals::client_config.add_value("player_look.mouse.raw_input", mouse_raw_input);
    globals::client_config.add_value("player_look.mouse.sensitivity", mouse_sensitivity);
    globals::client_config.add_value("player_look.gamepad.fastlook_factor", gamepad_fastlook_factor);
    globals::client_config.add_value("player_look.gamepad.accel_pitch", gamepad_accel_pitch);
    globals::client_config.add_value("player_look.gamepad.accel_yaw", gamepad_accel_yaw);
    globals::client_config.add_value("player_look.gp_axis.pitch", axis_pitch);
    globals::client_config.add_value("player_look.gp_axis.yaw", axis_yaw);
    globals::client_config.add_value("player_look.gp_button.fastlook", button_fastlook);

    settings::add_slider(0, mouse_sensitivity, settings_location::MOUSE, "player_look.mouse.sensitivity", true);
    settings::add_checkbox(1, mouse_raw_input, settings_location::MOUSE, "player_look.mouse.raw_input", true);

    settings::add_slider(0, gamepad_accel_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_pitch", false);
    settings::add_slider(1, gamepad_accel_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_yaw", false);
    settings::add_gamepad_axis(2, axis_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.pitch");
    settings::add_gamepad_axis(3, axis_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.yaw");
    settings::add_slider(
        4, gamepad_fastlook_factor, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.fastlook_factor", true, "%.02f");
    settings::add_gamepad_button(5, button_fastlook, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_button.fastlook");

    fastlook_enabled = false;
    last_cursor.x = 0.5f * static_cast<float>(globals::width);
    last_cursor.y = 0.5f * static_cast<float>(globals::height);

    globals::dispatcher.sink<io::GlfwCursorPosEvent>().connect<&on_glfw_cursor_pos>();
    globals::dispatcher.sink<io::GamepadButtonEvent>().connect<&on_gamepad_button>();
}

void entity::player_look::update_late(void)
{
    if(io::gamepad::available && io::gamepad::active.get_value() && !globals::gui_screen) {
        auto pitch_value = axis_pitch.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());
        auto yaw_value = axis_yaw.get_value(io::gamepad::state, io::gamepad::deadzone.get_value());

        if(fastlook_enabled) {
            // Fastlook allows the camera to
            // rotate quicker when a button is held down
            pitch_value *= gamepad_fastlook_factor.get_value();
            yaw_value *= gamepad_fastlook_factor.get_value();
        }

        pitch_value *= 0.001f * static_cast<float>(gamepad_accel_pitch.get_value());
        yaw_value *= 0.001f * static_cast<float>(gamepad_accel_yaw.get_value());

        add_angles(pitch_value, yaw_value);
    }

    if(!globals::gui_screen && session::is_ingame()) {
        glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
        glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, mouse_raw_input.get_value());
    }
    else {
        glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
        glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, false);
    }
}