1 #include <SDL2/SDL.h>
2 #include "video.h"
3 #include "wx-sdl2-video.h"
4 #include "wx-utils.h"
5 #include "ibm.h"
6 #include "wx-display.h"
7 #include "plat-keyboard.h"
8 
9 #ifdef __WINDOWS__
10 #define BITMAP WINDOWS_BITMAP
11 #undef UNICODE
12 #include <windows.h>
13 #include <windowsx.h>
14 #undef BITMAP
15 
16 HHOOK hKeyboardHook;
17 int modkeystate[255];
18 
19 #endif
20 
21 SDL_mutex* rendererMutex;
22 SDL_cond* rendererCond;
23 SDL_Thread* renderthread = NULL;
24 
25 SDL_Window* window = NULL;
26 
27 int rendering = 0;
28 
29 int mousecapture = 0;
30 
31 extern int pause;
32 extern int video_scale;
33 extern int take_screenshot;
34 
35 void* ghwnd;
36 void* menu;
37 
38 SDL_Rect remembered_rect;
39 int remembered_mouse_x = 0;
40 int remembered_mouse_y = 0;
41 
42 int custom_resolution_width = 640;
43 int custom_resolution_height = 480;
44 
45 int win_doresize = 0;
46 int winsizex = 640, winsizey = 480;
47 
48 void renderer_start();
49 void renderer_stop(int timeout);
50 
51 int trigger_fullscreen = 0;
52 int trigger_screenshot = 0;
53 int trigger_togglewindow = 0;
54 int trigger_inputrelease = 0;
55 
56 extern void device_force_redraw();
57 extern void mouse_wheel_update(int);
58 extern void toggle_fullscreen();
59 
display_resize(int width,int height)60 void display_resize(int width, int height)
61 {
62         winsizex = width*(video_scale+1) >> 1;
63         winsizey = height*(video_scale+1) >> 1;
64 
65         SDL_Rect rect;
66         rect.x = rect.y = 0;
67         rect.w = winsizex;
68         rect.h = winsizey;
69         sdl_scale(video_fullscreen_scale, rect, &rect, winsizex, winsizey);
70         winsizex = rect.w;
71         winsizey = rect.h;
72 
73         win_doresize = 1;
74 }
75 
releasemouse()76 void releasemouse()
77 {
78         if (mousecapture)
79         {
80                 SDL_SetWindowGrab(window, SDL_FALSE);
81                 SDL_SetRelativeMouseMode(SDL_FALSE);
82                 mousecapture = 0;
83         }
84 }
85 
display_init()86 int display_init()
87 {
88         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
89         {
90                 printf("SDL could not initialize! Error: %s\n", SDL_GetError());
91                 return 0;
92         }
93 
94         SDL_version ver;
95         SDL_GetVersion(&ver);
96         printf("SDL %i.%i.%i initialized.\n", ver.major, ver.minor, ver.patch);
97         return 1;
98 }
99 
display_close()100 void display_close()
101 {
102         SDL_Quit();
103 }
104 
display_start(void * hwnd)105 void display_start(void* hwnd)
106 {
107         ghwnd = hwnd;
108         menu = wx_getmenu(hwnd);
109         atexit(releasemouse);
110         rendererMutex = SDL_CreateMutex();
111         rendererCond = SDL_CreateCond();
112         renderer_start();
113 }
114 
display_stop()115 void display_stop()
116 {
117         renderer_stop(10 * 1000);
118 
119         SDL_DestroyMutex(rendererMutex);
120         SDL_DestroyCond(rendererCond);
121 #if SDL_VERSION_ATLEAST(2, 0, 2)
122         SDL_DetachThread(renderthread);
123 #endif
124         releasemouse();
125 }
126 
is_fullscreen()127 int is_fullscreen()
128 {
129         int flags = SDL_GetWindowFlags(window);
130         return (flags&SDL_WINDOW_FULLSCREEN) || (flags&SDL_WINDOW_FULLSCREEN_DESKTOP);
131 }
132 
sdl_set_window_title(const char * title)133 void sdl_set_window_title(const char* title) {
134         if (window && !is_fullscreen())
135                 SDL_SetWindowTitle(window, title);
136 }
137 
get_border_size(int * top,int * left,int * bottom,int * right)138 int get_border_size(int* top, int* left, int* bottom, int* right)
139 {
140 #if SDL_VERSION_ATLEAST(2, 0, 5)
141         return SDL_GetWindowBordersSize(window, top, left, bottom, right);
142 #else
143         if (top) *top = 0;
144         if (left) *left = 0;
145         if (bottom) *bottom = 0;
146         if (right) *right = 0;
147         return 0;
148 #endif
149 }
150 
151 static const struct {
152         SDL_Scancode sdl;
153         int system;
154 } SDLScancodeToSystemScancode[] = {
155                 { SDL_SCANCODE_A, 0x1e },
156                 { SDL_SCANCODE_B, 0x30 },
157                 { SDL_SCANCODE_C, 0x2e },
158                 { SDL_SCANCODE_D, 0x20 },
159                 { SDL_SCANCODE_E, 0x12 },
160                 { SDL_SCANCODE_F, 0x21 },
161                 { SDL_SCANCODE_G, 0x22 },
162                 { SDL_SCANCODE_H, 0x23 },
163                 { SDL_SCANCODE_I, 0x17 },
164                 { SDL_SCANCODE_J, 0x24 },
165                 { SDL_SCANCODE_K, 0x25 },
166                 { SDL_SCANCODE_L, 0x26 },
167                 { SDL_SCANCODE_M, 0x32 },
168                 { SDL_SCANCODE_N, 0x31 },
169                 { SDL_SCANCODE_O, 0x18 },
170                 { SDL_SCANCODE_P, 0x19 },
171                 { SDL_SCANCODE_Q, 0x10 },
172                 { SDL_SCANCODE_R, 0x13 },
173                 { SDL_SCANCODE_S, 0x1f },
174                 { SDL_SCANCODE_T, 0x14 },
175                 { SDL_SCANCODE_U, 0x16 },
176                 { SDL_SCANCODE_V, 0x2f },
177                 { SDL_SCANCODE_W, 0x11 },
178                 { SDL_SCANCODE_X, 0x2d },
179                 { SDL_SCANCODE_Y, 0x15 },
180                 { SDL_SCANCODE_Z, 0x2c },
181                 { SDL_SCANCODE_0, 0x0B },
182                 { SDL_SCANCODE_1, 0x02 },
183                 { SDL_SCANCODE_2, 0x03 },
184                 { SDL_SCANCODE_3, 0x04 },
185                 { SDL_SCANCODE_4, 0x05 },
186                 { SDL_SCANCODE_5, 0x06 },
187                 { SDL_SCANCODE_6, 0x07 },
188                 { SDL_SCANCODE_7, 0x08 },
189                 { SDL_SCANCODE_8, 0x09 },
190                 { SDL_SCANCODE_9, 0x0A },
191                 { SDL_SCANCODE_GRAVE, 0x29 },
192                 { SDL_SCANCODE_MINUS, 0x0c },
193                 { SDL_SCANCODE_EQUALS, 0x0d },
194                 { SDL_SCANCODE_NONUSBACKSLASH, 0x56 },
195                 { SDL_SCANCODE_BACKSLASH, 0x2b },
196                 { SDL_SCANCODE_BACKSPACE, 0x0e },
197                 { SDL_SCANCODE_SPACE, 0x39 },
198                 { SDL_SCANCODE_TAB, 0x0f },
199                 { SDL_SCANCODE_CAPSLOCK, 0x3a },
200                 { SDL_SCANCODE_LSHIFT, 0x2a },
201                 { SDL_SCANCODE_LCTRL, 0x1d },
202                 { SDL_SCANCODE_LGUI, 0xdb },
203                 { SDL_SCANCODE_LALT, 0x38 },
204                 { SDL_SCANCODE_RSHIFT, 0x36 },
205                 { SDL_SCANCODE_RCTRL, 0x9d },
206                 { SDL_SCANCODE_RGUI, 0xdc },
207                 { SDL_SCANCODE_RALT, 0xb8 },
208                 { SDL_SCANCODE_SYSREQ, 0x54 },
209                 { SDL_SCANCODE_APPLICATION, 0xdd },
210                 { SDL_SCANCODE_RETURN, 0x1c },
211                 { SDL_SCANCODE_ESCAPE, 0x01 },
212                 { SDL_SCANCODE_F1, 0x3B },
213                 { SDL_SCANCODE_F2, 0x3C },
214                 { SDL_SCANCODE_F3, 0x3D },
215                 { SDL_SCANCODE_F4, 0x3e },
216                 { SDL_SCANCODE_F5, 0x3f },
217                 { SDL_SCANCODE_F6, 0x40 },
218                 { SDL_SCANCODE_F7, 0x41 },
219                 { SDL_SCANCODE_F8, 0x42 },
220                 { SDL_SCANCODE_F9, 0x43 },
221                 { SDL_SCANCODE_F10, 0x44 },
222                 { SDL_SCANCODE_F11, 0x57 },
223                 { SDL_SCANCODE_F12, 0x58 },
224                 { SDL_SCANCODE_SCROLLLOCK, 0x46 },
225                 { SDL_SCANCODE_LEFTBRACKET, 0x1a },
226                 { SDL_SCANCODE_RIGHTBRACKET, 0x1b },
227                 { SDL_SCANCODE_INSERT, 0xd2 },
228                 { SDL_SCANCODE_HOME, 0xc7 },
229                 { SDL_SCANCODE_PAGEUP, 0xc9 },
230                 { SDL_SCANCODE_DELETE, 0xd3 },
231                 { SDL_SCANCODE_END, 0xcf },
232                 { SDL_SCANCODE_PAGEDOWN, 0xd1 },
233                 { SDL_SCANCODE_UP, 0xc8 },
234                 { SDL_SCANCODE_LEFT, 0xcb },
235                 { SDL_SCANCODE_DOWN, 0xd0 },
236                 { SDL_SCANCODE_RIGHT, 0xcd },
237                 { SDL_SCANCODE_NUMLOCKCLEAR, 0x45 },
238                 { SDL_SCANCODE_KP_DIVIDE, 0xb5 },
239                 { SDL_SCANCODE_KP_MULTIPLY, 0x37 },
240                 { SDL_SCANCODE_KP_MINUS, 0x4a },
241                 { SDL_SCANCODE_KP_PLUS, 0x4e },
242                 { SDL_SCANCODE_KP_ENTER, 0x9c },
243                 { SDL_SCANCODE_KP_PERIOD, 0x53 },
244                 { SDL_SCANCODE_KP_0, 0x52 },
245                 { SDL_SCANCODE_KP_1, 0x4f },
246                 { SDL_SCANCODE_KP_2, 0x50 },
247                 { SDL_SCANCODE_KP_3, 0x51 },
248                 { SDL_SCANCODE_KP_4, 0x4b },
249                 { SDL_SCANCODE_KP_5, 0x4c },
250                 { SDL_SCANCODE_KP_6, 0x4d },
251                 { SDL_SCANCODE_KP_7, 0x47 },
252                 { SDL_SCANCODE_KP_8, 0x48 },
253                 { SDL_SCANCODE_KP_9, 0x49 },
254                 { SDL_SCANCODE_SEMICOLON, 0x27 },
255                 { SDL_SCANCODE_APOSTROPHE, 0x28 },
256                 { SDL_SCANCODE_COMMA, 0x33 },
257                 { SDL_SCANCODE_PERIOD, 0x34 },
258                 { SDL_SCANCODE_SLASH, 0x35 },
259                 { SDL_SCANCODE_PRINTSCREEN, 0xb7 }
260 };
261 
sdl_scancode(SDL_Scancode scancode)262 int sdl_scancode(SDL_Scancode scancode)
263 {
264         int i;
265         for (i = 0; i < SDL_arraysize(SDLScancodeToSystemScancode); ++i) {
266                 if (SDLScancodeToSystemScancode[i].sdl == scancode) {
267                         return SDLScancodeToSystemScancode[i].system;
268                 }
269         }
270         return -1;
271 }
272 
273 SDL_Event event;
274 SDL_Rect rect;
275 int border_x, border_y = 0;
276 
277 uint64_t render_time = 0;
278 int render_fps = 0;
279 uint32_t render_frame_time = 0;
280 uint32_t render_frames = 0;
281 
window_setup()282 void window_setup()
283 {
284         SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1");
285 #if SDL_VERSION_ATLEAST(2, 0, 5)
286         SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
287 #endif
288 
289         if (start_in_fullscreen)
290         {
291                 start_in_fullscreen = 0;
292                 window_dofullscreen = 1;
293                 window_doinputgrab = 1;
294         }
295 
296         if (window_remember)
297         {
298                 rect.x = window_x;
299                 rect.y = window_y;
300                 rect.w = window_w;
301                 rect.h = window_h;
302         }
303         else
304         {
305                 rect.x = SDL_WINDOWPOS_CENTERED;
306                 rect.y = SDL_WINDOWPOS_CENTERED;
307                 rect.w = 640;
308                 rect.h = 480;
309         }
310 
311         if (vid_resize == 2)
312         {
313                 rect.w = custom_resolution_width;
314                 rect.h = custom_resolution_height;
315         }
316 }
317 
318 #ifdef __WINDOWS__
sdl_winhook(int code)319 int sdl_winhook(int code)
320 {
321         switch(code)
322         {
323                 case VK_LMENU:
324                         return SDL_SCANCODE_LALT;
325                 case VK_LCONTROL:
326                         return SDL_SCANCODE_LCTRL;
327                 case VK_LWIN:
328                         return SDL_SCANCODE_LGUI;
329                 case VK_LSHIFT:
330                         return SDL_SCANCODE_LSHIFT;
331                 case VK_RMENU:
332                         return SDL_SCANCODE_RALT;
333                 case VK_RCONTROL:
334                         return SDL_SCANCODE_RCTRL;
335                 case VK_RWIN:
336                         return SDL_SCANCODE_RGUI;
337                 case VK_RSHIFT:
338                         return SDL_SCANCODE_RSHIFT;
339         }
340 
341         return -1;
342 }
343 
LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)344 LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
345 {
346         KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
347 
348         int c = p->vkCode;
349 
350         int steal = 0;
351         int s = sdl_winhook(c);
352         if (s != -1)
353         {
354                 int key_state = !(p->flags & LLKHF_UP);
355                 if (abs(modkeystate[c]) != key_state)
356                 {
357                         /* if mousecapture is 0, key_state should be negative */
358                         if (!mousecapture)
359                                 key_state = -key_state;
360                         /* if key_state is 0 and modkeystate[c] is negative,
361                          an sdl_event should not be generated */
362                         if (key_state > 0 || modkeystate[c] > 0)
363                         {
364                                 steal = key_state != 0;
365                                 SDL_Event event;
366                                 event.key.keysym.scancode = s;
367                                 event.key.timestamp = p->time;
368 
369                                 event.type = key_state ? SDL_KEYDOWN : SDL_KEYUP;
370                                 SDL_PushEvent(&event);
371                         }
372                         modkeystate[c] = key_state;
373                 }
374                 if (steal)
375                         return 1;
376         }
377 
378         return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam );
379 }
380 #endif
381 
window_create()382 int window_create()
383 {
384         window = SDL_CreateWindow("PCem Display",
385                         rect.x, rect.y, rect.w, rect.h,
386                         requested_render_driver.sdl_window_params | (vid_resize == 1 ? SDL_WINDOW_RESIZABLE : 0));
387         if (!window)
388         {
389                 char message[200];
390                 sprintf(message,
391                                 "SDL window could not be created! Error: %s\n",
392                                 SDL_GetError());
393                 wx_messagebox(ghwnd, message, "SDL Error", WX_MB_OK);
394                 return 0;
395         }
396 
397 #ifdef __WINDOWS__
398         memset(modkeystate, 0, sizeof(modkeystate));
399         hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,  LowLevelKeyboardProc, GetModuleHandle(NULL), 0);
400 #endif
401 
402         render_time = 0;
403         render_fps = 0;
404         render_frame_time = SDL_GetTicks();
405         render_frames = 0;
406         return 1;
407 }
408 
window_close()409 void window_close()
410 {
411 #ifdef __WINDOWS__
412         UnhookWindowsHookEx( hKeyboardHook );
413 #endif
414 
415         sdl_renderer_close();
416 
417         if (window) {
418                 SDL_GetWindowPosition(window, &rect.x, &rect.y);
419                 SDL_GetWindowSize(window, &rect.w, &rect.h);
420                 get_border_size(&border_y, &border_x, 0, 0);
421                 rect.x -= border_x;
422                 rect.y -= border_y;
423 
424                 SDL_DestroyWindow(window);
425         }
426         window = NULL;
427 }
428 
render()429 int render()
430 {
431         uint64_t start_time = timer_read();
432         uint64_t end_time;
433 
434         if (window_dosetresize)
435         {
436                 window_dosetresize = 0;
437 #if SDL_VERSION_ATLEAST(2, 0, 5)
438                 SDL_GetWindowSize(window, &rect.w, &rect.h);
439                 SDL_SetWindowResizable(window, vid_resize == 1);
440                 SDL_SetWindowSize(window, rect.w, rect.h);
441 #else
442                 window_doreset = 1;
443 #endif
444                 if (vid_resize == 2)
445                         SDL_SetWindowSize(window, custom_resolution_width, custom_resolution_height);
446 
447                 device_force_redraw();
448         }
449         if (window_doreset)
450         {
451                 pclog("window_doreset\n");
452                 window_doreset = 0;
453                 renderer_doreset = 0;
454                 return 0;
455         }
456         if (renderer_doreset)
457         {
458                 pclog("renderer_doreset\n");
459                 renderer_doreset = 0;
460                 sdl_renderer_close();
461                 sdl_renderer_init(window);
462 
463                 device_force_redraw();
464                 video_wait_for_blit();
465         }
466         while(SDL_PollEvent(&event))
467         {
468                 switch (event.type) {
469                 case SDL_MOUSEBUTTONUP:
470                         if (!mousecapture)
471                         {
472                                 if (event.button.button == SDL_BUTTON_LEFT && !pause)
473                                 {
474                                         window_doinputgrab = 1;
475                                         if (video_fullscreen)
476                                                 window_dofullscreen = 1;
477                                 }
478                                 else if (event.button.button == SDL_BUTTON_RIGHT)
479                                         wx_popupmenu(ghwnd, menu, 0, 0);
480 
481                         }
482                         else if (event.button.button == SDL_BUTTON_MIDDLE && !is_fullscreen())
483                                 window_doinputrelease = 1;
484                         break;
485                 case SDL_MOUSEWHEEL:
486                         if (mousecapture) mouse_wheel_update(event.wheel.y);
487                         break;
488                 case SDL_WINDOWEVENT:
489                         if (event.window.event == SDL_WINDOWEVENT_CLOSE)
490                                 wx_stop_emulation(ghwnd);
491                         if (event.window.event == SDL_WINDOWEVENT_RESIZED)
492                                 device_force_redraw();
493                         if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
494                         {
495                                 if (is_fullscreen())
496                                         window_dowindowed = 1;
497                                 window_doinputrelease = 1;
498                         }
499 
500                         if (window_remember)
501                         {
502                                 int flags = SDL_GetWindowFlags(window);
503                                 if (!(flags&SDL_WINDOW_FULLSCREEN) && !(flags&SDL_WINDOW_FULLSCREEN_DESKTOP))
504                                 {
505                                         if (event.window.event == SDL_WINDOWEVENT_MOVED)
506                                         {
507                                                 get_border_size(&border_y, &border_x, 0, 0);
508                                                 window_x = event.window.data1-border_x;
509                                                 window_y = event.window.data2-border_y;
510                                         }
511                                         else if (event.window.event == SDL_WINDOWEVENT_RESIZED)
512                                         {
513                                                 window_w = event.window.data1;
514                                                 window_h = event.window.data2;
515                                         }
516                                         //save_window_pos = 1;
517                                 }
518                         }
519 
520                         break;
521                 case SDL_KEYDOWN:
522                 {
523 #ifdef __WINDOWS__
524                         /* international keyboard workaround */
525                         if (event.key.keysym.scancode == SDL_SCANCODE_RALT &&
526                                         (event.key.keysym.mod&KMOD_LCTRL) &&
527                                         event.key.timestamp == rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)])
528                                 rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] = 0;
529 #endif
530                         int key_idx = sdl_scancode(event.key.keysym.scancode);
531                         if (key_idx != -1)
532                                 rawinputkey[key_idx] = event.key.timestamp;
533                         break;
534                 }
535                 case SDL_KEYUP:
536                 {
537                         int key_idx = sdl_scancode(event.key.keysym.scancode);
538                         if (key_idx != -1)
539                                 rawinputkey[key_idx] = 0;
540                         break;
541                 }
542                 }
543         }
544         if (rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEDOWN)] &&
545                         (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) &&
546                         (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)]))
547                 trigger_fullscreen = 1;
548         else if (trigger_fullscreen)
549         {
550                 trigger_fullscreen = 0;
551                 toggle_fullscreen();
552         }
553         else if (rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEUP)] &&
554                         (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) &&
555                         (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)]))
556                 trigger_screenshot = 1;
557         else if (trigger_screenshot)
558         {
559                 trigger_screenshot = 0;
560                 take_screenshot = 1;
561         }
562         else if (event.key.keysym.scancode == SDL_SCANCODE_END &&
563                         (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]))
564                 trigger_inputrelease = 1;
565         else if (trigger_inputrelease)
566         {
567                 trigger_inputrelease = 0;
568                 if (!is_fullscreen())
569                         window_doinputrelease = 1;
570         }
571         if (window_doremember)
572         {
573                 window_doremember = 0;
574                 SDL_GetWindowPosition(window, &window_x, &window_y);
575                 SDL_GetWindowSize(window, &window_w, &window_h);
576                 get_border_size(&border_y, &border_x, 0, 0);
577                 window_x -= border_x;
578                 window_y -= border_y;
579                 saveconfig(NULL);
580         }
581 
582         if (window_dotogglefullscreen)
583         {
584                 window_dotogglefullscreen = 0;
585                 if (SDL_GetWindowGrab(window) || is_fullscreen())
586                 {
587                         window_doinputrelease = 1;
588                         if (is_fullscreen())
589                                 window_dowindowed = 1;
590                 }
591                 else
592                 {
593                         window_doinputgrab = 1;
594                         window_dofullscreen = 1;
595                 }
596         }
597 
598         if (window_dofullscreen)
599         {
600                 window_dofullscreen = 0;
601                 video_wait_for_blit();
602                 SDL_RaiseWindow(window);
603 #if SDL_VERSION_ATLEAST(2, 0, 4)
604                 SDL_GetGlobalMouseState(&remembered_mouse_x, &remembered_mouse_y);
605 #endif
606                 SDL_GetWindowPosition(window, &remembered_rect.x, &remembered_rect.y);
607                 get_border_size(&border_y, &border_x, 0, 0);
608                 remembered_rect.x -= border_x;
609                 remembered_rect.y -= border_y;
610                 SDL_GetWindowSize(window, &remembered_rect.w, &remembered_rect.h);
611                 SDL_SetWindowFullscreen(window, video_fullscreen_mode == 0 ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN);
612                 device_force_redraw();
613         }
614         if (window_doinputgrab) {
615                 window_doinputgrab = 0;
616                 mousecapture = 1;
617                 SDL_GetRelativeMouseState(0, 0);
618                 SDL_SetWindowGrab(window, SDL_TRUE);
619                 SDL_SetRelativeMouseMode(SDL_TRUE);
620         }
621 
622         if (window_doinputrelease) {
623                 window_doinputrelease = 0;
624                 mousecapture = 0;
625                 SDL_SetWindowGrab(window, SDL_FALSE);
626                 SDL_SetRelativeMouseMode(SDL_FALSE);
627         }
628         if (window_dowindowed)
629         {
630                 window_dowindowed = 0;
631                 SDL_SetWindowFullscreen(window, 0);
632                 SDL_SetWindowSize(window, remembered_rect.w, remembered_rect.h);
633                 SDL_SetWindowPosition(window, remembered_rect.x, remembered_rect.y);
634 #if SDL_VERSION_ATLEAST(2, 0, 4)
635                 SDL_WarpMouseGlobal(remembered_mouse_x, remembered_mouse_y);
636 #endif
637                 device_force_redraw();
638         }
639 
640         if (win_doresize)
641         {
642                 win_doresize = 0;
643                 if (!vid_resize || (flags&SDL_WINDOW_FULLSCREEN)) {
644                         SDL_GetWindowSize(window, &rect.w, &rect.h);
645                         if (rect.w != winsizex || rect.h != winsizey) {
646                                 SDL_GetWindowPosition(window, &rect.x, &rect.y);
647                                 SDL_SetWindowSize(window, winsizex, winsizey);
648                                 SDL_SetWindowPosition(window, rect.x, rect.y);
649                                 device_force_redraw();
650                         }
651                 }
652         }
653 
654         if (sdl_renderer_update(window)) sdl_renderer_present(window);
655 
656         end_time = timer_read();
657         render_time += end_time - start_time;
658 
659         ++render_frames;
660         uint32_t ticks = SDL_GetTicks();
661         if (ticks-render_frame_time >= 1000) {
662                 render_fps = render_frames/((ticks-render_frame_time)/1000.0);
663                 render_frames = 0;
664                 render_frame_time = ticks;
665         }
666 
667         return 1;
668 }
669 
renderer_thread(void * params)670 int renderer_thread(void* params)
671 {
672         int internal_rendering;
673 
674         SDL_LockMutex(rendererMutex);
675         SDL_CondSignal(rendererCond);
676         SDL_UnlockMutex(rendererMutex);
677 
678         window_setup();
679 
680         rendering = 1;
681         while (rendering) {
682 
683                 if (!window_create())
684                         rendering = 0;
685 
686                 renderer_doreset = 1;
687                 internal_rendering = 1;
688                 while (rendering && internal_rendering)
689                 {
690                         if (!render())
691                                 internal_rendering = 0;
692 
693                         SDL_Delay(1);
694                 }
695                 window_close();
696         }
697 
698         SDL_LockMutex(rendererMutex);
699         SDL_CondSignal(rendererCond);
700         SDL_UnlockMutex(rendererMutex);
701 
702         return SDL_TRUE;
703 }
704 
705 void* timer = 0;
706 
render_timer()707 void render_timer()
708 {
709 #ifdef PCEM_RENDER_TIMER_LOOP
710         /* For some reason this while-loop works on OSX, which also fixes missing events. No idea why though. */
711         renderer_thread(0);
712 #else
713         if (rendering && !render())
714         {
715                 window_close();
716                 window_create();
717                 renderer_doreset = 1;
718         }
719 #endif
720 }
721 
render_start_timer()722 void render_start_timer()
723 {
724 #ifdef PCEM_RENDER_TIMER_LOOP
725         timer = wx_createtimer(render_timer);
726         wx_starttimer(timer, 500, 1);
727 #else
728         window_setup();
729         if (window_create())
730         {
731                 rendering = 1;
732                 renderer_doreset = 1;
733                 wx_starttimer(timer, 1, 0);
734         }
735 #endif
736 }
737 
renderer_start()738 void renderer_start()
739 {
740         if (!rendering)
741         {
742 #ifdef PCEM_RENDER_WITH_TIMER
743                 render_start_timer();
744 #else
745                 SDL_LockMutex(rendererMutex);
746                 renderthread = SDL_CreateThread(renderer_thread, "SDL2 Thread", NULL);
747                 SDL_CondWait(rendererCond, rendererMutex);
748                 SDL_UnlockMutex(rendererMutex);
749 #endif
750         }
751 }
752 
renderer_stop(int timeout)753 void renderer_stop(int timeout)
754 {
755 #if defined(PCEM_RENDER_WITH_TIMER) && !defined(PCEM_RENDER_TIMER_LOOP)
756         rendering = 0;
757         window_close();
758         wx_destroytimer(timer);
759 #else
760         if (rendering)
761         {
762                 SDL_LockMutex(rendererMutex);
763                 rendering = 0;
764                 if (timeout)
765                         SDL_CondWaitTimeout(rendererCond, rendererMutex, timeout);
766                 else
767                         SDL_CondWait(rendererCond, rendererMutex);
768                 SDL_UnlockMutex(rendererMutex);
769                 renderthread = NULL;
770         }
771         if (timer)
772         	wx_destroytimer(timer);
773 #endif
774 }
775