From 7f1efce3103174614dc46df55d55e170eab5302c Mon Sep 17 00:00:00 2001 From: wanp Date: Tue, 30 Jul 2024 18:05:28 -0300 Subject: [PATCH] get the flycam going already --- apps/testgame/game.c | 19 +++++++++++++--- apps/testgame/scenes/ingame.c | 42 +++++++++++++++++++++++++++++++---- apps/testgame/scenes/ingame.h | 5 +++++ src/input.c | 15 +++++++++++++ src/input.h | 11 ++++++++- src/util.c | 23 +++++++++++++++++-- src/util.h | 13 +++++++++-- src/vec.h | 30 +++++++++++++++++++++++++ 8 files changed, 146 insertions(+), 12 deletions(-) diff --git a/apps/testgame/game.c b/apps/testgame/game.c index dd9b757..6c9a51a 100644 --- a/apps/testgame/game.c +++ b/apps/testgame/game.c @@ -3,6 +3,7 @@ #include "scenes/scene.h" #include "scenes/title.h" +#include #include #include #include @@ -22,16 +23,28 @@ void game_tick(void) { input_bind_action_scancode(&ctx.input, "debug_toggle", SDL_SCANCODE_BACKSPACE); input_add_action(&ctx.input, "player_left"); - input_bind_action_scancode(&ctx.input, "player_left", SDL_SCANCODE_LEFT); + input_bind_action_scancode(&ctx.input, "player_left", SDL_SCANCODE_A); input_add_action(&ctx.input, "player_right"); - input_bind_action_scancode(&ctx.input, "player_right", SDL_SCANCODE_RIGHT); + input_bind_action_scancode(&ctx.input, "player_right", SDL_SCANCODE_D); + + input_add_action(&ctx.input, "player_forward"); + input_bind_action_scancode(&ctx.input, "player_forward", SDL_SCANCODE_W); + + input_add_action(&ctx.input, "player_backward"); + input_bind_action_scancode(&ctx.input, "player_backward", SDL_SCANCODE_S); input_add_action(&ctx.input, "player_jump"); - input_bind_action_scancode(&ctx.input, "player_jump", SDL_SCANCODE_X); + input_bind_action_scancode(&ctx.input, "player_jump", SDL_SCANCODE_SPACE); + + input_add_action(&ctx.input, "player_run"); + input_bind_action_scancode(&ctx.input, "player_run", SDL_SCANCODE_LSHIFT); input_add_action(&ctx.input, "ui_accept"); input_bind_action_scancode(&ctx.input, "ui_accept", SDL_SCANCODE_RETURN); + + input_add_action(&ctx.input, "mouse_capture_toggle"); + input_bind_action_scancode(&ctx.input, "mouse_capture_toggle", SDL_SCANCODE_END); } struct state *state = ctx.udata; diff --git a/apps/testgame/scenes/ingame.c b/apps/testgame/scenes/ingame.c index a7000d1..472a54f 100644 --- a/apps/testgame/scenes/ingame.c +++ b/apps/testgame/scenes/ingame.c @@ -1,4 +1,5 @@ #include "ingame.h" +#include "src/input.h" #include "title.h" #include "scene.h" @@ -12,14 +13,45 @@ static void ingame_tick(struct state *state) { player_calc(scn->player); static t_camera cam = { .pos = { 32, 0, 1 }, .up = { 0, 1, 0 }, .fov = (float)M_PI_2 }; - cam.target = m_vec_norm(((t_fvec3){ -1, 0, 1 })); + const float sensitivity = 0.6f; /* TODO: put this in a better place */ + scn->yaw += (float)ctx.input.mouse_relative_position.x * sensitivity; + scn->pitch -= (float)ctx.input.mouse_relative_position.y * sensitivity; + scn->pitch = clampf(scn->pitch, -89.0f, 89.0f); + + const float yaw_rad = scn->yaw * (float)DEG2RAD; + const float pitch_rad = scn->pitch * (float)DEG2RAD; + + cam.target = m_vec_norm(((t_fvec3){ + cosf(yaw_rad) * cosf(pitch_rad), + sinf(pitch_rad), + sinf(yaw_rad) * cosf(pitch_rad) + })); + + const t_fvec3 right = m_vec_norm(m_vec_cross(cam.target, cam.up)); + const float speed = 0.04f; /* TODO: put this in a better place */ if (input_is_action_pressed(&ctx.input, "player_left")) - cam.pos.x -= 0.01f; + cam.pos = fvec3_sub(cam.pos, m_vec_scale(right, speed)); + if (input_is_action_pressed(&ctx.input, "player_right")) - cam.pos.x += 0.01f; + cam.pos = fvec3_add(cam.pos, m_vec_scale(right, speed)); + + if (input_is_action_pressed(&ctx.input, "player_forward")) + cam.pos = fvec3_add(cam.pos, m_vec_scale(cam.target, speed)); + + if (input_is_action_pressed(&ctx.input, "player_backward")) + cam.pos = fvec3_sub(cam.pos, m_vec_scale(cam.target, speed)); + if (input_is_action_pressed(&ctx.input, "player_jump")) - cam.pos.z += 0.01f; + cam.pos.y += speed; + + if (input_is_action_pressed(&ctx.input, "player_run")) + cam.pos.y -= speed; + + /* toggle mouse capture with end key */ + if (input_is_action_just_pressed(&ctx.input, "mouse_capture_toggle")) { + input_set_mouse_captured(&ctx.input, !input_is_mouse_captured(&ctx.input)); + } m_sprite(m_set(path, "/assets/light.png"), m_set(rect, ((t_frect){ 48, 64, 64, 64 })), @@ -93,5 +125,7 @@ struct scene *ingame_scene(struct state *state) { .repeat = true, }); + input_set_mouse_captured(&ctx.input, true); + return (struct scene *)new_scene; } diff --git a/apps/testgame/scenes/ingame.h b/apps/testgame/scenes/ingame.h index 1eb8d67..3901cd1 100644 --- a/apps/testgame/scenes/ingame.h +++ b/apps/testgame/scenes/ingame.h @@ -14,6 +14,11 @@ struct scene_ingame { struct world *world; struct player *player; + + /* TODO: put this in a better place */ + float yaw; + float pitch; + float roll; }; diff --git a/src/input.c b/src/input.c index ad9196e..bf9109f 100644 --- a/src/input.c +++ b/src/input.c @@ -1,5 +1,6 @@ #include "input.h" #include "util.h" +#include "context.h" #include #include @@ -190,6 +191,9 @@ void input_state_update(struct input_state *input) { input->mouse_state = SDL_GetMouseState(&input->mouse_window_position.x, &input->mouse_window_position.y); + SDL_GetRelativeMouseState(&input->mouse_relative_position.x, + &input->mouse_relative_position.y); + for (size_t i = 0; i < shlenu(input->action_hash); ++i) { struct action *action = &input->action_hash[i].value; update_action_pressed_state(input, action); @@ -296,3 +300,14 @@ t_fvec2 input_get_action_position(struct input_state *input, char *action_name) return action->value.position; } + + +void input_set_mouse_captured(struct input_state *input, bool enabled) { + /* TODO: returns -1 if not supported, but like... do we care? */ + SDL_SetRelativeMouseMode(enabled); +} + + +bool input_is_mouse_captured(struct input_state *input) { + return SDL_GetRelativeMouseMode(); +} diff --git a/src/input.h b/src/input.h index 0b7e501..cedf0de 100644 --- a/src/input.h +++ b/src/input.h @@ -2,6 +2,7 @@ #define INPUT_H #include "config.h" +#include "src/vec.h" #include "util.h" #include @@ -39,8 +40,12 @@ struct button { /* that is, changes in the states of any of the bound buttons will affect it */ struct action { size_t num_bindings; + + /* if you bind more than NUM_KEYBIND_SLOTS (set in config.h) */ + /* it forgets the first button to add the new one at the end */ struct button bindings[NUM_KEYBIND_SLOTS]; - t_fvec2 position; /* set if applicable */ + + t_fvec2 position; /* set if applicable, e.g. mouse click */ bool is_pressed; bool just_changed; }; @@ -57,6 +62,7 @@ struct input_state { const uint8_t *keyboard_state; /* array of booleans indexed by scancode */ uint32_t mouse_state; /* SDL mouse button bitmask */ t_vec2 mouse_window_position; + t_vec2 mouse_relative_position; enum button_source last_active_source; bool is_anything_just_pressed; }; @@ -85,7 +91,10 @@ void input_delete_action(struct input_state *input, char *action_name); bool input_is_action_pressed(struct input_state *input, char *action_name); bool input_is_action_just_pressed(struct input_state *input, char *action_name); bool input_is_action_just_released(struct input_state *input, char *action_name); + t_fvec2 input_get_action_position(struct input_state *input, char *action_name); +void input_set_mouse_captured(struct input_state *input, bool value); +bool input_is_mouse_captured(struct input_state *input); #endif diff --git a/src/util.c b/src/util.c index 5643e30..770a53a 100644 --- a/src/util.c +++ b/src/util.c @@ -101,6 +101,25 @@ void *ccalloc(size_t num, size_t size) { } +double clamp(double d, double min, double max) { + const double t = d < min ? min : d; + return t > max ? max : t; +} + + +float clampf(float f, float min, float max) { + const float t = f < min ? min : f; + return t > max ? max : t; +} + + +int clampi(int i, int min, int max) { + const int t = i < min ? min : i; + return t > max ? max : t; +} + + + int64_t file_to_bytes(const char *path, unsigned char **buf_out) { SDL_RWops *handle = PHYSFSRWOPS_openRead(path); @@ -135,7 +154,7 @@ char *file_to_str(const char *path) { SDL_RWread(handle, str_out, sizeof *str_out, len); SDL_RWclose(handle); /* we got all we needed from the stream */ - str_out[len] = '\0'; + str_out[len] = '\0'; return str_out; } @@ -147,7 +166,7 @@ bool strends(const char *str, const char *suffix) { if (suffix_length > str_length) return false; - + return memcmp((str + str_length) - suffix_length, suffix, suffix_length) == 0; } diff --git a/src/util.h b/src/util.h index f4b64fd..40ec551 100644 --- a/src/util.h +++ b/src/util.h @@ -18,8 +18,8 @@ /* */ void cry_impl(const char *file, const int line, const char *title, const char *text); -#define CRY(title, text) cry_impl(__FILE__, __LINE__, title, text) -#define CRY_SDL(title) cry_impl(__FILE__, __LINE__, title, SDL_GetError()) +#define CRY(title, text) cry_impl(__FILE__, __LINE__, title, text) +#define CRY_SDL(title) cry_impl(__FILE__, __LINE__, title, SDL_GetError()) #define CRY_PHYSFS(title) \ cry_impl(__FILE__, __LINE__, title, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())) @@ -53,6 +53,15 @@ void *ccalloc(size_t num, size_t size); #define M_PI 3.14159265358979323846264338327950288 /**< pi */ #endif +/* multiply by these to convert degrees <---> radians */ +#define DEG2RAD (M_PI / 180) +#define RAD2DEG (180 / M_PI) + +/* TODO: this is why generics were invented. sorry, i'm tired today */ +double clamp(double d, double min, double max); +float clampf(float f, float min, float max); +int clampi(int i, int min, int max); + /* sets buf_out to a pointer to a byte buffer which must be freed. */ /* returns the size of this buffer. */ int64_t file_to_bytes(const char *path, unsigned char **buf_out); diff --git a/src/vec.h b/src/vec.h index a468239..768a3dc 100644 --- a/src/vec.h +++ b/src/vec.h @@ -66,6 +66,10 @@ static inline t_fvec2 fvec2_from_shvec2(t_shvec2 vec) { }; } +static inline t_fvec3 fvec3_add(t_fvec3 a, t_fvec3 b) { + return (t_fvec3) { a.x + b.x, a.y + b.y, a.z + b.z }; +} + static inline t_fvec3 fvec3_sub(t_fvec3 a, t_fvec3 b) { return (t_fvec3) { a.x - b.x, a.y - b.y, a.z - b.z }; } @@ -97,6 +101,32 @@ static inline t_fvec3 fvec3_norm(t_fvec3 a) { return fvec3_scale(a, 1.0f / n); } +static inline t_fvec3 fvec3_rotate(t_fvec3 v, float angle, t_fvec3 axis) { + /* from cglm */ + t_fvec3 v1, v2, k; + float c, s; + + c = cosf(angle); + s = sinf(angle); + + k = fvec3_norm(axis); + + /* Right Hand, Rodrigues' rotation formula: + v = v*cos(t) + (kxv)sin(t) + k*(k.v)(1 - cos(t)) + */ + v1 = fvec3_scale(v, c); + + v2 = fvec3_cross(k, v); + v2 = fvec3_scale(v2, s); + + v1 = fvec3_add(v1, v2); + + v2 = fvec3_scale(k, fvec3_dot(k, v) * (1.0f - c)); + v = fvec3_add(v1, v2); + + return v; +} + #define m_to_fvec2(p_any_vec2) (_Generic((p_any_vec2), \ t_vec2: fvec2_from_vec2, \ t_shvec2: fvec2_from_shvec2 \