1 // SDL interface layer
2 // for the Build Engine
3 // by Jonathon Fowler (jf@jonof.id.au)
4 //
5 // Use SDL2 from http://www.libsdl.org
6
7 /*
8 * Re: SDL surface blit vs renderer.
9 *
10 * Experiments on a Raspberry Pi 3 Model B+ have demonstrated that
11 * there's merit in both 8-bit mode blitting techniques depending on
12 * the Pi's configuration. With the GL driver disabled, the surface blit
13 * path is significantly faster. With the GL driver enabled, the SDL
14 * renderer interface is slightly quicker. However, faster than both is
15 * the forthcoming GLSL 2 blitter. Also, on a Mac Mini G4 with hampered
16 * AGP under Debian 8, surface blit is fast and the renderer slower.
17 */
18 //#define SDLAYER_USE_RENDERER
19
20 // have stdio.h declare vasprintf
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE 1
23 #endif
24
25 #if defined __APPLE__
26 # include <SDL2/SDL.h>
27 #else
28 # include "SDL.h"
29 #endif
30
31 #if (SDL_MAJOR_VERSION != 2)
32 # error This must be built with SDL2
33 #endif
34
35 #include <stdlib.h>
36 #include <math.h>
37
38 #include "build.h"
39 #include "sdlayer.h"
40 #include "cache1d.h"
41 #include "pragmas.h"
42 #include "a.h"
43 #include "osd.h"
44 #include "glbuild.h"
45
46 #if defined(__APPLE__)
47 # include "osxbits.h"
48 #elif defined(HAVE_GTK)
49 # include "gtkbits.h"
50 #else
startwin_open(void)51 int startwin_open(void) { return 0; }
startwin_close(void)52 int startwin_close(void) { return 0; }
startwin_puts(const char * UNUSED (s))53 int startwin_puts(const char *UNUSED(s)) { return 0; }
startwin_idle(void * s)54 int startwin_idle(void *s) { return 0; }
startwin_settitle(const char * s)55 int startwin_settitle(const char *s) { s=s; return 0; }
56 #endif
57
58 // undefine to restrict windowed resolutions to conventional sizes
59 #define ANY_WINDOWED_SIZE
60
61 int _buildargc = 1;
62 const char **_buildargv = NULL;
63
64 char quitevent=0, appactive=1;
65
66 static char apptitle[256] = "Build Engine";
67 static char wintitle[256] = "";
68
69 // video
70 static SDL_Window *sdl_window;
71 #ifdef SDLAYER_USE_RENDERER
72 static SDL_Renderer *sdl_renderer; // For non-GL 8-bit mode output.
73 static SDL_Texture *sdl_texture; // For non-GL 8-bit mode output.
74 #else
75 static SDL_Surface *sdl_surface; // For non-GL 8-bit mode output.
76 #endif
77 static unsigned char *frame;
78 int xres=-1, yres=-1, bpp=0, fullscreen=0, bytesperline, imageSize;
79 intptr_t frameplace=0;
80 char modechange=1;
81 char offscreenrendering=0;
82 char videomodereset = 0;
83 extern int gammabrightness;
84 extern float curgamma;
85
86 #if USE_OPENGL
87 static SDL_GLContext sdl_glcontext;
88 static glbuild8bit gl8bit;
89 static char nogl=0;
90 static int glswapinterval = 1;
91
92 static int set_glswapinterval(const osdfuncparm_t *parm);
93 #endif
94
95 // input
96 int inputdevices=0;
97 char keystatus[256];
98 int keyfifo[KEYFIFOSIZ];
99 unsigned char keyasciififo[KEYFIFOSIZ];
100 int keyfifoplc, keyfifoend;
101 int keyasciififoplc, keyasciififoend;
102 static char keynames[256][24];
103 int mousex=0,mousey=0,mouseb=0;
104 int joyaxis[SDL_CONTROLLER_AXIS_MAX], joyb=0;
105 char joynumaxes=0, joynumbuttons=0;
106 static char mouseacquired=0,moustat=0;
107 static SDL_GameController *controller = NULL;
108
109 void (*keypresscallback)(int,int) = 0;
110 void (*mousepresscallback)(int,int) = 0;
111 void (*joypresscallback)(int,int) = 0;
112
113 struct keytranslate {
114 unsigned char normal;
115 unsigned char controlchar; // an ASCII control character to insert into the character fifo
116 };
117 #define WITH_CONTROL_KEY 0x80
118 static struct keytranslate keytranslation[SDL_NUM_SCANCODES];
119 static int buildkeytranslationtable(void);
120
121 static void shutdownvideo(void);
122
123 #ifndef __APPLE__
124 static SDL_Surface * loadappicon(void);
125 #endif
126
wm_msgbox(const char * name,const char * fmt,...)127 int wm_msgbox(const char *name, const char *fmt, ...)
128 {
129 char *buf = NULL;
130 int rv;
131 va_list va;
132
133 if (!name) {
134 name = apptitle;
135 }
136
137 va_start(va,fmt);
138 rv = vasprintf(&buf,fmt,va);
139 va_end(va);
140
141 if (rv < 0) return -1;
142
143 do {
144 rv = 0;
145
146 #if defined HAVE_GTK
147 if (wmgtk_msgbox(name, buf) >= 0) {
148 rv = 1;
149 break;
150 }
151 #endif
152 if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, name, buf, sdl_window) >= 0) {
153 rv = 1;
154 break;
155 }
156
157 puts(buf);
158 } while(0);
159
160 free(buf);
161
162 return rv;
163 }
164
wm_ynbox(const char * name,const char * fmt,...)165 int wm_ynbox(const char *name, const char *fmt, ...)
166 {
167 char *buf = NULL, ch;
168 int rv;
169 va_list va;
170
171 if (!name) {
172 name = apptitle;
173 }
174
175 va_start(va,fmt);
176 rv = vasprintf(&buf,fmt,va);
177 va_end(va);
178
179 if (rv < 0) return -1;
180
181 SDL_MessageBoxButtonData buttons[2] = {
182 { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Yes" },
183 { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "No" },
184 };
185 SDL_MessageBoxData msgbox = {
186 SDL_MESSAGEBOX_INFORMATION,
187 sdl_window,
188 name,
189 buf,
190 SDL_arraysize(buttons),
191 buttons,
192 NULL
193 };
194
195 do {
196 rv = 0;
197
198 #if defined HAVE_GTK
199 if ((rv = wmgtk_ynbox(name, buf)) >= 0) {
200 break;
201 }
202 #endif
203 if (SDL_ShowMessageBox(&msgbox, &rv) >= 0) {
204 rv = (rv == 1);
205 break;
206 }
207
208 puts(buf);
209 puts(" (assuming 'No')");
210 rv = 0;
211 } while(0);
212
213 free(buf);
214
215 return rv;
216 }
217
wm_filechooser(const char * initialdir,const char * initialfile,const char * type,int foropen,char ** choice)218 int wm_filechooser(const char *initialdir, const char *initialfile, const char *type, int foropen, char **choice)
219 {
220 #if defined __APPLE__ || defined HAVE_GTK
221 int rv;
222 if (mouseacquired && moustat) {
223 SDL_SetRelativeMouseMode(SDL_FALSE);
224 }
225 #if defined __APPLE__
226 rv = wmosx_filechooser(initialdir, initialfile, type, foropen, choice);
227 #elif defined HAVE_GTK
228 rv = wmgtk_filechooser(initialdir, initialfile, type, foropen, choice);
229 #endif
230 SDL_RaiseWindow(sdl_window);
231 if (mouseacquired && moustat) {
232 SDL_SetRelativeMouseMode(SDL_TRUE);
233 }
234 return rv;
235 #endif
236 return -1;
237 }
238
wm_idle(void * ptr)239 int wm_idle(void *ptr)
240 {
241 #if defined HAVE_GTK
242 return wmgtk_idle(ptr);
243 #else
244 (void)ptr;
245 return 0;
246 #endif
247 }
248
wm_setapptitle(const char * name)249 void wm_setapptitle(const char *name)
250 {
251 if (name) {
252 Bstrncpy(apptitle, name, sizeof(apptitle)-1);
253 apptitle[ sizeof(apptitle)-1 ] = 0;
254 }
255 #if defined HAVE_GTK
256 wmgtk_setapptitle(apptitle);
257 #endif
258 }
259
wm_setwindowtitle(const char * name)260 void wm_setwindowtitle(const char *name)
261 {
262 if (name) {
263 Bstrncpy(wintitle, name, sizeof(wintitle)-1);
264 wintitle[ sizeof(wintitle)-1 ] = 0;
265 }
266
267 if (sdl_window) {
268 SDL_SetWindowTitle(sdl_window, wintitle);
269 }
270 }
271
272
273 //
274 //
275 // ---------------------------------------
276 //
277 // System
278 //
279 // ---------------------------------------
280 //
281 //
282
main(int argc,char * argv[])283 int main(int argc, char *argv[])
284 {
285 int r;
286
287 buildkeytranslationtable();
288
289 // SDL must be initialised before GTK or else crashing will ensue.
290 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) {
291 buildprintf("Early initialisation of SDL failed! (%s)\n", SDL_GetError());
292 return 1;
293 }
294
295 #ifdef HAVE_GTK
296 wmgtk_init(&argc, &argv);
297 #endif
298
299 #ifdef __APPLE__
300 // consume Xcode's "-NSDocumentRevisionsDebugMode xx" parameter
301 _buildargv = calloc(argc+1, sizeof(char *));
302 for (r = _buildargc = 0; r < argc; r++) {
303 if (strcmp(argv[r], "-NSDocumentRevisionsDebugMode") == 0) {
304 r++;
305 } else {
306 _buildargv[_buildargc++] = argv[r];
307 }
308 }
309 _buildargv[_buildargc] = 0;
310 #else
311 _buildargc = argc;
312 _buildargv = (const char **)argv;
313 #endif
314
315 startwin_open();
316 baselayer_init();
317
318 // This avoids doubled character input in the (OSX) startup window's edit fields.
319 SDL_EventState(SDL_TEXTINPUT, SDL_IGNORE);
320
321 r = app_main(_buildargc, (char const * const*)_buildargv);
322
323 #ifdef __APPLE__
324 free(_buildargv);
325 #endif
326
327 startwin_close();
328 #ifdef HAVE_GTK
329 wmgtk_exit();
330 #endif
331
332 SDL_Quit();
333
334 return r;
335 }
336
337
338 //
339 // initsystem() -- init SDL systems
340 //
initsystem(void)341 int initsystem(void)
342 {
343 SDL_version linked;
344 SDL_version compiled;
345
346 SDL_GetVersion(&linked);
347 SDL_VERSION(&compiled);
348
349 buildprintf("SDL2 system interface "
350 "(compiled with SDL version %d.%d.%d, runtime version %d.%d.%d)\n",
351 linked.major, linked.minor, linked.patch,
352 compiled.major, compiled.minor, compiled.patch);
353
354 atexit(uninitsystem);
355
356 #if USE_OPENGL
357 if (getenv("BUILD_NOGL")) {
358 buildputs("OpenGL disabled.\n");
359 nogl = 1;
360 } else {
361 nogl = loadgldriver(getenv("BUILD_GLDRV"));
362 if (nogl) {
363 buildputs("Failed loading OpenGL driver. GL modes will be unavailable.\n");
364 }
365 }
366
367 OSD_RegisterFunction("glswapinterval", "glswapinterval: frame swap interval for OpenGL modes (0 = no vsync, max 2)", set_glswapinterval);
368 #endif
369
370 return 0;
371 }
372
373
374 //
375 // uninitsystem() -- uninit SDL systems
376 //
uninitsystem(void)377 void uninitsystem(void)
378 {
379 uninitinput();
380 uninitmouse();
381 uninittimer();
382
383 shutdownvideo();
384 #if USE_OPENGL
385 glbuild_unloadfunctions();
386 unloadgldriver();
387 #endif
388 }
389
390
391 //
392 // initputs() -- prints a string to the intitialization window
393 //
initputs(const char * str)394 void initputs(const char *str)
395 {
396 startwin_puts(str);
397 startwin_idle(NULL);
398 wm_idle(NULL);
399 }
400
401
402 //
403 // debugprintf() -- prints a debug string to stderr
404 //
debugprintf(const char * f,...)405 void debugprintf(const char *f, ...)
406 {
407 #ifdef DEBUGGINGAIDS
408 va_list va;
409
410 va_start(va,f);
411 Bvfprintf(stderr, f, va);
412 va_end(va);
413 #endif
414 }
415
416
417 //
418 //
419 // ---------------------------------------
420 //
421 // All things Input
422 //
423 // ---------------------------------------
424 //
425 //
426
427 //
428 // initinput() -- init input system
429 //
initinput(void)430 int initinput(void)
431 {
432 int i,j;
433
434 inputdevices = 1|2; // keyboard (1) and mouse (2)
435 mouseacquired = 0;
436
437 memset(keynames,0,sizeof(keynames));
438 for (i=0; i<SDL_NUM_SCANCODES; i++) {
439 if (!keytranslation[i].normal) continue;
440 strncpy(keynames[ keytranslation[i].normal ], SDL_GetScancodeName(i), sizeof(keynames[i])-1);
441 }
442
443 if (!SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)) {
444 int flen, fh;
445 char *dbuf = NULL;
446 SDL_RWops *rwops = NULL;
447
448 // Load an available controller mappings file.
449 fh = kopen4load("gamecontrollerdb.txt", 0);
450 if (fh >= 0) {
451 flen = kfilelength(fh);
452 if (flen >= 0) {
453 dbuf = (char *)malloc(flen + 1);
454 }
455 }
456 if (dbuf) {
457 flen = kread(fh, dbuf, flen);
458 dbuf[flen+1] = 0;
459 kclose(fh);
460 if (flen >= 0) {
461 rwops = SDL_RWFromConstMem(dbuf, flen);
462 }
463 }
464 if (rwops) {
465 i = SDL_GameControllerAddMappingsFromRW(rwops, 0);
466 buildprintf("Added %d game controller mappings\n", i);
467 free(dbuf);
468 SDL_free(rwops);
469 }
470
471 // Enumerate game controllers.
472 if (SDL_NumJoysticks() < 1) {
473 buildputs("No game controllers found\n");
474 } else {
475 int numjoysticks = SDL_NumJoysticks();
476 buildputs("Game controllers:\n");
477 for (i = 0; i < numjoysticks; i++) {
478 if (SDL_IsGameController(i)) {
479 buildprintf(" - %s\n", SDL_GameControllerNameForIndex(i));
480 if (!controller) {
481 controller = SDL_GameControllerOpen(i);
482 }
483 }
484 }
485 if (controller) {
486 buildprintf("Using controller %s\n", SDL_GameControllerName(controller));
487
488 inputdevices |= 4;
489 joynumaxes = SDL_CONTROLLER_AXIS_MAX;
490 joynumbuttons = SDL_CONTROLLER_BUTTON_MAX;
491 } else {
492 buildprintf("No controllers are usable\n");
493 }
494 }
495 }
496
497 return 0;
498 }
499
500 //
501 // uninitinput() -- uninit input system
502 //
uninitinput(void)503 void uninitinput(void)
504 {
505 uninitmouse();
506
507 if (controller) {
508 SDL_GameControllerClose(controller);
509 controller = NULL;
510 }
511 }
512
getkeyname(int num)513 const char *getkeyname(int num)
514 {
515 if ((unsigned)num >= 256) return NULL;
516 return keynames[num];
517 }
518
getjoyname(int what,int num)519 const char *getjoyname(int what, int num)
520 {
521 switch (what) {
522 case 0: // axis
523 return SDL_GameControllerGetStringForAxis(num);
524 case 1: // button
525 return SDL_GameControllerGetStringForButton(num);
526 default:
527 return NULL;
528 }
529 }
530
531 //
532 // bgetchar, bkbhit, bflushchars -- character-based input functions
533 //
bgetchar(void)534 unsigned char bgetchar(void)
535 {
536 unsigned char c;
537 if (keyasciififoplc == keyasciififoend) return 0;
538 c = keyasciififo[keyasciififoplc];
539 keyasciififoplc = ((keyasciififoplc+1)&(KEYFIFOSIZ-1));
540 #ifdef __APPLE__
541 if (c == SDL_SCANCODE_DELETE) c = SDL_SCANCODE_BACKSPACE;
542 #endif
543 return c;
544 }
545
bkbhit(void)546 int bkbhit(void)
547 {
548 return (keyasciififoplc != keyasciififoend);
549 }
550
bflushchars(void)551 void bflushchars(void)
552 {
553 keyasciififoplc = keyasciififoend = 0;
554 }
555
556
557 //
558 // set{key|mouse|joy}presscallback() -- sets a callback which gets notified when keys are pressed
559 //
setkeypresscallback(void (* callback)(int,int))560 void setkeypresscallback(void (*callback)(int, int)) { keypresscallback = callback; }
setmousepresscallback(void (* callback)(int,int))561 void setmousepresscallback(void (*callback)(int, int)) { mousepresscallback = callback; }
setjoypresscallback(void (* callback)(int,int))562 void setjoypresscallback(void (*callback)(int, int)) { joypresscallback = callback; }
563
564 //
565 // initmouse() -- init mouse input
566 //
initmouse(void)567 int initmouse(void)
568 {
569 moustat=1;
570 grabmouse(1);
571 return 0;
572 }
573
574 //
575 // uninitmouse() -- uninit mouse input
576 //
uninitmouse(void)577 void uninitmouse(void)
578 {
579 grabmouse(0);
580 moustat=0;
581 }
582
583
584 //
585 // grabmouse() -- show/hide mouse cursor
586 //
grabmouse(int a)587 void grabmouse(int a)
588 {
589 if (appactive && moustat) {
590 if (a != mouseacquired) {
591 SDL_SetRelativeMouseMode(a ? SDL_TRUE : SDL_FALSE);
592 mouseacquired = a;
593 }
594 } else {
595 mouseacquired = a;
596 }
597 mousex = mousey = 0;
598 }
599
600
601 //
602 // readmousexy() -- return mouse motion information
603 //
readmousexy(int * x,int * y)604 void readmousexy(int *x, int *y)
605 {
606 if (!mouseacquired || !appactive || !moustat) { *x = *y = 0; return; }
607 *x = mousex;
608 *y = mousey;
609 mousex = mousey = 0;
610 }
611
612 //
613 // readmousebstatus() -- return mouse button information
614 //
readmousebstatus(int * b)615 void readmousebstatus(int *b)
616 {
617 if (!mouseacquired || !appactive || !moustat) *b = 0;
618 else *b = mouseb;
619 // clear mousewheel events - the game has them now (in *b)
620 // the other mousebuttons are cleared when there's a "button released"
621 // event, but for the mousewheel that doesn't work, as it's released immediately
622 mouseb &= ~(1<<4 | 1<<5);
623 }
624
625 //
626 // releaseallbuttons()
627 //
releaseallbuttons(void)628 void releaseallbuttons(void)
629 {
630 }
631
632
633 //
634 //
635 // ---------------------------------------
636 //
637 // All things Timer
638 // Ken did this
639 //
640 // ---------------------------------------
641 //
642 //
643
644 static Uint64 timerfreq=0;
645 static Uint32 timerlastsample=0;
646 static Uint32 timerticspersec=0;
647 static void (*usertimercallback)(void) = NULL;
648
649 //
650 // inittimer() -- initialise timer
651 //
inittimer(int tickspersecond)652 int inittimer(int tickspersecond)
653 {
654 if (timerfreq) return 0; // already installed
655
656 buildputs("Initialising timer\n");
657
658 timerfreq = SDL_GetPerformanceFrequency();
659 timerticspersec = tickspersecond;
660 timerlastsample = (Uint32)(SDL_GetPerformanceCounter() * timerticspersec / timerfreq);
661
662 usertimercallback = NULL;
663
664 return 0;
665 }
666
667 //
668 // uninittimer() -- shut down timer
669 //
uninittimer(void)670 void uninittimer(void)
671 {
672 if (!timerfreq) return;
673
674 timerfreq=0;
675 }
676
677 //
678 // sampletimer() -- update totalclock
679 //
sampletimer(void)680 void sampletimer(void)
681 {
682 int n;
683
684 if (!timerfreq) return;
685
686 n = (int)(SDL_GetPerformanceCounter() * timerticspersec / timerfreq) - timerlastsample;
687 if (n>0) {
688 totalclock += n;
689 timerlastsample += n;
690 }
691
692 if (usertimercallback) for (; n>0; n--) usertimercallback();
693 }
694
695 //
696 // getticks() -- returns a millisecond ticks count
697 //
getticks(void)698 unsigned int getticks(void)
699 {
700 return (unsigned int)SDL_GetTicks();
701 }
702
703 //
704 // getusecticks() -- returns a microsecond ticks count
705 //
getusecticks(void)706 unsigned int getusecticks(void)
707 {
708 return (unsigned int)SDL_GetTicks() * 1000;
709 }
710
711
712 //
713 // gettimerfreq() -- returns the number of ticks per second the timer is configured to generate
714 //
gettimerfreq(void)715 int gettimerfreq(void)
716 {
717 return timerticspersec;
718 }
719
720
721 //
722 // installusertimercallback() -- set up a callback function to be called when the timer is fired
723 //
installusertimercallback(void (* callback)(void))724 void (*installusertimercallback(void (*callback)(void)))(void)
725 {
726 void (*oldtimercallback)(void);
727
728 oldtimercallback = usertimercallback;
729 usertimercallback = callback;
730
731 return oldtimercallback;
732 }
733
734
735
736 //
737 //
738 // ---------------------------------------
739 //
740 // All things Video
741 //
742 // ---------------------------------------
743 //
744 //
745
746
747 //
748 // getvalidmodes() -- figure out what video modes are available
749 //
sortmodes(const struct validmode_t * a,const struct validmode_t * b)750 static int sortmodes(const struct validmode_t *a, const struct validmode_t *b)
751 {
752 int x;
753
754 if ((x = a->fs - b->fs) != 0) return x;
755 if ((x = a->bpp - b->bpp) != 0) return x;
756 if ((x = a->xdim - b->xdim) != 0) return x;
757 if ((x = a->ydim - b->ydim) != 0) return x;
758
759 return 0;
760 }
761 static char modeschecked=0;
getvalidmodes(void)762 void getvalidmodes(void)
763 {
764 static int defaultres[][2] = {
765 {1920,1200},{1920,1080},{1600,1200},{1680,1050},{1600,900},{1400,1050},{1440,900},{1366,768},
766 {1280,1024},{1280,960},{1280,800},{1280,720},{1152,864},{1024,768},{800,600},{640,480},
767 {640,400},{512,384},{480,360},{400,300},{320,240},{320,200},{0,0}
768 };
769 SDL_DisplayMode mode, desktop;
770 int i, j, maxx=0, maxy=0;
771
772 if (modeschecked) return;
773
774 validmodecnt=0;
775
776 if (SDL_GetNumVideoDisplays() < 1) {
777 buildputs("No video displays available!\n");
778 return;
779 }
780
781 buildputs("Detecting video modes:\n");
782
783 #define ADDMODE(x,y,c,f) if (validmodecnt<MAXVALIDMODES) { \
784 int mn; \
785 for(mn=0;mn<validmodecnt;mn++) \
786 if (validmode[mn].xdim==x && validmode[mn].ydim==y && \
787 validmode[mn].bpp==c && validmode[mn].fs==f) break; \
788 if (mn==validmodecnt) { \
789 validmode[validmodecnt].xdim=x; \
790 validmode[validmodecnt].ydim=y; \
791 validmode[validmodecnt].bpp=c; \
792 validmode[validmodecnt].fs=f; \
793 validmodecnt++; \
794 buildprintf(" - %dx%d %d-bit %s\n", x, y, c, (f&1)?"fullscreen":"windowed"); \
795 } \
796 }
797
798 #define CHECKL(w,h) if ((w < maxx) && (h < maxy))
799 #define CHECKLE(w,h) if ((w <= maxx) && (h <= maxy))
800
801 SDL_GetDesktopDisplayMode(0, &desktop);
802 maxx = desktop.w;
803 maxy = desktop.h;
804
805 // Fullscreen 8-bit modes: upsamples to the desktop mode
806 for (i=0; defaultres[i][0]; i++)
807 CHECKLE(defaultres[i][0],defaultres[i][1])
808 ADDMODE(defaultres[i][0],defaultres[i][1],8,1)
809
810 #if USE_POLYMOST && USE_OPENGL
811 // Fullscreen >8-bit modes
812 if (!nogl) {
813 for (j = SDL_GetNumDisplayModes(0) - 1; j >= 0; j--) {
814 SDL_GetDisplayMode(0, j, &mode);
815 if ((mode.w > MAXXDIM) || (mode.h > MAXYDIM)) continue;
816 if (SDL_BITSPERPIXEL(mode.format) < 8) continue;
817 ADDMODE(mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), 1)
818 }
819 }
820 #endif
821
822 // Windowed 8-bit modes
823 for (i=0; defaultres[i][0]; i++) {
824 CHECKL(defaultres[i][0],defaultres[i][1]) {
825 ADDMODE(defaultres[i][0], defaultres[i][1], 8, 0)
826 }
827 }
828
829 #if USE_POLYMOST && USE_OPENGL
830 // Windowed >8-bit modes
831 if (!nogl) {
832 for (i=0; defaultres[i][0]; i++) {
833 CHECKL(defaultres[i][0],defaultres[i][1]) {
834 ADDMODE(defaultres[i][0], defaultres[i][1], SDL_BITSPERPIXEL(desktop.format), 0)
835 }
836 }
837 }
838 #endif
839
840 #undef CHECK
841 #undef ADDMODE
842
843 qsort((void*)validmode, validmodecnt, sizeof(struct validmode_t), (int(*)(const void*,const void*))sortmodes);
844
845 modeschecked=1;
846 }
847
848
849 //
850 // checkvideomode() -- makes sure the video mode passed is legal
851 //
checkvideomode(int * x,int * y,int c,int fs,int forced)852 int checkvideomode(int *x, int *y, int c, int fs, int forced)
853 {
854 int i, nearest=-1, dx, dy, odx=9999, ody=9999;
855
856 getvalidmodes();
857
858 #if USE_POLYMOST && USE_OPENGL
859 if (c > 8 && nogl) return -1;
860 #else
861 if (c > 8) return -1;
862 #endif
863
864 // fix up the passed resolution values to be multiples of 8
865 // and at least 320x200 or at most MAXXDIMxMAXYDIM
866 if (*x < 320) *x = 320;
867 if (*y < 200) *y = 200;
868 if (*x > MAXXDIM) *x = MAXXDIM;
869 if (*y > MAXYDIM) *y = MAXYDIM;
870 *x &= 0xfffffff8l;
871
872 for (i=0; i<validmodecnt; i++) {
873 if (validmode[i].bpp != c) continue;
874 if (validmode[i].fs != fs) continue;
875 dx = klabs(validmode[i].xdim - *x);
876 dy = klabs(validmode[i].ydim - *y);
877 if (!(dx | dy)) { // perfect match
878 nearest = i;
879 break;
880 }
881 if ((dx <= odx) && (dy <= ody)) {
882 nearest = i;
883 odx = dx; ody = dy;
884 }
885 }
886
887 #ifdef ANY_WINDOWED_SIZE
888 if (!forced && (fs&1) == 0 && (nearest < 0 || (validmode[nearest].xdim!=*x || validmode[nearest].ydim!=*y)))
889 return 0x7fffffffl;
890 #endif
891
892 if (nearest < 0) {
893 // no mode that will match (eg. if no fullscreen modes)
894 return -1;
895 }
896
897 *x = validmode[nearest].xdim;
898 *y = validmode[nearest].ydim;
899
900 return nearest; // JBF 20031206: Returns the mode number
901 }
902
903
shutdownvideo(void)904 static void shutdownvideo(void)
905 {
906 if (frame) {
907 free(frame);
908 frame = NULL;
909 }
910 #if USE_OPENGL
911 if (!nogl) {
912 glbuild_delete_8bit_shader(&gl8bit);
913 }
914 if (sdl_glcontext) {
915 #if USE_POLYMOST
916 polymost_glreset();
917 #endif
918
919 SDL_GL_DeleteContext(sdl_glcontext);
920 sdl_glcontext = NULL;
921 }
922 #endif
923 #ifdef SDLAYER_USE_RENDERER
924 if (sdl_texture) {
925 SDL_DestroyTexture(sdl_texture);
926 sdl_texture = NULL;
927 }
928 if (sdl_renderer) {
929 SDL_DestroyRenderer(sdl_renderer);
930 sdl_renderer = NULL;
931 }
932 #else
933 if (sdl_surface) {
934 SDL_FreeSurface(sdl_surface);
935 sdl_surface = NULL;
936 }
937 #endif
938 if (sdl_window) {
939 SDL_DestroyWindow(sdl_window);
940 sdl_window = NULL;
941 }
942 }
943
944 //
945 // setvideomode() -- set SDL video mode
946 //
setvideomode(int x,int y,int c,int fs)947 int setvideomode(int x, int y, int c, int fs)
948 {
949 int modenum, regrab = 0;
950 int flags;
951
952 if ((fs == fullscreen) && (x == xres) && (y == yres) && (c == bpp) &&
953 !videomodereset) {
954 OSD_ResizeDisplay(xres,yres);
955 return 0;
956 }
957
958 if (checkvideomode(&x,&y,c,fs,0) < 0) return -1; // Will return if GL mode not available.
959
960 if (mouseacquired) {
961 regrab = 1;
962 grabmouse(0);
963 }
964
965 shutdownvideo();
966
967 buildprintf("Setting video mode %dx%d (%d-bpp %s)\n", x,y,c,
968 (fs & 1) ? "fullscreen" : "windowed");
969
970 do {
971 flags = SDL_WINDOW_HIDDEN;
972
973 #if USE_OPENGL
974 if (!nogl) {
975 #if (USE_OPENGL == USE_GLES2)
976 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
977 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
978 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
979 #elif (USE_OPENGL == USE_GL3)
980 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
981 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
982 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
983 #else
984 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
985 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
986 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
987 #endif
988
989 SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
990 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
991 #if USE_POLYMOST
992 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, glmultisample > 0);
993 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, glmultisample);
994 #endif
995
996 flags |= SDL_WINDOW_OPENGL;
997 }
998 #endif
999
1000 if (fs & 1) {
1001 if (c > 8) flags |= SDL_WINDOW_FULLSCREEN;
1002 else flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
1003 }
1004
1005 sdl_window = SDL_CreateWindow(wintitle, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, x, y, flags);
1006 if (!sdl_window) {
1007 buildprintf("Error creating window: %s\n", SDL_GetError());
1008
1009 #if USE_POLYMOST && USE_OPENGL
1010 if (glmultisample > 0) {
1011 buildprintf("Retrying without multisampling.\n");
1012 glmultisample = 0;
1013 continue;
1014 }
1015 #endif
1016
1017 return -1;
1018 }
1019 break;
1020 } while (1);
1021
1022 #ifndef __APPLE__
1023 {
1024 SDL_Surface *icon = loadappicon();
1025 SDL_SetWindowIcon(sdl_window, icon);
1026 SDL_FreeSurface(icon);
1027 }
1028 #endif
1029
1030 if (c == 8) {
1031 int i, j, pitch;
1032
1033 // Round up to a multiple of 4.
1034 pitch = (((x|1) + 4) & ~3);
1035
1036 #if USE_OPENGL
1037 if (nogl) {
1038 #endif
1039 #ifdef SDLAYER_USE_RENDERER
1040 // 8-bit software with no GL shader blitting goes via the SDL rendering apparatus.
1041 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
1042
1043 sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_PRESENTVSYNC);
1044 if (!sdl_renderer) {
1045 buildprintf("Error creating renderer: %s\n", SDL_GetError());
1046 return -1;
1047 }
1048 SDL_RenderSetLogicalSize(sdl_renderer, x, y);
1049 SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
1050 SDL_RenderClear(sdl_renderer);
1051
1052 sdl_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, x, y);
1053 if (!sdl_texture) {
1054 buildprintf("Error creating texture: %s\n", SDL_GetError());
1055 return -1;
1056 }
1057 #else
1058 // 8-bit software with no GL shader blitting goes via the SDL rendering apparatus.
1059 sdl_surface = SDL_CreateRGBSurface(0, x, y, 8, 0, 0, 0, 0);
1060 if (!sdl_surface) {
1061 buildprintf("Error creating surface: %s\n", SDL_GetError());
1062 return -1;
1063 }
1064 #endif
1065 #if USE_OPENGL
1066 } else {
1067 // Prepare the GLSL shader for 8-bit blitting.
1068 sdl_glcontext = SDL_GL_CreateContext(sdl_window);
1069 if (!sdl_glcontext) {
1070 buildprintf("Error creating OpenGL context: %s\n", SDL_GetError());
1071 nogl = 1;
1072 } else if (baselayer_setupopengl()) {
1073 nogl = 1;
1074 } else if (glbuild_prepare_8bit_shader(&gl8bit, x, y, pitch) < 0) {
1075 nogl = 1;
1076 }
1077 if (nogl) {
1078 // Try again but without OpenGL.
1079 buildputs("Falling back to non-OpenGL render.\n");
1080 return setvideomode(x, y, c, fs);
1081 }
1082 }
1083 #endif
1084
1085 frame = (unsigned char *) malloc(pitch * y);
1086 if (!frame) {
1087 buildputs("Unable to allocate framebuffer\n");
1088 return -1;
1089 }
1090
1091 frameplace = (intptr_t) frame;
1092 bytesperline = pitch;
1093 imageSize = bytesperline * y;
1094 numpages = 1;
1095
1096 setvlinebpl(bytesperline);
1097 for (i = j = 0; i <= y; i++) {
1098 ylookup[i] = j;
1099 j += bytesperline;
1100 }
1101
1102 } else {
1103 #if USE_OPENGL
1104 sdl_glcontext = SDL_GL_CreateContext(sdl_window);
1105 if (!sdl_glcontext) {
1106 buildprintf("Error creating OpenGL context: %s\n", SDL_GetError());
1107 return -1;
1108 }
1109
1110 if (baselayer_setupopengl()) {
1111 shutdownvideo();
1112 return -1;
1113 }
1114 #if USE_POLYMOST
1115 polymost_glreset();
1116 #endif
1117
1118 frameplace = 0;
1119 bytesperline = 0;
1120 imageSize = 0;
1121 numpages = 127;
1122 #else
1123 return -1;
1124 #endif
1125 }
1126
1127 SDL_ShowWindow(sdl_window);
1128
1129 xres = x;
1130 yres = y;
1131 bpp = c;
1132 fullscreen = fs;
1133 modechange = 1;
1134 videomodereset = 0;
1135 OSD_ResizeDisplay(xres,yres);
1136 #if USE_OPENGL
1137 if (sdl_glcontext) {
1138 if (SDL_GL_SetSwapInterval(glswapinterval) < 0) {
1139 buildputs("note: OpenGL swap interval could not be changed\n");
1140 }
1141 }
1142 #endif
1143
1144 gammabrightness = (SDL_SetWindowBrightness(sdl_window, curgamma) == 0);
1145
1146 // setpalettefade will set the palette according to whether gamma worked
1147 setpalettefade(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta);
1148
1149 if (regrab) grabmouse(1);
1150
1151 startwin_close();
1152
1153 // Start listening for character input.
1154 SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE);
1155
1156 return 0;
1157 }
1158
1159
1160 //
1161 // resetvideomode() -- resets the video system
1162 //
resetvideomode(void)1163 void resetvideomode(void)
1164 {
1165 videomodereset = 1;
1166 modeschecked = 0;
1167 }
1168
1169
1170 //
1171 // begindrawing() -- locks the framebuffer for drawing
1172 //
begindrawing(void)1173 void begindrawing(void)
1174 {
1175 }
1176
1177
1178 //
1179 // enddrawing() -- unlocks the framebuffer
1180 //
enddrawing(void)1181 void enddrawing(void)
1182 {
1183 }
1184
1185
1186 //
1187 // showframe() -- update the display
1188 //
showframe(void)1189 void showframe(void)
1190 {
1191 int i,j;
1192
1193 #if USE_OPENGL
1194 if (!nogl) {
1195 if (bpp == 8) {
1196 glbuild_update_8bit_frame(&gl8bit, frame, xres, yres, bytesperline);
1197 glbuild_draw_8bit_frame(&gl8bit);
1198 }
1199
1200 SDL_GL_SwapWindow(sdl_window);
1201 return;
1202 }
1203 #endif
1204
1205 unsigned char *pixels, *in;
1206 int pitch, y, x;
1207
1208 #ifdef SDLAYER_USE_RENDERER
1209 if (SDL_LockTexture(sdl_texture, NULL, (void**)&pixels, &pitch)) {
1210 debugprintf("Could not lock texture: %s\n", SDL_GetError());
1211 return;
1212 }
1213
1214 in = frame;
1215 for (y = yres - 1; y >= 0; y--) {
1216 for (x = xres - 1; x >= 0; x--) {
1217 #if B_LITTLE_ENDIAN
1218 // RGBA -> BGRA, ignoring A
1219 /*
1220 pixels[(x<<2)+0] = curpalettefaded[in[x]].b;
1221 pixels[(x<<2)+1] = curpalettefaded[in[x]].g;
1222 pixels[(x<<2)+2] = curpalettefaded[in[x]].r;
1223 pixels[(x<<2)+3] = 0;
1224 */
1225 ((unsigned int *)pixels)[x] = B_SWAP32(*(unsigned int *)&curpalettefaded[in[x]]) >> 8;
1226 #else
1227 pixels[(x<<2)+0] = 0;
1228 pixels[(x<<2)+1] = curpalettefaded[in[x]].r;
1229 pixels[(x<<2)+2] = curpalettefaded[in[x]].g;
1230 pixels[(x<<2)+3] = curpalettefaded[in[x]].b;
1231 #endif
1232 }
1233 pixels += pitch;
1234 in += bytesperline;
1235 }
1236
1237 SDL_UnlockTexture(sdl_texture);
1238 if (SDL_RenderCopy(sdl_renderer, sdl_texture, NULL, NULL)) {
1239 debugprintf("Could not copy render texture: %s\n", SDL_GetError());
1240 }
1241 SDL_RenderPresent(sdl_renderer);
1242
1243 #else //SDLAYER_USE_RENDERER
1244 SDL_Surface *winsurface;
1245
1246 if (SDL_LockSurface(sdl_surface)) {
1247 debugprintf("Could not lock surface: %s\n", SDL_GetError());
1248 return;
1249 }
1250 pixels = (unsigned char *)sdl_surface->pixels;
1251 pitch = sdl_surface->pitch;
1252
1253 in = frame;
1254 for (y = yres - 1; y >= 0; y--) {
1255 memcpy(pixels, in, xres);
1256 pixels += pitch;
1257 in += bytesperline;
1258 }
1259
1260 SDL_UnlockSurface(sdl_surface);
1261
1262 winsurface = SDL_GetWindowSurface(sdl_window);
1263 if (!winsurface) {
1264 debugprintf("Could not get window surface: %s\n", SDL_GetError());
1265 return;
1266 }
1267 SDL_BlitSurface(sdl_surface, NULL, winsurface, NULL);
1268 SDL_UpdateWindowSurface(sdl_window);
1269 #endif //SDLAYER_USE_RENDERER
1270 }
1271
1272
1273 //
1274 // setpalette() -- set palette values
1275 //
setpalette(int UNUSED (start),int UNUSED (num),unsigned char * UNUSED (dapal))1276 int setpalette(int UNUSED(start), int UNUSED(num), unsigned char * UNUSED(dapal))
1277 {
1278 #if USE_OPENGL
1279 if (!nogl) {
1280 glbuild_update_8bit_palette(&gl8bit, curpalettefaded);
1281 }
1282 #endif
1283 #ifndef SDLAYER_USE_RENDERER
1284 if (sdl_surface) {
1285 if (SDL_SetPaletteColors(sdl_surface->format->palette, (const SDL_Color *)curpalettefaded, 0, 256)) {
1286 debugprintf("Could not set palette: %s\n", SDL_GetError());
1287 }
1288 }
1289 #endif
1290 return 0;
1291 }
1292
1293 //
1294 // setgamma
1295 //
setgamma(float gamma)1296 int setgamma(float gamma)
1297 {
1298 if (sdl_window) {
1299 return SDL_SetWindowBrightness(sdl_window, gamma) == 0;
1300 }
1301 return 0;
1302 }
1303
1304
1305 #if USE_OPENGL
1306 //
1307 // loadgldriver -- loads an OpenGL DLL
1308 //
loadgldriver(const char * soname)1309 int loadgldriver(const char *soname)
1310 {
1311 const char *name = soname;
1312 if (!name) {
1313 name = "system OpenGL library";
1314 }
1315
1316 buildprintf("Loading %s\n", name);
1317 if (SDL_GL_LoadLibrary(soname)) return -1;
1318 return 0;
1319 }
1320
unloadgldriver(void)1321 int unloadgldriver(void)
1322 {
1323 SDL_GL_UnloadLibrary();
1324 return 0;
1325 }
1326
1327 //
1328 // getglprocaddress
1329 //
getglprocaddress(const char * name,int UNUSED (ext))1330 void *getglprocaddress(const char *name, int UNUSED(ext))
1331 {
1332 return (void*)SDL_GL_GetProcAddress(name);
1333 }
1334 #endif
1335
1336
1337 #ifndef __APPLE__
1338 extern struct sdlappicon sdlappicon;
loadappicon(void)1339 static SDL_Surface * loadappicon(void)
1340 {
1341 SDL_Surface *surf;
1342
1343 surf = SDL_CreateRGBSurfaceFrom((void*)sdlappicon.pixels,
1344 sdlappicon.width, sdlappicon.height, 32, sdlappicon.width*4,
1345 0xffl,0xff00l,0xff0000l,0xff000000l);
1346
1347 return surf;
1348 }
1349 #endif
1350
1351 //
1352 //
1353 // ---------------------------------------
1354 //
1355 // Miscellany
1356 //
1357 // ---------------------------------------
1358 //
1359 //
1360
1361
1362 //
1363 // handleevents() -- process the SDL message queue
1364 // returns !0 if there was an important event worth checking (like quitting)
1365 //
handleevents(void)1366 int handleevents(void)
1367 {
1368 int code, rv=0, j, control;
1369 SDL_Event ev;
1370 static int firstcall = 1;
1371 int eattextinput = 0;
1372
1373 #define SetKey(key,state) { \
1374 keystatus[key] = state; \
1375 if (state) { \
1376 keyfifo[keyfifoend] = key; \
1377 keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = state; \
1378 keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); \
1379 } \
1380 }
1381
1382 while (SDL_PollEvent(&ev)) {
1383 switch (ev.type) {
1384 case SDL_TEXTINPUT:
1385 if (eattextinput) {
1386 eattextinput = 0;
1387 break;
1388 }
1389 for (j = 0; j < SDL_TEXTINPUTEVENT_TEXT_SIZE && ev.text.text[j]; j++) {
1390 if (ev.text.text[j] & 0x80) {
1391 continue; // UTF8 character byte
1392 }
1393 code = ev.text.text[j];
1394 if (OSD_HandleChar(code)) {
1395 if (((keyasciififoend+1)&(KEYFIFOSIZ-1)) != keyasciififoplc) {
1396 keyasciififo[keyasciififoend] = code;
1397 keyasciififoend = ((keyasciififoend+1)&(KEYFIFOSIZ-1));
1398 }
1399 }
1400 }
1401 break;
1402
1403 case SDL_KEYUP:
1404 // (un)grab mouse with ctrl-g
1405 if (ev.key.keysym.sym == SDLK_g
1406 && (ev.key.keysym.mod & KMOD_CTRL)) {
1407 grabmouse(!mouseacquired);
1408 break;
1409 }
1410 // else: fallthrough
1411 case SDL_KEYDOWN:
1412 code = keytranslation[ev.key.keysym.scancode].normal;
1413 control = keytranslation[ev.key.keysym.scancode].controlchar;
1414
1415 if (control && ev.key.type == SDL_KEYDOWN) {
1416 int needcontrol = (control & WITH_CONTROL_KEY) == WITH_CONTROL_KEY;
1417 int mod = ev.key.keysym.mod & ~(KMOD_CAPS|KMOD_NUM);
1418 control &= ~WITH_CONTROL_KEY;
1419
1420 // May need to insert a control character into the ascii input
1421 // FIFO depending on what the state of the control keys are.
1422 if ((needcontrol && mod && (mod & KMOD_CTRL) == mod) ||
1423 (!needcontrol && (mod == KMOD_NONE))) {
1424 if (OSD_HandleChar(control)) {
1425 if (((keyasciififoend+1)&(KEYFIFOSIZ-1)) != keyasciififoplc) {
1426 keyasciififo[keyasciififoend] = control;
1427 keyasciififoend = ((keyasciififoend+1)&(KEYFIFOSIZ-1));
1428 }
1429 }
1430 }
1431 }
1432
1433 // hook in the osd
1434 if (code == OSD_CaptureKey(-1)) {
1435 if (ev.key.type == SDL_KEYDOWN) {
1436 // The character produced by the OSD toggle key needs to be ignored.
1437 eattextinput = 1;
1438
1439 OSD_ShowDisplay(-1);
1440 }
1441 break;
1442 } else if (OSD_HandleKey(code, (ev.key.type == SDL_KEYDOWN)) == 0)
1443 break;
1444
1445 if (ev.key.type == SDL_KEYDOWN) {
1446 if (!keystatus[code]) {
1447 SetKey(code, 1);
1448 if (keypresscallback)
1449 keypresscallback(code, 1);
1450 }
1451 } else {
1452 SetKey(code, 0);
1453 if (keypresscallback)
1454 keypresscallback(code, 0);
1455 }
1456 break;
1457
1458 case SDL_WINDOWEVENT:
1459 if (ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED ||
1460 ev.window.event == SDL_WINDOWEVENT_FOCUS_LOST) {
1461 appactive = ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED;
1462 if (mouseacquired && moustat) {
1463 SDL_SetRelativeMouseMode(appactive ? SDL_TRUE : SDL_FALSE);
1464 }
1465 rv=-1;
1466 }
1467 break;
1468
1469 case SDL_MOUSEBUTTONDOWN:
1470 case SDL_MOUSEBUTTONUP:
1471 switch (ev.button.button) {
1472 case SDL_BUTTON_LEFT: j = 0; break;
1473 case SDL_BUTTON_RIGHT: j = 1; break;
1474 case SDL_BUTTON_MIDDLE: j = 2; break;
1475 default: j = -1; break;
1476 }
1477 if (j<0) break;
1478
1479 if (ev.button.state == SDL_PRESSED)
1480 mouseb |= (1<<j);
1481 else
1482 mouseb &= ~(1<<j);
1483
1484 if (mousepresscallback)
1485 mousepresscallback(j+1, ev.button.state == SDL_PRESSED);
1486 break;
1487
1488 case SDL_MOUSEWHEEL:
1489 if (ev.wheel.y > 0) { // Up
1490 j = 5;
1491 } else if (ev.wheel.y < 0) { // Down
1492 j = 4;
1493 } else {
1494 break;
1495 }
1496 mouseb |= 1<<j;
1497 // 'release' is done in readmousebstatus()
1498 if (mousepresscallback) {
1499 mousepresscallback(j+1, 1);
1500 mousepresscallback(j+1, 0);
1501 }
1502 break;
1503
1504 case SDL_MOUSEMOTION:
1505 if (!firstcall) {
1506 if (appactive) {
1507 mousex += ev.motion.xrel;
1508 mousey += ev.motion.yrel;
1509 }
1510 }
1511 break;
1512
1513 case SDL_CONTROLLERAXISMOTION:
1514 if (appactive) {
1515 joyaxis[ ev.caxis.axis ] = ev.caxis.value;
1516 }
1517 break;
1518
1519 case SDL_CONTROLLERBUTTONDOWN:
1520 case SDL_CONTROLLERBUTTONUP:
1521 if (appactive) {
1522 if (ev.cbutton.state == SDL_PRESSED)
1523 joyb |= 1 << ev.cbutton.button;
1524 else
1525 joyb &= ~(1 << ev.cbutton.button);
1526 }
1527 break;
1528
1529 case SDL_QUIT:
1530 quitevent = 1;
1531 rv=-1;
1532 break;
1533
1534 default:
1535 //buildprintf("Got event (%d)\n", ev.type);
1536 break;
1537 }
1538 }
1539
1540 sampletimer();
1541 startwin_idle(NULL);
1542 wm_idle(NULL);
1543 #undef SetKey
1544
1545 firstcall = 0;
1546
1547 return rv;
1548 }
1549
1550
buildkeytranslationtable(void)1551 static int buildkeytranslationtable(void)
1552 {
1553 memset(keytranslation,0,sizeof(keytranslation));
1554
1555 #define MAP(x,y) keytranslation[x].normal = y
1556 #define MAPC(x,y,c) keytranslation[x].normal = y, keytranslation[x].controlchar = c
1557
1558 MAPC(SDL_SCANCODE_BACKSPACE, 0xe, 0x8);
1559 MAPC(SDL_SCANCODE_TAB, 0xf, 0x9);
1560 MAPC(SDL_SCANCODE_RETURN, 0x1c, 0xd);
1561 MAP(SDL_SCANCODE_PAUSE, 0x59); // 0x1d + 0x45 + 0x9d + 0xc5
1562 MAPC(SDL_SCANCODE_ESCAPE, 0x1, 0x1b);
1563 MAP(SDL_SCANCODE_SPACE, 0x39);
1564 MAP(SDL_SCANCODE_APOSTROPHE, 0x28);
1565 MAP(SDL_SCANCODE_COMMA, 0x33);
1566 MAP(SDL_SCANCODE_MINUS, 0xc);
1567 MAP(SDL_SCANCODE_PERIOD, 0x34);
1568 MAP(SDL_SCANCODE_SLASH, 0x35);
1569 MAP(SDL_SCANCODE_0, 0xb);
1570 MAP(SDL_SCANCODE_1, 0x2);
1571 MAP(SDL_SCANCODE_2, 0x3);
1572 MAP(SDL_SCANCODE_3, 0x4);
1573 MAP(SDL_SCANCODE_4, 0x5);
1574 MAP(SDL_SCANCODE_5, 0x6);
1575 MAP(SDL_SCANCODE_6, 0x7);
1576 MAP(SDL_SCANCODE_7, 0x8);
1577 MAP(SDL_SCANCODE_8, 0x9);
1578 MAP(SDL_SCANCODE_9, 0xa);
1579 MAP(SDL_SCANCODE_SEMICOLON, 0x27);
1580 MAP(SDL_SCANCODE_EQUALS, 0xd);
1581 MAPC(SDL_SCANCODE_LEFTBRACKET, 0x1a, 0x1b | WITH_CONTROL_KEY);
1582 MAPC(SDL_SCANCODE_BACKSLASH, 0x2b, 0x1c | WITH_CONTROL_KEY);
1583 MAPC(SDL_SCANCODE_RIGHTBRACKET, 0x1b, 0x1d | WITH_CONTROL_KEY);
1584 MAP(SDL_SCANCODE_GRAVE, 0x29);
1585 MAPC(SDL_SCANCODE_A, 0x1e, 0x1 | WITH_CONTROL_KEY);
1586 MAPC(SDL_SCANCODE_B, 0x30, 0x2 | WITH_CONTROL_KEY);
1587 MAPC(SDL_SCANCODE_C, 0x2e, 0x3 | WITH_CONTROL_KEY);
1588 MAPC(SDL_SCANCODE_D, 0x20, 0x4 | WITH_CONTROL_KEY);
1589 MAPC(SDL_SCANCODE_E, 0x12, 0x5 | WITH_CONTROL_KEY);
1590 MAPC(SDL_SCANCODE_F, 0x21, 0x6 | WITH_CONTROL_KEY);
1591 MAPC(SDL_SCANCODE_G, 0x22, 0x7 | WITH_CONTROL_KEY);
1592 MAPC(SDL_SCANCODE_H, 0x23, 0x8 | WITH_CONTROL_KEY);
1593 MAPC(SDL_SCANCODE_I, 0x17, 0x9 | WITH_CONTROL_KEY);
1594 MAPC(SDL_SCANCODE_J, 0x24, 0xa | WITH_CONTROL_KEY);
1595 MAPC(SDL_SCANCODE_K, 0x25, 0xb | WITH_CONTROL_KEY);
1596 MAPC(SDL_SCANCODE_L, 0x26, 0xc | WITH_CONTROL_KEY);
1597 MAPC(SDL_SCANCODE_M, 0x32, 0xd | WITH_CONTROL_KEY);
1598 MAPC(SDL_SCANCODE_N, 0x31, 0xe | WITH_CONTROL_KEY);
1599 MAPC(SDL_SCANCODE_O, 0x18, 0xf | WITH_CONTROL_KEY);
1600 MAPC(SDL_SCANCODE_P, 0x19, 0x10 | WITH_CONTROL_KEY);
1601 MAPC(SDL_SCANCODE_Q, 0x10, 0x11 | WITH_CONTROL_KEY);
1602 MAPC(SDL_SCANCODE_R, 0x13, 0x12 | WITH_CONTROL_KEY);
1603 MAPC(SDL_SCANCODE_S, 0x1f, 0x13 | WITH_CONTROL_KEY);
1604 MAPC(SDL_SCANCODE_T, 0x14, 0x14 | WITH_CONTROL_KEY);
1605 MAPC(SDL_SCANCODE_U, 0x16, 0x15 | WITH_CONTROL_KEY);
1606 MAPC(SDL_SCANCODE_V, 0x2f, 0x16 | WITH_CONTROL_KEY);
1607 MAPC(SDL_SCANCODE_W, 0x11, 0x17 | WITH_CONTROL_KEY);
1608 MAPC(SDL_SCANCODE_X, 0x2d, 0x18 | WITH_CONTROL_KEY);
1609 MAPC(SDL_SCANCODE_Y, 0x15, 0x19 | WITH_CONTROL_KEY);
1610 MAPC(SDL_SCANCODE_Z, 0x2c, 0x1a | WITH_CONTROL_KEY);
1611 MAP(SDL_SCANCODE_DELETE, 0xd3);
1612 MAP(SDL_SCANCODE_KP_0, 0x52);
1613 MAP(SDL_SCANCODE_KP_1, 0x4f);
1614 MAP(SDL_SCANCODE_KP_2, 0x50);
1615 MAP(SDL_SCANCODE_KP_3, 0x51);
1616 MAP(SDL_SCANCODE_KP_4, 0x4b);
1617 MAP(SDL_SCANCODE_KP_5, 0x4c);
1618 MAP(SDL_SCANCODE_KP_6, 0x4d);
1619 MAP(SDL_SCANCODE_KP_7, 0x47);
1620 MAP(SDL_SCANCODE_KP_8, 0x48);
1621 MAP(SDL_SCANCODE_KP_9, 0x49);
1622 MAP(SDL_SCANCODE_KP_PERIOD, 0x53);
1623 MAP(SDL_SCANCODE_KP_DIVIDE, 0xb5);
1624 MAP(SDL_SCANCODE_KP_MULTIPLY, 0x37);
1625 MAP(SDL_SCANCODE_KP_MINUS, 0x4a);
1626 MAP(SDL_SCANCODE_KP_PLUS, 0x4e);
1627 MAPC(SDL_SCANCODE_KP_ENTER, 0x9c, 0xd);
1628 MAP(SDL_SCANCODE_UP, 0xc8);
1629 MAP(SDL_SCANCODE_DOWN, 0xd0);
1630 MAP(SDL_SCANCODE_RIGHT, 0xcd);
1631 MAP(SDL_SCANCODE_LEFT, 0xcb);
1632 MAP(SDL_SCANCODE_INSERT, 0xd2);
1633 MAP(SDL_SCANCODE_HOME, 0xc7);
1634 MAP(SDL_SCANCODE_END, 0xcf);
1635 MAP(SDL_SCANCODE_PAGEUP, 0xc9);
1636 MAP(SDL_SCANCODE_PAGEDOWN, 0xd1);
1637 MAP(SDL_SCANCODE_F1, 0x3b);
1638 MAP(SDL_SCANCODE_F2, 0x3c);
1639 MAP(SDL_SCANCODE_F3, 0x3d);
1640 MAP(SDL_SCANCODE_F4, 0x3e);
1641 MAP(SDL_SCANCODE_F5, 0x3f);
1642 MAP(SDL_SCANCODE_F6, 0x40);
1643 MAP(SDL_SCANCODE_F7, 0x41);
1644 MAP(SDL_SCANCODE_F8, 0x42);
1645 MAP(SDL_SCANCODE_F9, 0x43);
1646 MAP(SDL_SCANCODE_F10, 0x44);
1647 MAP(SDL_SCANCODE_F11, 0x57);
1648 MAP(SDL_SCANCODE_F12, 0x58);
1649 MAP(SDL_SCANCODE_NUMLOCKCLEAR, 0x45);
1650 MAP(SDL_SCANCODE_CAPSLOCK, 0x3a);
1651 MAP(SDL_SCANCODE_SCROLLLOCK, 0x46);
1652 MAP(SDL_SCANCODE_RSHIFT, 0x36);
1653 MAP(SDL_SCANCODE_LSHIFT, 0x2a);
1654 MAP(SDL_SCANCODE_RCTRL, 0x9d);
1655 MAP(SDL_SCANCODE_LCTRL, 0x1d);
1656 MAP(SDL_SCANCODE_RALT, 0xb8);
1657 MAP(SDL_SCANCODE_LALT, 0x38);
1658 MAP(SDL_SCANCODE_LGUI, 0xdb); // win l
1659 MAP(SDL_SCANCODE_RGUI, 0xdc); // win r
1660 MAP(SDL_SCANCODE_PRINTSCREEN, -2); // 0xaa + 0xb7
1661 MAP(SDL_SCANCODE_SYSREQ, 0x54); // alt+printscr
1662 MAP(SDL_SCANCODE_APPLICATION, 0xdd); // win menu?
1663
1664 return 0;
1665 }
1666
1667 #if USE_OPENGL
set_glswapinterval(const osdfuncparm_t * parm)1668 static int set_glswapinterval(const osdfuncparm_t *parm)
1669 {
1670 int interval;
1671
1672 if (nogl) {
1673 buildputs("glswapinterval is not adjustable\n");
1674 return OSDCMD_OK;
1675 }
1676 if (parm->numparms == 0) {
1677 buildprintf("glswapinterval = %d\n", glswapinterval);
1678 return OSDCMD_OK;
1679 }
1680 if (parm->numparms != 1) return OSDCMD_SHOWHELP;
1681
1682 interval = Batol(parm->parms[0]);
1683 if (interval < 0 || interval > 2) return OSDCMD_SHOWHELP;
1684
1685 if (SDL_GL_SetSwapInterval(interval) < 0) {
1686 buildputs("note: OpenGL swap interval could not be changed\n");
1687 } else {
1688 glswapinterval = interval;
1689 }
1690 return OSDCMD_OK;
1691 }
1692 #endif
1693