1 #include <asprintf/asprintf.h>
5 #include "client/camera.h"
6 #include "client/client.h"
7 #include "client/client_player.h"
8 #include "client/debug_menu.h"
9 #include "client/game.h"
10 #include "client/gui.h"
11 #include "client/input.h"
12 #include "client/window.h"
20 static bool paused = false;
22 static GUIElement *pause_menu;
23 static GUIElement *status_message;
25 static KeyListener listener_pause = {GLFW_KEY_ESCAPE, false};
26 static KeyListener listener_fullscreen = {GLFW_KEY_F11, false};
27 static KeyListener listener_fly = {GLFW_KEY_F, false};
28 static KeyListener listener_collision = {GLFW_KEY_C, false};
29 static KeyListener listener_timelapse = {GLFW_KEY_T, false};
30 static KeyListener listener_debug_menu = {GLFW_KEY_F3, false};
31 static KeyListener listener_screenshot = {GLFW_KEY_F2, false};
33 static double cursor_last_x = 0.0;
34 static double cursor_last_y = 0.0;
36 // movement mutex needs to be locked
37 static bool move(int forward, int backward, vec3 dir)
42 if (glfwGetKey(window.handle, forward) == GLFW_PRESS)
44 else if (glfwGetKey(window.handle, backward) == GLFW_PRESS)
49 client_player.velocity.x += dir[0] * client_player.movement.speed * sign;
50 client_player.velocity.y += dir[1] * client_player.movement.speed * sign;
51 client_player.velocity.z += dir[2] * client_player.movement.speed * sign;
56 static void enter_game()
58 glfwSetInputMode(window.handle, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
59 pause_menu->visible = false;
62 static bool key_listener(KeyListener *listener)
64 bool was = listener->state;
65 return !(listener->state = (glfwGetKey(window.handle, listener->key) == GLFW_PRESS)) && was;
68 static void set_status_message(char *message)
70 gui_text(status_message, message);
71 status_message->def.text_color.w = 1.01f;
76 pause_menu = gui_add(NULL, (GUIElementDefinition) {
81 .align = {0.0f, 0.0f},
82 .scale = {1.0f, 1.0f},
83 .scale_type = SCALE_PARENT,
84 .affect_parent_scale = false,
87 .text_color = {0.0f, 0.0f, 0.0f, 0.0f},
88 .bg_color = {0.0f, 0.0f, 0.0f, 0.4f},
91 status_message = gui_add(NULL, (GUIElementDefinition) {
96 .align = {0.5f, 0.5f},
97 .scale = {1.0f, 1.0f},
98 .scale_type = SCALE_TEXT,
99 .affect_parent_scale = false,
102 .text_color = {1.0f, 0.91f, 0.13f, 0.0f},
103 .bg_color = {0.0f, 0.0f, 0.0f, 0.0f},
106 glfwSetInputMode(window.handle, GLFW_STICKY_KEYS, GL_TRUE);
110 void input_tick(f64 dtime)
112 if (status_message->def.text_color.w > 1.0f)
113 status_message->def.text_color.w = 1.0f;
114 else if (status_message->def.text_color.w > 0.0f)
115 status_message->def.text_color.w -= dtime * 1.0f;
117 if (key_listener(&listener_pause)) {
121 glfwSetInputMode(window.handle, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
122 pause_menu->visible = true;
128 if (key_listener(&listener_fullscreen)) {
129 if (window.fullscreen)
130 window_exit_fullscreen();
132 window_enter_fullscreen();
136 if (key_listener(&listener_fly)) {
137 pthread_rwlock_wrlock(&client_player.lock_movement);
138 client_player.movement.flight = !client_player.movement.flight;
141 asprintf(&msg, "Flight %s", client_player.movement.flight ? "Enabled" : "Disabled");
142 set_status_message(msg);
143 debug_menu_changed(ENTRY_FLIGHT);
145 pthread_rwlock_unlock(&client_player.lock_movement);
148 if (key_listener(&listener_collision)) {
149 pthread_rwlock_wrlock(&client_player.lock_movement);
150 client_player.movement.collision = !client_player.movement.collision;
153 asprintf(&msg, "Collision %s", client_player.movement.collision ? "Enabled" : "Disabled");
154 set_status_message(msg);
155 debug_menu_changed(ENTRY_COLLISION);
157 pthread_rwlock_unlock(&client_player.lock_movement);
160 if (key_listener(&listener_timelapse)) {
161 f64 current_time = get_time_of_day();
162 timelapse = !timelapse;
163 set_time_of_day(current_time);
166 asprintf(&msg, "Timelapse %s", timelapse ? "Enabled" : "Disabled");
167 set_status_message(msg);
168 debug_menu_changed(ENTRY_TIMELAPSE);
171 if (key_listener(&listener_debug_menu))
174 if (key_listener(&listener_screenshot)) {
175 char *screenshot_filename = game_take_screenshot();
177 asprintf(&msg, "Screenshot saved to %s", screenshot_filename);
178 set_status_message(msg);
179 free(screenshot_filename);
183 pthread_rwlock_rdlock(&client_player.lock_movement);
185 client_player.velocity.x = 0.0f;
186 client_player.velocity.z = 0.0f;
188 if (client_player.movement.flight)
189 client_player.velocity.y = 0.0f;
192 move(GLFW_KEY_W, GLFW_KEY_S, camera.movement_dirs.front);
193 move(GLFW_KEY_D, GLFW_KEY_A, camera.movement_dirs.right);
195 if (client_player.movement.flight)
196 move(GLFW_KEY_SPACE, GLFW_KEY_LEFT_SHIFT, camera.movement_dirs.up);
197 else if (glfwGetKey(window.handle, GLFW_KEY_SPACE) == GLFW_PRESS)
198 client_player_jump();
201 pthread_rwlock_unlock(&client_player.lock_movement);
204 void input_cursor(double current_x, double current_y)
209 double delta_x = current_x - cursor_last_x;
210 double delta_y = current_y - cursor_last_y;
211 cursor_last_x = current_x;
212 cursor_last_y = current_y;
214 ClientEntity *entity = client_player_entity();
218 pthread_rwlock_wrlock(&entity->lock_pos_rot);
220 entity->data.rot.x += (f32) delta_x * M_PI / 180.0f / 8.0f;
221 entity->data.rot.y -= (f32) delta_y * M_PI / 180.0f / 8.0f;
223 entity->data.rot.x = fmod(entity->data.rot.x + M_PI * 2.0f, M_PI * 2.0f);
224 entity->data.rot.y = f32_clamp(entity->data.rot.y, -M_PI / 2.0f + 0.01f, M_PI / 2.0f - 0.01f);
226 client_player_update_rot(entity);
227 pthread_rwlock_unlock(&entity->lock_pos_rot);
228 refcount_drp(&entity->rc);