455 lines
13 KiB
C++
455 lines
13 KiB
C++
// IAEngine: 2D Game Engine by IA
|
|
// Copyright (C) 2025 IASoft (PVT) LTD (oss@iasoft.dev)
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#include <IAEngine/Engine.hpp>
|
|
#include <InputManager.hpp>
|
|
|
|
namespace ia::iae
|
|
{
|
|
struct OnScreenGamepadState
|
|
{
|
|
Vec2 KnobPosition;
|
|
Vec2 ThumbstickPosition{};
|
|
FLOAT32 ThumbstickRadius{};
|
|
} g_onScreenGamepadState{};
|
|
|
|
EXTERN SDL_Window *g_windowHandle;
|
|
|
|
BOOL InputManager::s_keys[256];
|
|
BOOL InputManager::s_prevKeys[256];
|
|
Vec2 InputManager::s_pointerPosition{};
|
|
BOOL InputManager::s_pointerState{};
|
|
BOOL InputManager::s_pointerPrevState{};
|
|
InputManager::KeyboardGamePadMapping InputManager::s_keyboardGamePadMapping{};
|
|
|
|
BOOL InputManager::s_buttonA{};
|
|
BOOL InputManager::s_buttonB{};
|
|
BOOL InputManager::s_buttonC{};
|
|
BOOL InputManager::s_buttonD{};
|
|
INT16 InputManager::s_verticalAxis{};
|
|
INT16 InputManager::s_horizontalAxis{};
|
|
|
|
BOOL InputManager::s_onScreenGamePadEnabled{};
|
|
BOOL InputManager::s_keyboardGamePadEnabled{};
|
|
|
|
VOID InputManager::Initialize()
|
|
{
|
|
memset(s_keys, 0, sizeof(s_keys));
|
|
memset(s_prevKeys, 0, sizeof(s_prevKeys));
|
|
|
|
g_onScreenGamepadState.KnobPosition = {};
|
|
g_onScreenGamepadState.ThumbstickRadius = 64.0f;
|
|
}
|
|
|
|
VOID InputManager::Terminate()
|
|
{
|
|
}
|
|
|
|
VOID InputManager::OnSDLEvent(IN SDL_Event *event)
|
|
{
|
|
s_pointerPrevState = s_pointerState;
|
|
memcpy(s_prevKeys, s_keys, sizeof(s_prevKeys));
|
|
switch (event->type)
|
|
{
|
|
case SDL_EVENT_KEY_DOWN:
|
|
s_keys[event->key.scancode] = true;
|
|
break;
|
|
|
|
case SDL_EVENT_KEY_UP:
|
|
s_keys[event->key.scancode] = false;
|
|
break;
|
|
|
|
case SDL_EVENT_FINGER_MOTION:
|
|
case SDL_EVENT_MOUSE_MOTION:
|
|
if((event->motion.x >= 1) && (event->motion.y >= 1))
|
|
s_pointerPosition = {event->motion.x, event->motion.y};
|
|
break;
|
|
|
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
|
case SDL_EVENT_FINGER_DOWN:
|
|
s_pointerState = true;
|
|
break;
|
|
|
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
|
case SDL_EVENT_FINGER_UP:
|
|
s_pointerState = false;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
VOID InputManager::SwitchModeToText()
|
|
{
|
|
SDL_StartTextInput(g_windowHandle);
|
|
}
|
|
|
|
VOID InputManager::SwitchModeToAction()
|
|
{
|
|
SDL_StopTextInput(g_windowHandle);
|
|
}
|
|
|
|
BOOL InputManager::IsPointerDown()
|
|
{
|
|
return s_pointerState;
|
|
}
|
|
|
|
Vec2 InputManager::GetPointerPosition()
|
|
{
|
|
return s_pointerPosition;
|
|
}
|
|
|
|
BOOL InputManager::IsKeyDown(IN InputKey key)
|
|
{
|
|
return s_keys[(UINT8) key];
|
|
}
|
|
|
|
BOOL InputManager::WasKeyPressed(IN InputKey key)
|
|
{
|
|
return !s_prevKeys[(UINT8) key] && s_keys[(UINT8) key];
|
|
}
|
|
|
|
BOOL InputManager::WasKeyReleased(IN InputKey key)
|
|
{
|
|
return s_prevKeys[(UINT8) key] && !s_keys[(UINT8) key];
|
|
}
|
|
|
|
VOID InputManager::SetupOnScreenGamePad()
|
|
{
|
|
// Initialize
|
|
|
|
// Disable till manually enabled by calling Input_EnableOnScreenGamePad
|
|
s_onScreenGamePadEnabled = false;
|
|
}
|
|
|
|
VOID InputManager::SetupKeyboardGamePad(IN CONST KeyboardGamePadMapping &mapping)
|
|
{
|
|
s_keyboardGamePadEnabled = true;
|
|
s_keyboardGamePadMapping = mapping;
|
|
}
|
|
|
|
BOOL InputManager::GetButtonA()
|
|
{
|
|
return s_buttonA;
|
|
}
|
|
|
|
BOOL InputManager::GetButtonB()
|
|
{
|
|
return s_buttonB;
|
|
}
|
|
|
|
BOOL InputManager::GetButtonC()
|
|
{
|
|
return s_buttonC;
|
|
}
|
|
|
|
BOOL InputManager::GetButtonD()
|
|
{
|
|
return s_buttonD;
|
|
}
|
|
|
|
INT16 InputManager::GetVerticalAxis()
|
|
{
|
|
return s_verticalAxis;
|
|
}
|
|
|
|
INT16 InputManager::GetHorizontalAxis()
|
|
{
|
|
return s_horizontalAxis;
|
|
}
|
|
|
|
IVec2 InputManager::GetDirectionalInput()
|
|
{
|
|
return IVec2{GetHorizontalAxis(), GetVerticalAxis()};
|
|
}
|
|
|
|
VOID InputManager::SetButtonA(IN BOOL value)
|
|
{
|
|
s_buttonA = value;
|
|
}
|
|
|
|
VOID InputManager::SetButtonB(IN BOOL value)
|
|
{
|
|
s_buttonB = value;
|
|
}
|
|
|
|
VOID InputManager::SetButtonC(IN BOOL value)
|
|
{
|
|
s_buttonC = value;
|
|
}
|
|
|
|
VOID InputManager::SetButtonD(IN BOOL value)
|
|
{
|
|
s_buttonD = value;
|
|
}
|
|
|
|
VOID InputManager::SetVerticalAxis(IN INT16 value)
|
|
{
|
|
s_verticalAxis = value;
|
|
}
|
|
|
|
VOID InputManager::SetHorizontalAxis(IN INT16 value)
|
|
{
|
|
s_horizontalAxis = value;
|
|
}
|
|
|
|
VOID InputManager::Draw()
|
|
{
|
|
if (s_onScreenGamePadEnabled)
|
|
{
|
|
g_onScreenGamepadState.ThumbstickPosition =
|
|
Engine::CalculatePercentPosition({92.5f, 90.0f}) - Vec2{0, 32.0f};
|
|
Engine::SetRenderState_CameraRelative(false);
|
|
Engine::SetRenderState_ColorOverlay({0x80, 0x80, 0x80, 0x80});
|
|
Engine::DrawCircle(g_onScreenGamepadState.ThumbstickPosition, 0, g_onScreenGamepadState.ThumbstickRadius, 0,
|
|
0xFF, 0);
|
|
Engine::SetRenderState_ColorOverlay({0x20, 0x20, 0x20, 0xB0});
|
|
Engine::DrawCircle(g_onScreenGamepadState.ThumbstickPosition + g_onScreenGamepadState.KnobPosition, 0, 16,
|
|
0, 0xFF, 0);
|
|
}
|
|
}
|
|
|
|
VOID InputManager::Update()
|
|
{
|
|
s_buttonA = false;
|
|
s_buttonB = false;
|
|
s_buttonC = false;
|
|
s_buttonD = false;
|
|
s_verticalAxis = 0;
|
|
s_horizontalAxis = 0;
|
|
|
|
if (s_onScreenGamePadEnabled)
|
|
{
|
|
STATIC CONSTEXPR INT16 DIRECTION_MAP_VERTICAL[] = {0, 1, 1, 1, 0, -1, -1, -1};
|
|
STATIC CONSTEXPR INT16 DIRECTION_MAP_HORIZONTAL[] = {1, 1, 0, -1, -1, -1, 0, 1};
|
|
|
|
const auto ps = g_onScreenGamepadState;
|
|
g_onScreenGamepadState.ThumbstickPosition *= Engine::GetSceneScalingFactor();
|
|
g_onScreenGamepadState.ThumbstickRadius *= Engine::GetSceneScalingFactor().x;
|
|
|
|
if (Engine::Input_IsPointerDown(g_onScreenGamepadState.ThumbstickPosition,
|
|
g_onScreenGamepadState.ThumbstickRadius))
|
|
g_onScreenGamepadState.KnobPosition =
|
|
Engine::Input_GetPointerPosition() - g_onScreenGamepadState.ThumbstickPosition;
|
|
else
|
|
g_onScreenGamepadState.KnobPosition = {};
|
|
|
|
auto verticalAxis = abs(g_onScreenGamepadState.KnobPosition.y);
|
|
auto horizontalAxis = abs(g_onScreenGamepadState.KnobPosition.x);
|
|
verticalAxis = (verticalAxis > FLOAT32_EPSILON) ? g_onScreenGamepadState.KnobPosition.y / ((FLOAT32)g_onScreenGamepadState.ThumbstickRadius) : 0;
|
|
horizontalAxis = (horizontalAxis > FLOAT32_EPSILON) ? g_onScreenGamepadState.KnobPosition.x / ((FLOAT32)g_onScreenGamepadState.ThumbstickRadius) : 0;
|
|
|
|
if ((abs(verticalAxis) > FLOAT32_EPSILON) || (abs(horizontalAxis) > FLOAT32_EPSILON))
|
|
{
|
|
auto angle = glm::degrees(atan2(verticalAxis, horizontalAxis));
|
|
if (angle < 0)
|
|
angle += 360;
|
|
const auto t = INT32((angle + 22.5) / 45) % 8;
|
|
s_verticalAxis = DIRECTION_MAP_VERTICAL[t];
|
|
s_horizontalAxis = DIRECTION_MAP_HORIZONTAL[t];
|
|
}
|
|
|
|
g_onScreenGamepadState.ThumbstickPosition = ps.ThumbstickPosition;
|
|
g_onScreenGamepadState.ThumbstickRadius = ps.ThumbstickRadius;
|
|
}
|
|
|
|
if (s_keyboardGamePadEnabled)
|
|
{
|
|
s_buttonA |= IsKeyDown(s_keyboardGamePadMapping.ButtonA);
|
|
s_buttonB |= IsKeyDown(s_keyboardGamePadMapping.ButtonB);
|
|
s_buttonC |= IsKeyDown(s_keyboardGamePadMapping.ButtonC);
|
|
s_buttonD |= IsKeyDown(s_keyboardGamePadMapping.ButtonD);
|
|
s_verticalAxis +=
|
|
IsKeyDown(s_keyboardGamePadMapping.AxisDown) + IsKeyDown(s_keyboardGamePadMapping.AxisUp) * -1;
|
|
s_horizontalAxis +=
|
|
IsKeyDown(s_keyboardGamePadMapping.AxisRight) + IsKeyDown(s_keyboardGamePadMapping.AxisLeft) * -1;
|
|
}
|
|
}
|
|
|
|
BOOL InputManager::IsPointerDown(IN CONST Vec2 &start, IN CONST Vec2 &end)
|
|
{
|
|
if (!s_pointerState)
|
|
return false;
|
|
return (s_pointerPosition.x >= start.x) && (s_pointerPosition.x <= end.x) && (s_pointerPosition.y >= start.y) &&
|
|
(s_pointerPosition.y <= end.y);
|
|
}
|
|
|
|
BOOL InputManager::IsPointerDown(IN CONST Vec2 ¢er, IN FLOAT32 radius)
|
|
{
|
|
if (!s_pointerState)
|
|
return false;
|
|
const auto dx = s_pointerPosition.x - center.x;
|
|
const auto dy = s_pointerPosition.y - center.y;
|
|
const auto d = (dx * dx) + (dy * dy);
|
|
return d <= (radius * radius);
|
|
}
|
|
|
|
BOOL InputManager::DidPointerClick(IN CONST Vec2 &start, IN CONST Vec2 &end)
|
|
{
|
|
return IsPointerDown(start, end) && !s_pointerPrevState;
|
|
}
|
|
|
|
BOOL InputManager::DidPointerClick(IN CONST Vec2 ¢er, IN FLOAT32 radius)
|
|
{
|
|
return IsPointerDown(center, radius) && !s_pointerPrevState;
|
|
}
|
|
} // namespace ia::iae
|
|
|
|
namespace ia::iae
|
|
{
|
|
VOID Engine::Input_SwitchModeToText()
|
|
{
|
|
InputManager::SwitchModeToText();
|
|
}
|
|
|
|
VOID Engine::Input_SwitchModeToAction()
|
|
{
|
|
InputManager::SwitchModeToAction();
|
|
}
|
|
|
|
Vec2 Engine::Input_GetPointerPosition()
|
|
{
|
|
return InputManager::GetPointerPosition();
|
|
}
|
|
|
|
BOOL Engine::Input_IsPointerDown()
|
|
{
|
|
return InputManager::IsPointerDown();
|
|
}
|
|
|
|
BOOL Engine::Input_IsPointerDown(IN CONST Vec2 &start, IN CONST Vec2 &end)
|
|
{
|
|
return InputManager::IsPointerDown(start, end);
|
|
}
|
|
|
|
BOOL Engine::Input_DidPointerClick(IN CONST Vec2 &start, IN CONST Vec2 &end)
|
|
{
|
|
return InputManager::DidPointerClick(start, end);
|
|
}
|
|
|
|
BOOL Engine::Input_IsKeyDown(IN InputKey key)
|
|
{
|
|
return InputManager::IsKeyDown(key);
|
|
}
|
|
|
|
BOOL Engine::Input_WasKeyPressed(IN InputKey key)
|
|
{
|
|
return InputManager::WasKeyPressed(key);
|
|
}
|
|
|
|
BOOL Engine::Input_WasKeyReleased(IN InputKey key)
|
|
{
|
|
return InputManager::WasKeyReleased(key);
|
|
}
|
|
|
|
VOID Engine::Input_SetupOnScreenGamePad()
|
|
{
|
|
InputManager::SetupOnScreenGamePad();
|
|
}
|
|
|
|
VOID Engine::Input_SetupKeyboardGamePad(IN InputKey axisLeft, IN InputKey axisRight, IN InputKey axisDown,
|
|
IN InputKey axisUp, IN InputKey buttonA, IN InputKey buttonB,
|
|
IN InputKey buttonC, IN InputKey buttonD)
|
|
{
|
|
InputManager::SetupKeyboardGamePad({axisLeft, axisRight, axisDown, axisUp, buttonA, buttonB, buttonC, buttonD});
|
|
}
|
|
|
|
BOOL Engine::Input_GetButtonA()
|
|
{
|
|
return InputManager::GetButtonA();
|
|
}
|
|
|
|
BOOL Engine::Input_GetButtonB()
|
|
{
|
|
return InputManager::GetButtonB();
|
|
}
|
|
|
|
BOOL Engine::Input_GetButtonC()
|
|
{
|
|
return InputManager::GetButtonC();
|
|
}
|
|
|
|
BOOL Engine::Input_GetButtonD()
|
|
{
|
|
return InputManager::GetButtonD();
|
|
}
|
|
|
|
INT16 Engine::Input_GetVerticalAxis()
|
|
{
|
|
return InputManager::GetVerticalAxis();
|
|
}
|
|
|
|
INT16 Engine::Input_GetHorizontalAxis()
|
|
{
|
|
return InputManager::GetHorizontalAxis();
|
|
}
|
|
|
|
IVec2 Engine::Input_GetDirectionalInput()
|
|
{
|
|
return InputManager::GetDirectionalInput();
|
|
}
|
|
|
|
VOID Engine::Input_SetButtonA(IN BOOL value)
|
|
{
|
|
InputManager::SetButtonA(value);
|
|
}
|
|
|
|
VOID Engine::Input_SetButtonB(IN BOOL value)
|
|
{
|
|
InputManager::SetButtonB(value);
|
|
}
|
|
|
|
VOID Engine::Input_SetButtonC(IN BOOL value)
|
|
{
|
|
InputManager::SetButtonC(value);
|
|
}
|
|
|
|
VOID Engine::Input_SetButtonD(IN BOOL value)
|
|
{
|
|
InputManager::SetButtonD(value);
|
|
}
|
|
|
|
VOID Engine::Input_SetVerticalAxis(IN INT16 value)
|
|
{
|
|
InputManager::SetVerticalAxis(value);
|
|
}
|
|
|
|
VOID Engine::Input_SetHorizontalAxis(IN INT16 value)
|
|
{
|
|
InputManager::SetHorizontalAxis(value);
|
|
}
|
|
|
|
BOOL Engine::Input_DidPointerClick(IN CONST Vec2 ¢er, IN FLOAT32 radius)
|
|
{
|
|
return InputManager::DidPointerClick(center, radius);
|
|
}
|
|
|
|
BOOL Engine::Input_IsPointerDown(IN CONST Vec2 ¢er, IN FLOAT32 radius)
|
|
{
|
|
return InputManager::IsPointerDown(center, radius);
|
|
}
|
|
|
|
VOID Engine::Input_EnableOnScreenGamePad()
|
|
{
|
|
InputManager::s_onScreenGamePadEnabled = true;
|
|
}
|
|
|
|
VOID Engine::Input_DisableOnScreenGamePad()
|
|
{
|
|
InputManager::s_onScreenGamePadEnabled = false;
|
|
}
|
|
} // namespace ia::iae
|