mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-02 10:33:57 +00:00
273 lines
7.0 KiB
C++
273 lines
7.0 KiB
C++
#include "extensions/thirdpersoncamera/inputhandler.h"
|
|
|
|
#include "extensions/thirdpersoncamera/orbitcamera.h"
|
|
|
|
#include <SDL3/SDL_stdinc.h>
|
|
#include <SDL3/SDL_timer.h>
|
|
#include <utility>
|
|
|
|
using namespace Extensions::ThirdPersonCamera;
|
|
|
|
InputHandler::InputHandler()
|
|
: m_touch{}, m_wantsAutoDisable(false), m_wantsAutoEnable(false), m_rightButtonHeld(false), m_leftButtonHeld(false),
|
|
m_leftButtonDownTime(0), m_savedMouseX(0.0f), m_savedMouseY(0.0f)
|
|
{
|
|
}
|
|
|
|
bool InputHandler::TryClaimFinger(const SDL_TouchFingerEvent& p_event, bool p_active)
|
|
{
|
|
if (!p_active || m_touch.count >= 2 || p_event.x < CAMERA_ZONE_X) {
|
|
return false;
|
|
}
|
|
|
|
int idx = m_touch.count;
|
|
m_touch.id[idx] = p_event.fingerID;
|
|
m_touch.x[idx] = p_event.x;
|
|
m_touch.y[idx] = p_event.y;
|
|
m_touch.synced[idx] = true;
|
|
m_touch.count++;
|
|
|
|
if (m_touch.count == 2) {
|
|
float dx = m_touch.x[1] - m_touch.x[0];
|
|
float dy = m_touch.y[1] - m_touch.y[0];
|
|
m_touch.initialPinchDist = SDL_sqrtf(dx * dx + dy * dy);
|
|
m_touch.gesturePinchDist = m_touch.initialPinchDist;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool InputHandler::TryReleaseFinger(SDL_FingerID p_id)
|
|
{
|
|
for (int i = 0; i < m_touch.count; i++) {
|
|
if (m_touch.id[i] == p_id) {
|
|
if (i == 0 && m_touch.count == 2) {
|
|
m_touch.id[0] = m_touch.id[1];
|
|
m_touch.x[0] = m_touch.x[1];
|
|
m_touch.y[0] = m_touch.y[1];
|
|
m_touch.synced[0] = m_touch.synced[1];
|
|
}
|
|
m_touch.count--;
|
|
m_touch.initialPinchDist = 0.0f;
|
|
m_touch.gesturePinchDist = 0.0f;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InputHandler::IsFingerTracked(SDL_FingerID p_id) const
|
|
{
|
|
for (int i = 0; i < m_touch.count; i++) {
|
|
if (m_touch.id[i] == p_id) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InputHandler::ConsumeAutoDisable()
|
|
{
|
|
return std::exchange(m_wantsAutoDisable, false);
|
|
}
|
|
|
|
bool InputHandler::ConsumeAutoEnable()
|
|
{
|
|
return std::exchange(m_wantsAutoEnable, false);
|
|
}
|
|
|
|
bool InputHandler::IsLmbHeldForMovement() const
|
|
{
|
|
return m_leftButtonHeld && m_leftButtonDownTime > 0 &&
|
|
(m_rightButtonHeld || (SDL_GetTicks() - m_leftButtonDownTime) >= LMB_HOLD_THRESHOLD_MS);
|
|
}
|
|
|
|
void InputHandler::SuppressGestures()
|
|
{
|
|
m_touch.synced[0] = false;
|
|
m_touch.synced[1] = false;
|
|
m_touch.initialPinchDist = 0.0f;
|
|
m_touch.gesturePinchDist = 0.0f;
|
|
}
|
|
|
|
void InputHandler::HandleSDLEvent(SDL_Event* p_event, OrbitCamera& p_orbit, bool p_active)
|
|
{
|
|
switch (p_event->type) {
|
|
case SDL_EVENT_MOUSE_WHEEL:
|
|
if (!p_active) {
|
|
if (p_event->wheel.y < 0) {
|
|
m_wantsAutoEnable = true;
|
|
}
|
|
break;
|
|
}
|
|
if (p_orbit.GetOrbitDistance() <= OrbitCamera::SWITCH_TO_FIRST_PERSON_DISTANCE && p_event->wheel.y > 0) {
|
|
m_wantsAutoDisable = true;
|
|
break;
|
|
}
|
|
p_orbit.AdjustDistance(-p_event->wheel.y * 0.5f);
|
|
p_orbit.ClampDistance();
|
|
break;
|
|
|
|
case SDL_EVENT_MOUSE_MOTION:
|
|
if (!p_active) {
|
|
break;
|
|
}
|
|
if (m_rightButtonHeld) {
|
|
p_orbit.AdjustYaw(-p_event->motion.xrel * 0.005f);
|
|
p_orbit.AdjustPitch(p_event->motion.yrel * 0.005f);
|
|
p_orbit.ClampPitch();
|
|
}
|
|
break;
|
|
|
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
|
case SDL_EVENT_MOUSE_BUTTON_UP: {
|
|
if (p_event->button.button == SDL_BUTTON_RIGHT) {
|
|
m_rightButtonHeld = p_event->button.down;
|
|
SDL_Window* window = SDL_GetWindowFromID(p_event->button.windowID);
|
|
if (window) {
|
|
if (m_rightButtonHeld) {
|
|
if (p_active) {
|
|
SDL_GetMouseState(&m_savedMouseX, &m_savedMouseY);
|
|
SDL_SetWindowRelativeMouseMode(window, true);
|
|
}
|
|
}
|
|
else if (SDL_GetWindowRelativeMouseMode(window)) {
|
|
SDL_SetWindowRelativeMouseMode(window, false);
|
|
SDL_WarpMouseInWindow(window, m_savedMouseX, m_savedMouseY);
|
|
}
|
|
}
|
|
}
|
|
else if (p_event->button.button == SDL_BUTTON_LEFT) {
|
|
m_leftButtonHeld = p_event->button.down;
|
|
m_leftButtonDownTime = p_event->button.down ? SDL_GetTicks() : 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_EVENT_FINGER_DOWN: {
|
|
if (!IsFingerTracked(p_event->tfinger.fingerID) && m_touch.count < 2 && p_event->tfinger.x >= CAMERA_ZONE_X) {
|
|
int idx = m_touch.count;
|
|
m_touch.id[idx] = p_event->tfinger.fingerID;
|
|
m_touch.x[idx] = p_event->tfinger.x;
|
|
m_touch.y[idx] = p_event->tfinger.y;
|
|
m_touch.synced[idx] = true;
|
|
m_touch.count++;
|
|
|
|
if (m_touch.count == 2) {
|
|
float dx = m_touch.x[1] - m_touch.x[0];
|
|
float dy = m_touch.y[1] - m_touch.y[0];
|
|
m_touch.initialPinchDist = SDL_sqrtf(dx * dx + dy * dy);
|
|
m_touch.gesturePinchDist = m_touch.initialPinchDist;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_EVENT_FINGER_MOTION: {
|
|
if (m_touch.count == 1) {
|
|
if (!p_active) {
|
|
break;
|
|
}
|
|
if (m_touch.id[0] == p_event->tfinger.fingerID) {
|
|
if (!m_touch.synced[0]) {
|
|
m_touch.x[0] = p_event->tfinger.x;
|
|
m_touch.y[0] = p_event->tfinger.y;
|
|
m_touch.synced[0] = true;
|
|
break;
|
|
}
|
|
|
|
float oldX = m_touch.x[0];
|
|
float oldY = m_touch.y[0];
|
|
m_touch.x[0] = p_event->tfinger.x;
|
|
m_touch.y[0] = p_event->tfinger.y;
|
|
|
|
float moveX = m_touch.x[0] - oldX;
|
|
float moveY = m_touch.y[0] - oldY;
|
|
p_orbit.AdjustYaw(-moveX * 2.0f);
|
|
p_orbit.AdjustPitch(moveY * 2.0f);
|
|
p_orbit.ClampPitch();
|
|
}
|
|
}
|
|
else if (m_touch.count == 2) {
|
|
int idx = -1;
|
|
for (int i = 0; i < 2; i++) {
|
|
if (m_touch.id[i] == p_event->tfinger.fingerID) {
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
if (idx < 0) {
|
|
break;
|
|
}
|
|
|
|
if (!m_touch.synced[idx]) {
|
|
m_touch.x[idx] = p_event->tfinger.x;
|
|
m_touch.y[idx] = p_event->tfinger.y;
|
|
m_touch.synced[idx] = true;
|
|
|
|
if (m_touch.synced[0] && m_touch.synced[1]) {
|
|
float dx = m_touch.x[1] - m_touch.x[0];
|
|
float dy = m_touch.y[1] - m_touch.y[0];
|
|
m_touch.initialPinchDist = SDL_sqrtf(dx * dx + dy * dy);
|
|
m_touch.gesturePinchDist = m_touch.initialPinchDist;
|
|
}
|
|
break;
|
|
}
|
|
|
|
float oldX = m_touch.x[idx];
|
|
float oldY = m_touch.y[idx];
|
|
m_touch.x[idx] = p_event->tfinger.x;
|
|
m_touch.y[idx] = p_event->tfinger.y;
|
|
|
|
float dx = m_touch.x[1] - m_touch.x[0];
|
|
float dy = m_touch.y[1] - m_touch.y[0];
|
|
float newDist = SDL_sqrtf(dx * dx + dy * dy);
|
|
|
|
if (m_touch.initialPinchDist > 0.001f) {
|
|
float pinchDelta = m_touch.initialPinchDist - newDist;
|
|
|
|
if (!p_active) {
|
|
float totalDelta = m_touch.gesturePinchDist - newDist;
|
|
if (totalDelta > PINCH_TRANSITION_THRESHOLD) {
|
|
m_wantsAutoEnable = true;
|
|
m_touch.gesturePinchDist = newDist;
|
|
}
|
|
m_touch.initialPinchDist = newDist;
|
|
break;
|
|
}
|
|
|
|
if (p_orbit.GetOrbitDistance() <= OrbitCamera::SWITCH_TO_FIRST_PERSON_DISTANCE) {
|
|
float totalDelta = newDist - m_touch.gesturePinchDist;
|
|
if (totalDelta > PINCH_TRANSITION_THRESHOLD) {
|
|
m_wantsAutoDisable = true;
|
|
m_touch.initialPinchDist = newDist;
|
|
m_touch.gesturePinchDist = newDist;
|
|
break;
|
|
}
|
|
}
|
|
|
|
p_orbit.AdjustDistance(pinchDelta * 6.0f);
|
|
p_orbit.ClampDistance();
|
|
m_touch.initialPinchDist = newDist;
|
|
}
|
|
|
|
float moveX = m_touch.x[idx] - oldX;
|
|
float moveY = m_touch.y[idx] - oldY;
|
|
p_orbit.AdjustYaw(-moveX * 2.0f);
|
|
p_orbit.AdjustPitch(moveY * 2.0f);
|
|
p_orbit.ClampPitch();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SDL_EVENT_FINGER_UP:
|
|
case SDL_EVENT_FINGER_CANCELED: {
|
|
TryReleaseFinger(p_event->tfinger.fingerID);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|