From 73a227cefd99e682891fe0498c0e8dca1465c7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Mon, 15 Dec 2014 20:58:54 -0800 Subject: [PATCH] SDL2: Added gamepad support. --- examples/13-stencil/stencil.cpp | 2 +- examples/14-shadowvolumes/shadowvolumes.cpp | 2 +- examples/16-shadowmaps/shadowmaps.cpp | 2 +- examples/21-deferred/deferred.cpp | 2 +- examples/common/entry/entry.cpp | 76 +++++--- examples/common/entry/entry.h | 49 ++++- examples/common/entry/entry_p.h | 51 ++++-- examples/common/entry/entry_sdl.cpp | 190 +++++++++++++++++++- examples/common/entry/input.cpp | 40 +++++ examples/common/entry/input.h | 7 +- 10 files changed, 372 insertions(+), 49 deletions(-) diff --git a/examples/13-stencil/stencil.cpp b/examples/13-stencil/stencil.cpp index 6b634e76..f9a2ab96 100644 --- a/examples/13-stencil/stencil.cpp +++ b/examples/13-stencil/stencil.cpp @@ -1111,7 +1111,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); // Update camera. - cameraUpdate(deltaTime, mouseState.m_mx, mouseState.m_my, !!mouseState.m_buttons[entry::MouseButton::Right]); + cameraUpdate(deltaTime, mouseState); cameraGetViewMtx(viewState.m_view); static float lightTimeAccumulator = 0.0f; diff --git a/examples/14-shadowvolumes/shadowvolumes.cpp b/examples/14-shadowvolumes/shadowvolumes.cpp index b704b110..ff9356aa 100644 --- a/examples/14-shadowvolumes/shadowvolumes.cpp +++ b/examples/14-shadowvolumes/shadowvolumes.cpp @@ -2197,7 +2197,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) s_uniforms.m_time = time; // Update camera. - cameraUpdate(deltaTime, mouseState.m_mx, mouseState.m_my, !!mouseState.m_buttons[entry::MouseButton::Right]); + cameraUpdate(deltaTime, mouseState); // Set view and projection matrix for view 0. const bgfx::HMD* hmd = bgfx::getHMD(); diff --git a/examples/16-shadowmaps/shadowmaps.cpp b/examples/16-shadowmaps/shadowmaps.cpp index e720e53d..893f4edc 100644 --- a/examples/16-shadowmaps/shadowmaps.cpp +++ b/examples/16-shadowmaps/shadowmaps.cpp @@ -2239,7 +2239,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs); // Update camera. - cameraUpdate(deltaTime, mouseState.m_mx, mouseState.m_my, !!mouseState.m_buttons[entry::MouseButton::Right]); + cameraUpdate(deltaTime, mouseState); // Update view mtx. cameraGetViewMtx(viewState.m_view); diff --git a/examples/21-deferred/deferred.cpp b/examples/21-deferred/deferred.cpp index b9604039..497a19dc 100644 --- a/examples/21-deferred/deferred.cpp +++ b/examples/21-deferred/deferred.cpp @@ -439,7 +439,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) imguiEndFrame(); // Update camera. - cameraUpdate(deltaTime, mouseState.m_mx, mouseState.m_my, !!mouseState.m_buttons[entry::MouseButton::Right]); + cameraUpdate(deltaTime, mouseState); cameraGetViewMtx(view); // Setup views diff --git a/examples/common/entry/entry.cpp b/examples/common/entry/entry.cpp index e11d6aac..d587f574 100644 --- a/examples/common/entry/entry.cpp +++ b/examples/common/entry/entry.cpp @@ -17,7 +17,6 @@ extern "C" int _main_(int _argc, char** _argv); namespace entry { - const uint16_t WindowHandle::invalidHandle = UINT16_MAX; static uint32_t s_debug = BGFX_DEBUG_NONE; static uint32_t s_reset = BGFX_RESET_NONE; static bool s_exit = false; @@ -112,16 +111,17 @@ namespace entry static const InputBinding s_bindings[] = { - { entry::Key::KeyQ, entry::Modifier::LeftCtrl, 1, cmd, "exit" }, - { entry::Key::F1, entry::Modifier::None, 1, cmd, "graphics stats" }, - { entry::Key::F1, entry::Modifier::LeftShift, 1, cmd, "graphics stats 0\ngraphics text 0" }, - { entry::Key::F3, entry::Modifier::None, 1, cmd, "graphics wireframe" }, - { entry::Key::F4, entry::Modifier::None, 1, cmd, "graphics hmd" }, - { entry::Key::F4, entry::Modifier::LeftShift, 1, cmd, "graphics hmdrecenter" }, - { entry::Key::F4, entry::Modifier::LeftCtrl, 1, cmd, "graphics hmddbg" }, - { entry::Key::F7, entry::Modifier::None, 1, cmd, "graphics vsync" }, - { entry::Key::F8, entry::Modifier::None, 1, cmd, "graphics msaa" }, - { entry::Key::Print, entry::Modifier::None, 1, cmd, "graphics screenshot" }, + { entry::Key::KeyQ, entry::Modifier::LeftCtrl, 1, cmd, "exit" }, + { entry::Key::F1, entry::Modifier::None, 1, cmd, "graphics stats" }, + { entry::Key::GamepadStart, entry::Modifier::None, 1, cmd, "graphics stats" }, + { entry::Key::F1, entry::Modifier::LeftShift, 1, cmd, "graphics stats 0\ngraphics text 0" }, + { entry::Key::F3, entry::Modifier::None, 1, cmd, "graphics wireframe" }, + { entry::Key::F4, entry::Modifier::None, 1, cmd, "graphics hmd" }, + { entry::Key::F4, entry::Modifier::LeftShift, 1, cmd, "graphics hmdrecenter" }, + { entry::Key::F4, entry::Modifier::LeftCtrl, 1, cmd, "graphics hmddbg" }, + { entry::Key::F7, entry::Modifier::None, 1, cmd, "graphics vsync" }, + { entry::Key::F8, entry::Modifier::None, 1, cmd, "graphics msaa" }, + { entry::Key::Print, entry::Modifier::None, 1, cmd, "graphics screenshot" }, INPUT_BINDING_END }; @@ -157,6 +157,16 @@ namespace entry return result; } + static const char* s_gamepadAxisName[GamepadAxis::Count] = + { + "LeftX", + "LeftY", + "LeftZ", + "RightX", + "RightY", + "RightZ", + }; + bool processEvents(uint32_t& _width, uint32_t& _height, uint32_t& _debug, uint32_t& _reset, MouseState* _mouse) { s_debug = _debug; @@ -176,6 +186,20 @@ namespace entry { switch (ev->m_type) { + case Event::Axis: + { + const AxisEvent* axis = static_cast(ev); + inputSetGamepadAxis(axis->m_gamepad, axis->m_axis, axis->m_value); + } + break; + + case Event::Char: + { + const CharEvent* chev = static_cast(ev); + inputChar(chev->m_len, chev->m_char); + } + break; + case Event::Exit: return true; @@ -219,13 +243,6 @@ namespace entry } break; - case Event::Char: - { - const CharEvent* chev = static_cast(ev); - inputChar(chev->m_len, chev->m_char); - } - break; - case Event::Size: { const SizeEvent* size = static_cast(ev); @@ -302,6 +319,21 @@ namespace entry switch (ev->m_type) { + case Event::Axis: + { + const AxisEvent* axis = static_cast(ev); + inputSetGamepadAxis(axis->m_gamepad, axis->m_axis, axis->m_value); + } + break; + + case Event::Char: + { + const CharEvent* chev = static_cast(ev); + win.m_handle = chev->m_handle; + inputChar(chev->m_len, chev->m_char); + } + break; + case Event::Exit: return true; @@ -344,14 +376,6 @@ namespace entry } break; - case Event::Char: - { - const CharEvent* chev = static_cast(ev); - win.m_handle = chev->m_handle; - inputChar(chev->m_len, chev->m_char); - } - break; - case Event::Size: { const SizeEvent* size = static_cast(ev); diff --git a/examples/common/entry/entry.h b/examples/common/entry/entry.h index f2fc2b32..fc156274 100644 --- a/examples/common/entry/entry.h +++ b/examples/common/entry/entry.h @@ -20,8 +20,11 @@ extern "C" int _main_(int _argc, char** _argv); namespace entry { - struct WindowHandle { uint16_t idx; static const uint16_t invalidHandle; }; - inline bool isValid(WindowHandle _handle) { return WindowHandle::invalidHandle != _handle.idx; } + struct WindowHandle { uint16_t idx; }; + inline bool isValid(WindowHandle _handle) { return UINT16_MAX != _handle.idx; } + + struct GamepadHandle { uint16_t idx; }; + inline bool isValid(GamepadHandle _handle) { return UINT16_MAX != _handle.idx; } struct MouseButton { @@ -36,6 +39,21 @@ namespace entry }; }; + struct GamepadAxis + { + enum Enum + { + LeftX, + LeftY, + LeftZ, + RightX, + RightY, + RightZ, + + Count + }; + }; + struct Modifier { enum Enum @@ -132,7 +150,22 @@ namespace entry KeyY, KeyZ, - Count, + GamepadA, + GamepadB, + GamepadX, + GamepadY, + GamepadThumbL, + GamepadThumbR, + GamepadShoulderL, + GamepadShoulderR, + GamepadUp, + GamepadDown, + GamepadLeft, + GamepadRight, + GamepadBack, + GamepadStart, + + Count }; }; @@ -155,6 +188,16 @@ namespace entry uint8_t m_buttons[entry::MouseButton::Count]; }; + struct GamepadState + { + GamepadState() + { + memset(m_axis, 0, sizeof(m_axis) ); + } + + int32_t m_axis[entry::GamepadAxis::Count]; + }; + bool processEvents(uint32_t& _width, uint32_t& _height, uint32_t& _debug, uint32_t& _reset, MouseState* _mouse = NULL); bx::FileReaderI* getFileReader(); diff --git a/examples/common/entry/entry_p.h b/examples/common/entry/entry_p.h index 1b42df0c..cd1e426b 100644 --- a/examples/common/entry/entry_p.h +++ b/examples/common/entry/entry_p.h @@ -26,6 +26,10 @@ # define ENTRY_CONFIG_MAX_WINDOWS 8 #endif // ENTRY_CONFIG_MAX_WINDOWS +#ifndef ENTRY_CONFIG_MAX_GAMEPADS +# define ENTRY_CONFIG_MAX_GAMEPADS 4 +#endif // ENTRY_CONFIG_MAX_GAMEPADS + #if !defined(ENTRY_DEFAULT_WIDTH) && !defined(ENTRY_DEFAULT_HEIGHT) # define ENTRY_DEFAULT_WIDTH 1280 # define ENTRY_DEFAULT_HEIGHT 720 @@ -44,9 +48,10 @@ namespace entry { enum Enum { + Axis, + Char, Exit, Key, - Char, Mouse, Size, Window, @@ -68,13 +73,13 @@ namespace entry WindowHandle m_handle; }; - struct KeyEvent : public Event + struct AxisEvent : public Event { - ENTRY_IMPLEMENT_EVENT(KeyEvent, Event::Key); + ENTRY_IMPLEMENT_EVENT(AxisEvent, Event::Axis); - Key::Enum m_key; - uint8_t m_modifiers; - bool m_down; + GamepadAxis::Enum m_axis; + int32_t m_value; + GamepadHandle m_gamepad; }; struct CharEvent : public Event @@ -97,6 +102,15 @@ namespace entry bool m_move; }; + struct KeyEvent : public Event + { + ENTRY_IMPLEMENT_EVENT(KeyEvent, Event::Key); + + Key::Enum m_key; + uint8_t m_modifiers; + bool m_down; + }; + struct SizeEvent : public Event { ENTRY_IMPLEMENT_EVENT(SizeEvent, Event::Size); @@ -119,6 +133,23 @@ namespace entry class EventQueue { public: + void postAxisEvent(WindowHandle _handle, GamepadHandle _gamepad, GamepadAxis::Enum _axis, int32_t _value) + { + AxisEvent* ev = new AxisEvent(_handle); + ev->m_gamepad = _gamepad; + ev->m_axis = _axis; + ev->m_value = _value; + m_queue.push(ev); + } + + void postCharEvent(WindowHandle _handle, uint8_t _len, const uint8_t _char[4]) + { + CharEvent* ev = new CharEvent(_handle); + ev->m_len = _len; + memcpy(ev->m_char, _char, 4); + m_queue.push(ev); + } + void postExitEvent() { Event* ev = new Event(Event::Exit); @@ -134,14 +165,6 @@ namespace entry m_queue.push(ev); } - void postCharEvent(WindowHandle _handle, uint8_t _len, const uint8_t _char[4]) - { - CharEvent* ev = new CharEvent(_handle); - ev->m_len = _len; - memcpy(ev->m_char, _char, 4); - m_queue.push(ev); - } - void postMouseEvent(WindowHandle _handle, int32_t _mx, int32_t _my, int32_t _mz) { MouseEvent* ev = new MouseEvent(_handle); diff --git a/examples/common/entry/entry_sdl.cpp b/examples/common/entry/entry_sdl.cpp index f399b7d0..1464a298 100644 --- a/examples/common/entry/entry_sdl.cpp +++ b/examples/common/entry/entry_sdl.cpp @@ -49,6 +49,80 @@ namespace entry return (Key::Enum)s_translateKey[_sdl&0xff]; } + static uint8_t s_translateGamepad[256]; + + static void initTranslateGamepad(uint8_t _sdl, Key::Enum _button) + { + s_translateGamepad[_sdl] = _button; + } + + static Key::Enum translateGamepad(uint8_t _sdl) + { + return Key::Enum(s_translateGamepad[_sdl]); + } + + static uint8_t s_translateGamepadAxis[256]; + + static void initTranslateGamepadAxis(uint8_t _sdl, GamepadAxis::Enum _axis) + { + s_translateGamepadAxis[_sdl] = uint8_t(_axis); + } + + static GamepadAxis::Enum translateGamepadAxis(uint8_t _sdl) + { + return GamepadAxis::Enum(s_translateGamepadAxis[_sdl]); + } + + struct GamepadSDL + { + GamepadSDL() + : m_controller(NULL) + , m_jid(INT32_MAX) + { + memset(m_value, 0, sizeof(m_value) ); + + // Deadzone values from xinput.h + m_deadzone[GamepadAxis::LeftX ] = + m_deadzone[GamepadAxis::LeftY ] = 7849; + m_deadzone[GamepadAxis::RightX] = + m_deadzone[GamepadAxis::RightY] = 8689; + m_deadzone[GamepadAxis::LeftZ ] = + m_deadzone[GamepadAxis::RightZ] = 30; + } + + void create(int32_t _jid) + { + m_controller = SDL_GameControllerOpen(_jid); + SDL_Joystick* joystick = SDL_GameControllerGetJoystick(m_controller); + m_jid = SDL_JoystickInstanceID(joystick); + } + + void destroy() + { + SDL_GameControllerClose(m_controller); + m_controller = NULL; + m_jid = INT32_MAX; + } + + bool filter(GamepadAxis::Enum _axis, int32_t* _value) + { + const int32_t old = m_value[_axis]; + const int32_t deadzone = m_deadzone[_axis]; + int32_t value = *_value; + value = value > deadzone || value < -deadzone ? value : 0; + m_value[_axis] = value; + *_value = value; + return old != value; + } + + int32_t m_value[GamepadAxis::Count]; + int32_t m_deadzone[GamepadAxis::Count]; + + SDL_GameController* m_controller; +// SDL_Haptic* m_haptic; + SDL_JoystickID m_jid; + }; + struct MainThreadEntry { int m_argc; @@ -213,6 +287,30 @@ namespace entry initTranslateKey(SDL_SCANCODE_X, Key::KeyX); initTranslateKey(SDL_SCANCODE_Y, Key::KeyY); initTranslateKey(SDL_SCANCODE_Z, Key::KeyZ); + + memset(s_translateGamepad, uint8_t(Key::Count), sizeof(s_translateGamepad) ); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_A, Key::GamepadA); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_B, Key::GamepadB); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_X, Key::GamepadX); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_Y, Key::GamepadY); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_LEFTSTICK, Key::GamepadThumbL); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_RIGHTSTICK, Key::GamepadThumbR); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, Key::GamepadShoulderL); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, Key::GamepadShoulderR); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_UP, Key::GamepadUp); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_DOWN, Key::GamepadDown); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_LEFT, Key::GamepadLeft); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_RIGHT, Key::GamepadRight); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_BACK, Key::GamepadBack); + initTranslateGamepad(SDL_CONTROLLER_BUTTON_START, Key::GamepadStart); + + memset(s_translateGamepadAxis, uint8_t(GamepadAxis::Count), sizeof(s_translateGamepadAxis) ); + initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_LEFTX, GamepadAxis::LeftX); + initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_LEFTY, GamepadAxis::LeftY); + initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT, GamepadAxis::LeftZ); + initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_RIGHTX, GamepadAxis::RightX); + initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_RIGHTY, GamepadAxis::RightY); + initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, GamepadAxis::RightZ); } void run(int _argc, char** _argv) @@ -220,7 +318,10 @@ namespace entry m_mte.m_argc = _argc; m_mte.m_argv = _argv; - SDL_Init(SDL_INIT_VIDEO); + SDL_Init(0 + | SDL_INIT_VIDEO + | SDL_INIT_GAMECONTROLLER + ); m_windowAlloc.alloc(); m_window[0] = SDL_CreateWindow("bgfx" @@ -248,6 +349,12 @@ namespace entry WindowHandle defaultWindow = { 0 }; setWindowSize(defaultWindow, m_width, m_height, true); + SDL_RWops* rw = SDL_RWFromFile("gamecontrollerdb.txt", "rb"); + if (NULL != rw) + { + SDL_GameControllerAddMappingsFromRW(rw, 1); + } + bool exit = false; SDL_Event event; while (!exit) @@ -355,6 +462,68 @@ namespace entry } break; + case SDL_CONTROLLERAXISMOTION: + { + const SDL_ControllerAxisEvent& aev = event.caxis; + GamepadHandle handle = findGamepad(aev.which); + if (isValid(handle) ) + { + GamepadAxis::Enum axis = translateGamepadAxis(aev.axis); + int32_t value = aev.value; + if (m_gamepad[handle.idx].filter(axis, &value) ) + { + m_eventQueue.postAxisEvent(defaultWindow, handle, axis, value); + } + } + } + break; + + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + { + const SDL_ControllerButtonEvent& bev = event.cbutton; + GamepadHandle handle = findGamepad(bev.which); + if (isValid(handle) ) + { + Key::Enum key = translateGamepad(bev.button); + if (Key::Count != key) + { + m_eventQueue.postKeyEvent(defaultWindow, key, 0, event.type == SDL_CONTROLLERBUTTONDOWN); + } + } + } + break; + + case SDL_CONTROLLERDEVICEADDED: + { + const SDL_ControllerDeviceEvent& cev = event.cdevice; + + GamepadHandle handle = { m_gamepadAlloc.alloc() }; + if (isValid(handle) ) + { + m_gamepad[handle.idx].create(cev.which); + } + } + break; + + case SDL_CONTROLLERDEVICEREMAPPED: + { + + } + break; + + case SDL_CONTROLLERDEVICEREMOVED: + { + const SDL_ControllerDeviceEvent& cev = event.cdevice; + GamepadHandle handle = findGamepad(cev.which); + if (isValid(handle) ) + { + m_gamepad[handle.idx].destroy(); + m_gamepadAlloc.free(handle.idx); + } + } + break; + default: { const SDL_UserEvent& uev = event.user; @@ -515,6 +684,22 @@ namespace entry } } + GamepadHandle findGamepad(SDL_JoystickID _jid) + { + for (uint32_t ii = 0, num = m_gamepadAlloc.getNumHandles(); ii < num; ++ii) + { + uint16_t idx = m_gamepadAlloc.getHandleAt(ii); + if (_jid == m_gamepad[idx].m_jid) + { + GamepadHandle handle = { idx }; + return handle; + } + } + + GamepadHandle invalid = { UINT16_MAX }; + return invalid; + } + MainThreadEntry m_mte; bx::Thread m_thread; @@ -525,6 +710,9 @@ namespace entry SDL_Window* m_window[ENTRY_CONFIG_MAX_WINDOWS]; uint32_t m_flags[ENTRY_CONFIG_MAX_WINDOWS]; + bx::HandleAllocT m_gamepadAlloc; + GamepadSDL m_gamepad[ENTRY_CONFIG_MAX_GAMEPADS]; + uint32_t m_width; uint32_t m_height; float m_aspectRatio; diff --git a/examples/common/entry/input.cpp b/examples/common/entry/input.cpp index 543100be..5f156e80 100644 --- a/examples/common/entry/input.cpp +++ b/examples/common/entry/input.cpp @@ -139,6 +139,31 @@ struct Keyboard uint8_t m_char[256]; }; +struct Gamepad +{ + Gamepad() + { + reset(); + } + + void reset() + { + memset(m_axis, 0, sizeof(m_axis) ); + } + + void setAxis(entry::GamepadAxis::Enum _axis, int32_t _value) + { + m_axis[_axis] = _value; + } + + int32_t getAxis(entry::GamepadAxis::Enum _axis) + { + return m_axis[_axis]; + } + + int32_t m_axis[entry::GamepadAxis::Count]; +}; + struct Input { Input() @@ -211,12 +236,17 @@ struct Input { m_mouse.reset(); m_keyboard.reset(); + for (uint32_t ii = 0; ii < BX_COUNTOF(m_gamepad); ++ii) + { + m_gamepad[ii].reset(); + } } typedef stl::unordered_map InputBindingMap; InputBindingMap m_inputBindingsMap; Mouse m_mouse; Keyboard m_keyboard; + Gamepad m_gamepad[ENTRY_CONFIG_MAX_GAMEPADS]; }; static Input s_input; @@ -301,3 +331,13 @@ void inputSetMouseLock(bool _lock) } } } + +void inputSetGamepadAxis(entry::GamepadHandle _handle, entry::GamepadAxis::Enum _axis, int32_t _value) +{ + s_input.m_gamepad[_handle.idx].setAxis(_axis, _value); +} + +int32_t inputGetGamepadAxis(entry::GamepadHandle _handle, entry::GamepadAxis::Enum _axis) +{ + return s_input.m_gamepad[_handle.idx].getAxis(_axis); +} diff --git a/examples/common/entry/input.h b/examples/common/entry/input.h index a48a182d..8e9ec1f8 100644 --- a/examples/common/entry/input.h +++ b/examples/common/entry/input.h @@ -6,7 +6,6 @@ #ifndef INPUT_H_HEADER_GUARD #define INPUT_H_HEADER_GUARD -#include #include "entry.h" typedef void (*InputBindingFn)(const void* _userData); @@ -61,4 +60,10 @@ void inputGetMouse(float _mouse[3]); /// bool inputIsMouseLocked(); +/// +void inputSetGamepadAxis(entry::GamepadHandle _handle, entry::GamepadAxis::Enum _axis, int32_t _value); + +/// +int32_t inputGetGamepadAxis(entry::GamepadHandle _handle, entry::GamepadAxis::Enum _axis); + #endif // INPUT_H_HEADER_GUARD