Browse Source

SDL2: Added gamepad support.

Branimir Karadžić 11 years ago
parent
commit
73a227cefd

+ 1 - 1
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);
 		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);
 
 
 		// Update camera.
 		// Update camera.
-		cameraUpdate(deltaTime, mouseState.m_mx, mouseState.m_my, !!mouseState.m_buttons[entry::MouseButton::Right]);
+		cameraUpdate(deltaTime, mouseState);
 		cameraGetViewMtx(viewState.m_view);
 		cameraGetViewMtx(viewState.m_view);
 
 
 		static float lightTimeAccumulator = 0.0f;
 		static float lightTimeAccumulator = 0.0f;

+ 1 - 1
examples/14-shadowvolumes/shadowvolumes.cpp

@@ -2197,7 +2197,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 		s_uniforms.m_time = time;
 		s_uniforms.m_time = time;
 
 
 		// Update camera.
 		// 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.
 		// Set view and projection matrix for view 0.
 		const bgfx::HMD* hmd = bgfx::getHMD();
 		const bgfx::HMD* hmd = bgfx::getHMD();

+ 1 - 1
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);
 		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);
 
 
 		// Update camera.
 		// Update camera.
-		cameraUpdate(deltaTime, mouseState.m_mx, mouseState.m_my, !!mouseState.m_buttons[entry::MouseButton::Right]);
+		cameraUpdate(deltaTime, mouseState);
 
 
 		// Update view mtx.
 		// Update view mtx.
 		cameraGetViewMtx(viewState.m_view);
 		cameraGetViewMtx(viewState.m_view);

+ 1 - 1
examples/21-deferred/deferred.cpp

@@ -439,7 +439,7 @@ int _main_(int /*_argc*/, char** /*_argv*/)
 			imguiEndFrame();
 			imguiEndFrame();
 
 
 			// Update camera.
 			// Update camera.
-			cameraUpdate(deltaTime, mouseState.m_mx, mouseState.m_my, !!mouseState.m_buttons[entry::MouseButton::Right]);
+			cameraUpdate(deltaTime, mouseState);
 			cameraGetViewMtx(view);
 			cameraGetViewMtx(view);
 
 
 			// Setup views
 			// Setup views

+ 50 - 26
examples/common/entry/entry.cpp

@@ -17,7 +17,6 @@ extern "C" int _main_(int _argc, char** _argv);
 
 
 namespace entry
 namespace entry
 {
 {
-	const uint16_t WindowHandle::invalidHandle = UINT16_MAX;
 	static uint32_t s_debug = BGFX_DEBUG_NONE;
 	static uint32_t s_debug = BGFX_DEBUG_NONE;
 	static uint32_t s_reset = BGFX_RESET_NONE;
 	static uint32_t s_reset = BGFX_RESET_NONE;
 	static bool s_exit = false;
 	static bool s_exit = false;
@@ -112,16 +111,17 @@ namespace entry
 
 
 	static const InputBinding s_bindings[] = 
 	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
 		INPUT_BINDING_END
 	};
 	};
