Skip to content

Commit

Permalink
[Input] Accounted fixed axis inputs for controllers (by accounting fo…
Browse files Browse the repository at this point in the history
…r deadzone) and enable camera control via a controller (tested with PS5)
  • Loading branch information
PanosK92 committed Sep 5, 2022
1 parent ba7339e commit 9eee3d4
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 128 deletions.
48 changes: 24 additions & 24 deletions editor/Widgets/Properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -824,17 +824,17 @@ void Properties::ShowCamera(Camera* camera) const

if (helper::ComponentBegin("Camera", IconType::Component_Camera, camera))
{
//= REFLECT ========================================================
vector<string> projection_types = { "Perspective", "Orthographic" };
float aperture = camera->GetAperture();
float shutter_speed = camera->GetShutterSpeed();
float iso = camera->GetIso();
float fov = camera->GetFovHorizontalDeg();
float near_plane = camera->GetNearPlane();
float far_plane = camera->GetFarPlane();
bool fps_control_enabled = camera->GetFpsControlEnabled();
//= REFLECT ====================================================================
static vector<string> projection_types = { "Perspective", "Orthographic" };
float aperture = camera->GetAperture();
float shutter_speed = camera->GetShutterSpeed();
float iso = camera->GetIso();
float fov = camera->GetFovHorizontalDeg();
float near_plane = camera->GetNearPlane();
float far_plane = camera->GetFarPlane();
bool first_person_control_enabled = camera->GetFirstPersonControlEnabled();
m_colorPicker_camera->SetColor(camera->GetClearColor());
//==================================================================
//==============================================================================

const auto input_text_flags = ImGuiInputTextFlags_CharsDecimal;

Expand Down Expand Up @@ -878,20 +878,20 @@ void Properties::ShowCamera(Camera* camera) const
ImGui::SetCursorPosX(helper::g_column); ImGui::PushItemWidth(130); ImGui::InputFloat("Far", &far_plane, 0.01f, 0.01f, "%.2f", input_text_flags); ImGui::PopItemWidth();

// FPS Control
ImGui::Text("FPS Control");
ImGui::SameLine(helper::g_column); ImGui::Checkbox("##camera_fps_control", &fps_control_enabled);
imgui_extension::tooltip("Enables FPS control while holding down the right mouse button");

//= MAP =================================================================================================================
if (aperture != camera->GetAperture()) camera->SetAperture(aperture);
if (shutter_speed != camera->GetShutterSpeed()) camera->SetShutterSpeed(shutter_speed);
if (iso != camera->GetIso()) camera->SetIso(iso);
if (fov != camera->GetFovHorizontalDeg()) camera->SetFovHorizontalDeg(fov);
if (near_plane != camera->GetNearPlane()) camera->SetNearPlane(near_plane);
if (far_plane != camera->GetFarPlane()) camera->SetFarPlane(far_plane);
if (fps_control_enabled != camera->GetFpsControlEnabled()) camera->SetFpsControlEnabled(fps_control_enabled);
if (m_colorPicker_camera->GetColor() != camera->GetClearColor()) camera->SetClearColor(m_colorPicker_camera->GetColor());
//=======================================================================================================================
ImGui::Text("First Person Control");
ImGui::SameLine(helper::g_column); ImGui::Checkbox("##camera_first_person_control", &first_person_control_enabled);
imgui_extension::tooltip("Enables first person control while holding down the right mouse button (or when a controller is connected)");

//= MAP =======================================================================================================================================
if (aperture != camera->GetAperture()) camera->SetAperture(aperture);
if (shutter_speed != camera->GetShutterSpeed()) camera->SetShutterSpeed(shutter_speed);
if (iso != camera->GetIso()) camera->SetIso(iso);
if (fov != camera->GetFovHorizontalDeg()) camera->SetFovHorizontalDeg(fov);
if (near_plane != camera->GetNearPlane()) camera->SetNearPlane(near_plane);
if (far_plane != camera->GetFarPlane()) camera->SetFarPlane(far_plane);
if (first_person_control_enabled != camera->GetFirstPersonControlEnabled()) camera->SetFirstPersonControlEnabled(first_person_control_enabled);
if (m_colorPicker_camera->GetColor() != camera->GetClearColor()) camera->SetClearColor(m_colorPicker_camera->GetColor());
//=============================================================================================================================================
}
helper::ComponentEnd();
}
Expand Down
1 change: 1 addition & 0 deletions runtime/Input/Input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace Spartan

