]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceSDL.cpp
6ebf63b975ff7cb316879b9fca6a632b15f227bb
[irrlicht.git] / source / Irrlicht / CIrrDeviceSDL.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 \r
6 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_\r
7 \r
8 #include "CIrrDeviceSDL.h"\r
9 #include "IEventReceiver.h"\r
10 #include "IGUIElement.h"\r
11 #include "IGUIEnvironment.h"\r
12 #include "os.h"\r
13 #include "CTimer.h"\r
14 #include "irrString.h"\r
15 #include "Keycodes.h"\r
16 #include "COSOperator.h"\r
17 #include <stdio.h>\r
18 #include <stdlib.h>\r
19 #include "SIrrCreationParameters.h"\r
20 #include <SDL_video.h>\r
21 \r
22 #ifdef _IRR_EMSCRIPTEN_PLATFORM_\r
23 #ifdef _IRR_COMPILE_WITH_OGLES2_\r
24 #include "CEGLManager.h"\r
25 #endif\r
26 #include <emscripten.h>\r
27 #endif\r
28 \r
29 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
30 #include "CSDLManager.h"\r
31 #endif\r
32 \r
33 static int SDLDeviceInstances = 0;\r
34 \r
35 namespace irr\r
36 {\r
37         namespace video\r
38         {\r
39                 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
40                 IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
41                 #else\r
42                 static IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
43                 {\r
44                         os::Printer::log("No OpenGL support compiled in.", ELL_ERROR);\r
45                         return nullptr;\r
46                 }\r
47                 #endif\r
48 \r
49                 #ifdef ENABLE_OPENGL3\r
50                 IVideoDriver* createOpenGL3Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
51                 #else\r
52                 static IVideoDriver* createOpenGL3Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
53                 {\r
54                         os::Printer::log("No OpenGL 3 support compiled in.", ELL_ERROR);\r
55                         return nullptr;\r
56                 }\r
57                 #endif\r
58 \r
59                 #ifdef _IRR_COMPILE_WITH_OGLES2_\r
60                 IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
61                 #else\r
62                 static IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
63                 {\r
64                         os::Printer::log("No OpenGL ES 2 support compiled in.", ELL_ERROR);\r
65                         return nullptr;\r
66                 }\r
67                 #endif\r
68 \r
69                 #ifdef _IRR_COMPILE_WITH_WEBGL1_\r
70                 IVideoDriver* createWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
71                 #else\r
72                 static IVideoDriver* createWebGL1Driver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager)\r
73                 {\r
74                         os::Printer::log("No WebGL 1 support compiled in.", ELL_ERROR);\r
75                         return nullptr;\r
76                 }\r
77                 #endif\r
78         } // end namespace video\r
79 \r
80 } // end namespace irr\r
81 \r
82 \r
83 namespace irr\r
84 {\r
85 #ifdef _IRR_EMSCRIPTEN_PLATFORM_\r
86 EM_BOOL CIrrDeviceSDL::MouseUpDownCallback(int eventType, const EmscriptenMouseEvent * event, void* userData)\r
87 {\r
88         // We need this callback so far only because otherwise "emscripten_request_pointerlock" calls will\r
89         // fail as their request are infinitely deferred.\r
90         // Not exactly certain why, maybe SDL does catch those mouse-events otherwise and not pass them on.\r
91         return EM_FALSE;\r
92 }\r
93 \r
94 EM_BOOL CIrrDeviceSDL::MouseEnterCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)\r
95 {\r
96         CIrrDeviceSDL * This = static_cast<CIrrDeviceSDL*>(userData);\r
97 \r
98         SEvent irrevent;\r
99 \r
100         irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;\r
101         irrevent.MouseInput.Event = irr::EMIE_MOUSE_ENTER_CANVAS;\r
102         This->MouseX = irrevent.MouseInput.X = mouseEvent->canvasX;\r
103         This->MouseY = irrevent.MouseInput.Y = mouseEvent->canvasY;\r
104         This->MouseXRel = mouseEvent->movementX; // should be 0 I guess? Or can it enter while pointer is locked()?\r
105         This->MouseYRel = mouseEvent->movementY;\r
106         irrevent.MouseInput.ButtonStates = This->MouseButtonStates;     // TODO: not correct, but couldn't figure out the bitset of mouseEvent->buttons yet.\r
107         irrevent.MouseInput.Shift = mouseEvent->shiftKey;\r
108         irrevent.MouseInput.Control = mouseEvent->ctrlKey;\r
109 \r
110         This->postEventFromUser(irrevent);\r
111 \r
112         return EM_FALSE;\r
113 }\r
114 \r
115 EM_BOOL CIrrDeviceSDL::MouseLeaveCallback(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)\r
116 {\r
117         CIrrDeviceSDL * This = static_cast<CIrrDeviceSDL*>(userData);\r
118 \r
119         SEvent irrevent;\r
120 \r
121         irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;\r
122         irrevent.MouseInput.Event = irr::EMIE_MOUSE_LEAVE_CANVAS;\r
123         This->MouseX = irrevent.MouseInput.X = mouseEvent->canvasX;\r
124         This->MouseY = irrevent.MouseInput.Y = mouseEvent->canvasY;\r
125         This->MouseXRel = mouseEvent->movementX; // should be 0 I guess? Or can it enter while pointer is locked()?\r
126         This->MouseYRel = mouseEvent->movementY;\r
127         irrevent.MouseInput.ButtonStates = This->MouseButtonStates;     // TODO: not correct, but couldn't figure out the bitset of mouseEvent->buttons yet.\r
128         irrevent.MouseInput.Shift = mouseEvent->shiftKey;\r
129         irrevent.MouseInput.Control = mouseEvent->ctrlKey;\r
130 \r
131         This->postEventFromUser(irrevent);\r
132 \r
133         return EM_FALSE;\r
134 }\r
135 #endif\r
136 \r
137 \r
138 bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key)\r
139 {\r
140         switch ( key )\r
141         {\r
142                 // keys which are known to have safe special character interpretation\r
143                 // could need changes over time (removals and additions!)\r
144                 case KEY_RETURN:\r
145                 case KEY_PAUSE:\r
146                 case KEY_ESCAPE:\r
147                 case KEY_PRIOR:\r
148                 case KEY_NEXT:\r
149                 case KEY_HOME:\r
150                 case KEY_END:\r
151                 case KEY_LEFT:\r
152                 case KEY_UP:\r
153                 case KEY_RIGHT:\r
154                 case KEY_DOWN:\r
155                 case KEY_TAB:\r
156                 case KEY_PRINT:\r
157                 case KEY_SNAPSHOT:\r
158                 case KEY_INSERT:\r
159                 case KEY_BACK:\r
160                 case KEY_DELETE:\r
161                 case KEY_HELP:\r
162                 case KEY_APPS:\r
163                 case KEY_SLEEP:\r
164                 case KEY_F1:\r
165                 case KEY_F2:\r
166                 case KEY_F3:\r
167                 case KEY_F4:\r
168                 case KEY_F5:\r
169                 case KEY_F6:\r
170                 case KEY_F7:\r
171                 case KEY_F8:\r
172                 case KEY_F9:\r
173                 case KEY_F10:\r
174                 case KEY_F11:\r
175                 case KEY_F12:\r
176                 case KEY_F13:\r
177                 case KEY_F14:\r
178                 case KEY_F15:\r
179                 case KEY_F16:\r
180                 case KEY_F17:\r
181                 case KEY_F18:\r
182                 case KEY_F19:\r
183                 case KEY_F20:\r
184                 case KEY_F21:\r
185                 case KEY_F22:\r
186                 case KEY_F23:\r
187                 case KEY_F24:\r
188                 case KEY_NUMLOCK:\r
189                 case KEY_SCROLL:\r
190                 case KEY_LCONTROL:\r
191                 case KEY_RCONTROL:\r
192                         return true;\r
193 \r
194                 default:\r
195                         return false;\r
196         }\r
197 }\r
198 \r
199 int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key) {\r
200         // SDL in-place ORs values with no character representation with 1<<30\r
201         // https://wiki.libsdl.org/SDL2/SDLKeycodeLookup\r
202         if (assumedChar & (1<<30))\r
203                 return 0;\r
204 \r
205         switch (key) {\r
206                 case KEY_PRIOR:\r
207                 case KEY_NEXT:\r
208                 case KEY_HOME:\r
209                 case KEY_END:\r
210                 case KEY_LEFT:\r
211                 case KEY_UP:\r
212                 case KEY_RIGHT:\r
213                 case KEY_DOWN:\r
214                 case KEY_NUMLOCK:\r
215                         return 0;\r
216                 default:\r
217                         return assumedChar;\r
218         }\r
219 }\r
220 \r
221 void CIrrDeviceSDL::resetReceiveTextInputEvents() {\r
222         gui::IGUIElement *elem = GUIEnvironment->getFocus();\r
223         if (elem && elem->acceptsIME())\r
224                 SDL_StartTextInput();\r
225         else\r
226                 SDL_StopTextInput();\r
227 }\r
228 \r
229 //! constructor\r
230 CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters& param)\r
231         : CIrrDeviceStub(param),\r
232         Window((SDL_Window*)param.WindowId), SDL_Flags(0),\r
233         MouseX(0), MouseY(0), MouseXRel(0), MouseYRel(0), MouseButtonStates(0),\r
234         Width(param.WindowSize.Width), Height(param.WindowSize.Height),\r
235         Resizable(param.WindowResizable == 1 ? true : false)\r
236 {\r
237         #ifdef _DEBUG\r
238         setDebugName("CIrrDeviceSDL");\r
239         #endif\r
240 \r
241         if ( ++SDLDeviceInstances == 1 )\r
242         {\r
243                 u32 flags = SDL_INIT_TIMER | SDL_INIT_EVENTS;\r
244                 if (CreationParams.DriverType != video::EDT_NULL)\r
245                         flags |= SDL_INIT_VIDEO;\r
246 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
247                 flags |= SDL_INIT_JOYSTICK;\r
248 #endif\r
249                 if (SDL_Init(flags) < 0)\r
250                 {\r
251                         os::Printer::log( "Unable to initialize SDL!", SDL_GetError());\r
252                         Close = true;\r
253                 }\r
254                 else\r
255                 {\r
256                         os::Printer::log("SDL initialized", ELL_INFORMATION);\r
257                 }\r
258         }\r
259 \r
260         // create keymap\r
261         createKeyMap();\r
262 \r
263         // create window\r
264         if (CreationParams.DriverType != video::EDT_NULL)\r
265         {\r
266                 // create the window, only if we do not use the null device\r
267                 createWindow();\r
268         }\r
269 \r
270 \r
271         SDL_VERSION(&Info.version);\r
272 \r
273 #ifndef _IRR_EMSCRIPTEN_PLATFORM_\r
274         SDL_GetWindowWMInfo(Window,&Info);\r
275 #endif //_IRR_EMSCRIPTEN_PLATFORM_\r
276         core::stringc sdlversion = "SDL Version ";\r
277         sdlversion += Info.version.major;\r
278         sdlversion += ".";\r
279         sdlversion += Info.version.minor;\r
280         sdlversion += ".";\r
281         sdlversion += Info.version.patch;\r
282 \r
283         Operator = new COSOperator(sdlversion);\r
284         if (SDLDeviceInstances == 1) {\r
285                 os::Printer::log(sdlversion.c_str(), ELL_INFORMATION);\r
286         }\r
287 \r
288         // create cursor control\r
289         CursorControl = new CCursorControl(this);\r
290 \r
291         // create driver\r
292         createDriver();\r
293 \r
294         if (VideoDriver) {\r
295                 createGUIAndScene();\r
296                 VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));\r
297         }\r
298 }\r
299 \r
300 \r
301 //! destructor\r
302 CIrrDeviceSDL::~CIrrDeviceSDL()\r
303 {\r
304         if ( --SDLDeviceInstances == 0 )\r
305         {\r
306 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
307                 const u32 numJoysticks = Joysticks.size();\r
308                 for (u32 i=0; i<numJoysticks; ++i)\r
309                         SDL_JoystickClose(Joysticks[i]);\r
310 #endif\r
311                 if (Window)\r
312                 {\r
313                         SDL_GL_MakeCurrent(Window, NULL);\r
314                         SDL_GL_DeleteContext(Context);\r
315                         SDL_DestroyWindow(Window);\r
316                 }\r
317                 SDL_Quit();\r
318 \r
319                 os::Printer::log("Quit SDL", ELL_INFORMATION);\r
320         }\r
321 }\r
322 \r
323 void CIrrDeviceSDL::logAttributes()\r
324 {\r
325         core::stringc sdl_attr("SDL attribs:");\r
326         int value = 0;\r
327         if ( SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &value ) == 0 )\r
328                 sdl_attr += core::stringc(" r:") + core::stringc(value);\r
329         if ( SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &value ) == 0 )\r
330                 sdl_attr += core::stringc(" g:") + core::stringc(value);\r
331         if ( SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &value ) == 0 )\r
332                 sdl_attr += core::stringc(" b:") + core::stringc(value);\r
333         if ( SDL_GL_GetAttribute( SDL_GL_ALPHA_SIZE, &value ) == 0 )\r
334                 sdl_attr += core::stringc(" a:") + core::stringc(value);\r
335 \r
336         if ( SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &value) == 0 )\r
337                 sdl_attr += core::stringc(" depth:") + core::stringc(value);\r
338         if ( SDL_GL_GetAttribute( SDL_GL_STENCIL_SIZE, &value ) == 0 )\r
339                 sdl_attr += core::stringc(" stencil:") + core::stringc(value);\r
340         if ( SDL_GL_GetAttribute( SDL_GL_DOUBLEBUFFER, &value ) == 0 )\r
341                 sdl_attr += core::stringc(" doublebuf:") + core::stringc(value);\r
342         if ( SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &value ) == 0 )\r
343                 sdl_attr += core::stringc(" aa:") + core::stringc(value);\r
344         if ( SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &value ) == 0 )\r
345                 sdl_attr += core::stringc(" aa-samples:") + core::stringc(value);\r
346 \r
347         os::Printer::log(sdl_attr.c_str());\r
348 }\r
349 \r
350 bool CIrrDeviceSDL::createWindow()\r
351 {\r
352         if (CreationParams.Fullscreen) {\r
353                 SDL_Flags |= SDL_WINDOW_FULLSCREEN;\r
354         } else  {\r
355                 if (Resizable)\r
356                         SDL_Flags |= SDL_WINDOW_RESIZABLE;\r
357                 if (CreationParams.WindowMaximized)\r
358                         SDL_Flags |= SDL_WINDOW_MAXIMIZED;\r
359         }\r
360         SDL_Flags |= SDL_WINDOW_OPENGL;\r
361 \r
362 #ifdef _IRR_EMSCRIPTEN_PLATFORM_\r
363         if ( Width != 0 || Height != 0 )\r
364                 emscripten_set_canvas_size( Width, Height);\r
365         else\r
366         {\r
367                 int w, h, fs;\r
368                 emscripten_get_canvas_size(&w, &h, &fs);\r
369                 Width = w;\r
370                 Height = h;\r
371         }\r
372 \r
373         SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );\r
374         SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );\r
375         SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );\r
376         SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, CreationParams.WithAlphaChannel?8:0 );\r
377 \r
378         SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, CreationParams.ZBufferBits);\r
379         SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, CreationParams.Stencilbuffer ? 8 : 0);\r
380         SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, CreationParams.Doublebuffer ? 1 : 0);\r
381 \r
382         if (CreationParams.AntiAlias>1)\r
383         {\r
384                 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );\r
385                 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, CreationParams.AntiAlias );\r
386         }\r
387         else\r
388         {\r
389                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);\r
390                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);\r
391         }\r
392 \r
393         SDL_CreateWindowAndRenderer(0, 0, SDL_Flags, &Window, &Renderer); // 0,0 will use the canvas size\r
394 \r
395         logAttributes();\r
396 \r
397         // "#canvas" is for the opengl context\r
398         emscripten_set_mousedown_callback("#canvas", (void*)this, true, MouseUpDownCallback);\r
399     emscripten_set_mouseup_callback("#canvas", (void*)this, true, MouseUpDownCallback);\r
400     emscripten_set_mouseenter_callback("#canvas", (void*)this, false, MouseEnterCallback);\r
401     emscripten_set_mouseleave_callback("#canvas", (void*)this, false, MouseLeaveCallback);\r
402 \r
403         return true;\r
404 #else // !_IRR_EMSCRIPTEN_PLATFORM_\r
405         if ( Close )\r
406                 return false;\r
407 \r
408         switch (CreationParams.DriverType) {\r
409                 case video::EDT_OPENGL:\r
410                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);\r
411                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);\r
412                         break;\r
413                 case video::EDT_OPENGL3:\r
414                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);\r
415                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);\r
416                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);\r
417                         break;\r
418                 case video::EDT_OGLES1:\r
419                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);\r
420                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);\r
421                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);\r
422                         break;\r
423                 case video::EDT_OGLES2:\r
424                 case video::EDT_WEBGL1:\r
425                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);\r
426                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);\r
427                         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);\r
428                         break;\r
429                 default:;\r
430         }\r
431 \r
432 #ifdef _DEBUG\r
433         SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG);\r
434 #endif\r
435 \r
436         if (CreationParams.Bits == 16) {\r
437                 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);\r
438                 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);\r
439                 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);\r
440                 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, CreationParams.WithAlphaChannel ? 1 : 0);\r
441         } else {\r
442                 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);\r
443                 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);\r
444                 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);\r
445                 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, CreationParams.WithAlphaChannel ? 8 : 0);\r
446         }\r
447         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, CreationParams.ZBufferBits);\r
448         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, CreationParams.Doublebuffer);\r
449         SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, CreationParams.Stencilbuffer ? 8 : 0);\r
450         SDL_GL_SetAttribute(SDL_GL_STEREO, CreationParams.Stereobuffer);\r
451         if (CreationParams.AntiAlias > 1) {\r
452                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);\r
453                 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, CreationParams.AntiAlias);\r
454         }\r
455         if (!Window)\r
456                 Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_Flags);\r
457         if (!Window) {\r
458                 os::Printer::log("Could not create window...", SDL_GetError(), ELL_WARNING);\r
459         }\r
460         if (!Window && CreationParams.AntiAlias > 1) {\r
461                 while (--CreationParams.AntiAlias > 1) {\r
462                         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, CreationParams.AntiAlias);\r
463                         Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_Flags);\r
464                         if (Window)\r
465                                 break;\r
466                 }\r
467                 if (!Window) {\r
468                         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);\r
469                         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);\r
470                         Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_Flags);\r
471                         if (Window)\r
472                                 os::Printer::log("AntiAliasing disabled due to lack of support!", ELL_WARNING);\r
473                 }\r
474         }\r
475 \r
476         if ( !Window && CreationParams.Doublebuffer)\r
477         {\r
478                 // Try single buffer\r
479                 if (CreationParams.DriverType == video::EDT_OPENGL)\r
480                         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);\r
481                 Window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Width, Height, SDL_Flags);\r
482         }\r
483         if ( !Window )\r
484         {\r
485                 os::Printer::log("Could not initialize display", SDL_GetError(), ELL_ERROR);\r
486                 return false;\r
487         }\r
488 \r
489         Context = SDL_GL_CreateContext(Window);\r
490         if (!Context) {\r
491                 os::Printer::log("Could not initialize context", SDL_GetError(), ELL_ERROR);\r
492                 SDL_DestroyWindow(Window);\r
493                 return false;\r
494         }\r
495 \r
496         return true;\r
497 #endif // !_IRR_EMSCRIPTEN_PLATFORM_\r
498 }\r
499 \r
500 \r
501 //! create the driver\r
502 void CIrrDeviceSDL::createDriver()\r
503 {\r
504         if (CreationParams.DriverType == video::EDT_NULL) {\r
505                 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);\r
506                 return;\r
507         }\r
508 \r
509         ContextManager = new video::CSDLManager(this);\r
510         switch(CreationParams.DriverType)\r
511         {\r
512         case video::EDT_OPENGL: VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); break;\r
513         case video::EDT_OPENGL3: VideoDriver = video::createOpenGL3Driver(CreationParams, FileSystem, ContextManager); break;\r
514         case video::EDT_OGLES2: VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); break;\r
515         case video::EDT_WEBGL1: VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager); break;\r
516         default:;\r
517         }\r
518         if (!VideoDriver)\r
519                 os::Printer::log("Could not create video driver", ELL_ERROR);\r
520 }\r
521 \r
522 \r
523 //! runs the device. Returns false if device wants to be deleted\r
524 bool CIrrDeviceSDL::run()\r
525 {\r
526         os::Timer::tick();\r
527 \r
528         SEvent irrevent;\r
529         SDL_Event SDL_event;\r
530 \r
531         while ( !Close && SDL_PollEvent( &SDL_event ) )\r
532         {\r
533                 // os::Printer::log("event: ", core::stringc((int)SDL_event.type).c_str(),   ELL_INFORMATION);  // just for debugging\r
534 \r
535                 switch ( SDL_event.type )\r
536                 {\r
537                 case SDL_MOUSEMOTION: {\r
538                         SDL_Keymod keymod = SDL_GetModState();\r
539 \r
540                         irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;\r
541                         irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;\r
542                         MouseX = irrevent.MouseInput.X = SDL_event.motion.x;\r
543                         MouseY = irrevent.MouseInput.Y = SDL_event.motion.y;\r
544                         MouseXRel = SDL_event.motion.xrel;\r
545                         MouseYRel = SDL_event.motion.yrel;\r
546                         irrevent.MouseInput.ButtonStates = MouseButtonStates;\r
547                         irrevent.MouseInput.Shift = (keymod & KMOD_SHIFT) != 0;\r
548                         irrevent.MouseInput.Control = (keymod & KMOD_CTRL) != 0;\r
549 \r
550                         postEventFromUser(irrevent);\r
551                         break;\r
552                 }\r
553                 case SDL_MOUSEWHEEL: {\r
554                         SDL_Keymod keymod = SDL_GetModState();\r
555 \r
556                         irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;\r
557                         irrevent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL;\r
558                         irrevent.MouseInput.Wheel = static_cast<float>(SDL_event.wheel.y);\r
559                         irrevent.MouseInput.Shift = (keymod & KMOD_SHIFT) != 0;\r
560                         irrevent.MouseInput.Control = (keymod & KMOD_CTRL) != 0;\r
561                         irrevent.MouseInput.X = MouseX;\r
562                         irrevent.MouseInput.Y = MouseY;\r
563 \r
564                         postEventFromUser(irrevent);\r
565                         break;\r
566                 }\r
567                 case SDL_MOUSEBUTTONDOWN:\r
568                 case SDL_MOUSEBUTTONUP: {\r
569                         SDL_Keymod keymod = SDL_GetModState();\r
570 \r
571                         irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;\r
572                         irrevent.MouseInput.X = SDL_event.button.x;\r
573                         irrevent.MouseInput.Y = SDL_event.button.y;\r
574                         irrevent.MouseInput.Shift = (keymod & KMOD_SHIFT) != 0;\r
575                         irrevent.MouseInput.Control = (keymod & KMOD_CTRL) != 0;\r
576 \r
577                         irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;\r
578 \r
579 \r
580 #ifdef _IRR_EMSCRIPTEN_PLATFORM_\r
581                         // Handle mouselocking in emscripten in Windowed mode.\r
582                         // In fullscreen SDL will handle it.\r
583                         // The behavior we want windowed is - when the canvas was clicked then\r
584                         // we will lock the mouse-pointer if it should be invisible.\r
585                         // For security reasons this will be delayed until the next mouse-up event.\r
586                         // We do not pass on this event as we don't want the activation click to do anything.\r
587                         if ( SDL_event.type == SDL_MOUSEBUTTONDOWN && !isFullscreen() )\r
588                         {\r
589                                 EmscriptenPointerlockChangeEvent pointerlockStatus; // let's hope that test is not expensive ...\r
590                                 if ( emscripten_get_pointerlock_status(&pointerlockStatus) == EMSCRIPTEN_RESULT_SUCCESS )\r
591                                 {\r
592                                         if ( CursorControl->isVisible() && pointerlockStatus.isActive )\r
593                                         {\r
594                                                 emscripten_exit_pointerlock();\r
595                                                 return !Close;\r
596                                         }\r
597                                         else if ( !CursorControl->isVisible() && !pointerlockStatus.isActive )\r
598                                         {\r
599                                                 emscripten_request_pointerlock(0, true);\r
600                                                 return !Close;\r
601                                         }\r
602                                 }\r
603                         }\r
604 #endif\r
605 \r
606                         switch(SDL_event.button.button)\r
607                         {\r
608                         case SDL_BUTTON_LEFT:\r
609                                 if (SDL_event.type == SDL_MOUSEBUTTONDOWN)\r
610                                 {\r
611                                         irrevent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;\r
612                                         MouseButtonStates |= irr::EMBSM_LEFT;\r
613                                 }\r
614                                 else\r
615                                 {\r
616                                         irrevent.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP;\r
617                                         MouseButtonStates &= ~irr::EMBSM_LEFT;\r
618                                 }\r
619                                 break;\r
620 \r
621                         case SDL_BUTTON_RIGHT:\r
622                                 if (SDL_event.type == SDL_MOUSEBUTTONDOWN)\r
623                                 {\r
624                                         irrevent.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN;\r
625                                         MouseButtonStates |= irr::EMBSM_RIGHT;\r
626                                 }\r
627                                 else\r
628                                 {\r
629                                         irrevent.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP;\r
630                                         MouseButtonStates &= ~irr::EMBSM_RIGHT;\r
631                                 }\r
632                                 break;\r
633 \r
634                         case SDL_BUTTON_MIDDLE:\r
635                                 if (SDL_event.type == SDL_MOUSEBUTTONDOWN)\r
636                                 {\r
637                                         irrevent.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN;\r
638                                         MouseButtonStates |= irr::EMBSM_MIDDLE;\r
639                                 }\r
640                                 else\r
641                                 {\r
642                                         irrevent.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP;\r
643                                         MouseButtonStates &= ~irr::EMBSM_MIDDLE;\r
644                                 }\r
645                                 break;\r
646                         }\r
647 \r
648                         irrevent.MouseInput.ButtonStates = MouseButtonStates;\r
649 \r
650                         if (irrevent.MouseInput.Event != irr::EMIE_MOUSE_MOVED)\r
651                         {\r
652                                 postEventFromUser(irrevent);\r
653 \r
654                                 if ( irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN )\r
655                                 {\r
656                                         u32 clicks = checkSuccessiveClicks(irrevent.MouseInput.X, irrevent.MouseInput.Y, irrevent.MouseInput.Event);\r
657                                         if ( clicks == 2 )\r
658                                         {\r
659                                                 irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);\r
660                                                 postEventFromUser(irrevent);\r
661                                         }\r
662                                         else if ( clicks == 3 )\r
663                                         {\r
664                                                 irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);\r
665                                                 postEventFromUser(irrevent);\r
666                                         }\r
667                                 }\r
668                         }\r
669                         break;\r
670                 }\r
671 \r
672                 case SDL_TEXTINPUT:\r
673                         {\r
674                                 irrevent.EventType = irr::EET_STRING_INPUT_EVENT;\r
675                                 irrevent.StringInput.Str = new core::stringw();\r
676                                 irr::core::multibyteToWString(*irrevent.StringInput.Str, SDL_event.text.text);\r
677                                 postEventFromUser(irrevent);\r
678                                 delete irrevent.StringInput.Str;\r
679                                 irrevent.StringInput.Str = NULL;\r
680                         }\r
681                         break;\r
682 \r
683                 case SDL_KEYDOWN:\r
684                 case SDL_KEYUP:\r
685                         {\r
686                                 SKeyMap mp;\r
687                                 mp.SDLKey = SDL_event.key.keysym.sym;\r
688                                 s32 idx = KeyMap.binary_search(mp);\r
689 \r
690                                 EKEY_CODE key;\r
691                                 if (idx == -1)\r
692                                         key = (EKEY_CODE)0;\r
693                                 else\r
694                                         key = (EKEY_CODE)KeyMap[idx].Win32Key;\r
695 \r
696                                 // Make sure to only input special characters if something is in focus, as SDL_TEXTINPUT handles normal unicode already\r
697                                 if (SDL_IsTextInputActive() && !keyIsKnownSpecial(key) && (SDL_event.key.keysym.mod & KMOD_CTRL) == 0)\r
698                                         break;\r
699 \r
700 #ifdef _IRR_WINDOWS_API_\r
701                                 // handle alt+f4 in Windows, because SDL seems not to\r
702                                 if ( (SDL_event.key.keysym.mod & KMOD_LALT) && key == KEY_F4)\r
703                                 {\r
704                                         Close = true;\r
705                                         break;\r
706                                 }\r
707 #endif\r
708                                 irrevent.EventType = irr::EET_KEY_INPUT_EVENT;\r
709                                 irrevent.KeyInput.Key = key;\r
710                                 irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);\r
711                                 irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;\r
712                                 irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL ) != 0;\r
713                                 irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key);\r
714                                 postEventFromUser(irrevent);\r
715                         }\r
716                         break;\r
717 \r
718                 case SDL_QUIT:\r
719                         Close = true;\r
720                         break;\r
721 \r
722                 case SDL_WINDOWEVENT:\r
723                         switch (SDL_event.window.event)\r
724                         {\r
725                         case SDL_WINDOWEVENT_RESIZED:\r
726                                 if ((SDL_event.window.data1 != (int)Width) || (SDL_event.window.data2 != (int)Height))\r
727                                 {\r
728                                         Width = SDL_event.window.data1;\r
729                                         Height = SDL_event.window.data2;\r
730                                         if (VideoDriver)\r
731                                                 VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));\r
732                                 }\r
733                                 break;\r
734                         }\r
735 \r
736                 case SDL_USEREVENT:\r
737                         irrevent.EventType = irr::EET_USER_EVENT;\r
738                         irrevent.UserEvent.UserData1 = reinterpret_cast<uintptr_t>(SDL_event.user.data1);\r
739                         irrevent.UserEvent.UserData2 = reinterpret_cast<uintptr_t>(SDL_event.user.data2);\r
740 \r
741                         postEventFromUser(irrevent);\r
742                         break;\r
743 \r
744                 default:\r
745                         break;\r
746                 } // end switch\r
747         resetReceiveTextInputEvents();\r
748         } // end while\r
749 \r
750 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
751         // TODO: Check if the multiple open/close calls are too expensive, then\r
752         // open/close in the constructor/destructor instead\r
753 \r
754         // update joystick states manually\r
755         SDL_JoystickUpdate();\r
756         // we'll always send joystick input events...\r
757         SEvent joyevent;\r
758         joyevent.EventType = EET_JOYSTICK_INPUT_EVENT;\r
759         for (u32 i=0; i<Joysticks.size(); ++i)\r
760         {\r
761                 SDL_Joystick* joystick = Joysticks[i];\r
762                 if (joystick)\r
763                 {\r
764                         int j;\r
765                         // query all buttons\r
766                         const int numButtons = core::min_(SDL_JoystickNumButtons(joystick), 32);\r
767                         joyevent.JoystickEvent.ButtonStates=0;\r
768                         for (j=0; j<numButtons; ++j)\r
769                                 joyevent.JoystickEvent.ButtonStates |= (SDL_JoystickGetButton(joystick, j)<<j);\r
770 \r
771                         // query all axes, already in correct range\r
772                         const int numAxes = core::min_(SDL_JoystickNumAxes(joystick), (int)SEvent::SJoystickEvent::NUMBER_OF_AXES);\r
773                         joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X]=0;\r
774                         joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y]=0;\r
775                         joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z]=0;\r
776                         joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R]=0;\r
777                         joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U]=0;\r
778                         joyevent.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V]=0;\r
779                         for (j=0; j<numAxes; ++j)\r
780                                 joyevent.JoystickEvent.Axis[j] = SDL_JoystickGetAxis(joystick, j);\r
781 \r
782                         // we can only query one hat, SDL only supports 8 directions\r
783                         if (SDL_JoystickNumHats(joystick)>0)\r
784                         {\r
785                                 switch (SDL_JoystickGetHat(joystick, 0))\r
786                                 {\r
787                                         case SDL_HAT_UP:\r
788                                                 joyevent.JoystickEvent.POV=0;\r
789                                                 break;\r
790                                         case SDL_HAT_RIGHTUP:\r
791                                                 joyevent.JoystickEvent.POV=4500;\r
792                                                 break;\r
793                                         case SDL_HAT_RIGHT:\r
794                                                 joyevent.JoystickEvent.POV=9000;\r
795                                                 break;\r
796                                         case SDL_HAT_RIGHTDOWN:\r
797                                                 joyevent.JoystickEvent.POV=13500;\r
798                                                 break;\r
799                                         case SDL_HAT_DOWN:\r
800                                                 joyevent.JoystickEvent.POV=18000;\r
801                                                 break;\r
802                                         case SDL_HAT_LEFTDOWN:\r
803                                                 joyevent.JoystickEvent.POV=22500;\r
804                                                 break;\r
805                                         case SDL_HAT_LEFT:\r
806                                                 joyevent.JoystickEvent.POV=27000;\r
807                                                 break;\r
808                                         case SDL_HAT_LEFTUP:\r
809                                                 joyevent.JoystickEvent.POV=31500;\r
810                                                 break;\r
811                                         case SDL_HAT_CENTERED:\r
812                                         default:\r
813                                                 joyevent.JoystickEvent.POV=65535;\r
814                                                 break;\r
815                                 }\r
816                         }\r
817                         else\r
818                         {\r
819                                 joyevent.JoystickEvent.POV=65535;\r
820                         }\r
821 \r
822                         // we map the number directly\r
823                         joyevent.JoystickEvent.Joystick=static_cast<u8>(i);\r
824                         // now post the event\r
825                         postEventFromUser(joyevent);\r
826                         // and close the joystick\r
827                 }\r
828         }\r
829 #endif\r
830         return !Close;\r
831 }\r
832 \r
833 //! Activate any joysticks, and generate events for them.\r
834 bool CIrrDeviceSDL::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)\r
835 {\r
836 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
837         joystickInfo.clear();\r
838 \r
839         // we can name up to 256 different joysticks\r
840         const int numJoysticks = core::min_(SDL_NumJoysticks(), 256);\r
841         Joysticks.reallocate(numJoysticks);\r
842         joystickInfo.reallocate(numJoysticks);\r
843 \r
844         int joystick = 0;\r
845         for (; joystick<numJoysticks; ++joystick)\r
846         {\r
847                 Joysticks.push_back( SDL_JoystickOpen(joystick));\r
848                 SJoystickInfo info;\r
849 \r
850                 info.Joystick = joystick;\r
851                 info.Axes = SDL_JoystickNumAxes(Joysticks[joystick]);\r
852                 info.Buttons = SDL_JoystickNumButtons(Joysticks[joystick]);\r
853                 info.Name = SDL_JoystickName(Joysticks[joystick]);\r
854                 info.PovHat = (SDL_JoystickNumHats(Joysticks[joystick]) > 0)\r
855                                                 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;\r
856 \r
857                 joystickInfo.push_back(info);\r
858         }\r
859 \r
860         for(joystick = 0; joystick < (int)joystickInfo.size(); ++joystick)\r
861         {\r
862                 char logString[256];\r
863                 snprintf_irr(logString, sizeof(logString), "Found joystick %d, %d axes, %d buttons '%s'",\r
864                         joystick, joystickInfo[joystick].Axes,\r
865                         joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());\r
866                 os::Printer::log(logString, ELL_INFORMATION);\r
867         }\r
868 \r
869         return true;\r
870 \r
871 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
872 \r
873         return false;\r
874 }\r
875 \r
876 void CIrrDeviceSDL::SwapWindow()\r
877 {\r
878         SDL_GL_SwapWindow(Window);\r
879 }\r
880 \r
881 \r
882 \r
883 //! pause execution temporarily\r
884 void CIrrDeviceSDL::yield()\r
885 {\r
886         SDL_Delay(0);\r
887 }\r
888 \r
889 \r
890 //! pause execution for a specified time\r
891 void CIrrDeviceSDL::sleep(u32 timeMs, bool pauseTimer)\r
892 {\r
893         const bool wasStopped = Timer ? Timer->isStopped() : true;\r
894         if (pauseTimer && !wasStopped)\r
895                 Timer->stop();\r
896 \r
897         SDL_Delay(timeMs);\r
898 \r
899         if (pauseTimer && !wasStopped)\r
900                 Timer->start();\r
901 }\r
902 \r
903 \r
904 //! sets the caption of the window\r
905 void CIrrDeviceSDL::setWindowCaption(const wchar_t* text)\r
906 {\r
907         core::stringc textc;\r
908         core::wStringToMultibyte(textc, text);\r
909         SDL_SetWindowTitle(Window, textc.c_str());\r
910 }\r
911 \r
912 \r
913 //! notifies the device that it should close itself\r
914 void CIrrDeviceSDL::closeDevice()\r
915 {\r
916         Close = true;\r
917 }\r
918 \r
919 \r
920 //! Sets if the window should be resizable in windowed mode.\r
921 void CIrrDeviceSDL::setResizable(bool resize)\r
922 {\r
923 #ifdef _IRR_EMSCRIPTEN_PLATFORM_\r
924         os::Printer::log("Resizable not available on the web." , ELL_WARNING);\r
925         return;\r
926 #else // !_IRR_EMSCRIPTEN_PLATFORM_\r
927         if (resize != Resizable) {\r
928                 if (resize)\r
929                         SDL_Flags |= SDL_WINDOW_RESIZABLE;\r
930                 else\r
931                         SDL_Flags &= ~SDL_WINDOW_RESIZABLE;\r
932 \r
933                 if (Window) {\r
934                         SDL_SetWindowResizable(Window, (SDL_bool)resize);\r
935                 }\r
936                 Resizable = resize;\r
937         }\r
938 #endif // !_IRR_EMSCRIPTEN_PLATFORM_\r
939 }\r
940 \r
941 \r
942 //! Minimizes window if possible\r
943 void CIrrDeviceSDL::minimizeWindow()\r
944 {\r
945         if (Window)\r
946                 SDL_MinimizeWindow(Window);\r
947 }\r
948 \r
949 \r
950 //! Maximize window\r
951 void CIrrDeviceSDL::maximizeWindow()\r
952 {\r
953         if (Window)\r
954                 SDL_MaximizeWindow(Window);\r
955 }\r
956 \r
957 //! Get the position of this window on screen\r
958 core::position2di CIrrDeviceSDL::getWindowPosition()\r
959 {\r
960     return core::position2di(-1, -1);\r
961 }\r
962 \r
963 \r
964 //! Restore original window size\r
965 void CIrrDeviceSDL::restoreWindow()\r
966 {\r
967         if (Window)\r
968                 SDL_RestoreWindow(Window);\r
969 }\r
970 \r
971 bool CIrrDeviceSDL::isWindowMaximized() const\r
972 {\r
973         return Window && (SDL_GetWindowFlags(Window) & SDL_WINDOW_MAXIMIZED) != 0;\r
974 }\r
975 \r
976 bool CIrrDeviceSDL::isFullscreen() const\r
977 {\r
978 #ifdef _IRR_EMSCRIPTEN_PLATFORM_\r
979         return SDL_GetWindowFlags(0) == SDL_WINDOW_FULLSCREEN;\r
980 #else\r
981 \r
982         return CIrrDeviceStub::isFullscreen();\r
983 #endif\r
984 }\r
985 \r
986 \r
987 //! returns if window is active. if not, nothing need to be drawn\r
988 bool CIrrDeviceSDL::isWindowActive() const\r
989 {\r
990 #ifdef _IRR_EMSCRIPTEN_PLATFORM_\r
991         // Hidden test only does something in some browsers (when tab in background or window is minimized)\r
992         // In other browsers code automatically doesn't seem to be called anymore.\r
993         EmscriptenVisibilityChangeEvent emVisibility;\r
994         if ( emscripten_get_visibility_status(&emVisibility) == EMSCRIPTEN_RESULT_SUCCESS)\r
995         {\r
996                 if ( emVisibility.hidden )\r
997                         return false;\r
998         }\r
999 #endif\r
1000         const u32 windowFlags = SDL_GetWindowFlags(Window);\r
1001         return windowFlags & SDL_WINDOW_SHOWN && windowFlags & SDL_WINDOW_INPUT_FOCUS;\r
1002 }\r
1003 \r
1004 \r
1005 //! returns if window has focus.\r
1006 bool CIrrDeviceSDL::isWindowFocused() const\r
1007 {\r
1008         return Window && (SDL_GetWindowFlags(Window) & SDL_WINDOW_INPUT_FOCUS) != 0;\r
1009 }\r
1010 \r
1011 \r
1012 //! returns if window is minimized.\r
1013 bool CIrrDeviceSDL::isWindowMinimized() const\r
1014 {\r
1015         return Window && (SDL_GetWindowFlags(Window) & SDL_WINDOW_MINIMIZED) != 0;\r
1016 }\r
1017 \r
1018 \r
1019 //! returns color format of the window.\r
1020 video::ECOLOR_FORMAT CIrrDeviceSDL::getColorFormat() const\r
1021 {\r
1022         if (Window)\r
1023         {\r
1024                 SDL_Surface *surface = SDL_GetWindowSurface(Window);\r
1025                 if (surface->format->BitsPerPixel == 16)\r
1026                 {\r
1027                         if (surface->format->Amask != 0)\r
1028                                 return video::ECF_A1R5G5B5;\r
1029                         else\r
1030                                 return video::ECF_R5G6B5;\r
1031                 }\r
1032                 else\r
1033                 {\r
1034                         if (surface->format->Amask != 0)\r
1035                                 return video::ECF_A8R8G8B8;\r
1036                         else\r
1037                                 return video::ECF_R8G8B8;\r
1038                 }\r
1039         }\r
1040         else\r
1041                 return CIrrDeviceStub::getColorFormat();\r
1042 }\r
1043 \r
1044 \r
1045 void CIrrDeviceSDL::createKeyMap()\r
1046 {\r
1047         // I don't know if this is the best method  to create\r
1048         // the lookuptable, but I'll leave it like that until\r
1049         // I find a better version.\r
1050 \r
1051         KeyMap.reallocate(105);\r
1052 \r
1053         // buttons missing\r
1054 \r
1055         KeyMap.push_back(SKeyMap(SDLK_BACKSPACE, KEY_BACK));\r
1056         KeyMap.push_back(SKeyMap(SDLK_TAB, KEY_TAB));\r
1057         KeyMap.push_back(SKeyMap(SDLK_CLEAR, KEY_CLEAR));\r
1058         KeyMap.push_back(SKeyMap(SDLK_RETURN, KEY_RETURN));\r
1059 \r
1060         // combined modifiers missing\r
1061 \r
1062         KeyMap.push_back(SKeyMap(SDLK_PAUSE, KEY_PAUSE));\r
1063         KeyMap.push_back(SKeyMap(SDLK_CAPSLOCK, KEY_CAPITAL));\r
1064 \r
1065         // asian letter keys missing\r
1066 \r
1067         KeyMap.push_back(SKeyMap(SDLK_ESCAPE, KEY_ESCAPE));\r
1068 \r
1069         // asian letter keys missing\r
1070 \r
1071         KeyMap.push_back(SKeyMap(SDLK_SPACE, KEY_SPACE));\r
1072         KeyMap.push_back(SKeyMap(SDLK_PAGEUP, KEY_PRIOR));\r
1073         KeyMap.push_back(SKeyMap(SDLK_PAGEDOWN, KEY_NEXT));\r
1074         KeyMap.push_back(SKeyMap(SDLK_END, KEY_END));\r
1075         KeyMap.push_back(SKeyMap(SDLK_HOME, KEY_HOME));\r
1076         KeyMap.push_back(SKeyMap(SDLK_LEFT, KEY_LEFT));\r
1077         KeyMap.push_back(SKeyMap(SDLK_UP, KEY_UP));\r
1078         KeyMap.push_back(SKeyMap(SDLK_RIGHT, KEY_RIGHT));\r
1079         KeyMap.push_back(SKeyMap(SDLK_DOWN, KEY_DOWN));\r
1080 \r
1081         // select missing\r
1082         KeyMap.push_back(SKeyMap(SDLK_PRINTSCREEN, KEY_PRINT));\r
1083         // execute missing\r
1084         KeyMap.push_back(SKeyMap(SDLK_PRINTSCREEN, KEY_SNAPSHOT));\r
1085 \r
1086         KeyMap.push_back(SKeyMap(SDLK_INSERT, KEY_INSERT));\r
1087         KeyMap.push_back(SKeyMap(SDLK_DELETE, KEY_DELETE));\r
1088         KeyMap.push_back(SKeyMap(SDLK_HELP, KEY_HELP));\r
1089 \r
1090         KeyMap.push_back(SKeyMap(SDLK_0, KEY_KEY_0));\r
1091         KeyMap.push_back(SKeyMap(SDLK_1, KEY_KEY_1));\r
1092         KeyMap.push_back(SKeyMap(SDLK_2, KEY_KEY_2));\r
1093         KeyMap.push_back(SKeyMap(SDLK_3, KEY_KEY_3));\r
1094         KeyMap.push_back(SKeyMap(SDLK_4, KEY_KEY_4));\r
1095         KeyMap.push_back(SKeyMap(SDLK_5, KEY_KEY_5));\r
1096         KeyMap.push_back(SKeyMap(SDLK_6, KEY_KEY_6));\r
1097         KeyMap.push_back(SKeyMap(SDLK_7, KEY_KEY_7));\r
1098         KeyMap.push_back(SKeyMap(SDLK_8, KEY_KEY_8));\r
1099         KeyMap.push_back(SKeyMap(SDLK_9, KEY_KEY_9));\r
1100 \r
1101         KeyMap.push_back(SKeyMap(SDLK_a, KEY_KEY_A));\r
1102         KeyMap.push_back(SKeyMap(SDLK_b, KEY_KEY_B));\r
1103         KeyMap.push_back(SKeyMap(SDLK_c, KEY_KEY_C));\r
1104         KeyMap.push_back(SKeyMap(SDLK_d, KEY_KEY_D));\r
1105         KeyMap.push_back(SKeyMap(SDLK_e, KEY_KEY_E));\r
1106         KeyMap.push_back(SKeyMap(SDLK_f, KEY_KEY_F));\r
1107         KeyMap.push_back(SKeyMap(SDLK_g, KEY_KEY_G));\r
1108         KeyMap.push_back(SKeyMap(SDLK_h, KEY_KEY_H));\r
1109         KeyMap.push_back(SKeyMap(SDLK_i, KEY_KEY_I));\r
1110         KeyMap.push_back(SKeyMap(SDLK_j, KEY_KEY_J));\r
1111         KeyMap.push_back(SKeyMap(SDLK_k, KEY_KEY_K));\r
1112         KeyMap.push_back(SKeyMap(SDLK_l, KEY_KEY_L));\r
1113         KeyMap.push_back(SKeyMap(SDLK_m, KEY_KEY_M));\r
1114         KeyMap.push_back(SKeyMap(SDLK_n, KEY_KEY_N));\r
1115         KeyMap.push_back(SKeyMap(SDLK_o, KEY_KEY_O));\r
1116         KeyMap.push_back(SKeyMap(SDLK_p, KEY_KEY_P));\r
1117         KeyMap.push_back(SKeyMap(SDLK_q, KEY_KEY_Q));\r
1118         KeyMap.push_back(SKeyMap(SDLK_r, KEY_KEY_R));\r
1119         KeyMap.push_back(SKeyMap(SDLK_s, KEY_KEY_S));\r
1120         KeyMap.push_back(SKeyMap(SDLK_t, KEY_KEY_T));\r
1121         KeyMap.push_back(SKeyMap(SDLK_u, KEY_KEY_U));\r
1122         KeyMap.push_back(SKeyMap(SDLK_v, KEY_KEY_V));\r
1123         KeyMap.push_back(SKeyMap(SDLK_w, KEY_KEY_W));\r
1124         KeyMap.push_back(SKeyMap(SDLK_x, KEY_KEY_X));\r
1125         KeyMap.push_back(SKeyMap(SDLK_y, KEY_KEY_Y));\r
1126         KeyMap.push_back(SKeyMap(SDLK_z, KEY_KEY_Z));\r
1127 \r
1128         KeyMap.push_back(SKeyMap(SDLK_LGUI, KEY_LWIN));\r
1129         KeyMap.push_back(SKeyMap(SDLK_RGUI, KEY_RWIN));\r
1130         // apps missing\r
1131         KeyMap.push_back(SKeyMap(SDLK_POWER, KEY_SLEEP)); //??\r
1132 \r
1133         KeyMap.push_back(SKeyMap(SDLK_KP_0, KEY_NUMPAD0));\r
1134         KeyMap.push_back(SKeyMap(SDLK_KP_1, KEY_NUMPAD1));\r
1135         KeyMap.push_back(SKeyMap(SDLK_KP_2, KEY_NUMPAD2));\r
1136         KeyMap.push_back(SKeyMap(SDLK_KP_3, KEY_NUMPAD3));\r
1137         KeyMap.push_back(SKeyMap(SDLK_KP_4, KEY_NUMPAD4));\r
1138         KeyMap.push_back(SKeyMap(SDLK_KP_5, KEY_NUMPAD5));\r
1139         KeyMap.push_back(SKeyMap(SDLK_KP_6, KEY_NUMPAD6));\r
1140         KeyMap.push_back(SKeyMap(SDLK_KP_7, KEY_NUMPAD7));\r
1141         KeyMap.push_back(SKeyMap(SDLK_KP_8, KEY_NUMPAD8));\r
1142         KeyMap.push_back(SKeyMap(SDLK_KP_9, KEY_NUMPAD9));\r
1143         KeyMap.push_back(SKeyMap(SDLK_KP_MULTIPLY, KEY_MULTIPLY));\r
1144         KeyMap.push_back(SKeyMap(SDLK_KP_PLUS, KEY_ADD));\r
1145 //      KeyMap.push_back(SKeyMap(SDLK_KP_, KEY_SEPARATOR));\r
1146         KeyMap.push_back(SKeyMap(SDLK_KP_MINUS, KEY_SUBTRACT));\r
1147         KeyMap.push_back(SKeyMap(SDLK_KP_PERIOD, KEY_DECIMAL));\r
1148         KeyMap.push_back(SKeyMap(SDLK_KP_DIVIDE, KEY_DIVIDE));\r
1149 \r
1150         KeyMap.push_back(SKeyMap(SDLK_F1,  KEY_F1));\r
1151         KeyMap.push_back(SKeyMap(SDLK_F2,  KEY_F2));\r
1152         KeyMap.push_back(SKeyMap(SDLK_F3,  KEY_F3));\r
1153         KeyMap.push_back(SKeyMap(SDLK_F4,  KEY_F4));\r
1154         KeyMap.push_back(SKeyMap(SDLK_F5,  KEY_F5));\r
1155         KeyMap.push_back(SKeyMap(SDLK_F6,  KEY_F6));\r
1156         KeyMap.push_back(SKeyMap(SDLK_F7,  KEY_F7));\r
1157         KeyMap.push_back(SKeyMap(SDLK_F8,  KEY_F8));\r
1158         KeyMap.push_back(SKeyMap(SDLK_F9,  KEY_F9));\r
1159         KeyMap.push_back(SKeyMap(SDLK_F10, KEY_F10));\r
1160         KeyMap.push_back(SKeyMap(SDLK_F11, KEY_F11));\r
1161         KeyMap.push_back(SKeyMap(SDLK_F12, KEY_F12));\r
1162         KeyMap.push_back(SKeyMap(SDLK_F13, KEY_F13));\r
1163         KeyMap.push_back(SKeyMap(SDLK_F14, KEY_F14));\r
1164         KeyMap.push_back(SKeyMap(SDLK_F15, KEY_F15));\r
1165         // no higher F-keys\r
1166 \r
1167         KeyMap.push_back(SKeyMap(SDLK_NUMLOCKCLEAR, KEY_NUMLOCK));\r
1168         KeyMap.push_back(SKeyMap(SDLK_SCROLLLOCK, KEY_SCROLL));\r
1169         KeyMap.push_back(SKeyMap(SDLK_LSHIFT, KEY_LSHIFT));\r
1170         KeyMap.push_back(SKeyMap(SDLK_RSHIFT, KEY_RSHIFT));\r
1171         KeyMap.push_back(SKeyMap(SDLK_LCTRL,  KEY_LCONTROL));\r
1172         KeyMap.push_back(SKeyMap(SDLK_RCTRL,  KEY_RCONTROL));\r
1173         KeyMap.push_back(SKeyMap(SDLK_LALT,  KEY_LMENU));\r
1174         KeyMap.push_back(SKeyMap(SDLK_RALT,  KEY_RMENU));\r
1175 \r
1176         KeyMap.push_back(SKeyMap(SDLK_PLUS,   KEY_PLUS));\r
1177         KeyMap.push_back(SKeyMap(SDLK_COMMA,  KEY_COMMA));\r
1178         KeyMap.push_back(SKeyMap(SDLK_MINUS,  KEY_MINUS));\r
1179         KeyMap.push_back(SKeyMap(SDLK_PERIOD, KEY_PERIOD));\r
1180 \r
1181         // some special keys missing\r
1182 \r
1183         KeyMap.sort();\r
1184 }\r
1185 \r
1186 void CIrrDeviceSDL::CCursorControl::initCursors()\r
1187 {\r
1188         Cursors.reserve(gui::ECI_COUNT);\r
1189 \r
1190         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW));     // ECI_NORMAL\r
1191         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR)); // ECI_CROSS\r
1192         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND));      // ECI_HAND\r
1193         Cursors.emplace_back(nullptr);                                             // ECI_HELP\r
1194         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM));     // ECI_IBEAM\r
1195         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO));        // ECI_NO\r
1196         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT));      // ECI_WAIT\r
1197         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL));   // ECI_SIZEALL\r
1198         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW));  // ECI_SIZENESW\r
1199         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE));  // ECI_SIZENWSE\r
1200         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS));    // ECI_SIZENS\r
1201         Cursors.emplace_back(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE));    // ECI_SIZEWE\r
1202         Cursors.emplace_back(nullptr);                                             // ECI_UP\r
1203 }\r
1204 \r
1205 } // end namespace irr\r
1206 \r
1207 #endif // _IRR_COMPILE_WITH_SDL_DEVICE_\r
1208 \r