@@ -157,6 +157,16 @@ namespace entry
 		return result;
 		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)
 	bool processEvents(uint32_t& _width, uint32_t& _height, uint32_t& _debug, uint32_t& _reset, MouseState* _mouse)
 	{
 	{
 		s_debug = _debug;
 		s_debug = _debug;
@@ -176,6 +186,20 @@ namespace entry
 			{
 			{
 				switch (ev->m_type)
 				switch (ev->m_type)
 				{
 				{
+				case Event::Axis:
+					{
+						const AxisEvent* axis = static_cast<const AxisEvent*>(ev);
+						inputSetGamepadAxis(axis->m_gamepad, axis->m_axis, axis->m_value);
+					}
+					break;
+
+				case Event::Char:
+					{
+						const CharEvent* chev = static_cast<const CharEvent*>(ev);
+						inputChar(chev->m_len, chev->m_char);
+					}
+					break;
+
 				case Event::Exit:
 				case Event::Exit:
 					return true;
 					return true;
 
 
@@ -219,13 +243,6 @@ namespace entry
 					}
 					}
 					break;
 					break;
 
 
-				case Event::Char:
-					{
-						const CharEvent* chev = static_cast<const CharEvent*>(ev);
-						inputChar(chev->m_len, chev->m_char);
-					}
-					break;
-
 				case Event::Size:
 				case Event::Size:
 					{
 					{
 						const SizeEvent* size = static_cast<const SizeEvent*>(ev);
 						const SizeEvent* size = static_cast<const SizeEvent*>(ev);
@@ -302,6 +319,21 @@ namespace entry
 
 
 				switch (ev->m_type)
 				switch (ev->m_type)
 				{
 				{
+				case Event::Axis:
+					{
+						const AxisEvent* axis = static_cast<const AxisEvent*>(ev);
+						inputSetGamepadAxis(axis->m_gamepad, axis->m_axis, axis->m_value);
+					}
+					break;
+
+				case Event::Char:
+					{
+						const CharEvent* chev = static_cast<const CharEvent*>(ev);
+						win.m_handle = chev->m_handle;
+						inputChar(chev->m_len, chev->m_char);
+					}
+					break;
+
 				case Event::Exit:
 				case Event::Exit:
 					return true;
 					return true;
 
 
@@ -344,14 +376,6 @@ namespace entry
 					}
 					}
 					break;
 					break;
 
 
-				case Event::Char:
-					{
-						const CharEvent* chev = static_cast<const CharEvent*>(ev);
-						win.m_handle = chev->m_handle;
-						inputChar(chev->m_len, chev->m_char);
-					}
-					break;
-
 				case Event::Size:
 				case Event::Size:
 					{
 					{
 						const SizeEvent* size = static_cast<const SizeEvent*>(ev);
 						const SizeEvent* size = static_cast<const SizeEvent*>(ev);

+ 46 - 3
examples/common/entry/entry.h

@@ -20,8 +20,11 @@ extern "C" int _main_(int _argc, char** _argv);
 
 
 namespace entry
 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
 	struct MouseButton
 	{
 	{
@@ -36,6 +39,21 @@ namespace entry
 		};
 		};
 	};
 	};
 
 
+	struct GamepadAxis
+	{
+		enum Enum
+		{
+			LeftX,
+			LeftY,
+			LeftZ,
+			RightX,
+			RightY,
+			RightZ,
+
+			Count
+		};
+	};
+
 	struct Modifier
 	struct Modifier
 	{
 	{
 		enum Enum
 		enum Enum
@@ -132,7 +150,22 @@ namespace entry
 			KeyY,
 			KeyY,
 			KeyZ,
 			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];
 		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);
 	bool processEvents(uint32_t& _width, uint32_t& _height, uint32_t& _debug, uint32_t& _reset, MouseState* _mouse = NULL);
 
 
 	bx::FileReaderI* getFileReader();
 	bx::FileReaderI* getFileReader();

+ 37 - 14
examples/common/entry/entry_p.h

@@ -26,6 +26,10 @@
 #	define ENTRY_CONFIG_MAX_WINDOWS 8
 #	define ENTRY_CONFIG_MAX_WINDOWS 8
 #endif // ENTRY_CONFIG_MAX_WINDOWS
 #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)
 #if !defined(ENTRY_DEFAULT_WIDTH) && !defined(ENTRY_DEFAULT_HEIGHT)
 #	define ENTRY_DEFAULT_WIDTH  1280
 #	define ENTRY_DEFAULT_WIDTH  1280
 #	define ENTRY_DEFAULT_HEIGHT 720
 #	define ENTRY_DEFAULT_HEIGHT 720
@@ -44,9 +48,10 @@ namespace entry
 	{
 	{
 		enum Enum
 		enum Enum
 		{
 		{
+			Axis,
+			Char,
 			Exit,
 			Exit,
 			Key,
 			Key,
-			Char,
 			Mouse,
 			Mouse,
 			Size,
 			Size,
 			Window,
 			Window,
@@ -68,13 +73,13 @@ namespace entry
 		WindowHandle m_handle;
 		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
 	struct CharEvent : public Event
@@ -97,6 +102,15 @@ namespace entry
 		bool m_move;
 		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
 	struct SizeEvent : public Event
 	{
 	{
 		ENTRY_IMPLEMENT_EVENT(SizeEvent, Event::Size);
 		ENTRY_IMPLEMENT_EVENT(SizeEvent, Event::Size);
@@ -119,6 +133,23 @@ namespace entry
 	class EventQueue
 	class EventQueue
 	{
 	{
 	public:
 	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()
 		void postExitEvent()
 		{
 		{
 			Event* ev = new Event(Event::Exit);
 			Event* ev = new Event(Event::Exit);
@@ -134,14 +165,6 @@ namespace entry
 			m_queue.push(ev);
 			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)
 		void postMouseEvent(WindowHandle _handle, int32_t _mx, int32_t _my, int32_t _mz)
 		{
 		{
 			MouseEvent* ev = new MouseEvent(_handle);
 			MouseEvent* ev = new MouseEvent(_handle);

+ 189 - 1
examples/common/entry/entry_sdl.cpp

@@ -49,6 +49,80 @@ namespace entry
 		return (Key::Enum)s_translateKey[_sdl&0xff];
 		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
 	struct MainThreadEntry
 	{
 	{
 		int m_argc;
 		int m_argc;
@@ -213,6 +287,30 @@ namespace entry
 			initTranslateKey(SDL_SCANCODE_X,            Key::KeyX);
 			initTranslateKey(SDL_SCANCODE_X,            Key::KeyX);
 			initTranslateKey(SDL_SCANCODE_Y,            Key::KeyY);
 			initTranslateKey(SDL_SCANCODE_Y,            Key::KeyY);
 			initTranslateKey(SDL_SCANCODE_Z,            Key::KeyZ);
 			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)
 		void run(int _argc, char** _argv)
@@ -220,7 +318,10 @@ namespace entry
 			m_mte.m_argc = _argc;
 			m_mte.m_argc = _argc;
 			m_mte.m_argv = _argv;
 			m_mte.m_argv = _argv;
 
 
-			SDL_Init(SDL_INIT_VIDEO);
+			SDL_Init(0
+				| SDL_INIT_VIDEO
+				| SDL_INIT_GAMECONTROLLER
+				);
 
 
 			m_windowAlloc.alloc();
 			m_windowAlloc.alloc();
 			m_window[0] = SDL_CreateWindow("bgfx"
 			m_window[0] = SDL_CreateWindow("bgfx"
@@ -248,6 +349,12 @@ namespace entry
 			WindowHandle defaultWindow = { 0 };
 			WindowHandle defaultWindow = { 0 };
 			setWindowSize(defaultWindow, m_width, m_height, true);
 			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;
 			bool exit = false;
 			SDL_Event event;
 			SDL_Event event;
 			while (!exit)
 			while (!exit)
@@ -355,6 +462,68 @@ namespace entry
 						}
 						}
 						break;
 						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:
 					default:
 						{
 						{
 							const SDL_UserEvent& uev = event.user;
 							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;
 		MainThreadEntry m_mte;
 		bx::Thread m_thread;
 		bx::Thread m_thread;
 
 
@@ -525,6 +710,9 @@ namespace entry
 		SDL_Window* m_window[ENTRY_CONFIG_MAX_WINDOWS];
 		SDL_Window* m_window[ENTRY_CONFIG_MAX_WINDOWS];
 		uint32_t m_flags[ENTRY_CONFIG_MAX_WINDOWS];
 		uint32_t m_flags[ENTRY_CONFIG_MAX_WINDOWS];
 
 
+		bx::HandleAllocT<ENTRY_CONFIG_MAX_GAMEPADS> m_gamepadAlloc;
+		GamepadSDL m_gamepad[ENTRY_CONFIG_MAX_GAMEPADS];
+
 		uint32_t m_width;
 		uint32_t m_width;
 		uint32_t m_height;
 		uint32_t m_height;
 		float m_aspectRatio;
 		float m_aspectRatio;

+ 40 - 0
examples/common/entry/input.cpp

@@ -139,6 +139,31 @@ struct Keyboard
 	uint8_t m_char[256];
 	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
 struct Input
 {
 {
 	Input()
 	Input()
@@ -211,12 +236,17 @@ struct Input
 	{
 	{
 		m_mouse.reset();
 		m_mouse.reset();
 		m_keyboard.reset();
 		m_keyboard.reset();
+		for (uint32_t ii = 0; ii < BX_COUNTOF(m_gamepad); ++ii)
+		{
+			m_gamepad[ii].reset();
+		}
 	}
 	}
 
 
 	typedef stl::unordered_map<const char*, const InputBinding*> InputBindingMap;
 	typedef stl::unordered_map<const char*, const InputBinding*> InputBindingMap;
 	InputBindingMap m_inputBindingsMap;
 	InputBindingMap m_inputBindingsMap;
 	Mouse m_mouse;
 	Mouse m_mouse;
 	Keyboard m_keyboard;
 	Keyboard m_keyboard;
+	Gamepad m_gamepad[ENTRY_CONFIG_MAX_GAMEPADS];
 };
 };
 
 
 static Input s_input;
 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);
+}

+ 6 - 1
examples/common/entry/input.h

@@ -6,7 +6,6 @@
 #ifndef INPUT_H_HEADER_GUARD
 #ifndef INPUT_H_HEADER_GUARD
 #define INPUT_H_HEADER_GUARD
 #define INPUT_H_HEADER_GUARD
 
 
-#include <stdint.h>
 #include "entry.h"
 #include "entry.h"
 
 
 typedef void (*InputBindingFn)(const void* _userData);
 typedef void (*InputBindingFn)(const void* _userData);
@@ -61,4 +60,10 @@ void inputGetMouse(float _mouse[3]);
 ///
 ///
 bool inputIsMouseLocked();
 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
 #endif // INPUT_H_HEADER_GUARD