PollMouse();
PollKeyboard();
PollController();
}

void Input::OnPostTick()
Expand Down
11 changes: 7 additions & 4 deletions runtime/Input/Input.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ namespace Spartan
// Polling driven input
void PollMouse();
void PollKeyboard();
void PollController();

// Event driven input
void OnEvent(const Variant& event_variant);
Expand All @@ -123,11 +124,11 @@ namespace Spartan
const Math::Vector2 GetMousePositionRelativeToEditorViewport() const;

// Controller
bool ControllerIsConnected() const { return m_controller_connected; }
bool IsControllerConnected() const { return m_is_controller_connected; }
const Math::Vector2& GetControllerThumbStickLeft() const { return m_controller_thumb_left; }
const Math::Vector2& GetControllerThumbStickRight() const { return m_controller_thumb_right; }
float GetControllerTriggerLeft() const { return m_controller_trigger_left; }
float GetControllerTriggerRight() const { return m_gamepad_trigger_right; }
float GetControllerTriggerRight() const { return m_controller_trigger_right; }
// Vibrate the gamepad.
// Motor speed range is from 0.0 to 1.0f.
// The left motor is the low-frequency rumble motor.
Expand All @@ -151,10 +152,12 @@ namespace Spartan

// Controller
void* m_controller = nullptr;
bool m_controller_connected = false;
bool m_is_controller_connected = false;
std::string m_controller_name = "";
uint32_t m_controller_index = 0;
Math::Vector2 m_controller_thumb_left = Math::Vector2::Zero;
Math::Vector2 m_controller_thumb_right = Math::Vector2::Zero;
float m_controller_trigger_left = 0.0f;
float m_gamepad_trigger_right = 0.0f;
float m_controller_trigger_right = 0.0f;
};
}
138 changes: 76 additions & 62 deletions runtime/Input/InputController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,44 @@ using namespace Spartan::Math;

