rework input to be in line with rendering semantics

This commit is contained in:
veclavtalica
2024-10-22 20:32:17 +03:00
parent a22bcfd97e
commit 9da26638c8
13 changed files with 98 additions and 130 deletions

View File

@ -64,15 +64,15 @@ typedef struct EngineContext {
int64_t delta_averager_residual;
int64_t time_averager[4];
SDL_GLContext *gl_context;
SDL_Window *window;
uint32_t window_id;
/* this should be a multiple of the current ticks per second */
/* use it to simulate low framerate (e.g. at 60 tps, set to 2 for 30 fps) */
/* it can be changed at runtime; any resulting logic anomalies are bugs */
uint32_t update_multiplicity;
SDL_GLContext *gl_context;
SDL_Window *window;
uint32_t window_id;
bool is_running;
bool window_size_has_changed;
bool resync_flag;

View File

@ -9,7 +9,6 @@
#include <stb_ds.h>
#include <stdbool.h>
#include <stdlib.h>
static void update_action_pressed_state(InputState *input, Action *action) {
@ -71,20 +70,40 @@ static void update_action_pressed_state(InputState *input, Action *action) {
}
static ActionHashItem *input_add_action(char const *action_name) {
SDL_assert(action_name);
Action new_action = { 0 };
new_action.bindings = SDL_calloc(ctx.keybind_slots, sizeof *new_action.bindings);
shput(ctx.input.action_hash, action_name, new_action);
return shgetp(ctx.input.action_hash, action_name);
}
static void input_delete_action(char const *action_name) {
SDL_assert(action_name);
ActionHashItem *action = shgetp_null(ctx.input.action_hash, action_name);
SDL_assert(action);
SDL_free(action->value.bindings);
shdel(ctx.input.action_hash, action_name);
}
static void input_bind_code_to_action(InputState *input,
char const *action_name,
ButtonSource source,
union ButtonCode code)
{
ActionHashItem *action_item = shgetp_null(input->action_hash, action_name);
if (action_item == NULL) {
log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name);
return;
}
if (!action_item)
action_item = input_add_action(action_name);
Action *action = &action_item->value;
/* check every binding to make sure this code isn't already bound */
for (size_t i = 0; i < (uint64_t)ctx.keybind_slots; ++i) {
for (size_t i = 0; i < action->num_bindings; ++i) {
Button *binding = &action->bindings[i];
if (binding->source != source)
@ -111,7 +130,8 @@ static void input_bind_code_to_action(InputState *input,
}
if (is_already_bound) {
log_warn("(%s) Code already bound to action \"%s\".", __func__, action_name);
/* keep it alive */
binding->in_use = true;
return;
}
}
@ -119,13 +139,14 @@ static void input_bind_code_to_action(InputState *input,
/* if we're at max bindings, forget the first element and shift the rest */
if (action->num_bindings == (uint64_t)ctx.keybind_slots) {
--action->num_bindings;
size_t shifted_size = (sizeof action->bindings) - (sizeof action->bindings[0]);
size_t shifted_size = sizeof action->bindings[0] * (ctx.keybind_slots - 1);
SDL_memmove(action->bindings, action->bindings + 1, shifted_size);
}
action->bindings[action->num_bindings++] = (Button) {
.source = source,
.code = code,
.in_use = true,
};
}
@ -136,16 +157,15 @@ static void input_unbind_code_from_action(InputState *input,
union ButtonCode code)
{
ActionHashItem *action_item = shgetp_null(input->action_hash, action_name);
if (action_item == NULL) {
log_warn("(%s) Action \"%s\" does not exist.", __func__, action_name);
return;
}
if (!action_item)
action_item = input_add_action(action_name);
Action *action = &action_item->value;
/* check every binding to make sure this code is bound */
size_t index = 0;
bool is_bound = false;
for (index = 0; index < (uint64_t)ctx.keybind_slots; ++index) {
for (index = 0; index < action->num_bindings; ++index) {
Button *binding = &action->bindings[index];
if (binding->source != source)
@ -175,10 +195,8 @@ static void input_unbind_code_from_action(InputState *input,
break;
}
if (!is_bound) {
log_warn("(%s) Code is not bound to action \"%s\".", __func__, action_name);
if (!is_bound)
return;
}
/* remove the element to unbind and shift the rest so there isn't a gap */
size_t elements_after_index = action->num_bindings - index;
@ -199,6 +217,10 @@ void input_state_deinit(InputState *input) {
void input_state_update(InputState *input) {
/* TODO: don't spam it if it happens */
if (SDL_SetRelativeMouseMode(input->mouse_captured) != 0)
log_warn("(%s) Mouse capture isn't supported.", __func__);
input->keyboard_state = SDL_GetKeyboardState(NULL);
input->mouse_state = SDL_GetMouseState(&input->mouse_window_position.x,
&input->mouse_window_position.y);
@ -211,8 +233,23 @@ void input_state_update(InputState *input) {
for (size_t i = 0; i < shlenu(input->action_hash); ++i) {
Action *action = &input->action_hash[i].value;
/* collect unused */
for (size_t u = 0; u < action->num_bindings; ++u) {
Button *button = &action->bindings[u];
if (!button->in_use)
input_unbind_code_from_action(input, input->action_hash[i].key, button->source, button->code);
else
button->in_use = false;
}
update_action_pressed_state(input, action);
}
size_t removed = 0;
for (size_t i = 0; i < shlenu(input->action_hash); ++i) {
if (input->action_hash[i - removed].value.num_bindings == 0)
input_delete_action(input->action_hash[i - removed].key);
}
}
@ -260,34 +297,6 @@ void input_unbind_action_control(char const *action_name,
}
void input_add_action(char const *action_name) {
SDL_assert_always(action_name);
if (shgeti(ctx.input.action_hash, action_name) >= 0) {
log_warn("(%s) Action \"%s\" is already registered.", __func__, action_name);
return;
}
Action new_action = { 0 };
new_action.bindings = ccalloc(ctx.keybind_slots, sizeof *new_action.bindings);
shput(ctx.input.action_hash, action_name, new_action);
}
void input_delete_action(char const *action_name) {
SDL_assert_always(action_name);
ActionHashItem *action = shgetp_null(ctx.input.action_hash, action_name);
if (action == NULL) {
log_warn("(%s) Action \"%s\" is not registered.", __func__, action_name);
return;
}
SDL_free(action->value.bindings);
shdel(ctx.input.action_hash, action_name);
}
bool input_is_action_pressed(char const *action_name) {
SDL_assert_always(action_name);
@ -338,13 +347,7 @@ Vec2 input_get_action_position(char const *action_name) {
void input_set_mouse_captured(bool enabled) {
if (SDL_SetRelativeMouseMode(enabled) != 0)
log_warn("(%s) Mouse capture isn't supported.", __func__);
}
bool input_is_mouse_captured(void) {
return SDL_GetRelativeMouseMode();
ctx.input.mouse_captured = enabled;
}

View File

@ -33,6 +33,7 @@ typedef enum ButtonSource {
typedef struct Button {
enum ButtonSource source;
union ButtonCode code;
bool in_use;
} Button;

View File

@ -204,8 +204,8 @@ static void main_loop(void) {
/* TODO: disable rendering pushes on not-last ? */
render_queue_clear();
poll_events();
input_state_update(&ctx.input);
game_object_tick();
input_state_update(&ctx.input);
preserve_persistent_ctx_fields();
ctx.frame_accumulator -= ctx.desired_frametime;