#include "input_axis.h" #include "debug.h" #include "input.h" impl_default_Drop_for( KeyBind ) impl_InputAxis_for(KeyBind, keybind_is_changed_by, keybind_evaluate, keybind_set_device ) impl_default_Drop_for( ControllerAxis ) impl_InputAxis_for(ControllerAxis, controlleraxis_is_changed_by, controlleraxis_evaluate, controlleraxis_set_device ) impl_default_Drop_for( ControllerButton ) impl_InputAxis_for(ControllerButton, controllerbutton_is_changed_by, controllerbutton_evaluate, controllerbutton_set_device ) impl_Drop_for(CompositeAxis1D, compositeaxis1d_drop ) impl_InputAxis_for(CompositeAxis1D, compositeaxis1d_is_changed_by, compositeaxis1d_evaluate, compositeaxis1d_set_device ) KeyBind* keybind_new(SDL_Scancode key) { KeyBind* self = malloc(sizeof(KeyBind)); ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for KeyBind instance"); *self = (KeyBind) { .device = NULL, .scancode = key, .state = 0 }; return self; } int keybind_is_changed_by(KeyBind* self, SDL_Event event) { return self->device->type == InputDevice_KBM && (event.type == SDL_KEYUP || event.type == SDL_KEYDOWN) && event.key.keysym.scancode == self->scancode && event.key.repeat == 0; } InputEvent keybind_evaluate(KeyBind* self, SDL_Event event) { return (InputEvent) { .type = InputEvent_Bool, .as_bool = self->device->keyboard.state[self->scancode] }; } void keybind_set_device(KeyBind* self, InputDevice* device) { self->device = device; } ControllerAxis* controlleraxis_new(int axis) { ControllerAxis* self = malloc(sizeof(ControllerAxis)); ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for ControllerAxis instance"); *self = (ControllerAxis){ .axis = axis, .device = NULL }; return self; } int controlleraxis_is_changed_by(ControllerAxis* self, SDL_Event event) { int r = self->device->type == InputDevice_Gamepad && event.type == SDL_CONTROLLERAXISMOTION && event.caxis.which == self->device->gamepad.id && event.caxis.axis == self->axis; return r; } InputEvent controlleraxis_evaluate(ControllerAxis* self, SDL_Event event) { float result = (float)event.caxis.value / 32767.0f; return (InputEvent) { .type = InputEvent_Float, .as_float = result }; } void controlleraxis_set_device(ControllerAxis* self, InputDevice* device) { self->device = device; } ControllerButton* controllerbutton_new(int button) { ControllerButton* self = malloc(sizeof(ControllerButton)); ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for ControllerButton instance"); *self = (ControllerButton) { .button = button, .device = NULL }; return self; } int controllerbutton_is_changed_by(ControllerButton* self, SDL_Event event) { return self->device->type == InputDevice_Gamepad && event.cbutton.which == self->device->gamepad.id && (event.type == SDL_CONTROLLERBUTTONUP || event.type == SDL_CONTROLLERBUTTONDOWN) && event.cbutton.button == self->button; } InputEvent controllerbutton_evaluate(ControllerButton* self, SDL_Event event) { return (InputEvent) { .type = InputEvent_Bool, .as_bool = event.cbutton.state }; } void controllerbutton_set_device(ControllerButton* self, InputDevice* device) { self->device = device; } CompositeAxis1D* compositeaxis1d_new(InputAxis left, InputAxis right, InputEventType type) { CompositeAxis1D* self = malloc(sizeof(CompositeAxis1D)); ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for CompositeAxis1D instance"); *self = (CompositeAxis1D) { .left = left, .right = right, .type = type, }; return self; } int compositeaxis1d_is_changed_by(CompositeAxis1D* self, SDL_Event event) { return self->left.tc->is_changed_by(self->left.data, event) || self->right.tc->is_changed_by(self->right.data, event); } static inline InputEvent _internal_event_to_type(InputEventType type, InputEvent event) { if(type == InputEvent_Vector && event.type == InputEvent_Vector) return event; float as_float = 0; switch(event.type) { case InputEvent_Vector: LOG_ERROR("No (1)"); break; case InputEvent_Bool: as_float = (float)event.as_bool; break; case InputEvent_Float: as_float = event.as_float; break; case InputEvent_Int: as_float = (float)event.as_int; break; } event.type = type; switch(type) { case InputEvent_Int: event.as_int = (int)round(as_float); return event; case InputEvent_Float: event.as_float = as_float; return event; case InputEvent_Bool: event.as_bool = as_float != 0; return event; case InputEvent_Vector: LOG_ERROR("No (2)"); return event; } return event; } InputEvent compositeaxis1d_evaluate(CompositeAxis1D* self, SDL_Event event) { InputEvent left_result = self->left.tc->evaluate(self->left.data, event); InputEvent right_result = self->right.tc->evaluate(self->right.data, event); ASSERT_RETURN(self->type != InputEvent_Vector || (left_result.type == InputEvent_Vector && right_result.type == InputEvent_Vector), ((InputEvent){.type = 0, .as_bool = 0}), "Composite axis can only output vector if both composite elements output vector."); InputEvent final = { .type = self->type }; // if both outputs are booleans, they will be combined to an int if(final.type == InputEvent_Bool) final.type = InputEvent_Int; left_result = _internal_event_to_type(final.type, left_result); right_result = _internal_event_to_type(final.type, right_result); switch(final.type) { default: LOG_ERROR("Invalid composite input result"); final.type = InputEvent_Bool; final.as_bool = 0; return final; case InputEvent_Int: final.as_int = right_result.as_int - left_result.as_int; return final; case InputEvent_Float: final.as_float = right_result.as_float - left_result.as_float; return final; case InputEvent_Vector: final.as_vector = vsubf(right_result.as_vector, left_result.as_vector); return final; } } void compositeaxis1d_set_device(CompositeAxis1D* self, InputDevice* device) { self->left.tc->set_device(self->left.data, device); self->right.tc->set_device(self->right.data, device); } void compositeaxis1d_drop(CompositeAxis1D* self) { self->left.drop->drop(self->left.data); self->right.drop->drop(self->right.data); free(self); } CompositeAxis1D* compositeaxis1d_from_keys(SDL_Scancode negative, SDL_Scancode positive) { return compositeaxis1d_new( KeyBind_as_InputAxis(keybind_new(negative)), KeyBind_as_InputAxis(keybind_new(positive)), InputEvent_Float); } CompositeAxis1D* compositeaxis1d_from_buttons(int negative, int positive) { return compositeaxis1d_new( ControllerButton_as_InputAxis(controllerbutton_new(negative)), ControllerButton_as_InputAxis(controllerbutton_new(positive)), InputEvent_Float); }