1 /*
2  * Copyright 2011-2019 Branimir Karadzic. All rights reserved.
3  * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
4  */
5 
6 #include "entry_p.h"
7 
8 #if ENTRY_CONFIG_USE_SDL
9 
10 #if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
11 #	if ENTRY_CONFIG_USE_WAYLAND
12 #		include <wayland-egl.h>
13 #	endif
14 #elif BX_PLATFORM_WINDOWS
15 #	define SDL_MAIN_HANDLED
16 #endif
17 
18 #include <bx/os.h>
19 
20 #include <SDL2/SDL.h>
21 
22 BX_PRAGMA_DIAGNOSTIC_PUSH()
23 BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG("-Wextern-c-compat")
24 #include <SDL2/SDL_syswm.h>
25 BX_PRAGMA_DIAGNOSTIC_POP()
26 
27 #include <bgfx/platform.h>
28 #if defined(None) // X11 defines this...
29 #	undef None
30 #endif // defined(None)
31 
32 #include <bx/mutex.h>
33 #include <bx/thread.h>
34 #include <bx/handlealloc.h>
35 #include <bx/readerwriter.h>
36 #include <tinystl/allocator.h>
37 #include <tinystl/string.h>
38 
39 namespace entry
40 {
41 	///
sdlNativeWindowHandle(SDL_Window * _window)42 	static void* sdlNativeWindowHandle(SDL_Window* _window)
43 	{
44 		SDL_SysWMinfo wmi;
45 		SDL_VERSION(&wmi.version);
46 		if (!SDL_GetWindowWMInfo(_window, &wmi) )
47 		{
48 			return NULL;
49 		}
50 
51 #	if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
52 #		if ENTRY_CONFIG_USE_WAYLAND
53 		wl_egl_window *win_impl = (wl_egl_window*)SDL_GetWindowData(_window, "wl_egl_window");
54 		if(!win_impl)
55 		{
56 			int width, height;
57 			SDL_GetWindowSize(_window, &width, &height);
58 			struct wl_surface* surface = wmi.info.wl.surface;
59 			if(!surface)
60 				return nullptr;
61 			win_impl = wl_egl_window_create(surface, width, height);
62 			SDL_SetWindowData(_window, "wl_egl_window", win_impl);
63 		}
64 		return (void*)(uintptr_t)win_impl;
65 #		else
66 		return (void*)wmi.info.x11.window;
67 #		endif
68 #	elif BX_PLATFORM_OSX
69 		return wmi.info.cocoa.window;
70 #	elif BX_PLATFORM_WINDOWS
71 		return wmi.info.win.window;
72 #	elif BX_PLATFORM_STEAMLINK
73 		return wmi.info.vivante.window;
74 #	endif // BX_PLATFORM_
75 	}
76 
sdlSetWindow(SDL_Window * _window)77 	inline bool sdlSetWindow(SDL_Window* _window)
78 	{
79 		SDL_SysWMinfo wmi;
80 		SDL_VERSION(&wmi.version);
81 		if (!SDL_GetWindowWMInfo(_window, &wmi) )
82 		{
83 			return false;
84 		}
85 
86 		bgfx::PlatformData pd;
87 #	if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
88 #		if ENTRY_CONFIG_USE_WAYLAND
89 		pd.ndt          = wmi.info.wl.display;
90 #		else
91 		pd.ndt          = wmi.info.x11.display;
92 #		endif
93 #	elif BX_PLATFORM_OSX
94 		pd.ndt          = NULL;
95 #	elif BX_PLATFORM_WINDOWS
96 		pd.ndt          = NULL;
97 #	elif BX_PLATFORM_STEAMLINK
98 		pd.ndt          = wmi.info.vivante.display;
99 #	endif // BX_PLATFORM_
100 		pd.nwh          = sdlNativeWindowHandle(_window);
101 
102 		pd.context      = NULL;
103 		pd.backBuffer   = NULL;
104 		pd.backBufferDS = NULL;
105 		bgfx::setPlatformData(pd);
106 
107 		return true;
108 	}
109 
sdlDestroyWindow(SDL_Window * _window)110 	static void sdlDestroyWindow(SDL_Window* _window)
111 	{
112 		if(!_window)
113 			return;
114 #	if BX_PLATFORM_LINUX || BX_PLATFORM_BSD
115 #		if ENTRY_CONFIG_USE_WAYLAND
116 		wl_egl_window *win_impl = (wl_egl_window*)SDL_GetWindowData(_window, "wl_egl_window");
117 		if(win_impl)
118 		{
119 			SDL_SetWindowData(_window, "wl_egl_window", nullptr);
120 			wl_egl_window_destroy(win_impl);
121 		}
122 #		endif
123 #	endif
124 		SDL_DestroyWindow(_window);
125 	}
126 
translateKeyModifiers(uint16_t _sdl)127 	static uint8_t translateKeyModifiers(uint16_t _sdl)
128 	{
129 		uint8_t modifiers = 0;
130 		modifiers |= _sdl & KMOD_LALT   ? Modifier::LeftAlt    : 0;
131 		modifiers |= _sdl & KMOD_RALT   ? Modifier::RightAlt   : 0;
132 		modifiers |= _sdl & KMOD_LCTRL  ? Modifier::LeftCtrl   : 0;
133 		modifiers |= _sdl & KMOD_RCTRL  ? Modifier::RightCtrl  : 0;
134 		modifiers |= _sdl & KMOD_LSHIFT ? Modifier::LeftShift  : 0;
135 		modifiers |= _sdl & KMOD_RSHIFT ? Modifier::RightShift : 0;
136 		modifiers |= _sdl & KMOD_LGUI   ? Modifier::LeftMeta   : 0;
137 		modifiers |= _sdl & KMOD_RGUI   ? Modifier::RightMeta  : 0;
138 		return modifiers;
139 	}
140 
translateKeyModifierPress(uint16_t _key)141 	static uint8_t translateKeyModifierPress(uint16_t _key)
142 	{
143 		uint8_t modifier;
144 		switch (_key)
145 		{
146 			case SDL_SCANCODE_LALT:   { modifier = Modifier::LeftAlt;    } break;
147 			case SDL_SCANCODE_RALT:   { modifier = Modifier::RightAlt;   } break;
148 			case SDL_SCANCODE_LCTRL:  { modifier = Modifier::LeftCtrl;   } break;
149 			case SDL_SCANCODE_RCTRL:  { modifier = Modifier::RightCtrl;  } break;
150 			case SDL_SCANCODE_LSHIFT: { modifier = Modifier::LeftShift;  } break;
151 			case SDL_SCANCODE_RSHIFT: { modifier = Modifier::RightShift; } break;
152 			case SDL_SCANCODE_LGUI:   { modifier = Modifier::LeftMeta;   } break;
153 			case SDL_SCANCODE_RGUI:   { modifier = Modifier::RightMeta;  } break;
154 			default:                  { modifier = 0;                    } break;
155 		}
156 
157 		return modifier;
158 	}
159 
160 	static uint8_t s_translateKey[256];
161 
initTranslateKey(uint16_t _sdl,Key::Enum _key)162 	static void initTranslateKey(uint16_t _sdl, Key::Enum _key)
163 	{
164 		BX_CHECK(_sdl < BX_COUNTOF(s_translateKey), "Out of bounds %d.", _sdl);
165 		s_translateKey[_sdl&0xff] = (uint8_t)_key;
166 	}
167 
translateKey(SDL_Scancode _sdl)168 	static Key::Enum translateKey(SDL_Scancode _sdl)
169 	{
170 		return (Key::Enum)s_translateKey[_sdl&0xff];
171 	}
172 
173 	static uint8_t s_translateGamepad[256];
174 
initTranslateGamepad(uint8_t _sdl,Key::Enum _button)175 	static void initTranslateGamepad(uint8_t _sdl, Key::Enum _button)
176 	{
177 		s_translateGamepad[_sdl] = _button;
178 	}
179 
translateGamepad(uint8_t _sdl)180 	static Key::Enum translateGamepad(uint8_t _sdl)
181 	{
182 		return Key::Enum(s_translateGamepad[_sdl]);
183 	}
184 
185 	static uint8_t s_translateGamepadAxis[256];
186 
initTranslateGamepadAxis(uint8_t _sdl,GamepadAxis::Enum _axis)187 	static void initTranslateGamepadAxis(uint8_t _sdl, GamepadAxis::Enum _axis)
188 	{
189 		s_translateGamepadAxis[_sdl] = uint8_t(_axis);
190 	}
191 
translateGamepadAxis(uint8_t _sdl)192 	static GamepadAxis::Enum translateGamepadAxis(uint8_t _sdl)
193 	{
194 		return GamepadAxis::Enum(s_translateGamepadAxis[_sdl]);
195 	}
196 
197 	struct AxisDpadRemap
198 	{
199 		Key::Enum first;
200 		Key::Enum second;
201 	};
202 
203 	static AxisDpadRemap s_axisDpad[] =
204 	{
205 		{ Key::GamepadLeft, Key::GamepadRight },
206 		{ Key::GamepadUp,   Key::GamepadDown  },
207 		{ Key::None,        Key::None         },
208 		{ Key::GamepadLeft, Key::GamepadRight },
209 		{ Key::GamepadUp,   Key::GamepadDown  },
210 		{ Key::None,        Key::None         },
211 	};
212 
213 	struct GamepadSDL
214 	{
GamepadSDLentry::GamepadSDL215 		GamepadSDL()
216 			: m_controller(NULL)
217 			, m_jid(INT32_MAX)
218 		{
219 			bx::memSet(m_value, 0, sizeof(m_value) );
220 
221 			// Deadzone values from xinput.h
222 			m_deadzone[GamepadAxis::LeftX ] =
223 			m_deadzone[GamepadAxis::LeftY ] = 7849;
224 			m_deadzone[GamepadAxis::RightX] =
225 			m_deadzone[GamepadAxis::RightY] = 8689;
226 			m_deadzone[GamepadAxis::LeftZ ] =
227 			m_deadzone[GamepadAxis::RightZ] = 30;
228 		}
229 
createentry::GamepadSDL230 		void create(const SDL_JoyDeviceEvent& _jev)
231 		{
232 			m_joystick = SDL_JoystickOpen(_jev.which);
233 			SDL_Joystick* joystick = m_joystick;
234 			m_jid = SDL_JoystickInstanceID(joystick);
235 		}
236 
createentry::GamepadSDL237 		void create(const SDL_ControllerDeviceEvent& _cev)
238 		{
239 			m_controller = SDL_GameControllerOpen(_cev.which);
240 			SDL_Joystick* joystick = SDL_GameControllerGetJoystick(m_controller);
241 			m_jid = SDL_JoystickInstanceID(joystick);
242 		}
243 
updateentry::GamepadSDL244 		void update(EventQueue& _eventQueue, WindowHandle _handle, GamepadHandle _gamepad, GamepadAxis::Enum _axis, int32_t _value)
245 		{
246 			if (filter(_axis, &_value) )
247 			{
248 				_eventQueue.postAxisEvent(_handle, _gamepad, _axis, _value);
249 
250 				if (Key::None != s_axisDpad[_axis].first)
251 				{
252 					if (_value == 0)
253 					{
254 						_eventQueue.postKeyEvent(_handle, s_axisDpad[_axis].first,  0, false);
255 						_eventQueue.postKeyEvent(_handle, s_axisDpad[_axis].second, 0, false);
256 					}
257 					else
258 					{
259 						_eventQueue.postKeyEvent(_handle
260 								, 0 > _value ? s_axisDpad[_axis].first : s_axisDpad[_axis].second
261 								, 0
262 								, true
263 								);
264 					}
265 				}
266 			}
267 		}
268 
destroyentry::GamepadSDL269 		void destroy()
270 		{
271 			if (NULL != m_controller)
272 			{
273 				SDL_GameControllerClose(m_controller);
274 				m_controller = NULL;
275 			}
276 
277 			if (NULL != m_joystick)
278 			{
279 				SDL_JoystickClose(m_joystick);
280 				m_joystick = NULL;
281 			}
282 
283 			m_jid = INT32_MAX;
284 		}
285 
filterentry::GamepadSDL286 		bool filter(GamepadAxis::Enum _axis, int32_t* _value)
287 		{
288 			const int32_t old = m_value[_axis];
289 			const int32_t deadzone = m_deadzone[_axis];
290 			int32_t value = *_value;
291 			value = value > deadzone || value < -deadzone ? value : 0;
292 			m_value[_axis] = value;
293 			*_value = value;
294 			return old != value;
295 		}
296 
297 		int32_t m_value[GamepadAxis::Count];
298 		int32_t m_deadzone[GamepadAxis::Count];
299 
300 		SDL_Joystick*       m_joystick;
301 		SDL_GameController* m_controller;
302 //		SDL_Haptic*         m_haptic;
303 		SDL_JoystickID      m_jid;
304 	};
305 
306 	struct MainThreadEntry
307 	{
308 		int m_argc;
309 		char** m_argv;
310 
311 		static int32_t threadFunc(bx::Thread* _thread, void* _userData);
312 	};
313 
314 	struct Msg
315 	{
Msgentry::Msg316 		Msg()
317 			: m_x(0)
318 			, m_y(0)
319 			, m_width(0)
320 			, m_height(0)
321 			, m_flags(0)
322 			, m_flagsEnabled(false)
323 		{
324 		}
325 
326 		int32_t  m_x;
327 		int32_t  m_y;
328 		uint32_t m_width;
329 		uint32_t m_height;
330 		uint32_t m_flags;
331 		tinystl::string m_title;
332 		bool m_flagsEnabled;
333 	};
334 
335 	static uint32_t s_userEventStart;
336 
337 	enum SDL_USER_WINDOW
338 	{
339 		SDL_USER_WINDOW_CREATE,
340 		SDL_USER_WINDOW_DESTROY,
341 		SDL_USER_WINDOW_SET_TITLE,
342 		SDL_USER_WINDOW_SET_FLAGS,
343 		SDL_USER_WINDOW_SET_POS,
344 		SDL_USER_WINDOW_SET_SIZE,
345 		SDL_USER_WINDOW_TOGGLE_FRAME,
346 		SDL_USER_WINDOW_TOGGLE_FULL_SCREEN,
347 		SDL_USER_WINDOW_MOUSE_LOCK,
348 	};
349 
sdlPostEvent(SDL_USER_WINDOW _type,WindowHandle _handle,Msg * _msg=NULL,uint32_t _code=0)350 	static void sdlPostEvent(SDL_USER_WINDOW _type, WindowHandle _handle, Msg* _msg = NULL, uint32_t _code = 0)
351 	{
352 		SDL_Event event;
353 		SDL_UserEvent& uev = event.user;
354 		uev.type = s_userEventStart + _type;
355 
356 		union { void* p; WindowHandle h; } cast;
357 		cast.h = _handle;
358 		uev.data1 = cast.p;
359 
360 		uev.data2 = _msg;
361 		uev.code = _code;
362 		SDL_PushEvent(&event);
363 	}
364 
getWindowHandle(const SDL_UserEvent & _uev)365 	static WindowHandle getWindowHandle(const SDL_UserEvent& _uev)
366 	{
367 		union { void* p; WindowHandle h; } cast;
368 		cast.p = _uev.data1;
369 		return cast.h;
370 	}
371 
372 	struct Context
373 	{
Contextentry::Context374 		Context()
375 			: m_width(ENTRY_DEFAULT_WIDTH)
376 			, m_height(ENTRY_DEFAULT_HEIGHT)
377 			, m_aspectRatio(16.0f/9.0f)
378 			, m_mx(0)
379 			, m_my(0)
380 			, m_mz(0)
381 			, m_mouseLock(false)
382 			, m_fullscreen(false)
383 		{
384 			bx::memSet(s_translateKey, 0, sizeof(s_translateKey) );
385 			initTranslateKey(SDL_SCANCODE_ESCAPE,       Key::Esc);
386 			initTranslateKey(SDL_SCANCODE_RETURN,       Key::Return);
387 			initTranslateKey(SDL_SCANCODE_TAB,          Key::Tab);
388 			initTranslateKey(SDL_SCANCODE_BACKSPACE,    Key::Backspace);
389 			initTranslateKey(SDL_SCANCODE_SPACE,        Key::Space);
390 			initTranslateKey(SDL_SCANCODE_UP,           Key::Up);
391 			initTranslateKey(SDL_SCANCODE_DOWN,         Key::Down);
392 			initTranslateKey(SDL_SCANCODE_LEFT,         Key::Left);
393 			initTranslateKey(SDL_SCANCODE_RIGHT,        Key::Right);
394 			initTranslateKey(SDL_SCANCODE_PAGEUP,       Key::PageUp);
395 			initTranslateKey(SDL_SCANCODE_PAGEDOWN,     Key::PageDown);
396 			initTranslateKey(SDL_SCANCODE_HOME,         Key::Home);
397 			initTranslateKey(SDL_SCANCODE_END,          Key::End);
398 			initTranslateKey(SDL_SCANCODE_PRINTSCREEN,  Key::Print);
399 			initTranslateKey(SDL_SCANCODE_KP_PLUS,      Key::Plus);
400 			initTranslateKey(SDL_SCANCODE_EQUALS,       Key::Plus);
401 			initTranslateKey(SDL_SCANCODE_KP_MINUS,     Key::Minus);
402 			initTranslateKey(SDL_SCANCODE_MINUS,        Key::Minus);
403 			initTranslateKey(SDL_SCANCODE_GRAVE,        Key::Tilde);
404 			initTranslateKey(SDL_SCANCODE_KP_COMMA,     Key::Comma);
405 			initTranslateKey(SDL_SCANCODE_COMMA,        Key::Comma);
406 			initTranslateKey(SDL_SCANCODE_KP_PERIOD,    Key::Period);
407 			initTranslateKey(SDL_SCANCODE_PERIOD,       Key::Period);
408 			initTranslateKey(SDL_SCANCODE_SLASH,        Key::Slash);
409 			initTranslateKey(SDL_SCANCODE_F1,           Key::F1);
410 			initTranslateKey(SDL_SCANCODE_F2,           Key::F2);
411 			initTranslateKey(SDL_SCANCODE_F3,           Key::F3);
412 			initTranslateKey(SDL_SCANCODE_F4,           Key::F4);
413 			initTranslateKey(SDL_SCANCODE_F5,           Key::F5);
414 			initTranslateKey(SDL_SCANCODE_F6,           Key::F6);
415 			initTranslateKey(SDL_SCANCODE_F7,           Key::F7);
416 			initTranslateKey(SDL_SCANCODE_F8,           Key::F8);
417 			initTranslateKey(SDL_SCANCODE_F9,           Key::F9);
418 			initTranslateKey(SDL_SCANCODE_F10,          Key::F10);
419 			initTranslateKey(SDL_SCANCODE_F11,          Key::F11);
420 			initTranslateKey(SDL_SCANCODE_F12,          Key::F12);
421 			initTranslateKey(SDL_SCANCODE_KP_0,         Key::NumPad0);
422 			initTranslateKey(SDL_SCANCODE_KP_1,         Key::NumPad1);
423 			initTranslateKey(SDL_SCANCODE_KP_2,         Key::NumPad2);
424 			initTranslateKey(SDL_SCANCODE_KP_3,         Key::NumPad3);
425 			initTranslateKey(SDL_SCANCODE_KP_4,         Key::NumPad4);
426 			initTranslateKey(SDL_SCANCODE_KP_5,         Key::NumPad5);
427 			initTranslateKey(SDL_SCANCODE_KP_6,         Key::NumPad6);
428 			initTranslateKey(SDL_SCANCODE_KP_7,         Key::NumPad7);
429 			initTranslateKey(SDL_SCANCODE_KP_8,         Key::NumPad8);
430 			initTranslateKey(SDL_SCANCODE_KP_9,         Key::NumPad9);
431 			initTranslateKey(SDL_SCANCODE_0,            Key::Key0);
432 			initTranslateKey(SDL_SCANCODE_1,            Key::Key1);
433 			initTranslateKey(SDL_SCANCODE_2,            Key::Key2);
434 			initTranslateKey(SDL_SCANCODE_3,            Key::Key3);
435 			initTranslateKey(SDL_SCANCODE_4,            Key::Key4);
436 			initTranslateKey(SDL_SCANCODE_5,            Key::Key5);
437 			initTranslateKey(SDL_SCANCODE_6,            Key::Key6);
438 			initTranslateKey(SDL_SCANCODE_7,            Key::Key7);
439 			initTranslateKey(SDL_SCANCODE_8,            Key::Key8);
440 			initTranslateKey(SDL_SCANCODE_9,            Key::Key9);
441 			initTranslateKey(SDL_SCANCODE_A,            Key::KeyA);
442 			initTranslateKey(SDL_SCANCODE_B,            Key::KeyB);
443 			initTranslateKey(SDL_SCANCODE_C,            Key::KeyC);
444 			initTranslateKey(SDL_SCANCODE_D,            Key::KeyD);
445 			initTranslateKey(SDL_SCANCODE_E,            Key::KeyE);
446 			initTranslateKey(SDL_SCANCODE_F,            Key::KeyF);
447 			initTranslateKey(SDL_SCANCODE_G,            Key::KeyG);
448 			initTranslateKey(SDL_SCANCODE_H,            Key::KeyH);
449 			initTranslateKey(SDL_SCANCODE_I,            Key::KeyI);
450 			initTranslateKey(SDL_SCANCODE_J,            Key::KeyJ);
451 			initTranslateKey(SDL_SCANCODE_K,            Key::KeyK);
452 			initTranslateKey(SDL_SCANCODE_L,            Key::KeyL);
453 			initTranslateKey(SDL_SCANCODE_M,            Key::KeyM);
454 			initTranslateKey(SDL_SCANCODE_N,            Key::KeyN);
455 			initTranslateKey(SDL_SCANCODE_O,            Key::KeyO);
456 			initTranslateKey(SDL_SCANCODE_P,            Key::KeyP);
457 			initTranslateKey(SDL_SCANCODE_Q,            Key::KeyQ);
458 			initTranslateKey(SDL_SCANCODE_R,            Key::KeyR);
459 			initTranslateKey(SDL_SCANCODE_S,            Key::KeyS);
460 			initTranslateKey(SDL_SCANCODE_T,            Key::KeyT);
461 			initTranslateKey(SDL_SCANCODE_U,            Key::KeyU);
462 			initTranslateKey(SDL_SCANCODE_V,            Key::KeyV);
463 			initTranslateKey(SDL_SCANCODE_W,            Key::KeyW);
464 			initTranslateKey(SDL_SCANCODE_X,            Key::KeyX);
465 			initTranslateKey(SDL_SCANCODE_Y,            Key::KeyY);
466 			initTranslateKey(SDL_SCANCODE_Z,            Key::KeyZ);
467 
468 			bx::memSet(s_translateGamepad, uint8_t(Key::Count), sizeof(s_translateGamepad) );
469 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_A,             Key::GamepadA);
470 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_B,             Key::GamepadB);
471 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_X,             Key::GamepadX);
472 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_Y,             Key::GamepadY);
473 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_LEFTSTICK,     Key::GamepadThumbL);
474 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_RIGHTSTICK,    Key::GamepadThumbR);
475 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_LEFTSHOULDER,  Key::GamepadShoulderL);
476 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, Key::GamepadShoulderR);
477 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_UP,       Key::GamepadUp);
478 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_DOWN,     Key::GamepadDown);
479 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_LEFT,     Key::GamepadLeft);
480 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_DPAD_RIGHT,    Key::GamepadRight);
481 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_BACK,          Key::GamepadBack);
482 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_START,         Key::GamepadStart);
483 			initTranslateGamepad(SDL_CONTROLLER_BUTTON_GUIDE,         Key::GamepadGuide);
484 
485 			bx::memSet(s_translateGamepadAxis, uint8_t(GamepadAxis::Count), sizeof(s_translateGamepadAxis) );
486 			initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_LEFTX,        GamepadAxis::LeftX);
487 			initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_LEFTY,        GamepadAxis::LeftY);
488 			initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT,  GamepadAxis::LeftZ);
489 			initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_RIGHTX,       GamepadAxis::RightX);
490 			initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_RIGHTY,       GamepadAxis::RightY);
491 			initTranslateGamepadAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, GamepadAxis::RightZ);
492 		}
493 
runentry::Context494 		int run(int _argc, char** _argv)
495 		{
496 			m_mte.m_argc = _argc;
497 			m_mte.m_argv = _argv;
498 
499 			SDL_Init(0
500 				| SDL_INIT_GAMECONTROLLER
501 				);
502 
503 			m_windowAlloc.alloc();
504 			m_window[0] = SDL_CreateWindow("bgfx"
505 							, SDL_WINDOWPOS_UNDEFINED
506 							, SDL_WINDOWPOS_UNDEFINED
507 							, m_width
508 							, m_height
509 							, SDL_WINDOW_SHOWN
510 							| SDL_WINDOW_RESIZABLE
511 							);
512 
513 			m_flags[0] = 0
514 				| ENTRY_WINDOW_FLAG_ASPECT_RATIO
515 				| ENTRY_WINDOW_FLAG_FRAME
516 				;
517 
518 			s_userEventStart = SDL_RegisterEvents(7);
519 
520 			sdlSetWindow(m_window[0]);
521 			bgfx::renderFrame();
522 
523 			m_thread.init(MainThreadEntry::threadFunc, &m_mte);
524 
525 			// Force window resolution...
526 			WindowHandle defaultWindow = { 0 };
527 			setWindowSize(defaultWindow, m_width, m_height, true);
528 
529 			SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
530 
531 			bx::FileReaderI* reader = NULL;
532 			while (NULL == reader)
533 			{
534 				reader = getFileReader();
535 				bx::sleep(100);
536 			}
537 
538 			if (bx::open(reader, "gamecontrollerdb.txt") )
539 			{
540 				bx::AllocatorI* allocator = getAllocator();
541 				uint32_t size = (uint32_t)bx::getSize(reader);
542 				void* data = BX_ALLOC(allocator, size + 1);
543 				bx::read(reader, data, size);
544 				bx::close(reader);
545 				((char*)data)[size] = '\0';
546 
547 				if (SDL_GameControllerAddMapping( (char*)data) < 0) {
548 					DBG("SDL game controller add mapping failed: %s", SDL_GetError());
549 				}
550 
551 				BX_FREE(allocator, data);
552 			}
553 
554 			bool exit = false;
555 			SDL_Event event;
556 			while (!exit)
557 			{
558 				bgfx::renderFrame();
559 
560 				while (SDL_PollEvent(&event) )
561 				{
562 					switch (event.type)
563 					{
564 					case SDL_QUIT:
565 						m_eventQueue.postExitEvent();
566 						exit = true;
567 						break;
568 
569 					case SDL_MOUSEMOTION:
570 						{
571 							const SDL_MouseMotionEvent& mev = event.motion;
572 							m_mx = mev.x;
573 							m_my = mev.y;
574 
575 							WindowHandle handle = findHandle(mev.windowID);
576 							if (isValid(handle) )
577 							{
578 								m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_mz);
579 							}
580 						}
581 						break;
582 
583 					case SDL_MOUSEBUTTONDOWN:
584 					case SDL_MOUSEBUTTONUP:
585 						{
586 							const SDL_MouseButtonEvent& mev = event.button;
587 							WindowHandle handle = findHandle(mev.windowID);
588 							if (isValid(handle) )
589 							{
590 								MouseButton::Enum button;
591 								switch (mev.button)
592 								{
593 								default:
594 								case SDL_BUTTON_LEFT:   button = MouseButton::Left;   break;
595 								case SDL_BUTTON_MIDDLE: button = MouseButton::Middle; break;
596 								case SDL_BUTTON_RIGHT:  button = MouseButton::Right;  break;
597 								}
598 
599 								m_eventQueue.postMouseEvent(handle
600 									, mev.x
601 									, mev.y
602 									, m_mz
603 									, button
604 									, mev.type == SDL_MOUSEBUTTONDOWN
605 									);
606 							}
607 						}
608 						break;
609 
610 					case SDL_MOUSEWHEEL:
611 						{
612 							const SDL_MouseWheelEvent& mev = event.wheel;
613 							m_mz += mev.y;
614 
615 							WindowHandle handle = findHandle(mev.windowID);
616 							if (isValid(handle) )
617 							{
618 								m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_mz);
619 							}
620 						}
621 						break;
622 
623 					case SDL_TEXTINPUT:
624 						{
625 							const SDL_TextInputEvent& tev = event.text;
626 							WindowHandle handle = findHandle(tev.windowID);
627 							if (isValid(handle) )
628 							{
629 								m_eventQueue.postCharEvent(handle, 1, (const uint8_t*)tev.text);
630 							}
631 						}
632 						break;
633 
634 					case SDL_KEYDOWN:
635 						{
636 							const SDL_KeyboardEvent& kev = event.key;
637 							WindowHandle handle = findHandle(kev.windowID);
638 							if (isValid(handle) )
639 							{
640 								uint8_t modifiers = translateKeyModifiers(kev.keysym.mod);
641 								Key::Enum key = translateKey(kev.keysym.scancode);
642 
643 #if 0
644 								DBG("SDL scancode %d, key %d, name %s, key name %s"
645 									, kev.keysym.scancode
646 									, key
647 									, SDL_GetScancodeName(kev.keysym.scancode)
648 									, SDL_GetKeyName(kev.keysym.scancode)
649 									);
650 #endif // 0
651 
652 								/// If you only press (e.g.) 'shift' and nothing else, then key == 'shift', modifier == 0.
653 								/// Further along, pressing 'shift' + 'ctrl' would be: key == 'shift', modifier == 'ctrl.
654 								if (0 == key && 0 == modifiers)
655 								{
656 									modifiers = translateKeyModifierPress(kev.keysym.scancode);
657 								}
658 
659 								if (Key::Esc == key)
660 								{
661 									uint8_t pressedChar[4];
662 									pressedChar[0] = 0x1b;
663 									m_eventQueue.postCharEvent(handle, 1, pressedChar);
664 								}
665 								else if (Key::Return == key)
666 								{
667 									uint8_t pressedChar[4];
668 									pressedChar[0] = 0x0d;
669 									m_eventQueue.postCharEvent(handle, 1, pressedChar);
670 								}
671 								else if (Key::Backspace == key)
672 								{
673 									uint8_t pressedChar[4];
674 									pressedChar[0] = 0x08;
675 									m_eventQueue.postCharEvent(handle, 1, pressedChar);
676 								}
677 
678 								m_eventQueue.postKeyEvent(handle, key, modifiers, kev.state == SDL_PRESSED);
679 							}
680 						}
681 						break;
682 
683 					case SDL_KEYUP:
684 						{
685 							const SDL_KeyboardEvent& kev = event.key;
686 							WindowHandle handle = findHandle(kev.windowID);
687 							if (isValid(handle) )
688 							{
689 								uint8_t modifiers = translateKeyModifiers(kev.keysym.mod);
690 								Key::Enum key = translateKey(kev.keysym.scancode);
691 								m_eventQueue.postKeyEvent(handle, key, modifiers, kev.state == SDL_PRESSED);
692 							}
693 						}
694 						break;
695 
696 					case SDL_WINDOWEVENT:
697 						{
698 							const SDL_WindowEvent& wev = event.window;
699 							switch (wev.event)
700 							{
701 							case SDL_WINDOWEVENT_RESIZED:
702 							case SDL_WINDOWEVENT_SIZE_CHANGED:
703 								{
704 									WindowHandle handle = findHandle(wev.windowID);
705 									setWindowSize(handle, wev.data1, wev.data2);
706 								}
707 								break;
708 
709 							case SDL_WINDOWEVENT_SHOWN:
710 							case SDL_WINDOWEVENT_HIDDEN:
711 							case SDL_WINDOWEVENT_EXPOSED:
712 							case SDL_WINDOWEVENT_MOVED:
713 							case SDL_WINDOWEVENT_MINIMIZED:
714 							case SDL_WINDOWEVENT_MAXIMIZED:
715 							case SDL_WINDOWEVENT_RESTORED:
716 							case SDL_WINDOWEVENT_ENTER:
717 							case SDL_WINDOWEVENT_LEAVE:
718 							case SDL_WINDOWEVENT_FOCUS_GAINED:
719 							case SDL_WINDOWEVENT_FOCUS_LOST:
720 								break;
721 
722 							case SDL_WINDOWEVENT_CLOSE:
723 								{
724 									WindowHandle handle = findHandle(wev.windowID);
725 									if (0 == handle.idx)
726 									{
727 										m_eventQueue.postExitEvent();
728 										exit = true;
729 									}
730 								}
731 								break;
732 							}
733 						}
734 						break;
735 
736 					case SDL_JOYAXISMOTION:
737 						{
738 							const SDL_JoyAxisEvent& jev = event.jaxis;
739 							GamepadHandle handle = findGamepad(jev.which);
740 							if (isValid(handle) )
741 							{
742 								GamepadAxis::Enum axis = translateGamepadAxis(jev.axis);
743 								m_gamepad[handle.idx].update(m_eventQueue, defaultWindow, handle, axis, jev.value);
744 							}
745 						}
746 						break;
747 
748 					case SDL_CONTROLLERAXISMOTION:
749 						{
750 							const SDL_ControllerAxisEvent& aev = event.caxis;
751 							GamepadHandle handle = findGamepad(aev.which);
752 							if (isValid(handle) )
753 							{
754 								GamepadAxis::Enum axis = translateGamepadAxis(aev.axis);
755 								m_gamepad[handle.idx].update(m_eventQueue, defaultWindow, handle, axis, aev.value);
756 							}
757 						}
758 						break;
759 
760 					case SDL_JOYBUTTONDOWN:
761 					case SDL_JOYBUTTONUP:
762 						{
763 							const SDL_JoyButtonEvent& bev = event.jbutton;
764 							GamepadHandle handle = findGamepad(bev.which);
765 
766 							if (isValid(handle) )
767 							{
768 								Key::Enum key = translateGamepad(bev.button);
769 								if (Key::Count != key)
770 								{
771 									m_eventQueue.postKeyEvent(defaultWindow, key, 0, event.type == SDL_JOYBUTTONDOWN);
772 								}
773 							}
774 						}
775 						break;
776 
777 					case SDL_CONTROLLERBUTTONDOWN:
778 					case SDL_CONTROLLERBUTTONUP:
779 						{
780 							const SDL_ControllerButtonEvent& bev = event.cbutton;
781 							GamepadHandle handle = findGamepad(bev.which);
782 							if (isValid(handle) )
783 							{
784 								Key::Enum key = translateGamepad(bev.button);
785 								if (Key::Count != key)
786 								{
787 									m_eventQueue.postKeyEvent(defaultWindow, key, 0, event.type == SDL_CONTROLLERBUTTONDOWN);
788 								}
789 							}
790 						}
791 						break;
792 
793 					case SDL_JOYDEVICEADDED:
794 						{
795 							GamepadHandle handle = { m_gamepadAlloc.alloc() };
796 							if (isValid(handle) )
797 							{
798 								const SDL_JoyDeviceEvent& jev = event.jdevice;
799 								m_gamepad[handle.idx].create(jev);
800 								m_eventQueue.postGamepadEvent(defaultWindow, handle, true);
801 							}
802 						}
803 						break;
804 
805 					case SDL_JOYDEVICEREMOVED:
806 						{
807 							const SDL_JoyDeviceEvent& jev = event.jdevice;
808 							GamepadHandle handle = findGamepad(jev.which);
809 							if (isValid(handle) )
810 							{
811 								m_gamepad[handle.idx].destroy();
812 								m_gamepadAlloc.free(handle.idx);
813 								m_eventQueue.postGamepadEvent(defaultWindow, handle, false);
814 							}
815 						}
816 						break;
817 
818 					case SDL_CONTROLLERDEVICEADDED:
819 						{
820 							GamepadHandle handle = { m_gamepadAlloc.alloc() };
821 							if (isValid(handle) )
822 							{
823 								const SDL_ControllerDeviceEvent& cev = event.cdevice;
824 								m_gamepad[handle.idx].create(cev);
825 								m_eventQueue.postGamepadEvent(defaultWindow, handle, true);
826 							}
827 						}
828 						break;
829 
830 					case SDL_CONTROLLERDEVICEREMAPPED:
831 						{
832 
833 						}
834 						break;
835 
836 					case SDL_CONTROLLERDEVICEREMOVED:
837 						{
838 							const SDL_ControllerDeviceEvent& cev = event.cdevice;
839 							GamepadHandle handle = findGamepad(cev.which);
840 							if (isValid(handle) )
841 							{
842 								m_gamepad[handle.idx].destroy();
843 								m_gamepadAlloc.free(handle.idx);
844 								m_eventQueue.postGamepadEvent(defaultWindow, handle, false);
845 							}
846 						}
847 						break;
848 
849 					case SDL_DROPFILE:
850 						{
851 							const SDL_DropEvent& dev = event.drop;
852 							WindowHandle handle = defaultWindow; //findHandle(dev.windowID);
853 							if (isValid(handle) )
854 							{
855 								m_eventQueue.postDropFileEvent(handle, dev.file);
856 								SDL_free(dev.file);
857 							}
858 						}
859 						break;
860 
861 					default:
862 						{
863 							const SDL_UserEvent& uev = event.user;
864 							switch (uev.type - s_userEventStart)
865 							{
866 							case SDL_USER_WINDOW_CREATE:
867 								{
868 									WindowHandle handle = getWindowHandle(uev);
869 									Msg* msg = (Msg*)uev.data2;
870 
871 									m_window[handle.idx] = SDL_CreateWindow(msg->m_title.c_str()
872 										, msg->m_x
873 										, msg->m_y
874 										, msg->m_width
875 										, msg->m_height
876 										, SDL_WINDOW_SHOWN
877 										| SDL_WINDOW_RESIZABLE
878 										);
879 
880 									m_flags[handle.idx] = msg->m_flags;
881 
882 									void* nwh = sdlNativeWindowHandle(m_window[handle.idx]);
883 									if (NULL != nwh)
884 									{
885 										m_eventQueue.postSizeEvent(handle, msg->m_width, msg->m_height);
886 										m_eventQueue.postWindowEvent(handle, nwh);
887 									}
888 
889 									delete msg;
890 								}
891 								break;
892 
893 							case SDL_USER_WINDOW_DESTROY:
894 								{
895 									WindowHandle handle = getWindowHandle(uev);
896 									if (isValid(handle) )
897 									{
898 										m_eventQueue.postWindowEvent(handle);
899 										sdlDestroyWindow(m_window[handle.idx]);
900 										m_window[handle.idx] = NULL;
901 									}
902 								}
903 								break;
904 
905 							case SDL_USER_WINDOW_SET_TITLE:
906 								{
907 									WindowHandle handle = getWindowHandle(uev);
908 									Msg* msg = (Msg*)uev.data2;
909 									if (isValid(handle) )
910 									{
911 										SDL_SetWindowTitle(m_window[handle.idx], msg->m_title.c_str() );
912 									}
913 									delete msg;
914 								}
915 								break;
916 
917 							case SDL_USER_WINDOW_SET_FLAGS:
918 								{
919 									WindowHandle handle = getWindowHandle(uev);
920 									Msg* msg = (Msg*)uev.data2;
921 
922 									if (msg->m_flagsEnabled)
923 									{
924 										m_flags[handle.idx] |= msg->m_flags;
925 									}
926 									else
927 									{
928 										m_flags[handle.idx] &= ~msg->m_flags;
929 									}
930 
931 									delete msg;
932 								}
933 								break;
934 
935 							case SDL_USER_WINDOW_SET_POS:
936 								{
937 									WindowHandle handle = getWindowHandle(uev);
938 									Msg* msg = (Msg*)uev.data2;
939 									SDL_SetWindowPosition(m_window[handle.idx], msg->m_x, msg->m_y);
940 									delete msg;
941 								}
942 								break;
943 
944 							case SDL_USER_WINDOW_SET_SIZE:
945 								{
946 									WindowHandle handle = getWindowHandle(uev);
947 									Msg* msg = (Msg*)uev.data2;
948 									if (isValid(handle) )
949 									{
950 										setWindowSize(handle, msg->m_width, msg->m_height);
951 									}
952 									delete msg;
953 								}
954 								break;
955 
956 							case SDL_USER_WINDOW_TOGGLE_FRAME:
957 								{
958 									WindowHandle handle = getWindowHandle(uev);
959 									if (isValid(handle) )
960 									{
961 										m_flags[handle.idx] ^= ENTRY_WINDOW_FLAG_FRAME;
962 										SDL_SetWindowBordered(m_window[handle.idx], (SDL_bool)!!(m_flags[handle.idx] & ENTRY_WINDOW_FLAG_FRAME) );
963 									}
964 								}
965 								break;
966 
967 							case SDL_USER_WINDOW_TOGGLE_FULL_SCREEN:
968 								{
969 									WindowHandle handle = getWindowHandle(uev);
970 									m_fullscreen = !m_fullscreen;
971 									SDL_SetWindowFullscreen(m_window[handle.idx], m_fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
972 								}
973 								break;
974 
975 							case SDL_USER_WINDOW_MOUSE_LOCK:
976 								{
977 									SDL_SetRelativeMouseMode(!!uev.code ? SDL_TRUE : SDL_FALSE);
978 								}
979 								break;
980 
981 							default:
982 								break;
983 							}
984 						}
985 						break;
986 					}
987 				}
988 			}
989 
990 			while (bgfx::RenderFrame::NoContext != bgfx::renderFrame() ) {};
991 			m_thread.shutdown();
992 
993 			sdlDestroyWindow(m_window[0]);
994 			SDL_Quit();
995 
996 			return m_thread.getExitCode();
997 		}
998 
findHandleentry::Context999 		WindowHandle findHandle(uint32_t _windowId)
1000 		{
1001 			SDL_Window* window = SDL_GetWindowFromID(_windowId);
1002 			return findHandle(window);
1003 		}
1004 
findHandleentry::Context1005 		WindowHandle findHandle(SDL_Window* _window)
1006 		{
1007 			bx::MutexScope scope(m_lock);
1008 			for (uint32_t ii = 0, num = m_windowAlloc.getNumHandles(); ii < num; ++ii)
1009 			{
1010 				uint16_t idx = m_windowAlloc.getHandleAt(ii);
1011 				if (_window == m_window[idx])
1012 				{
1013 					WindowHandle handle = { idx };
1014 					return handle;
1015 				}
1016 			}
1017 
1018 			WindowHandle invalid = { UINT16_MAX };
1019 			return invalid;
1020 		}
1021 
setWindowSizeentry::Context1022 		void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height, bool _force = false)
1023 		{
1024 			if (_width  != m_width
1025 			||  _height != m_height
1026 			||  _force)
1027 			{
1028 				m_width  = _width;
1029 				m_height = _height;
1030 
1031 				SDL_SetWindowSize(m_window[_handle.idx], m_width, m_height);
1032 				m_eventQueue.postSizeEvent(_handle, m_width, m_height);
1033 			}
1034 		}
1035 
findGamepadentry::Context1036 		GamepadHandle findGamepad(SDL_JoystickID _jid)
1037 		{
1038 			for (uint32_t ii = 0, num = m_gamepadAlloc.getNumHandles(); ii < num; ++ii)
1039 			{
1040 				uint16_t idx = m_gamepadAlloc.getHandleAt(ii);
1041 				if (_jid == m_gamepad[idx].m_jid)
1042 				{
1043 					GamepadHandle handle = { idx };
1044 					return handle;
1045 				}
1046 			}
1047 
1048 			GamepadHandle invalid = { UINT16_MAX };
1049 			return invalid;
1050 		}
1051 
1052 		MainThreadEntry m_mte;
1053 		bx::Thread m_thread;
1054 
1055 		EventQueue m_eventQueue;
1056 		bx::Mutex m_lock;
1057 
1058 		bx::HandleAllocT<ENTRY_CONFIG_MAX_WINDOWS> m_windowAlloc;
1059 		SDL_Window* m_window[ENTRY_CONFIG_MAX_WINDOWS];
1060 		uint32_t m_flags[ENTRY_CONFIG_MAX_WINDOWS];
1061 
1062 		bx::HandleAllocT<ENTRY_CONFIG_MAX_GAMEPADS> m_gamepadAlloc;
1063 		GamepadSDL m_gamepad[ENTRY_CONFIG_MAX_GAMEPADS];
1064 
1065 		uint32_t m_width;
1066 		uint32_t m_height;
1067 		float m_aspectRatio;
1068 
1069 		int32_t m_mx;
1070 		int32_t m_my;
1071 		int32_t m_mz;
1072 		bool m_mouseLock;
1073 		bool m_fullscreen;
1074 	};
1075 
1076 	static Context s_ctx;
1077 
poll()1078 	const Event* poll()
1079 	{
1080 		return s_ctx.m_eventQueue.poll();
1081 	}
1082 
poll(WindowHandle _handle)1083 	const Event* poll(WindowHandle _handle)
1084 	{
1085 		return s_ctx.m_eventQueue.poll(_handle);
1086 	}
1087 
release(const Event * _event)1088 	void release(const Event* _event)
1089 	{
1090 		s_ctx.m_eventQueue.release(_event);
1091 	}
1092 
createWindow(int32_t _x,int32_t _y,uint32_t _width,uint32_t _height,uint32_t _flags,const char * _title)1093 	WindowHandle createWindow(int32_t _x, int32_t _y, uint32_t _width, uint32_t _height, uint32_t _flags, const char* _title)
1094 	{
1095 		bx::MutexScope scope(s_ctx.m_lock);
1096 		WindowHandle handle = { s_ctx.m_windowAlloc.alloc() };
1097 
1098 		if (UINT16_MAX != handle.idx)
1099 		{
1100 			Msg* msg = new Msg;
1101 			msg->m_x      = _x;
1102 			msg->m_y      = _y;
1103 			msg->m_width  = _width;
1104 			msg->m_height = _height;
1105 			msg->m_title  = _title;
1106 			msg->m_flags  = _flags;
1107 
1108 			sdlPostEvent(SDL_USER_WINDOW_CREATE, handle, msg);
1109 		}
1110 
1111 		return handle;
1112 	}
1113 
destroyWindow(WindowHandle _handle)1114 	void destroyWindow(WindowHandle _handle)
1115 	{
1116 		if (UINT16_MAX != _handle.idx)
1117 		{
1118 			sdlPostEvent(SDL_USER_WINDOW_DESTROY, _handle);
1119 
1120 			bx::MutexScope scope(s_ctx.m_lock);
1121 			s_ctx.m_windowAlloc.free(_handle.idx);
1122 		}
1123 	}
1124 
setWindowPos(WindowHandle _handle,int32_t _x,int32_t _y)1125 	void setWindowPos(WindowHandle _handle, int32_t _x, int32_t _y)
1126 	{
1127 		Msg* msg = new Msg;
1128 		msg->m_x = _x;
1129 		msg->m_y = _y;
1130 
1131 		sdlPostEvent(SDL_USER_WINDOW_SET_POS, _handle, msg);
1132 	}
1133 
setWindowSize(WindowHandle _handle,uint32_t _width,uint32_t _height)1134 	void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
1135 	{
1136 		Msg* msg = new Msg;
1137 		msg->m_width  = _width;
1138 		msg->m_height = _height;
1139 
1140 		sdlPostEvent(SDL_USER_WINDOW_SET_SIZE, _handle, msg);
1141 	}
1142 
setWindowTitle(WindowHandle _handle,const char * _title)1143 	void setWindowTitle(WindowHandle _handle, const char* _title)
1144 	{
1145 		Msg* msg = new Msg;
1146 		msg->m_title = _title;
1147 
1148 		sdlPostEvent(SDL_USER_WINDOW_SET_TITLE, _handle, msg);
1149 	}
1150 
setWindowFlags(WindowHandle _handle,uint32_t _flags,bool _enabled)1151 	void setWindowFlags(WindowHandle _handle, uint32_t _flags, bool _enabled)
1152 	{
1153 		Msg* msg = new Msg;
1154 		msg->m_flags = _flags;
1155 		msg->m_flagsEnabled = _enabled;
1156 		sdlPostEvent(SDL_USER_WINDOW_SET_FLAGS, _handle, msg);
1157 	}
1158 
toggleFullscreen(WindowHandle _handle)1159 	void toggleFullscreen(WindowHandle _handle)
1160 	{
1161 		sdlPostEvent(SDL_USER_WINDOW_TOGGLE_FULL_SCREEN, _handle);
1162 	}
1163 
setMouseLock(WindowHandle _handle,bool _lock)1164 	void setMouseLock(WindowHandle _handle, bool _lock)
1165 	{
1166 		sdlPostEvent(SDL_USER_WINDOW_MOUSE_LOCK, _handle, NULL, _lock);
1167 	}
1168 
threadFunc(bx::Thread * _thread,void * _userData)1169 	int32_t MainThreadEntry::threadFunc(bx::Thread* _thread, void* _userData)
1170 	{
1171 		BX_UNUSED(_thread);
1172 
1173 		MainThreadEntry* self = (MainThreadEntry*)_userData;
1174 		int32_t result = main(self->m_argc, self->m_argv);
1175 
1176 		SDL_Event event;
1177 		SDL_QuitEvent& qev = event.quit;
1178 		qev.type = SDL_QUIT;
1179 		SDL_PushEvent(&event);
1180 		return result;
1181 	}
1182 
1183 } // namespace entry
1184 
main(int _argc,char ** _argv)1185 int main(int _argc, char** _argv)
1186 {
1187 	using namespace entry;
1188 	return s_ctx.run(_argc, _argv);
1189 }
1190 
1191 #endif // ENTRY_CONFIG_USE_SDL
1192