diff --git a/include/recomp_input.h b/include/recomp_input.h index ed116c8..266bffd 100644 --- a/include/recomp_input.h +++ b/include/recomp_input.h @@ -5,58 +5,47 @@ #include #include #include +#include namespace recomp { - struct ControllerState { - enum Button : uint32_t { - BUTTON_NORTH = 1 << 0, - BUTTON_SOUTH = 1 << 1, - BUTTON_EAST = 1 << 2, - BUTTON_WEST = 1 << 3, - BUTTON_L1 = 1 << 4, // Left Bumper - BUTTON_R1 = 1 << 5, // Right Bumper - BUTTON_L2 = 1 << 6, // Left Trigger Press - BUTTON_R2 = 1 << 7, // Right Trigger Press - BUTTON_L3 = 1 << 8, // Left Joystick Press - BUTTON_R3 = 1 << 9, // Right Joystick Press - BUTTON_DPAD_UP = 1 << 10, - BUTTON_DPAD_DOWN = 1 << 11, - BUTTON_DPAD_RIGHT = 1 << 12, - BUTTON_DPAD_LEFT = 1 << 13, - BUTTON_START = 1 << 14, - }; - enum Axis : size_t { - AXIS_LEFT_X, - AXIS_LEFT_Y, - AXIS_RIGHT_X, - AXIS_RIGHT_Y, - AXIS_LEFT_TRIGGER, - AXIS_RIGHT_TRIGGER, - AXIS_MAX - }; - uint32_t buttons; - float axes[AXIS_MAX]; + struct InputField { + uint32_t device_type; + int32_t input_id; }; - struct MouseState { - enum Button : uint32_t { - LEFT = 1 << 0, - RIGHT = 1 << 1, - MIDDLE = 1 << 2, - BACK = 1 << 3, - FORWARD = 1 << 4, - }; - int32_t wheel_pos; - int32_t position_x; - int32_t position_y; - uint32_t buttons; + void poll_inputs(); + float get_input_analog(const InputField& field); + float get_input_analog(const std::span fields); + bool get_input_digital(const InputField& field); + bool get_input_digital(const std::span fields); + + struct DefaultN64Mappings { + std::vector a; + std::vector b; + std::vector l; + std::vector r; + std::vector z; + std::vector start; + + std::vector c_left; + std::vector c_right; + std::vector c_up; + std::vector c_down; + + std::vector dpad_left; + std::vector dpad_right; + std::vector dpad_up; + std::vector dpad_down; + + std::vector analog_left; + std::vector analog_right; + std::vector analog_up; + std::vector analog_down; }; - using InputState = std::variant; + extern const DefaultN64Mappings default_n64_mappings; - void get_keyboard_input(uint16_t* buttons_out, float* x_out, float* y_out); void get_n64_input(uint16_t* buttons_out, float* x_out, float* y_out); - std::vector get_input_states(); void handle_events(); } diff --git a/patches/input.h b/patches/input.h index 8484b69..9b0ae4b 100644 --- a/patches/input.h +++ b/patches/input.h @@ -26,6 +26,23 @@ extern "C" { void name(uint8_t* rdram, recomp_context* ctx); #endif +enum RecompDigitalInput { + RECOMP_DIGITAL_INPUT_ITEM1, + RECOMP_DIGITAL_INPUT_ITEM2, + RECOMP_DIGITAL_INPUT_ITEM3, + RECOMP_DIGITAL_INPUT_MAX +}; + +enum RecompAnalogInput { + RECOMP_ANALOG_INPUT_MOVEMENT_X, + RECOMP_ANALOG_INPUT_MOVEMENT_Y, + RECOMP_ANALOG_INPUT_CAMERA_X, + RECOMP_ANALOG_INPUT_CAMERA_Y, + RECOMP_ANALOG_INPUT_MAX, +}; + +DECLARE_FUNC(u32, recomp_get_digital_input, u32 which); +DECLARE_FUNC(float, recomp_get_analog_input, u32 which); DECLARE_FUNC(void, recomp_get_item_inputs, u32* buttons); DECLARE_FUNC(void, recomp_get_camera_inputs, float* x_out, float* y_out); // TODO move this diff --git a/src/game/controls.cpp b/src/game/controls.cpp index 6258a96..d91c0f6 100644 --- a/src/game/controls.cpp +++ b/src/game/controls.cpp @@ -36,141 +36,80 @@ struct GameControllerButtonMapping { }; using button_map_t = std::vector; -uint32_t process_controller_mappings(const recomp::ControllerState& controller_state, const axis_map_t& axis_map, const button_map_t& button_map) { - uint32_t cur_buttons = 0; - - for (const auto& mapping : axis_map) { - float input_value = controller_state.axes[mapping.axis]; - if (mapping.threshold > 0) { - if (input_value > mapping.threshold) { - cur_buttons |= mapping.output_mask; - } - } - else { - if (input_value < mapping.threshold) { - cur_buttons |= mapping.output_mask; - } - } - } - - for (const auto& mapping : button_map) { - int input_value = controller_state.buttons & mapping.button; - if (input_value) { - cur_buttons |= mapping.output_mask; - } - } - - return cur_buttons; -} - void recomp::get_n64_input(uint16_t* buttons_out, float* x_out, float* y_out) { - static const axis_map_t general_axis_map{ - { recomp::ControllerState::AXIS_RIGHT_X, -controller_default_threshold, N64Inputs::C_LEFT }, - { recomp::ControllerState::AXIS_RIGHT_X, controller_default_threshold, N64Inputs::C_RIGHT }, - { recomp::ControllerState::AXIS_RIGHT_Y, -controller_default_threshold, N64Inputs::C_UP }, - { recomp::ControllerState::AXIS_RIGHT_Y, controller_default_threshold, N64Inputs::C_DOWN }, - { recomp::ControllerState::AXIS_LEFT_TRIGGER, 0.30f, N64Inputs::Z }, - }; - static const button_map_t general_button_map{ - { recomp::ControllerState::BUTTON_START, N64Inputs::START }, - { recomp::ControllerState::BUTTON_SOUTH, N64Inputs::A }, - { recomp::ControllerState::BUTTON_EAST, N64Inputs::B }, - { recomp::ControllerState::BUTTON_WEST, N64Inputs::B }, - { recomp::ControllerState::BUTTON_L1, N64Inputs::L }, - { recomp::ControllerState::BUTTON_R1, N64Inputs::R }, - { recomp::ControllerState::BUTTON_DPAD_LEFT, N64Inputs::DPAD_LEFT }, - { recomp::ControllerState::BUTTON_DPAD_RIGHT, N64Inputs::DPAD_RIGHT }, - { recomp::ControllerState::BUTTON_DPAD_UP, N64Inputs::DPAD_UP }, - { recomp::ControllerState::BUTTON_DPAD_DOWN, N64Inputs::DPAD_DOWN }, - }; uint16_t cur_buttons = 0; float cur_x = 0.0f; float cur_y = 0.0f; - recomp::get_keyboard_input(&cur_buttons, &cur_x, &cur_y); - - std::vector input_states = recomp::get_input_states(); - - for (const InputState& state : input_states) { - if (const auto* controller_state = std::get_if(&state)) { - cur_x += controller_state->axes[ControllerState::AXIS_LEFT_X]; - cur_y -= controller_state->axes[ControllerState::AXIS_LEFT_Y]; - - cur_buttons |= (uint16_t)process_controller_mappings(*controller_state, general_axis_map, general_button_map); - } - else if (const auto* mouse_state = std::get_if(&state)) { - // Mouse currently unused - } - } + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.a) ? N64Inputs::A : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.b) ? N64Inputs::B : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.l) ? N64Inputs::L : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.r) ? N64Inputs::R : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.z) ? N64Inputs::Z : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.start) ? N64Inputs::START : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.c_left) ? N64Inputs::C_LEFT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.c_right) ? N64Inputs::C_RIGHT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.c_up) ? N64Inputs::C_UP : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.c_down) ? N64Inputs::C_DOWN : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_left) ? N64Inputs::DPAD_LEFT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_right) ? N64Inputs::DPAD_RIGHT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_up) ? N64Inputs::DPAD_UP : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_down) ? N64Inputs::DPAD_DOWN : 0; *buttons_out = cur_buttons; - cur_x = std::clamp(cur_x, -1.0f, 1.0f); - cur_y = std::clamp(cur_y, -1.0f, 1.0f); + cur_x = recomp::get_input_analog(recomp::default_n64_mappings.analog_right) - recomp::get_input_analog(recomp::default_n64_mappings.analog_left); + cur_y = recomp::get_input_analog(recomp::default_n64_mappings.analog_up) - recomp::get_input_analog(recomp::default_n64_mappings.analog_down); *x_out = cur_x; *y_out = cur_y; } extern "C" void recomp_get_item_inputs(uint8_t* rdram, recomp_context* ctx) { - static const axis_map_t item_axis_map{ - { recomp::ControllerState::AXIS_RIGHT_X, -controller_default_threshold, N64Inputs::C_LEFT }, - { recomp::ControllerState::AXIS_RIGHT_X, controller_default_threshold, N64Inputs::C_RIGHT }, - { recomp::ControllerState::AXIS_RIGHT_Y, controller_default_threshold, N64Inputs::C_DOWN }, - }; - - static const button_map_t item_button_map { - { recomp::ControllerState::BUTTON_EAST, N64Inputs::B }, - { recomp::ControllerState::BUTTON_WEST, N64Inputs::B }, - { recomp::ControllerState::BUTTON_DPAD_LEFT, N64Inputs::DPAD_LEFT }, - { recomp::ControllerState::BUTTON_DPAD_RIGHT, N64Inputs::DPAD_RIGHT }, - { recomp::ControllerState::BUTTON_DPAD_UP, N64Inputs::DPAD_UP }, - { recomp::ControllerState::BUTTON_DPAD_DOWN, N64Inputs::DPAD_DOWN }, - }; - u32* buttons_out = _arg<0, u32*>(rdram, ctx); uint32_t cur_buttons = 0; - // TODO do this in a way that will allow for remapping keyboard inputs - uint16_t keyboard_buttons; - float dummy_x, dummy_y; - recomp::get_keyboard_input(&keyboard_buttons, &dummy_x, &dummy_y); - cur_buttons |= keyboard_buttons; - - // Process controller inputs - std::vector input_states = recomp::get_input_states(); - - for (const recomp::InputState& state : input_states) { - if (const auto* controller_state = std::get_if(&state)) { - cur_buttons |= process_controller_mappings(*controller_state, item_axis_map, item_button_map); - } - else if (const auto* mouse_state = std::get_if(&state)) { - // Mouse currently unused - } - } + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.b) ? N64Inputs::B : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.c_left) ? N64Inputs::C_LEFT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.c_right) ? N64Inputs::C_RIGHT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.c_down) ? N64Inputs::C_DOWN : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_left) ? N64Inputs::DPAD_LEFT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_right) ? N64Inputs::DPAD_RIGHT : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_up) ? N64Inputs::DPAD_UP : 0; + cur_buttons |= recomp::get_input_digital(recomp::default_n64_mappings.dpad_down) ? N64Inputs::DPAD_DOWN : 0; *buttons_out = cur_buttons; } +bool recomp_digital_input_state[RECOMP_DIGITAL_INPUT_MAX]; +float recomp_analog_input_state[RECOMP_ANALOG_INPUT_MAX]; + +extern "C" void recomp_update_inputs(uint8_t* rdram, recomp_context* ctx) { + recomp::poll_inputs(); +} + +extern "C" void recomp_get_digital_input(uint8_t* rdram, recomp_context* ctx) { + u32 input_slot = _arg<0, u32>(rdram, ctx); + + // TODO implement this + + _return(ctx, 0); +} + +extern "C" void recomp_get_analog_input(uint8_t* rdram, recomp_context* ctx) { + u32 input_slot = _arg<0, u32>(rdram, ctx); + + // TODO implement this + + _return(ctx, 0); +} + extern "C" void recomp_get_camera_inputs(uint8_t* rdram, recomp_context* ctx) { float* x_out = _arg<0, float*>(rdram, ctx); float* y_out = _arg<1, float*>(rdram, ctx); - float x_val = 0.0f; - float y_val = 0.0f; - - // Process controller inputs - std::vector input_states = recomp::get_input_states(); - - for (const recomp::InputState& state : input_states) { - if (const auto* controller_state = std::get_if(&state)) { - x_val += controller_state->axes[recomp::ControllerState::AXIS_RIGHT_X]; - y_val += controller_state->axes[recomp::ControllerState::AXIS_RIGHT_Y]; - } - else if (const auto* mouse_state = std::get_if(&state)) { - // Mouse currently unused - } - } + float x_val = recomp::get_input_analog(recomp::default_n64_mappings.c_right) - recomp::get_input_analog(recomp::default_n64_mappings.c_left); + float y_val = recomp::get_input_analog(recomp::default_n64_mappings.c_up) - recomp::get_input_analog(recomp::default_n64_mappings.c_down); *x_out = x_val; *y_out = y_val; diff --git a/src/game/input.cpp b/src/game/input.cpp index fce85c7..a8eda19 100644 --- a/src/game/input.cpp +++ b/src/game/input.cpp @@ -6,8 +6,14 @@ #include "recomp_ui.h" #include "SDL.h" -std::atomic_int32_t mouse_wheel_pos = 0; -std::vector controllers{}; + +static struct { + const Uint8* keys = nullptr; + int numkeys = 0; + std::atomic_int32_t mouse_wheel_pos = 0; + std::vector controller_ids{}; + std::vector cur_controllers{}; +} InputState; bool sdl_event_filter(void* userdata, SDL_Event* event) { switch (event->type) { @@ -36,7 +42,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) { printf("Controller added: %d\n", controller_event->which); if (controller != nullptr) { printf(" Instance ID: %d\n", SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))); - controllers.push_back(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))); + InputState.controller_ids.push_back(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller))); } } break; @@ -44,7 +50,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) { { SDL_ControllerDeviceEvent* controller_event = (SDL_ControllerDeviceEvent*)event; printf("Controller removed: %d\n", controller_event->which); - std::erase(controllers, controller_event->which); + std::erase(InputState.controller_ids, controller_event->which); } break; case SDL_EventType::SDL_QUIT: @@ -53,7 +59,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) { case SDL_EventType::SDL_MOUSEWHEEL: { SDL_MouseWheelEvent* wheel_event = (SDL_MouseWheelEvent*)event; - mouse_wheel_pos.fetch_add(wheel_event->y * (wheel_event->direction == SDL_MOUSEWHEEL_FLIPPED ? -1 : 1)); + InputState.mouse_wheel_pos.fetch_add(wheel_event->y * (wheel_event->direction == SDL_MOUSEWHEEL_FLIPPED ? -1 : 1)); } recomp::queue_event(*event); break; @@ -72,126 +78,203 @@ void recomp::handle_events() { } } -std::vector recomp::get_input_states() { - std::vector ret{}; +enum class DeviceType { + Keyboard, + Mouse, + ControllerDigital, + ControllerAnalog // Axis input_id values are the SDL value + 1 +}; - int32_t mouse_x; - int32_t mouse_y; +constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_SOUTH = SDL_CONTROLLER_BUTTON_A; +constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_EAST = SDL_CONTROLLER_BUTTON_B; +constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_WEST = SDL_CONTROLLER_BUTTON_X; +constexpr SDL_GameControllerButton SDL_CONTROLLER_BUTTON_NORTH = SDL_CONTROLLER_BUTTON_Y; - Uint32 sdl_mouse_buttons = SDL_GetMouseState(&mouse_x, &mouse_y); +const recomp::DefaultN64Mappings recomp::default_n64_mappings = { + .a = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_SOUTH}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_SPACE} + }, + .b = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_EAST}, + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_WEST}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_LSHIFT} + }, + .l = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_E} + }, + .r = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_R} + }, + .z = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_TRIGGERLEFT + 1}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_Q} + }, + .start = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_START}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_RETURN} + }, + .c_left = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_RIGHTX + 1)}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_LEFT} + }, + .c_right = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_RIGHTX + 1}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_RIGHT} + }, + .c_up = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_RIGHTY + 1)}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_UP} + }, + .c_down = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_RIGHTY + 1}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_DOWN} + }, + .dpad_left = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_J} + }, + .dpad_right = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_L} + }, + .dpad_up = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_UP}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_I} + }, + .dpad_down = { + {.device_type = (uint32_t)DeviceType::ControllerDigital, .input_id = SDL_CONTROLLER_BUTTON_DPAD_DOWN}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_K} + }, + .analog_left = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_LEFTX + 1)}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_A} + }, + .analog_right = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_LEFTX + 1}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_D} + }, + .analog_up = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = -(SDL_CONTROLLER_AXIS_LEFTY + 1)}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_W} + }, + .analog_down = { + {.device_type = (uint32_t)DeviceType::ControllerAnalog, .input_id = SDL_CONTROLLER_AXIS_LEFTY + 1}, + {.device_type = (uint32_t)DeviceType::Keyboard, .input_id = SDL_SCANCODE_S} + }, +}; - struct MouseButtonMapping { - Sint32 input; - decltype(MouseState::buttons) output; - }; - static const std::vector input_mouse_map{ - { SDL_BUTTON_LMASK, MouseState::LEFT }, - { SDL_BUTTON_RMASK, MouseState::RIGHT }, - { SDL_BUTTON_MMASK, MouseState::MIDDLE }, - { SDL_BUTTON_X1MASK, MouseState::BACK }, - { SDL_BUTTON_X2MASK, MouseState::FORWARD }, - }; +void recomp::poll_inputs() { + InputState.keys = SDL_GetKeyboardState(&InputState.numkeys); - decltype(MouseState::buttons) mouse_buttons = 0; - for (const MouseButtonMapping& mapping : input_mouse_map) { - if (sdl_mouse_buttons & mapping.input) { - mouse_buttons |= mapping.output; + InputState.cur_controllers.clear(); + + for (SDL_JoystickID id : InputState.controller_ids) { + SDL_GameController* controller = SDL_GameControllerFromInstanceID(id); + if (controller != nullptr) { + InputState.cur_controllers.push_back(controller); } } +} - if (mouse_buttons & MouseState::FORWARD) { - printf("forward\n"); - } +bool controller_button_state(int32_t input_id) { + if (input_id >= 0 && input_id < SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_MAX) { + SDL_GameControllerButton button = (SDL_GameControllerButton)input_id; + bool ret = false; - if (mouse_buttons & MouseState::BACK) { - printf("back\n"); - } - - ret.emplace_back( - MouseState { - .wheel_pos = mouse_wheel_pos, - .position_x = mouse_x, - .position_y = mouse_y, - .buttons = mouse_buttons + for (const auto& controller : InputState.cur_controllers) { + ret |= SDL_GameControllerGetButton(controller, button); } - ); - for (SDL_JoystickID controller_id : controllers) { - struct InputButtonMapping { - SDL_GameControllerButton input; - decltype(ControllerState::buttons) output; - }; - static const std::vector input_button_map{ - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_START, ControllerState::BUTTON_START }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_A, ControllerState::BUTTON_SOUTH }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_B, ControllerState::BUTTON_EAST }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_X, ControllerState::BUTTON_WEST }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_Y, ControllerState::BUTTON_NORTH }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSHOULDER, ControllerState::BUTTON_L1 }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, ControllerState::BUTTON_R1 }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_LEFTSTICK, ControllerState::BUTTON_L3 }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_RIGHTSTICK, ControllerState::BUTTON_R3 }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_LEFT, ControllerState::BUTTON_DPAD_LEFT }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_RIGHT, ControllerState::BUTTON_DPAD_RIGHT }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_UP, ControllerState::BUTTON_DPAD_UP }, - { SDL_GameControllerButton::SDL_CONTROLLER_BUTTON_DPAD_DOWN, ControllerState::BUTTON_DPAD_DOWN }, - }; - SDL_GameController* controller = SDL_GameControllerFromInstanceID(controller_id); - decltype(ControllerState::buttons) buttons = 0; + return ret; + } + return false; +} - for (const InputButtonMapping& mapping : input_button_map) { - if (SDL_GameControllerGetButton(controller, mapping.input)) { - buttons |= mapping.output; +float controller_axis_state(int32_t input_id) { + if (abs(input_id) - 1 < SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_MAX) { + SDL_GameControllerAxis axis = (SDL_GameControllerAxis)(abs(input_id) - 1); + bool negative_range = input_id < 0; + float ret = 0.0f; + + for (const auto& controller : InputState.cur_controllers) { + float cur_val = SDL_GameControllerGetAxis(controller, axis) * (1/32768.0f); + if (negative_range) { + cur_val = -cur_val; } + ret += std::clamp(cur_val, 0.0f, 1.0f); } - auto& new_input_state = ret.emplace_back( - ControllerState { - .buttons = buttons, - .axes = {}, - } - ); - auto& new_state = std::get(new_input_state); - new_state.axes[ControllerState::AXIS_LEFT_X] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX) * (1/32768.0f); - new_state.axes[ControllerState::AXIS_LEFT_Y] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY) * (1/32768.0f); - new_state.axes[ControllerState::AXIS_RIGHT_X] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX) * (1/32768.0f); - new_state.axes[ControllerState::AXIS_RIGHT_Y] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY) * (1/32768.0f); - new_state.axes[ControllerState::AXIS_LEFT_TRIGGER] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT) * (1/32768.0f); - new_state.axes[ControllerState::AXIS_LEFT_TRIGGER] = SDL_GameControllerGetAxis(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT) * (1/32768.0f); + return std::clamp(ret, 0.0f, 1.0f); } + return false; +} +float recomp::get_input_analog(const recomp::InputField& field) { + switch ((DeviceType)field.device_type) { + case DeviceType::Keyboard: + { + if (InputState.keys && field.input_id >= 0 && field.input_id < InputState.numkeys) { + return InputState.keys[field.input_id] ? 1.0f : 0.0f; + } + return 0.0f; + } + case DeviceType::ControllerDigital: + { + return controller_button_state(field.input_id) ? 1.0f : 0.0f; + } + case DeviceType::ControllerAnalog: + { + return controller_axis_state(field.input_id); + } + case DeviceType::Mouse: + { + // TODO mouse support + return 0.0f; + } + } +} + +float recomp::get_input_analog(const std::span fields) { + float ret = 0.0f; + for (const auto& field : fields) { + ret += get_input_analog(field); + } + return std::clamp(ret, 0.0f, 1.0f); +} + +bool recomp::get_input_digital(const recomp::InputField& field) { + switch ((DeviceType)field.device_type) { + case DeviceType::Keyboard: + { + if (InputState.keys && field.input_id >= 0 && field.input_id < InputState.numkeys) { + return InputState.keys[field.input_id] != 0; + } + return false; + } + case DeviceType::ControllerDigital: + { + return controller_button_state(field.input_id); + } + case DeviceType::ControllerAnalog: + { + // TODO adjustable threshold + return controller_axis_state(field.input_id) >= 0.5f; + } + case DeviceType::Mouse: + { + // TODO mouse support + return false; + } + } +} + +bool recomp::get_input_digital(const std::span fields) { + bool ret = 0; + for (const auto& field : fields) { + ret |= get_input_digital(field); + } return ret; } - -// TODO figure out a way to handle this more generally without exposing SDL to controls.cpp -void recomp::get_keyboard_input(uint16_t* buttons_out, float* x_out, float* y_out) { - static const std::vector> keyboard_button_map{ - { SDL_Scancode::SDL_SCANCODE_LEFT, 0x0002 }, // c left - { SDL_Scancode::SDL_SCANCODE_RIGHT, 0x0001 }, // c right - { SDL_Scancode::SDL_SCANCODE_UP, 0x0008 }, // c up - { SDL_Scancode::SDL_SCANCODE_DOWN, 0x0004 }, // c down - { SDL_Scancode::SDL_SCANCODE_RETURN, 0x1000 }, // start - { SDL_Scancode::SDL_SCANCODE_SPACE, 0x8000 }, // a - { SDL_Scancode::SDL_SCANCODE_LSHIFT, 0x4000 }, // b - { SDL_Scancode::SDL_SCANCODE_Q, 0x2000 }, // z - { SDL_Scancode::SDL_SCANCODE_E, 0x0020 }, // l - { SDL_Scancode::SDL_SCANCODE_R, 0x0010 }, // r - { SDL_Scancode::SDL_SCANCODE_J, 0x0200 }, // dpad left - { SDL_Scancode::SDL_SCANCODE_L, 0x0100 }, // dpad right - { SDL_Scancode::SDL_SCANCODE_I, 0x0800 }, // dpad up - { SDL_Scancode::SDL_SCANCODE_K, 0x0400 }, // dpad down - }; - - const Uint8* key_states = SDL_GetKeyboardState(nullptr); - - *buttons_out = 0; - - for (const auto& mapping : keyboard_button_map) { - if (key_states[mapping.first]) { - *buttons_out |= mapping.second; - } - } - - *x_out = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_D] - key_states[SDL_Scancode::SDL_SCANCODE_A]); - *y_out = (100.0f / 100.0f) * (key_states[SDL_Scancode::SDL_SCANCODE_W] - key_states[SDL_Scancode::SDL_SCANCODE_S]); -} diff --git a/src/main/main.cpp b/src/main/main.cpp index d8b1b82..86de7b2 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -184,6 +184,7 @@ int main(int argc, char** argv) { }; ultramodern::input_callbacks_t input_callbacks{ + .poll_input = recomp::poll_inputs, .get_input = recomp::get_n64_input, }; diff --git a/src/recomp/cont.cpp b/src/recomp/cont.cpp index bac45ed..b279eac 100644 --- a/src/recomp/cont.cpp +++ b/src/recomp/cont.cpp @@ -33,6 +33,10 @@ extern "C" void osContInit_recomp(uint8_t* rdram, recomp_context* ctx) { } extern "C" void osContStartReadData_recomp(uint8_t* rdram, recomp_context* ctx) { + if (input_callbacks.poll_input) { + input_callbacks.poll_input(); + } + ultramodern::send_si_message(); } diff --git a/ultramodern/ultramodern.hpp b/ultramodern/ultramodern.hpp index f5d2a77..7cad584 100644 --- a/ultramodern/ultramodern.hpp +++ b/ultramodern/ultramodern.hpp @@ -109,7 +109,9 @@ struct audio_callbacks_t { // Input struct input_callbacks_t { + using poll_input_t = void(void); using get_input_t = void(uint16_t*, float*, float*); + poll_input_t* poll_input; get_input_t* get_input; };