namespace Spartan
{
static float get_normalized_axis_value(SDL_GameController* controller, const SDL_GameControllerAxis axis)
{
int16_t value = SDL_GameControllerGetAxis(controller, axis);

// Account for deadzone.
static const uint16_t deadzone = 8000; // A good default as per SDL_GameController.h
if ((abs(value) - deadzone) < 0)
{
value = 0;
}
else
{
value -= value > 0 ? deadzone : -deadzone;
}

// Compute range
static const float range_negative = 32768.0f;
static const float range_positive = 32767.0f;
float range = value < 0 ? range_negative : range_positive;

// Normalize
return static_cast<float>(value) / (range - deadzone);
}

void Input::PollController()
{
SDL_GameController* controller = static_cast<SDL_GameController*>(m_controller);
if (!m_controller)
return;

m_controller_trigger_left = get_normalized_axis_value(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERLEFT); // L2
m_controller_trigger_right = get_normalized_axis_value(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_TRIGGERRIGHT); // R2
m_controller_thumb_left.x = get_normalized_axis_value(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTX); // LEFT THUMBSTICK
m_controller_thumb_left.y = get_normalized_axis_value(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_LEFTY); // LEFT THUMBSTICK
m_controller_thumb_right.x = get_normalized_axis_value(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTX); // RIGHT THUMBSTICK
m_controller_thumb_right.y = get_normalized_axis_value(controller, SDL_GameControllerAxis::SDL_CONTROLLER_AXIS_RIGHTY); // RIGHT THUMBSTICK
}

void Input::OnEventController(void* event_controller)
{
// Validate event
Expand All @@ -40,7 +78,7 @@ namespace Spartan
Uint32 event_type = sdl_event->type;

// Detect controller
if (!m_controller_connected)
if (!m_is_controller_connected)
{
for (int i = 0; i < SDL_NumJoysticks(); i++)
{
Expand All @@ -49,8 +87,9 @@ namespace Spartan
SDL_GameController* controller = SDL_GameControllerOpen(i);
if (SDL_GameControllerGetAttached(controller) == 1)
{
m_controller = controller;
m_controller_connected = true;
m_controller = controller;
m_controller_index = i;
m_is_controller_connected = true;
}
else
{
Expand All @@ -73,16 +112,17 @@ namespace Spartan
SDL_GameController* controller = SDL_GameControllerOpen(i);
if (SDL_GameControllerGetAttached(controller) == SDL_TRUE)
{
m_controller = controller;
m_controller_connected = true;
m_controller = controller;
m_is_controller_connected = true;
m_controller_name = SDL_GameControllerNameForIndex(i);
break;
}
}
}

if (m_controller_connected)
if (m_is_controller_connected)
{
SP_LOG_INFO("Controller connected.");
SP_LOG_INFO("Controller connected \"%s\".", m_controller_name.c_str());
}
else
{
Expand All @@ -93,8 +133,10 @@ namespace Spartan
// Disconnected
if (event_type == SDL_CONTROLLERDEVICEREMOVED)
{
m_controller = nullptr;
m_controller_connected = false;
m_controller = nullptr;
m_is_controller_connected = false;
m_controller_name = "";

SP_LOG_INFO("Controller disconnected.");
}

Expand All @@ -103,27 +145,27 @@ namespace Spartan
{
Uint8 button = sdl_event->cbutton.button;

m_keys[start_index_gamepad] = button == SDL_CONTROLLER_BUTTON_DPAD_UP;
m_keys[start_index_gamepad + 1] = button == SDL_CONTROLLER_BUTTON_DPAD_DOWN;
m_keys[start_index_gamepad + 2] = button == SDL_CONTROLLER_BUTTON_DPAD_LEFT;
m_keys[start_index_gamepad + 3] = button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
m_keys[start_index_gamepad + 4] = button == SDL_CONTROLLER_BUTTON_A;
m_keys[start_index_gamepad + 5] = button == SDL_CONTROLLER_BUTTON_B;
m_keys[start_index_gamepad + 6] = button == SDL_CONTROLLER_BUTTON_X;
m_keys[start_index_gamepad + 7] = button == SDL_CONTROLLER_BUTTON_Y;
m_keys[start_index_gamepad + 8] = button == SDL_CONTROLLER_BUTTON_BACK;
m_keys[start_index_gamepad + 9] = button == SDL_CONTROLLER_BUTTON_GUIDE;
m_keys[start_index_gamepad + 10] = button == SDL_CONTROLLER_BUTTON_START;
m_keys[start_index_gamepad + 11] = button == SDL_CONTROLLER_BUTTON_LEFTSTICK;
m_keys[start_index_gamepad + 12] = button == SDL_CONTROLLER_BUTTON_RIGHTSTICK;
m_keys[start_index_gamepad + 13] = button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
m_keys[start_index_gamepad + 14] = button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
m_keys[start_index_gamepad + 15] = button == SDL_CONTROLLER_BUTTON_MISC1;
m_keys[start_index_gamepad + 16] = button == SDL_CONTROLLER_BUTTON_PADDLE1;
m_keys[start_index_gamepad + 17] = button == SDL_CONTROLLER_BUTTON_PADDLE2;
m_keys[start_index_gamepad + 18] = button == SDL_CONTROLLER_BUTTON_PADDLE3;
m_keys[start_index_gamepad + 19] = button == SDL_CONTROLLER_BUTTON_PADDLE4;
m_keys[start_index_gamepad + 20] = button == SDL_CONTROLLER_BUTTON_TOUCHPAD;
m_keys[start_index_gamepad] = button == SDL_CONTROLLER_BUTTON_DPAD_UP;
m_keys[start_index_gamepad + 1] = button == SDL_CONTROLLER_BUTTON_DPAD_DOWN;
m_keys[start_index_gamepad + 2] = button == SDL_CONTROLLER_BUTTON_DPAD_LEFT;
m_keys[start_index_gamepad + 3] = button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
m_keys[start_index_gamepad + 4] = button == SDL_CONTROLLER_BUTTON_A;
m_keys[start_index_gamepad + 5] = button == SDL_CONTROLLER_BUTTON_B;
m_keys[start_index_gamepad + 6] = button == SDL_CONTROLLER_BUTTON_X;
m_keys[start_index_gamepad + 7] = button == SDL_CONTROLLER_BUTTON_Y;
m_keys[start_index_gamepad + 8] = button == SDL_CONTROLLER_BUTTON_BACK;
m_keys[start_index_gamepad + 9] = button == SDL_CONTROLLER_BUTTON_GUIDE;
m_keys[start_index_gamepad + 10] = button == SDL_CONTROLLER_BUTTON_START;
m_keys[start_index_gamepad + 11] = button == SDL_CONTROLLER_BUTTON_LEFTSTICK;
m_keys[start_index_gamepad + 12] = button == SDL_CONTROLLER_BUTTON_RIGHTSTICK;
m_keys[start_index_gamepad + 13] = button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
m_keys[start_index_gamepad + 14] = button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
m_keys[start_index_gamepad + 15] = button == SDL_CONTROLLER_BUTTON_MISC1;
m_keys[start_index_gamepad + 16] = button == SDL_CONTROLLER_BUTTON_PADDLE1;
m_keys[start_index_gamepad + 17] = button == SDL_CONTROLLER_BUTTON_PADDLE2;
m_keys[start_index_gamepad + 18] = button == SDL_CONTROLLER_BUTTON_PADDLE3;
m_keys[start_index_gamepad + 19] = button == SDL_CONTROLLER_BUTTON_PADDLE4;
m_keys[start_index_gamepad + 20] = button == SDL_CONTROLLER_BUTTON_TOUCHPAD;
}
else
{
Expand All @@ -132,44 +174,16 @@ namespace Spartan
m_keys[i] = false;
}
}

// Axes
if (event_type == SDL_CONTROLLERAXISMOTION)
{
SDL_ControllerAxisEvent event_axis = sdl_event->caxis;

switch (event_axis.axis)
{
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
m_controller_trigger_left = static_cast<float>(event_axis.value) / 32768.0f;
break;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
m_gamepad_trigger_right = static_cast<float>(event_axis.value) / 32768.0f;
break;
case SDL_CONTROLLER_AXIS_LEFTX:
m_controller_thumb_left.x = static_cast<float>(event_axis.value) / 32768.0f;
break;
case SDL_CONTROLLER_AXIS_LEFTY:
m_controller_thumb_left.y = static_cast<float>(event_axis.value) / 32768.0f;
break;
case SDL_CONTROLLER_AXIS_RIGHTX:
m_controller_thumb_right.x = static_cast<float>(event_axis.value) / 32768.0f;
break;
case SDL_CONTROLLER_AXIS_RIGHTY:
m_controller_thumb_right.y = static_cast<float>(event_axis.value) / 32768.0f;
break;
}
}
}

bool Input::GamepadVibrate(const float left_motor_speed, const float right_motor_speed) const
{
if (!m_controller_connected)
if (!m_is_controller_connected)
return false;

Uint16 low_frequency_rumble = static_cast<uint16_t>(Helper::Clamp(left_motor_speed, 0.0f, 1.0f) * 65535); // Convert [0, 1] to [0, 65535]
Uint16 high_frequency_rumble = static_cast<uint16_t>(Helper::Clamp(right_motor_speed, 0.0f, 1.0f) * 65535); // Convert [0, 1] to [0, 65535]
Uint32 duration_ms = 0xFFFFFFFF;
Uint16 low_frequency_rumble = static_cast<uint16_t>(Helper::Clamp(left_motor_speed, 0.0f, 1.0f) * 65535); // Convert [0, 1] to [0, 65535]
Uint16 high_frequency_rumble = static_cast<uint16_t>(Helper::Clamp(right_motor_speed, 0.0f, 1.0f) * 65535); // Convert [0, 1] to [0, 65535]
Uint32 duration_ms = 0xFFFFFFFF;

if (SDL_GameControllerRumble(static_cast<SDL_GameController*>(m_controller), low_frequency_rumble, high_frequency_rumble, duration_ms) == -1)
{
Expand Down
2 changes: 1 addition & 1 deletion runtime/Input/InputMouse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace Spartan
// Get state
int x, y;
Uint32 keys_states = SDL_GetGlobalMouseState(&x, &y);
Vector2 position = Vector2(static_cast<float>(x), static_cast<float>(y));
Vector2 position = Vector2(static_cast<float>(x), static_cast<float>(y));

// Get delta
m_mouse_delta = position - m_mouse_position;
Expand Down
Loading

0 comments on commit 9eee3d4

Please sign in to comment.