mirror of
https://github.com/open-goal/jak-project
synced 2026-07-30 07:55:01 -04:00
ad5cec1bb4
This moves the blerc math from mips2c to the Merc2 renderer, and uses floats instead. We could potentially do this on the GPU, which would be even faster, but this isn't that slow in the first place.
158 lines
5.8 KiB
C++
158 lines
5.8 KiB
C++
#include "game_controller.h"
|
|
|
|
#include "game/system/hid/sdl_util.h"
|
|
|
|
#include "third-party/fmt/core.h"
|
|
|
|
GameController::GameController(int sdl_device_id,
|
|
std::shared_ptr<game_settings::InputSettings> settings)
|
|
: m_sdl_instance_id(sdl_device_id) {
|
|
m_settings = settings;
|
|
m_loaded = false;
|
|
m_device_handle = SDL_GameControllerOpen(sdl_device_id);
|
|
if (!m_device_handle) {
|
|
sdl_util::log_error(fmt::format("Could not read data from device index: {}", sdl_device_id));
|
|
return;
|
|
}
|
|
|
|
auto joystick = SDL_GameControllerGetJoystick(m_device_handle);
|
|
if (!joystick) {
|
|
sdl_util::log_error(
|
|
fmt::format("Could not get underlying joystick for gamecontroller: id {}", sdl_device_id));
|
|
return;
|
|
}
|
|
m_sdl_instance_id = SDL_JoystickInstanceID(joystick);
|
|
if (m_sdl_instance_id < 0) {
|
|
sdl_util::log_error(
|
|
fmt::format("Could not get instance id for gamecontroller: id {}", sdl_device_id));
|
|
return;
|
|
}
|
|
const auto controller_guid = SDL_JoystickGetGUID(joystick);
|
|
char guidStr[33];
|
|
SDL_JoystickGetGUIDString(controller_guid, guidStr, sizeof(guidStr));
|
|
m_guid = guidStr;
|
|
|
|
auto name = SDL_GameControllerName(m_device_handle);
|
|
if (!name) {
|
|
sdl_util::log_error(fmt::format("Could not get device name with id: {}", sdl_device_id));
|
|
m_device_name = "";
|
|
} else {
|
|
m_device_name = name;
|
|
}
|
|
m_has_led = sdl_util::from_sdl_bool(SDL_GameControllerHasLED(m_device_handle));
|
|
|
|
if (m_settings->controller_binds.find(m_guid) == m_settings->controller_binds.end()) {
|
|
m_settings->controller_binds[m_guid] = DEFAULT_CONTROLLER_BINDS;
|
|
}
|
|
|
|
m_loaded = true;
|
|
}
|
|
|
|
void GameController::process_event(const SDL_Event& event,
|
|
const CommandBindingGroups& commands,
|
|
std::shared_ptr<PadData> data,
|
|
std::optional<InputBindAssignmentMeta>& bind_assignment,
|
|
bool /*ignore_inputs*/) {
|
|
if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.which == m_sdl_instance_id) {
|
|
// https://wiki.libsdl.org/SDL2/SDL_GameControllerAxis
|
|
if ((int)event.caxis.axis <= SDL_CONTROLLER_AXIS_INVALID ||
|
|
event.caxis.axis >= SDL_CONTROLLER_AXIS_MAX) {
|
|
return;
|
|
}
|
|
|
|
auto& binds = m_settings->controller_binds.at(m_guid);
|
|
|
|
// Handle analog stick binds
|
|
if (event.caxis.axis >= SDL_CONTROLLER_AXIS_LEFTX &&
|
|
event.caxis.axis <= SDL_CONTROLLER_AXIS_RIGHTY && !data->analogs_being_simulated() &&
|
|
binds.analog_axii.find(event.caxis.axis) != binds.analog_axii.end()) {
|
|
for (const auto& bind : binds.analog_axii.at(event.caxis.axis)) {
|
|
// Adjust the value range to 0-255 (127 being neutral)
|
|
// Values come out of SDL as -32,768 + 32,767
|
|
int axis_val = ((event.caxis.value + 32768) * 256) / 65536;
|
|
data->analog_data.at(bind.pad_data_index) = axis_val;
|
|
}
|
|
} else if (event.caxis.axis >= SDL_CONTROLLER_AXIS_TRIGGERLEFT &&
|
|
event.caxis.axis <= SDL_CONTROLLER_AXIS_TRIGGERRIGHT &&
|
|
binds.button_axii.find(event.caxis.axis) != binds.button_axii.end()) {
|
|
// Binding re-assignment
|
|
if (bind_assignment) {
|
|
if (bind_assignment->device_type == InputDeviceType::CONTROLLER &&
|
|
!bind_assignment->for_analog) {
|
|
binds.assign_button_bind(event.caxis.axis, bind_assignment.value(), true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// and analog triggers
|
|
for (const auto& bind : binds.button_axii.at(event.caxis.axis)) {
|
|
data->button_data.at(bind.pad_data_index) = event.caxis.value > 0;
|
|
}
|
|
}
|
|
} else if ((event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONUP) &&
|
|
event.cbutton.which == m_sdl_instance_id) {
|
|
auto& binds = m_settings->controller_binds.at(m_guid);
|
|
|
|
// https://wiki.libsdl.org/SDL2/SDL_GameControllerButton
|
|
if ((int)event.cbutton.button <= SDL_CONTROLLER_BUTTON_INVALID ||
|
|
event.cbutton.button >= SDL_CONTROLLER_BUTTON_MAX) {
|
|
return;
|
|
}
|
|
|
|
// Binding re-assignment
|
|
if (bind_assignment && event.type == SDL_CONTROLLERBUTTONDOWN) {
|
|
if (bind_assignment->device_type == InputDeviceType::CONTROLLER &&
|
|
!bind_assignment->for_analog) {
|
|
binds.assign_button_bind(event.cbutton.button, bind_assignment.value());
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (binds.buttons.find(event.cbutton.button) == binds.buttons.end()) {
|
|
return;
|
|
}
|
|
|
|
// Iterate the binds, and apply all of them
|
|
for (const auto& bind : binds.buttons.at(event.cbutton.button)) {
|
|
data->button_data.at(bind.pad_data_index) = event.type == SDL_CONTROLLERBUTTONDOWN;
|
|
}
|
|
|
|
// Check for commands
|
|
if (event.type == SDL_CONTROLLERBUTTONDOWN &&
|
|
commands.controller_binds.find(event.cbutton.button) != commands.controller_binds.end()) {
|
|
for (const auto& command : commands.controller_binds.at(event.cbutton.button)) {
|
|
command.command();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameController::close_device() {
|
|
if (m_device_handle) {
|
|
SDL_GameControllerClose(m_device_handle);
|
|
}
|
|
}
|
|
|
|
int GameController::update_rumble(const u8 low_rumble, const u8 high_rumble) {
|
|
if (m_device_handle) {
|
|
// https://wiki.libsdl.org/SDL2/SDL_GameControllerRumble
|
|
// Arbitrary duration, since it's called every frame anyway, just so the vibration doesn't last
|
|
// forever. SDL expects a value in the range of 0-0xFFFF, so the `257` is just normalizing the
|
|
// 0-255 we get to that range
|
|
if (SDL_GameControllerRumble(m_device_handle, low_rumble * 257, high_rumble * 257, 100) == 0) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void GameController::set_led(const u8 red, const u8 green, const u8 blue) {
|
|
if (!m_has_led) {
|
|
return;
|
|
}
|
|
auto ok = SDL_GameControllerSetLED(m_device_handle, red, green, blue);
|
|
if (ok != 0) {
|
|
m_has_led = false;
|
|
}
|
|
}
|