Subversion Repositories eduke32

Rev

Rev 8063 | Rev 8147 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
6828 terminx 1
// SDL interface layer for the Build Engine
4074 hendricks2 2
// Use SDL 1.2 or 2.0 from http://www.libsdl.org
5 Plagman 3
 
1485 helixhorne 4
#include <signal.h>
7186 terminx 5
 
5 Plagman 6
#include "a.h"
7
#include "build.h"
7186 terminx 8
#include "cache1d.h"
9
#include "compat.h"
10
#include "engine_priv.h"
5 Plagman 11
#include "osd.h"
5789 terminx 12
#include "palette.h"
7186 terminx 13
#include "renderlayer.h"
14
#include "sdl_inc.h"
15
#include "softsurface.h"
5 Plagman 16
 
17
#ifdef USE_OPENGL
6656 pogokeen 18
# include "glad/glad.h"
5 Plagman 19
# include "glbuild.h"
6919 pogokeen 20
# include "glsurface.h"
5 Plagman 21
#endif
22
 
4548 hendricks2 23
#if defined HAVE_GTK2
5 Plagman 24
# include "gtkbits.h"
4548 hendricks2 25
#endif
7186 terminx 26
 
4749 terminx 27
#ifdef __ANDROID__
4852 hendricks2 28
# include <android/log.h>
7186 terminx 29
#elif defined __APPLE__
30
# include "osxbits.h"
31
# include <mach/mach.h>
32
# include <mach/mach_time.h>
33
#elif defined GEKKO
4820 hendricks2 34
# include "wiibits.h"
35
# include <ogc/lwp.h>
36
# include <ogc/lwp_watchdog.h>
7186 terminx 37
#elif defined _WIN32
38
# include "winbits.h"
4819 hendricks2 39
#endif
1935 helixhorne 40
 
7359 hendricks2 41
#include "vfs.h"
8094 hendricks2 42
#include "communityapi.h"
7359 hendricks2 43
 
5955 hendricks2 44
#if SDL_MAJOR_VERSION != 1
5903 hendricks2 45
static SDL_version linked;
5955 hendricks2 46
#endif
5903 hendricks2 47
 
4648 hendricks2 48
#if !defined STARTUP_SETUP_WINDOW
1205 terminx 49
int32_t startwin_open(void) { return 0; }
50
int32_t startwin_close(void) { return 0; }
2158 helixhorne 51
int32_t startwin_puts(const char *s) { UNREFERENCED_PARAMETER(s); return 0; }
52
int32_t startwin_idle(void *s) { UNREFERENCED_PARAMETER(s); return 0; }
53
int32_t startwin_settitle(const char *s) { UNREFERENCED_PARAMETER(s); return 0; }
4766 hendricks2 54
int32_t startwin_run(void) { return 0; }
5 Plagman 55
#endif
56
 
1644 helixhorne 57
/// These can be useful for debugging sometimes...
58
//#define SDL_WM_GrabInput(x) SDL_WM_GrabInput(SDL_GRAB_OFF)
59
//#define SDL_ShowCursor(x) SDL_ShowCursor(SDL_ENABLE)
60
 
5 Plagman 61
#define SURFACE_FLAGS   (SDL_SWSURFACE|SDL_HWPALETTE|SDL_HWACCEL)
62
 
63
// undefine to restrict windowed resolutions to conventional sizes
64
#define ANY_WINDOWED_SIZE
65
 
258 terminx 66
// fix for mousewheel
4200 hendricks2 67
int32_t inputchecked = 0;
258 terminx 68
 
1762 terminx 69
char quitevent=0, appactive=1, novideo=0;
5 Plagman 70
 
71
// video
4089 hendricks2 72
static SDL_Surface *sdl_surface/*=NULL*/;
4432 terminx 73
 
2777 helixhorne 74
#if SDL_MAJOR_VERSION==2
4089 hendricks2 75
static SDL_Window *sdl_window=NULL;
76
static SDL_GLContext sdl_context=NULL;
2777 helixhorne 77
#endif
4432 terminx 78
 
8050 pogokeen 79
int32_t xres=-1, yres=-1, bpp=0, fullscreen=0, bytesperline, refreshfreq=-1;
618 terminx 80
intptr_t frameplace=0;
1205 terminx 81
int32_t lockcount=0;
5 Plagman 82
char modechange=1;
83
char offscreenrendering=0;
84
char videomodereset = 0;
4904 terminx 85
int32_t nofog=0;
5678 hendricks2 86
#ifndef EDUKE32_GLES
1205 terminx 87
static uint16_t sysgamma[3][256];
5678 hendricks2 88
#endif
5 Plagman 89
#ifdef USE_OPENGL
90
// OpenGL stuff
1036 terminx 91
char nogl=0;
5 Plagman 92
#endif
5956 hendricks2 93
static int32_t vsync_renderlayer;
5621 terminx 94
int32_t maxrefreshfreq=0;
8031 terminx 95
#if SDL_MAJOR_VERSION!=1
96
static double currentVBlankInterval;
97
#endif
2222 helixhorne 98
// last gamma, contrast, brightness
99
static float lastvidgcb[3];
100
 
2119 helixhorne 101
//#define KEY_PRINT_DEBUG
102
 
6056 hendricks2 103
#include "sdlkeytrans.cpp"
5 Plagman 104
 
1762 terminx 105
static SDL_Surface *appicon = NULL;
4852 hendricks2 106
#if !defined __APPLE__ && !defined EDUKE32_TOUCH_DEVICES
1762 terminx 107
static SDL_Surface *loadappicon(void);
4644 hendricks2 108
#endif
5 Plagman 109
 
1658 terminx 110
static mutex_t m_initprintf;
111
 
1716 plagman 112
// Joystick dead and saturation zones
7968 hendricks2 113
uint16_t joydead[9], joysatur[9];
1716 plagman 114
 
3219 hendricks2 115
#ifdef _WIN32
4774 hendricks2 116
# if SDL_MAJOR_VERSION != 1
3219 hendricks2 117
//
4084 hendricks2 118
// win_gethwnd() -- gets the window handle
119
//
120
HWND win_gethwnd(void)
121
{
122
    struct SDL_SysWMinfo wmInfo;
123
    SDL_VERSION(&wmInfo.version);
124
 
125
    if (SDL_GetWindowWMInfo(sdl_window, &wmInfo) != SDL_TRUE)
126
        return 0;
127
 
128
    if (wmInfo.subsystem == SDL_SYSWM_WINDOWS)
129
        return wmInfo.info.win.window;
130
 
131
    initprintf("win_gethwnd: Unknown WM subsystem?!\n");
132
 
133
    return 0;
134
}
4774 hendricks2 135
# endif
4084 hendricks2 136
//
3219 hendricks2 137
// win_gethinstance() -- gets the application instance
138
//
3278 hendricks2 139
HINSTANCE win_gethinstance(void)
3219 hendricks2 140
{
3278 hendricks2 141
    return (HINSTANCE)GetModuleHandle(NULL);
3219 hendricks2 142
}
143
#endif
144
 
4469 hendricks2 145
 
4558 hendricks2 146
int32_t wm_msgbox(const char *name, const char *fmt, ...)
5 Plagman 147
{
298 terminx 148
    char buf[2048];
109 terminx 149
    va_list va;
5 Plagman 150
 
659 plagman 151
    UNREFERENCED_PARAMETER(name);
152
 
109 terminx 153
    va_start(va,fmt);
4120 helixhorne 154
    vsnprintf(buf,sizeof(buf),fmt,va);
109 terminx 155
    va_end(va);
5 Plagman 156
 
4942 hendricks2 157
#if defined EDUKE32_OSX
109 terminx 158
    return osx_msgbox(name, buf);
4254 hendricks2 159
#elif defined _WIN32
160
    MessageBox(win_gethwnd(),buf,name,MB_OK|MB_TASKMODAL);
161
    return 0;
4852 hendricks2 162
#elif defined EDUKE32_TOUCH_DEVICES
4440 terminx 163
    initprintf("wm_msgbox called. Message: %s: %s",name,buf);
164
    return 0;
4825 hendricks2 165
#elif defined GEKKO
166
    puts(buf);
167
    return 0;
5961 hendricks2 168
#else
5976 hendricks2 169
# if defined HAVE_GTK2
170
    if (gtkbuild_msgbox(name, buf) >= 0)
171
        return 0;
172
# endif
173
# if SDL_MAJOR_VERSION > 1
174
#  if !defined _WIN32
175
    // Replace all tab chars with spaces because the hand-rolled SDL message
176
    // box diplays the former as N/L instead of whitespace.
177
    for (size_t i=0; i<sizeof(buf); i++)
178
        if (buf[i] == '\t')
179
            buf[i] = ' ';
180
#  endif
181
    return SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, name, buf, NULL);
182
# else
109 terminx 183
    puts(buf);
184
    puts("   (press Return or Enter to continue)");
185
    getchar();
5 Plagman 186
 
109 terminx 187
    return 0;
5976 hendricks2 188
# endif
5961 hendricks2 189
#endif
5 Plagman 190
}
191
 
4558 hendricks2 192
int32_t wm_ynbox(const char *name, const char *fmt, ...)
5 Plagman 193
{
298 terminx 194
    char buf[2048];
109 terminx 195
    va_list va;
5 Plagman 196
 
659 plagman 197
    UNREFERENCED_PARAMETER(name);
198
 
109 terminx 199
    va_start(va,fmt);
5976 hendricks2 200
    vsnprintf(buf,sizeof(buf),fmt,va);
109 terminx 201
    va_end(va);
5 Plagman 202
 
4942 hendricks2 203
#if defined EDUKE32_OSX
109 terminx 204
    return osx_ynbox(name, buf);
4254 hendricks2 205
#elif defined _WIN32
4476 helixhorne 206
    return (MessageBox(win_gethwnd(),buf,name,MB_YESNO|MB_ICONQUESTION|MB_TASKMODAL) == IDYES);
4852 hendricks2 207
#elif defined EDUKE32_TOUCH_DEVICES
4440 terminx 208
    initprintf("wm_ynbox called, this is bad! Message: %s: %s",name,buf);
209
    initprintf("Returning false..");
210
    return 0;
5976 hendricks2 211
#elif defined GEKKO
212
    puts(buf);
213
    puts("Assuming yes...");
214
    return 1;
4749 terminx 215
#else
5976 hendricks2 216
# if defined HAVE_GTK2
217
    int ret = gtkbuild_ynbox(name, buf);
218
    if (ret >= 0)
219
        return ret;
220
# endif
221
# if SDL_MAJOR_VERSION > 1
222
    int r = -1;
4476 helixhorne 223
 
5976 hendricks2 224
    const SDL_MessageBoxButtonData buttons[] = {
225
        {
226
            SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
227
            0,
228
            "No"
229
        },{
230
            SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
231
            1,
232
            "Yes"
233
        },
234
    };
4469 hendricks2 235
 
5976 hendricks2 236
    SDL_MessageBoxData data = {
237
        SDL_MESSAGEBOX_INFORMATION,
238
        NULL, /* no parent window */
239
        name,
240
        buf,
241
        2,
242
        buttons,
243
        NULL /* Default color scheme */
244
    };
4469 hendricks2 245
 
5976 hendricks2 246
    SDL_ShowMessageBox(&data, &r);
4469 hendricks2 247
 
5976 hendricks2 248
    return r;
249
# else
250
    char c;
251
 
252
    puts(buf);
253
    puts("   (type 'Y' or 'N', and press Return or Enter to continue)");
254
    do c = getchar(); while (c != 'Y' && c != 'y' && c != 'N' && c != 'n');
255
    return c == 'Y' || c == 'y';
256
# endif
5 Plagman 257
#endif
258
}
259
 
4558 hendricks2 260
void wm_setapptitle(const char *name)
5 Plagman 261
{
4852 hendricks2 262
#ifndef EDUKE32_TOUCH_DEVICES
4749 terminx 263
    if (name != apptitle)
264
        Bstrncpyz(apptitle, name, sizeof(apptitle));
265
 
266
#if !defined(__APPLE__)
4774 hendricks2 267
    if (!appicon)
268
        appicon = loadappicon();
4440 terminx 269
#endif
270
 
2777 helixhorne 271
#if SDL_MAJOR_VERSION == 1
109 terminx 272
    SDL_WM_SetCaption(apptitle, NULL);
4749 terminx 273
 
4774 hendricks2 274
    if (appicon && sdl_surface)
4749 terminx 275
        SDL_WM_SetIcon(appicon, 0);
2777 helixhorne 276
#else
5904 hendricks2 277
    if (sdl_window)
278
    {
279
        SDL_SetWindowTitle(sdl_window, apptitle);
4749 terminx 280
 
5904 hendricks2 281
        if (appicon)
282
        {
283
#if defined _WIN32
284
        if (!EDUKE32_SDL_LINKED_PREREQ(linked, 2, 0, 5))
2777 helixhorne 285
#endif
5904 hendricks2 286
            SDL_SetWindowIcon(sdl_window, appicon);
287
        }
288
    }
289
#endif
5 Plagman 290
 
194 terminx 291
    startwin_settitle(apptitle);
4852 hendricks2 292
#else
293
    UNREFERENCED_PARAMETER(name);
4749 terminx 294
#endif
5 Plagman 295
}
296
 
297
//
298
//
299
// ---------------------------------------
300
//
301
// System
302
//
303
// ---------------------------------------
304
//
305
//
306
 
4749 terminx 307
/* XXX: libexecinfo could be used on systems without gnu libc. */
4852 hendricks2 308
#if !defined _WIN32 && defined __GNUC__ && !defined __OpenBSD__ && !(defined __APPLE__ && defined __BIG_ENDIAN__) && !defined GEKKO && !defined EDUKE32_TOUCH_DEVICES && !defined __OPENDINGUX__
4749 terminx 309
# define PRINTSTACKONSEGV 1
310
# include <execinfo.h>
4557 hendricks2 311
#endif
312
 
4749 terminx 313
static inline char grabmouse_low(char a);
314
 
5679 hendricks2 315
#ifndef __ANDROID__
316
static void attach_debugger_here(void) {}
317
 
4749 terminx 318
static void sighandler(int signum)
319
{
320
    UNREFERENCED_PARAMETER(signum);
321
    //    if (signum==SIGSEGV)
322
    {
323
        grabmouse_low(0);
324
#if PRINTSTACKONSEGV
325
        {
326
            void *addr[32];
327
            int32_t errfd = fileno(stderr);
328
            int32_t n=backtrace(addr, ARRAY_SIZE(addr));
329
            backtrace_symbols_fd(addr, n, errfd);
330
        }
331
        // This is useful for attaching the debugger post-mortem. For those pesky
332
        // cases where the program runs through happily when inspected from the start.
333
        //        usleep(15000000);
334
#endif
335
        attach_debugger_here();
336
        app_crashhandler();
337
        uninitsystem();
338
        Bexit(8);
339
    }
340
}
5679 hendricks2 341
#endif
4749 terminx 342
 
4992 terminx 343
#ifdef __ANDROID__
344
int mobile_halted = 0;
345
#ifdef __cplusplus
346
extern "C"
347
{
348
#endif
349
void G_Shutdown(void);
350
#ifdef __cplusplus
351
}
352
#endif
353
 
354
int sdlayer_mobilefilter(void *userdata, SDL_Event *event)
355
{
356
    switch (event->type)
357
    {
358
        case SDL_APP_TERMINATING:
359
            // yes, this calls into the game, ugh
5000 terminx 360
            if (mobile_halted == 1)
361
                G_Shutdown();
362
 
363
            mobile_halted = 1;
4992 terminx 364
            return 0;
365
        case SDL_APP_LOWMEMORY:
366
            gltexinvalidatetype(INVALIDATE_ALL);
367
            return 0;
368
        case SDL_APP_WILLENTERBACKGROUND:
369
            mobile_halted = 1;
370
            return 0;
371
        case SDL_APP_DIDENTERBACKGROUND:
5663 terminx 372
            gltexinvalidatetype(INVALIDATE_ALL);
4992 terminx 373
            // tear down video?
374
            return 0;
375
        case SDL_APP_WILLENTERFOREGROUND:
376
            // restore video?
377
            return 0;
378
        case SDL_APP_DIDENTERFOREGROUND:
379
            mobile_halted = 0;
380
            return 0;
381
        default:
382
            return 1;//!halt;
383
    }
5679 hendricks2 384
 
385
    UNREFERENCED_PARAMETER(userdata);
4992 terminx 386
}
387
#endif
388
 
5706 hendricks2 389
#ifdef __ANDROID__
390
# include <setjmp.h>
391
static jmp_buf eduke32_exit_jmp_buf;
392
static int eduke32_return_value;
393
 
394
void eduke32_exit_return(int retval)
395
{
396
    eduke32_return_value = retval;
397
    longjmp(eduke32_exit_jmp_buf, 1);
5717 hendricks2 398
    EDUKE32_UNREACHABLE_SECTION(return);
5706 hendricks2 399
}
400
#endif
401
 
4983 terminx 402
#ifdef _WIN32
5980 hendricks2 403
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)
5717 hendricks2 404
#elif defined __ANDROID__
405
# ifdef __cplusplus
406
extern "C" int eduke32_android_main(int argc, char const *argv[]);
407
# endif
408
int eduke32_android_main(int argc, char const *argv[])
5981 hendricks2 409
#elif defined GEKKO
410
int SDL_main(int argc, char *argv[])
4983 terminx 411
#else
5980 hendricks2 412
int main(int argc, char *argv[])
4983 terminx 413
#endif
5 Plagman 414
{
5706 hendricks2 415
#ifdef __ANDROID__
416
    if (setjmp(eduke32_exit_jmp_buf))
417
    {
418
        return eduke32_return_value;
419
    }
420
#endif
421
 
5902 hendricks2 422
#if defined _WIN32 && defined SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING
423
    // Thread naming interferes with debugging using MinGW-w64's GDB.
424
    SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1");
425
#endif
426
 
1205 terminx 427
    int32_t r;
4749 terminx 428
 
3382 hendricks2 429
#ifdef USE_OPENGL
622 terminx 430
    char *argp;
109 terminx 431
 
4749 terminx 432
    if ((argp = Bgetenv("BUILD_NOFOG")) != NULL)
433
        nofog = Batol(argp);
6439 terminx 434
 
6444 terminx 435
#ifndef _WIN32
436
    setenv("__GL_THREADED_OPTIMIZATIONS", "1", 0);
4557 hendricks2 437
#endif
6444 terminx 438
#endif
4557 hendricks2 439
 
109 terminx 440
    buildkeytranslationtable();
441
 
4992 terminx 442
#ifndef __ANDROID__
4749 terminx 443
    signal(SIGSEGV, sighandler);
444
    signal(SIGILL, sighandler);  /* clang -fcatch-undefined-behavior uses an ill. insn */
445
    signal(SIGABRT, sighandler);
446
    signal(SIGFPE, sighandler);
4992 terminx 447
#else
448
    SDL_SetEventFilter(sdlayer_mobilefilter, NULL);
449
#endif
4447 Plagman 450
 
3221 hendricks2 451
#ifdef _WIN32
4983 terminx 452
    UNREFERENCED_PARAMETER(hInst);
453
    UNREFERENCED_PARAMETER(hPrevInst);
454
    UNREFERENCED_PARAMETER(lpCmdLine);
455
    UNREFERENCED_PARAMETER(nCmdShow);
456
 
4749 terminx 457
    win_open();
458
 
3221 hendricks2 459
    if (!CheckWinVersion())
460
    {
5639 hendricks2 461
        MessageBox(0, "This application requires a newer Windows version to run.", apptitle, MB_OK | MB_ICONSTOP);
3221 hendricks2 462
        return -1;
463
    }
4749 terminx 464
#elif defined(GEKKO)
4820 hendricks2 465
    wii_open();
4749 terminx 466
#elif defined(HAVE_GTK2)
467
    // Pre-initialize SDL video system in order to make sure XInitThreads() is called
468
    // before GTK starts talking to X11.
6704 hendricks2 469
    uint32_t inited = SDL_WasInit(SDL_INIT_VIDEO);
470
    if (inited == 0)
471
        SDL_Init(SDL_INIT_VIDEO);
472
    else if (!(inited & SDL_INIT_VIDEO))
473
        SDL_InitSubSystem(SDL_INIT_VIDEO);
4749 terminx 474
    gtkbuild_init(&argc, &argv);
3221 hendricks2 475
#endif
476
 
194 terminx 477
    startwin_open();
3377 helixhorne 478
    maybe_redirect_outputs();
1736 helixhorne 479
 
4983 terminx 480
#ifdef _WIN32
481
    char *argvbuf;
482
    int32_t buildargc = win_buildargs(&argvbuf);
7079 terminx 483
    const char **buildargv = (const char **) Xmalloc(sizeof(char *)*(buildargc+1));
4983 terminx 484
    char *wp = argvbuf;
485
 
5829 terminx 486
    for (bssize_t i=0; i<buildargc; i++, wp++)
4983 terminx 487
    {
488
        buildargv[i] = wp;
489
        while (*wp) wp++;
490
    }
491
    buildargv[buildargc] = NULL;
492
 
7359 hendricks2 493
#ifdef USE_PHYSFS
494
    PHYSFS_init(buildargv[0]);
495
    PHYSFS_setWriteDir(PHYSFS_getBaseDir());
496
#endif
4983 terminx 497
    r = app_main(buildargc, (const char **)buildargv);
498
#else
7359 hendricks2 499
#ifdef USE_PHYSFS
500
    int pfsi = PHYSFS_init(argv[0]);
501
    assert(pfsi != 0);
502
    PHYSFS_setWriteDir(PHYSFS_getUserDir());
503
#endif
5552 hendricks2 504
    r = app_main(argc, (char const * const *)argv);
4983 terminx 505
#endif
5 Plagman 506
 
194 terminx 507
    startwin_close();
4749 terminx 508
 
3221 hendricks2 509
#ifdef _WIN32
510
    win_close();
4749 terminx 511
#elif defined(HAVE_GTK2)
512
    gtkbuild_exit(r);
3221 hendricks2 513
#endif
514
 
109 terminx 515
    return r;
5 Plagman 516
}
517
 
5938 terminx 518
 
4769 hendricks2 519
#if SDL_MAJOR_VERSION != 1
6828 terminx 520
int32_t videoSetVsync(int32_t newSync)
889 terminx 521
{
5953 hendricks2 522
    if (vsync_renderlayer == newSync)
5938 terminx 523
        return newSync;
4102 hendricks2 524
 
5938 terminx 525
#ifdef USE_OPENGL
4090 hendricks2 526
    if (sdl_context)
5938 terminx 527
    {
528
        int result = SDL_GL_SetSwapInterval(newSync);
529
 
530
        if (result == -1)
531
        {
532
            if (newSync == -1)
533
            {
534
                newSync = 1;
535
                result = SDL_GL_SetSwapInterval(newSync);
536
            }
537
 
538
            if (result == -1)
539
            {
540
                newSync = 0;
541
                OSD_Printf("Unable to enable VSync!\n");
542
            }
543
        }
544
 
5953 hendricks2 545
        vsync_renderlayer = newSync;
5938 terminx 546
    }
547
    else
548
#endif
549
    {
5953 hendricks2 550
        vsync_renderlayer = newSync;
5938 terminx 551
 
6828 terminx 552
        videoResetMode();
6939 pogokeen 553
        if (videoSetGameMode(fullscreen, xres, yres, bpp, upscalefactor))
5938 terminx 554
            OSD_Printf("restartvid: Reset failed...\n");
555
    }
556
 
5954 hendricks2 557
    return newSync;
889 terminx 558
}
559
#endif
5 Plagman 560
 
4767 hendricks2 561
int32_t sdlayer_checkversion(void);
562
#if SDL_MAJOR_VERSION != 1
4749 terminx 563
int32_t sdlayer_checkversion(void)
564
{
565
    SDL_version compiled;
1485 helixhorne 566
 
4964 helixhorne 567
    SDL_GetVersion(&linked);
4749 terminx 568
    SDL_VERSION(&compiled);
3972 hendricks2 569
 
5536 terminx 570
    if (!Bmemcmp(&compiled, &linked, sizeof(SDL_version)))
571
        initprintf("Initializing SDL %d.%d.%d\n",
572
            compiled.major, compiled.minor, compiled.patch);
573
    else
574
    initprintf("Initializing SDL %d.%d.%d"
5759 hendricks2 575
               " (built against SDL version %d.%d.%d)\n",
5536 terminx 576
               linked.major, linked.minor, linked.patch, compiled.major, compiled.minor, compiled.patch);
1712 helixhorne 577
 
4964 helixhorne 578
    if (SDL_VERSIONNUM(linked.major, linked.minor, linked.patch) < SDL_REQUIREDVERSION)
1485 helixhorne 579
    {
4749 terminx 580
        /*reject running under SDL versions older than what is stated in sdl_inc.h */
581
        initprintf("You need at least v%d.%d.%d of SDL to run this game\n",SDL_MIN_X,SDL_MIN_Y,SDL_MIN_Z);
582
        return -1;
1485 helixhorne 583
    }
4749 terminx 584
 
585
    return 0;
1485 helixhorne 586
}
587
 
5 Plagman 588
//
589
// initsystem() -- init SDL systems
590
//
1205 terminx 591
int32_t initsystem(void)
5 Plagman 592
{
4749 terminx 593
    const int sdlinitflags = SDL_INIT_VIDEO;
5 Plagman 594
 
1658 terminx 595
    mutex_init(&m_initprintf);
596
 
3221 hendricks2 597
#ifdef _WIN32
598
    win_init();
599
#endif
600
 
4749 terminx 601
    if (sdlayer_checkversion())
710 terminx 602
        return -1;
603
 
6704 hendricks2 604
    int32_t err = 0;
605
    uint32_t inited = SDL_WasInit(sdlinitflags);
606
    if (inited == 0)
607
        err = SDL_Init(sdlinitflags);
608
    else if ((inited & sdlinitflags) != sdlinitflags)
609
        err = SDL_InitSubSystem(sdlinitflags & ~inited);
610
 
611
    if (err)
342 terminx 612
    {
1762 terminx 613
        initprintf("Initialization failed! (%s)\nNon-interactive mode enabled\n", SDL_GetError());
1810 plagman 614
        novideo = 1;
615
#ifdef USE_OPENGL
616
        nogl = 1;
617
#endif
109 terminx 618
    }
5 Plagman 619
 
5969 hendricks2 620
#if SDL_MAJOR_VERSION > 1
621
    SDL_StopTextInput();
622
#endif
623
 
109 terminx 624
    atexit(uninitsystem);
5 Plagman 625
 
109 terminx 626
    frameplace = 0;
627
    lockcount = 0;
5 Plagman 628
 
1762 terminx 629
    if (!novideo)
630
    {
4749 terminx 631
#ifdef USE_OPENGL
6656 pogokeen 632
        if (SDL_GL_LoadLibrary(0))
2777 helixhorne 633
        {
6656 pogokeen 634
            initprintf("Failed loading OpenGL Driver.  GL modes will be unavailable. Error: %s\n", SDL_GetError());
4749 terminx 635
            nogl = 1;
2777 helixhorne 636
        }
6656 pogokeen 637
#ifdef POLYMER
638
        if (loadglulibrary(getenv("BUILD_GLULIB")))
639
        {
640
            initprintf("Failed loading GLU.  GL modes will be unavailable. Error: %s\n", SDL_GetError());
641
            nogl = 1;
642
        }
5 Plagman 643
#endif
6656 pogokeen 644
#endif
5 Plagman 645
 
5536 terminx 646
#ifndef _WIN32
647
        const char *drvname = SDL_GetVideoDriver(0);
648
 
2777 helixhorne 649
        if (drvname)
650
            initprintf("Using \"%s\" video driver\n", drvname);
5536 terminx 651
#endif
4749 terminx 652
        wm_setapptitle(apptitle);
2777 helixhorne 653
    }
5 Plagman 654
 
109 terminx 655
    return 0;
5 Plagman 656
}
4767 hendricks2 657
#endif
5 Plagman 658
 
659
 
660
//
661
// uninitsystem() -- uninit SDL systems
662
//
663
void uninitsystem(void)
664
{
109 terminx 665
    uninitinput();
6828 terminx 666
    timerUninit();
5 Plagman 667
 
1544 terminx 668
    if (appicon)
1552 terminx 669
    {
1544 terminx 670
        SDL_FreeSurface(appicon);
1552 terminx 671
        appicon = NULL;
672
    }
1544 terminx 673
 
109 terminx 674
    SDL_Quit();
5 Plagman 675
 
3221 hendricks2 676
#ifdef _WIN32
677
    win_uninit();
678
#endif
679
 
5 Plagman 680
#ifdef USE_OPENGL
6939 pogokeen 681
# if SDL_MAJOR_VERSION!=1
6656 pogokeen 682
    SDL_GL_UnloadLibrary();
6939 pogokeen 683
# endif
684
# ifdef POLYMER
6656 pogokeen 685
    unloadglulibrary();
6939 pogokeen 686
# endif
5 Plagman 687
#endif
688
}
689
 
690
 
691
//
4090 hendricks2 692
// system_getcvars() -- propagate any cvars that are read post-initialization
693
//
694
void system_getcvars(void)
695
{
6828 terminx 696
    vsync = videoSetVsync(vsync);
4090 hendricks2 697
}
698
 
699
//
4555 hendricks2 700
// initprintf() -- prints a formatted string to the intitialization window
5 Plagman 701
//
702
void initprintf(const char *f, ...)
703
{
109 terminx 704
    va_list va;
1663 helixhorne 705
    char buf[2048];
5 Plagman 706
 
109 terminx 707
    va_start(va, f);
1663 helixhorne 708
    Bvsnprintf(buf, sizeof(buf), f, va);
109 terminx 709
    va_end(va);
5 Plagman 710
 
4555 hendricks2 711
    initputs(buf);
712
}
713
 
714
 
715
//
716
// initputs() -- prints a string to the intitialization window
717
//
718
void initputs(const char *buf)
719
{
720
    static char dabuf[2048];
721
 
4440 terminx 722
#ifdef __ANDROID__
723
    __android_log_print(ANDROID_LOG_INFO,"DUKE", "%s",buf);
724
#endif
4555 hendricks2 725
    OSD_Puts(buf);
1762 terminx 726
//    Bprintf("%s", buf);
109 terminx 727
 
7928 hendricks2 728
    mutex_lock(&m_initprintf);
1203 terminx 729
    if (Bstrlen(dabuf) + Bstrlen(buf) > 1022)
730
    {
731
        startwin_puts(dabuf);
732
        Bmemset(dabuf, 0, sizeof(dabuf));
733
    }
734
 
735
    Bstrcat(dabuf,buf);
736
 
6827 terminx 737
    if (g_logFlushWindow || Bstrlen(dabuf) > 768)
1203 terminx 738
    {
739
        startwin_puts(dabuf);
3219 hendricks2 740
#ifndef _WIN32
1203 terminx 741
        startwin_idle(NULL);
4086 hendricks2 742
#else
743
        handleevents();
3219 hendricks2 744
#endif
1203 terminx 745
        Bmemset(dabuf, 0, sizeof(dabuf));
746
    }
7928 hendricks2 747
    mutex_unlock(&m_initprintf);
5 Plagman 748
}
749
 
750
//
4555 hendricks2 751
// debugprintf() -- prints a formatted debug string to stderr
5 Plagman 752
//
753
void debugprintf(const char *f, ...)
754
{
1935 helixhorne 755
#if defined DEBUGGINGAIDS && !(defined __APPLE__ && defined __BIG_ENDIAN__)
109 terminx 756
    va_list va;
5 Plagman 757
 
109 terminx 758
    va_start(va,f);
759
    Bvfprintf(stderr, f, va);
760
    va_end(va);
661 plagman 761
#else
762
    UNREFERENCED_PARAMETER(f);
5 Plagman 763
#endif
764
}
765
 
766
 
767
//
768
//
769
// ---------------------------------------
770
//
771
// All things Input
772
//
773
// ---------------------------------------
774
//
775
//
776
 
1205 terminx 777
// static int32_t joyblast=0;
5 Plagman 778
static SDL_Joystick *joydev = NULL;
7958 hendricks2 779
#if SDL_MAJOR_VERSION >= 2
780
static SDL_GameController *controller = NULL;
5 Plagman 781
 
7958 hendricks2 782
static void LoadSDLControllerDB()
783
{
784
    buildvfs_kfd fh = kopen4load("gamecontrollerdb.txt", 0);
785
    if (fh == buildvfs_kfd_invalid)
786
        return;
787
 
788
    int flen = kfilelength(fh);
789
    if (flen <= 0)
790
    {
791
        kclose(fh);
792
        return;
793
    }
794
 
795
    char * dbuf = (char *)malloc(flen + 1);
796
    if (!dbuf)
797
    {
798
        kclose(fh);
799
        return;
800
    }
801
 
802
    if (kread_and_test(fh, dbuf, flen))
803
    {
804
        free(dbuf);
805
        kclose(fh);
806
        return;
807
    }
808
 
809
    dbuf[flen] = '\0';
810
    kclose(fh);
811
 
812
    SDL_RWops * rwops = SDL_RWFromConstMem(dbuf, flen);
813
    if (!rwops)
814
    {
815
        free(dbuf);
816
        return;
817
    }
818
 
819
    int i = SDL_GameControllerAddMappingsFromRW(rwops, 0);
820
    if (i == -1)
821
        buildprintf("Failed loading game controller database: %s\n", SDL_GetError());
822
    else
823
        buildputs("Loaded game controller database\n");
824
 
825
    SDL_free(rwops);
826
    free(dbuf);
827
}
828
#endif
829
 
7985 hendricks2 830
void joyScanDevices()
831
{
832
    inputdevices &= ~4;
833
 
834
    if (controller)
835
    {
836
        SDL_GameControllerClose(controller);
837
        controller = nullptr;
838
    }
839
    if (joydev)
840
    {
841
        SDL_JoystickClose(joydev);
842
        joydev = nullptr;
843
    }
844
 
8005 terminx 845
    int numjoysticks = SDL_NumJoysticks();
7985 hendricks2 846
    if (numjoysticks < 1)
847
    {
848
        buildputs("No game controllers found\n");
849
    }
850
    else
851
    {
852
        buildputs("Game controllers:\n");
853
        for (int i = 0; i < numjoysticks; i++)
854
        {
855
            const char * name;
856
#if SDL_MAJOR_VERSION >= 2
857
            if (SDL_IsGameController(i))
858
                name = SDL_GameControllerNameForIndex(i);
859
            else
860
#endif
861
                name = SDL_JoystickNameForIndex(i);
862
 
863
            buildprintf("  %d. %s\n", i+1, name);
864
        }
865
 
866
#if SDL_MAJOR_VERSION >= 2
867
        for (int i = 0; i < numjoysticks; i++)
868
        {
869
            if ((controller = SDL_GameControllerOpen(i)))
870
            {
871
                buildprintf("Using controller %s\n", SDL_GameControllerName(controller));
872
 
873
                joystick.numAxes    = SDL_CONTROLLER_AXIS_MAX;
874
                joystick.numButtons = SDL_CONTROLLER_BUTTON_MAX;
875
                joystick.numHats    = 0;
876
                joystick.isGameController = 1;
877
 
878
                Xfree(joystick.pAxis);
879
                joystick.pAxis = (int32_t *)Xcalloc(joystick.numAxes, sizeof(int32_t));
880
                Xfree(joystick.pHat);
881
                joystick.pHat = nullptr;
882
 
883
                inputdevices |= 4;
884
 
885
                return;
886
            }
887
        }
888
#endif
889
 
890
        for (int i = 0; i < numjoysticks; i++)
891
        {
892
            if ((joydev = SDL_JoystickOpen(i)))
893
            {
894
                buildprintf("Using joystick %s\n", SDL_JoystickName(joydev));
895
 
896
                // KEEPINSYNC duke3d/src/gamedefs.h, mact/include/_control.h
897
                joystick.numAxes = min(9, SDL_JoystickNumAxes(joydev));
898
                joystick.numButtons = min(32, SDL_JoystickNumButtons(joydev));
899
                joystick.numHats = min((36-joystick.numButtons)/4,SDL_JoystickNumHats(joydev));
900
                joystick.isGameController = 0;
901
 
902
                initprintf("Joystick %d has %d axes, %d buttons, and %d hat(s).\n", i+1, joystick.numAxes, joystick.numButtons, joystick.numHats);
903
 
904
                Xfree(joystick.pAxis);
905
                joystick.pAxis = (int32_t *)Xcalloc(joystick.numAxes, sizeof(int32_t));
906
 
907
                Xfree(joystick.pHat);
908
                if (joystick.numHats)
909
                    joystick.pHat = (int32_t *)Xcalloc(joystick.numHats, sizeof(int32_t));
910
                else
911
                    joystick.pHat = nullptr;
912
 
913
                for (int j = 0; j < joystick.numHats; j++)
914
                    joystick.pHat[j] = -1; // center
915
 
916
                SDL_JoystickEventState(SDL_ENABLE);
917
                inputdevices |= 4;
918
 
919
                return;
920
            }
921
        }
922
 
923
        buildputs("No controllers are usable\n");
924
    }
925
}
926
 
5 Plagman 927
//
928
// initinput() -- init input system
929
//
8005 terminx 930
int32_t initinput(void)
5 Plagman 931
{
7045 terminx 932
    int32_t i;
109 terminx 933
 
4482 helixhorne 934
#ifdef _WIN32
5970 hendricks2 935
    Win_GetOriginalLayoutName();
936
    Win_SetKeyboardLayoutUS(1);
4482 helixhorne 937
#endif
938
 
5169 hendricks2 939
#if defined EDUKE32_OSX
109 terminx 940
    // force OS X to operate in >1 button mouse mode so that LMB isn't adulterated
4749 terminx 941
    if (!getenv("SDL_HAS3BUTTONMOUSE"))
7045 terminx 942
    {
943
        static char sdl_has3buttonmouse[] = "SDL_HAS3BUTTONMOUSE=1";
5551 hendricks2 944
        putenv(sdl_has3buttonmouse);
7045 terminx 945
    }
5 Plagman 946
#endif
4749 terminx 947
 
948
    inputdevices = 1 | 2;  // keyboard (1) and mouse (2)
6827 terminx 949
    g_mouseGrabbed = 0;
5 Plagman 950
 
6827 terminx 951
    memset(g_keyNameTable, 0, sizeof(g_keyNameTable));
4432 terminx 952
 
953
#if SDL_MAJOR_VERSION == 1
4749 terminx 954
#define SDL_SCANCODE_TO_KEYCODE(x) (SDLKey)(x)
955
#define SDL_JoystickNameForIndex(x) SDL_JoystickName(x)
956
#define SDL_NUM_SCANCODES SDLK_LAST
957
    if (SDL_EnableKeyRepeat(250, 30))
958
        initprintf("Error enabling keyboard repeat.\n");
959
    SDL_EnableUNICODE(1);  // let's hope this doesn't hit us too hard
4432 terminx 960
#endif
961
 
4749 terminx 962
    for (i = SDL_NUM_SCANCODES - 1; i >= 0; i--)
342 terminx 963
    {
4749 terminx 964
        if (!keytranslation[i])
965
            continue;
966
 
7080 terminx 967
        Bstrncpyz(g_keyNameTable[keytranslation[i]], SDL_GetKeyName(SDL_SCANCODE_TO_KEYCODE(i)), sizeof(g_keyNameTable[0]));
1109 terminx 968
    }
5 Plagman 969
 
7958 hendricks2 970
#if SDL_MAJOR_VERSION >= 2
971
    if (!SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER))
972
#else
342 terminx 973
    if (!SDL_InitSubSystem(SDL_INIT_JOYSTICK))
7958 hendricks2 974
#endif
342 terminx 975
    {
7958 hendricks2 976
#if SDL_MAJOR_VERSION >= 2
977
        LoadSDLControllerDB();
978
#endif
8005 terminx 979
 
7985 hendricks2 980
        joyScanDevices();
109 terminx 981
    }
982
 
983
    return 0;
5 Plagman 984
}
985
 
986
//
987
// uninitinput() -- uninit input system
988
//
989
void uninitinput(void)
990
{
4482 helixhorne 991
#ifdef _WIN32
5970 hendricks2 992
    Win_SetKeyboardLayoutUS(0);
4482 helixhorne 993
#endif
6827 terminx 994
    mouseUninit();
5 Plagman 995
 
7958 hendricks2 996
#if SDL_MAJOR_VERSION >= 2
997
    if (controller)
998
    {
999
        SDL_GameControllerClose(controller);
1000
        controller = NULL;
1001
    }
1002
#endif
1003
 
342 terminx 1004
    if (joydev)
1005
    {
109 terminx 1006
        SDL_JoystickClose(joydev);
1007
        joydev = NULL;
1008
    }
5 Plagman 1009
}
1010
 
2624 helixhorne 1011
#ifndef GEKKO
6827 terminx 1012
const char *joyGetName(int32_t what, int32_t num)
5 Plagman 1013
{
109 terminx 1014
    static char tmp[64];
5 Plagman 1015
 
342 terminx 1016
    switch (what)
1017
    {
4749 terminx 1018
        case 0:  // axis
6827 terminx 1019
            if ((unsigned)num > (unsigned)joystick.numAxes)
4749 terminx 1020
                return NULL;
7958 hendricks2 1021
 
1022
#if SDL_MAJOR_VERSION >= 2
1023
            if (controller)
1024
            {
1025
# if 0
1026
                // Use this if SDL's provided strings ever become user-friendly.
1027
                return SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)num);
1028
# else
1029
                static char const * axisStrings[] =
1030
                {
1031
                    "Left Stick X-Axis",
1032
                    "Left Stick Y-Axis",
1033
                    "Right Stick X-Axis",
1034
                    "Right Stick Y-Axis",
1035
                    "Left Trigger",
1036
                    "Right Trigger",
1037
                    NULL
1038
                };
1039
                return axisStrings[num];
1040
# endif
1041
            }
1042
#endif
1043
 
4749 terminx 1044
            Bsprintf(tmp, "Axis %d", num);
1045
            return (char *)tmp;
5 Plagman 1046
 
4749 terminx 1047
        case 1:  // button
6827 terminx 1048
            if ((unsigned)num > (unsigned)joystick.numButtons)
4749 terminx 1049
                return NULL;
7958 hendricks2 1050
 
1051
#if SDL_MAJOR_VERSION >= 2
1052
            if (controller)
1053
            {
1054
# if 0
1055
                // See above.
1056
                return SDL_GameControllerGetStringForButton((SDL_GameControllerButton)num);
1057
# else
1058
                static char const * buttonStrings[] =
1059
                {
1060
                    "A",
1061
                    "B",
1062
                    "X",
1063
                    "Y",
1064
                    "Back",
1065
                    "Guide",
1066
                    "Start",
1067
                    "Left Stick",
1068
                    "Right Stick",
1069
                    "Left Shoulder",
1070
                    "Right Shoulder",
1071
                    "D-Pad Up",
1072
                    "D-Pad Down",
1073
                    "D-Pad Left",
1074
                    "D-Pad Right",
1075
                    NULL
1076
                };
1077
                return buttonStrings[num];
1078
# endif
1079
            }
1080
#endif
1081
 
4749 terminx 1082
            Bsprintf(tmp, "Button %d", num);
1083
            return (char *)tmp;
5 Plagman 1084
 
4749 terminx 1085
        case 2:  // hat
6827 terminx 1086
            if ((unsigned)num > (unsigned)joystick.numHats)
4749 terminx 1087
                return NULL;
1088
            Bsprintf(tmp, "Hat %d", num);
1089
            return (char *)tmp;
5 Plagman 1090
 
4749 terminx 1091
        default: return NULL;
109 terminx 1092
    }
5 Plagman 1093
}
2624 helixhorne 1094
#endif
1095
 
1096
 
5 Plagman 1097
//
1098
// initmouse() -- init mouse input
1099
//
7181 terminx 1100
void mouseInit(void)
5 Plagman 1101
{
7181 terminx 1102
    mouseGrabInput(g_mouseEnabled = g_mouseLockedToWindow);  // FIXME - SA
5 Plagman 1103
}
1104
 
1105
//
1106
// uninitmouse() -- uninit mouse input
1107
//
6827 terminx 1108
void mouseUninit(void)
5 Plagman 1109
{
6827 terminx 1110
    mouseGrabInput(0);
1111
    g_mouseEnabled = 0;
5 Plagman 1112
}
1113
 
1114
 
4767 hendricks2 1115
#if SDL_MAJOR_VERSION != 1
5 Plagman 1116
//
4089 hendricks2 1117
// grabmouse_low() -- show/hide mouse cursor, lower level (doesn't check state).
1118
//                    furthermore return 0 if successful.
1119
//
1120
 
1121
static inline char grabmouse_low(char a)
1122
{
5921 hendricks2 1123
#if !defined EDUKE32_TOUCH_DEVICES
4089 hendricks2 1124
    /* FIXME: Maybe it's better to make sure that grabmouse_low
1125
       is called only when a window is ready?                */
1126
    if (sdl_window)
1127
        SDL_SetWindowGrab(sdl_window, a ? SDL_TRUE : SDL_FALSE);
1128
    return SDL_SetRelativeMouseMode(a ? SDL_TRUE : SDL_FALSE);
4446 helixhorne 1129
#else
1130
    UNREFERENCED_PARAMETER(a);
1131
    return 0;
4432 terminx 1132
#endif
4089 hendricks2 1133
}
4767 hendricks2 1134
#endif
4089 hendricks2 1135
 
1136
//
5 Plagman 1137
// grabmouse() -- show/hide mouse cursor
1138
//
6851 terminx 1139
void mouseGrabInput(bool grab)
5 Plagman 1140
{
6827 terminx 1141
    if (appactive && g_mouseEnabled)
342 terminx 1142
    {
5921 hendricks2 1143
#if !defined EDUKE32_TOUCH_DEVICES
6851 terminx 1144
        if ((grab != g_mouseGrabbed) && !grabmouse_low(grab))
4095 helixhorne 1145
#endif
6851 terminx 1146
            g_mouseGrabbed = grab;
342 terminx 1147
    }
1148
    else
6851 terminx 1149
        g_mouseGrabbed = grab;
4749 terminx 1150
 
6827 terminx 1151
    g_mousePos.x = g_mousePos.y = 0;
5 Plagman 1152
}
1153
 
6827 terminx 1154
void mouseLockToWindow(char a)
4738 hendricks2 1155
{
4906 terminx 1156
    if (!(a & 2))
1157
    {
6827 terminx 1158
        mouseGrabInput(a);
1159
        g_mouseLockedToWindow = g_mouseGrabbed;
4906 terminx 1160
    }
1161
 
1162
    SDL_ShowCursor((osd && osd->flags & OSD_CAPTURE) ? SDL_ENABLE : SDL_DISABLE);
4738 hendricks2 1163
}
1164
 
5 Plagman 1165
//
1166
// setjoydeadzone() -- sets the dead and saturation zones for the joystick
1167
//
6827 terminx 1168
void joySetDeadZone(int32_t axis, uint16_t dead, uint16_t satur)
655 terminx 1169
{
1716 plagman 1170
    joydead[axis] = dead;
1171
    joysatur[axis] = satur;
655 terminx 1172
}
5 Plagman 1173
 
1174
 
1175
//
1176
// getjoydeadzone() -- gets the dead and saturation zones for the joystick
1177
//
6827 terminx 1178
void joyGetDeadZone(int32_t axis, uint16_t *dead, uint16_t *satur)
5 Plagman 1179
{
1716 plagman 1180
    *dead = joydead[axis];
1181
    *satur = joysatur[axis];
5 Plagman 1182
}
1183
 
1184
 
1185
//
1186
//
1187
// ---------------------------------------
1188
//
1189
// All things Timer
1190
// Ken did this
1191
//
1192
// ---------------------------------------
1193
//
1194
//
1195
 
1196
 
2778 helixhorne 1197
 
5 Plagman 1198
 
1199
//
1200
//
1201
// ---------------------------------------
1202
//
1203
// All things Video
1204
//
1205
// ---------------------------------------
1206
//
109 terminx 1207
//
5 Plagman 1208
 
1209
 
1210
//
1211
// getvalidmodes() -- figure out what video modes are available
1212
//
4068 helixhorne 1213
static int sortmodes(const void *a_, const void *b_)
5 Plagman 1214
{
7922 terminx 1215
    auto a = (const struct validmode_t *)b_;
1216
    auto b = (const struct validmode_t *)a_;
4068 helixhorne 1217
 
7164 terminx 1218
    int x;
1219
 
109 terminx 1220
    if ((x = a->fs   - b->fs)   != 0) return x;
1221
    if ((x = a->bpp  - b->bpp)  != 0) return x;
1222
    if ((x = a->xdim - b->xdim) != 0) return x;
1223
    if ((x = a->ydim - b->ydim) != 0) return x;
5 Plagman 1224
 
109 terminx 1225
    return 0;
5 Plagman 1226
}
4432 terminx 1227
 
5 Plagman 1228
static char modeschecked=0;
4432 terminx 1229
 
4749 terminx 1230
#if SDL_MAJOR_VERSION != 1
6828 terminx 1231
void videoGetModes(void)
5 Plagman 1232
{
4749 terminx 1233
    int32_t i, maxx = 0, maxy = 0;
4432 terminx 1234
    SDL_DisplayMode dispmode;
8063 terminx 1235
    int const display = r_displayindex < SDL_GetNumVideoDisplays() ? r_displayindex : 0;
4432 terminx 1236
 
4749 terminx 1237
    if (modeschecked || novideo)
1238
        return;
4432 terminx 1239
 
4749 terminx 1240
    validmodecnt = 0;
4432 terminx 1241
    //    initprintf("Detecting video modes:\n");
1242
 
1243
    // do fullscreen modes first
8063 terminx 1244
    for (i = 0; i < SDL_GetNumDisplayModes(display); i++)
4089 hendricks2 1245
    {
8063 terminx 1246
        SDL_GetDisplayMode(display, i, &dispmode);
6435 terminx 1247
 
1248
        if (!SDL_CHECKMODE(dispmode.w, dispmode.h) ||
5621 terminx 1249
            (maxrefreshfreq && (dispmode.refresh_rate > maxrefreshfreq)))
4749 terminx 1250
            continue;
4089 hendricks2 1251
 
1252
        // HACK: 8-bit == Software, 32-bit == OpenGL
4749 terminx 1253
        SDL_ADDMODE(dispmode.w, dispmode.h, 8, 1);
4089 hendricks2 1254
#ifdef USE_OPENGL
1255
        if (!nogl)
4749 terminx 1256
            SDL_ADDMODE(dispmode.w, dispmode.h, 32, 1);
4089 hendricks2 1257
#endif
4749 terminx 1258
        if ((dispmode.w > maxx) || (dispmode.h > maxy))
4089 hendricks2 1259
        {
1260
            maxx = dispmode.w;
1261
            maxy = dispmode.h;
1262
        }
1263
    }
5 Plagman 1264
 
4749 terminx 1265
    SDL_CHECKFSMODES(maxx, maxy);
1266
 
109 terminx 1267
    // add windowed modes next
7115 terminx 1268
    // SDL sorts display modes largest to smallest, so we can just compare with mode 0
1269
    // to make sure we aren't adding modes that are larger than the actual screen res
8063 terminx 1270
    SDL_GetDisplayMode(display, 0, &dispmode);
7115 terminx 1271
 
6827 terminx 1272
    for (i = 0; g_defaultVideoModes[i].x; i++)
342 terminx 1273
    {
7115 terminx 1274
        auto const &mode = g_defaultVideoModes[i];
1275
 
1276
        if (mode.x > dispmode.w || mode.y > dispmode.h || !SDL_CHECKMODE(mode.x, mode.y))
4749 terminx 1277
            continue;
1278
 
7115 terminx 1279
        // 8-bit == Software, 32-bit == OpenGL
1280
        SDL_ADDMODE(mode.x, mode.y, 8, 0);
4749 terminx 1281
 
4089 hendricks2 1282
#ifdef USE_OPENGL
4749 terminx 1283
        if (nogl)
1284
            continue;
1285
 
7115 terminx 1286
        SDL_ADDMODE(mode.x, mode.y, 32, 0);
4089 hendricks2 1287
#endif
4432 terminx 1288
    }
5 Plagman 1289
 
4749 terminx 1290
    qsort((void *)validmode, validmodecnt, sizeof(struct validmode_t), &sortmodes);
5 Plagman 1291
 
4749 terminx 1292
    modeschecked = 1;
5 Plagman 1293
}
4432 terminx 1294
#endif
5 Plagman 1295
 
1296
//
1297
// checkvideomode() -- makes sure the video mode passed is legal
1298
//
6828 terminx 1299
int32_t videoCheckMode(int32_t *x, int32_t *y, int32_t c, int32_t fs, int32_t forced)
5 Plagman 1300
{
1205 terminx 1301
    int32_t i, nearest=-1, dx, dy, odx=9999, ody=9999;
5 Plagman 1302
 
6828 terminx 1303
    videoGetModes();
5 Plagman 1304
 
109 terminx 1305
    if (c>8
5 Plagman 1306
#ifdef USE_OPENGL
109 terminx 1307
            && nogl
5 Plagman 1308
#endif
109 terminx 1309
       ) return -1;
5 Plagman 1310
 
109 terminx 1311
    // fix up the passed resolution values to be multiples of 8
1312
    // and at least 320x200 or at most MAXXDIMxMAXYDIM
4749 terminx 1313
    *x = clamp(*x, 320, MAXXDIM);
1314
    *y = clamp(*y, 200, MAXYDIM);
5 Plagman 1315
 
4749 terminx 1316
    for (i = 0; i < validmodecnt; i++)
342 terminx 1317
    {
4749 terminx 1318
        if (validmode[i].bpp != c || validmode[i].fs != fs)
1319
            continue;
1320
 
109 terminx 1321
        dx = klabs(validmode[i].xdim - *x);
1322
        dy = klabs(validmode[i].ydim - *y);
4749 terminx 1323
 
342 terminx 1324
        if (!(dx | dy))
584 terminx 1325
        {
1326
            // perfect match
109 terminx 1327
            nearest = i;
1328
            break;
1329
        }
4749 terminx 1330
 
342 terminx 1331
        if ((dx <= odx) && (dy <= ody))
1332
        {
109 terminx 1333
            nearest = i;
4749 terminx 1334
            odx = dx;
1335
            ody = dy;
109 terminx 1336
        }
1337
    }
1338
 
331 terminx 1339
#ifdef ANY_WINDOWED_SIZE
194 terminx 1340
    if (!forced && (fs&1) == 0 && (nearest < 0 || (validmode[nearest].xdim!=*x || validmode[nearest].ydim!=*y)))
109 terminx 1341
        return 0x7fffffffl;
331 terminx 1342
#endif
5 Plagman 1343
 
342 terminx 1344
    if (nearest < 0)
109 terminx 1345
        return -1;
5 Plagman 1346
 
109 terminx 1347
    *x = validmode[nearest].xdim;
1348
    *y = validmode[nearest].ydim;
5 Plagman 1349
 
4749 terminx 1350
    return nearest;
5 Plagman 1351
}
1352
 
4089 hendricks2 1353
static void destroy_window_resources()
2777 helixhorne 1354
{
4749 terminx 1355
/* We should NOT destroy the window surface. This is done automatically
1356
   when SDL_DestroyWindow or SDL_SetVideoMode is called.             */
1357
 
1358
#if SDL_MAJOR_VERSION == 2
1359
    if (sdl_context)
1360
        SDL_GL_DeleteContext(sdl_context);
1361
    sdl_context = NULL;
1362
    if (sdl_window)
1363
        SDL_DestroyWindow(sdl_window);
1364
    sdl_window = NULL;
4088 hendricks2 1365
#endif
2777 helixhorne 1366
}
1367
 
4749 terminx 1368
#ifdef USE_OPENGL
1369
void sdlayer_setvideomode_opengl(void)
1370
{
6919 pogokeen 1371
    glsurface_destroy();
4749 terminx 1372
    polymost_glreset();
1373
 
6656 pogokeen 1374
    glShadeModel(GL_SMOOTH);  // GL_FLAT
1375
    glClearColor(0, 0, 0, 1.0);  // Black Background
1376
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);  // Use FASTEST for ortho!
1377
//    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
4997 terminx 1378
 
1379
#ifndef EDUKE32_GLES
6656 pogokeen 1380
    glDisable(GL_DITHER);
4997 terminx 1381
#endif
4749 terminx 1382
 
6656 pogokeen 1383
    glinfo.vendor = (const char *) glGetString(GL_VENDOR);
1384
    glinfo.renderer = (const char *) glGetString(GL_RENDERER);
1385
    glinfo.version = (const char *) glGetString(GL_VERSION);
1386
    glinfo.extensions = (const char *) glGetString(GL_EXTENSIONS);
4749 terminx 1387
 
1388
#ifdef POLYMER
1389
    if (!Bstrcmp(glinfo.vendor, "ATI Technologies Inc."))
1390
    {
1391
        pr_ati_fboworkaround = 1;
1392
        initprintf("Enabling ATI FBO color attachment workaround.\n");
1393
 
1394
        if (Bstrstr(glinfo.renderer, "Radeon X1"))
1395
        {
1396
            pr_ati_nodepthoffset = 1;
1397
            initprintf("Enabling ATI R520 polygon offset workaround.\n");
1398
        }
1399
        else
1400
            pr_ati_nodepthoffset = 0;
1401
#ifdef __APPLE__
1402
        // See bug description at http://lists.apple.com/archives/mac-opengl/2005/Oct/msg00169.html
1403
        if (!Bstrncmp(glinfo.renderer, "ATI Radeon 9600", 15))
1404
        {
1405
            pr_ati_textureformat_one = 1;
1406
            initprintf("Enabling ATI Radeon 9600 texture format workaround.\n");
1407
        }
1408
        else
1409
            pr_ati_textureformat_one = 0;
1410
#endif
1411
    }
1412
    else
1413
        pr_ati_fboworkaround = 0;
1414
#endif  // defined POLYMER
1415
 
1416
    glinfo.maxanisotropy = 1.0;
1417
    glinfo.bgra = 0;
4992 terminx 1418
    glinfo.clamptoedge = 1;
1419
    glinfo.multitex = 1;
4749 terminx 1420
 
1421
    // process the extensions string and flag stuff we recognize
4992 terminx 1422
 
1423
    glinfo.texnpot = !!Bstrstr(glinfo.extensions, "GL_ARB_texture_non_power_of_two") || !!Bstrstr(glinfo.extensions, "GL_OES_texture_npot");
4752 terminx 1424
    glinfo.multisample = !!Bstrstr(glinfo.extensions, "GL_ARB_multisample");
1425
    glinfo.nvmultisamplehint = !!Bstrstr(glinfo.extensions, "GL_NV_multisample_filter_hint");
1426
    glinfo.arbfp = !!Bstrstr(glinfo.extensions, "GL_ARB_fragment_program");
1427
    glinfo.depthtex = !!Bstrstr(glinfo.extensions, "GL_ARB_depth_texture");
1428
    glinfo.shadow = !!Bstrstr(glinfo.extensions, "GL_ARB_shadow");
4992 terminx 1429
    glinfo.fbos = !!Bstrstr(glinfo.extensions, "GL_EXT_framebuffer_object") || !!Bstrstr(glinfo.extensions, "GL_OES_framebuffer_object");
1430
 
5690 hendricks2 1431
#if !defined EDUKE32_GLES
1432
    glinfo.texcompr = !!Bstrstr(glinfo.extensions, "GL_ARB_texture_compression") && Bstrcmp(glinfo.vendor, "ATI Technologies Inc.");
5673 hendricks2 1433
# ifdef DYNAMIC_GLEXT
6656 pogokeen 1434
    if (glinfo.texcompr && (!glCompressedTexImage2D || !glGetCompressedTexImage))
5673 hendricks2 1435
    {
1436
        // lacking the necessary extensions to do this
1437
        initprintf("Warning: the GL driver lacks necessary functions to use caching\n");
1438
        glinfo.texcompr = 0;
1439
    }
1440
# endif
1441
 
4997 terminx 1442
    glinfo.bgra = !!Bstrstr(glinfo.extensions, "GL_EXT_bgra");
4992 terminx 1443
    glinfo.clamptoedge = !!Bstrstr(glinfo.extensions, "GL_EXT_texture_edge_clamp") ||
1444
                         !!Bstrstr(glinfo.extensions, "GL_SGIS_texture_edge_clamp");
4752 terminx 1445
    glinfo.rect =
1446
    !!Bstrstr(glinfo.extensions, "GL_NV_texture_rectangle") || !!Bstrstr(glinfo.extensions, "GL_EXT_texture_rectangle");
4992 terminx 1447
 
4752 terminx 1448
    glinfo.multitex = !!Bstrstr(glinfo.extensions, "GL_ARB_multitexture");
4992 terminx 1449
 
4752 terminx 1450
    glinfo.envcombine = !!Bstrstr(glinfo.extensions, "GL_ARB_texture_env_combine");
1451
    glinfo.vbos = !!Bstrstr(glinfo.extensions, "GL_ARB_vertex_buffer_object");
1452
    glinfo.sm4 = !!Bstrstr(glinfo.extensions, "GL_EXT_gpu_shader4");
1453
    glinfo.occlusionqueries = !!Bstrstr(glinfo.extensions, "GL_ARB_occlusion_query");
1454
    glinfo.glsl = !!Bstrstr(glinfo.extensions, "GL_ARB_shader_objects");
1455
    glinfo.debugoutput = !!Bstrstr(glinfo.extensions, "GL_ARB_debug_output");
5298 Plagman 1456
    glinfo.bufferstorage = !!Bstrstr(glinfo.extensions, "GL_ARB_buffer_storage");
6662 pogokeen 1457
    glinfo.sync = !!Bstrstr(glinfo.extensions, "GL_ARB_sync");
7753 pogokeen 1458
    glinfo.depthclamp = !!Bstrstr(glinfo.extensions, "GL_ARB_depth_clamp");
1459
    glinfo.clipcontrol = !!Bstrstr(glinfo.extensions, "GL_ARB_clip_control");
4749 terminx 1460
 
4752 terminx 1461
    if (Bstrstr(glinfo.extensions, "WGL_3DFX_gamma_control"))
4749 terminx 1462
    {
1463
        static int32_t warnonce;
1464
        // 3dfx cards have issues with fog
1465
        nofog = 1;
1466
        if (!(warnonce & 1))
1467
            initprintf("3dfx card detected: OpenGL fog disabled\n");
1468
        warnonce |= 1;
1469
    }
5690 hendricks2 1470
#else
1471
    // don't bother checking because ETC2 et al. are not listed in extensions anyway
1472
    glinfo.texcompr = 1; // !!Bstrstr(glinfo.extensions, "GL_OES_compressed_ETC1_RGB8_texture");
4992 terminx 1473
#endif
4749 terminx 1474
 
4992 terminx 1475
//    if (Bstrstr(glinfo.extensions, "GL_EXT_texture_filter_anisotropic"))
6656 pogokeen 1476
        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glinfo.maxanisotropy);
4992 terminx 1477
 
4749 terminx 1478
    if (!glinfo.dumped)
1479
    {
1480
        int32_t oldbpp = bpp;
1481
        bpp = 32;
1482
        osdcmd_glinfo(NULL);
1483
        glinfo.dumped = 1;
1484
        bpp = oldbpp;
1485
    }
1486
}
1487
#endif  // defined USE_OPENGL
1488
 
5 Plagman 1489
//
1490
// setvideomode() -- set SDL video mode
1491
//
4749 terminx 1492
 
1493
int32_t setvideomode_sdlcommon(int32_t *x, int32_t *y, int32_t c, int32_t fs, int32_t *regrab)
5 Plagman 1494
{
4749 terminx 1495
    if ((fs == fullscreen) && (*x == xres) && (*y == yres) && (c == bpp) && !videomodereset)
109 terminx 1496
        return 0;
5 Plagman 1497
 
6828 terminx 1498
    if (videoCheckMode(x, y, c, fs, 0) < 0)
4749 terminx 1499
        return -1;
109 terminx 1500
 
4820 hendricks2 1501
#ifdef GEKKO
1502
    if (!sdl_surface) // only run this the first time we set a video mode
1503
        wii_initgamevideo();
1504
#endif
1505
 
194 terminx 1506
    startwin_close();
5 Plagman 1507
 
6827 terminx 1508
    if (g_mouseGrabbed)
342 terminx 1509
    {
4749 terminx 1510
        *regrab = 1;
6827 terminx 1511
        mouseGrabInput(0);
109 terminx 1512
    }
5 Plagman 1513
 
6828 terminx 1514
    while (lockcount) videoEndDrawing();
5 Plagman 1515
 
1820 terminx 1516
#ifdef USE_OPENGL
6919 pogokeen 1517
    if (sdl_surface)
1518
    {
1519
        if (bpp > 8)
1520
            polymost_glreset();
6938 pogokeen 1521
    }
1522
    if (!nogl)
1523
    {
1524
        if (bpp == 8)
6919 pogokeen 1525
            glsurface_destroy();
6938 pogokeen 1526
        if ((fs == fullscreen) && (*x == xres) && (*y == yres) && (bpp != 0) && !videomodereset)
1527
            return 0;
6919 pogokeen 1528
    }
6939 pogokeen 1529
    else
5 Plagman 1530
#endif
6939 pogokeen 1531
    {
1532
       softsurface_destroy();
1533
    }
5 Plagman 1534
 
2222 helixhorne 1535
    // clear last gamma/contrast/brightness so that it will be set anew
1536
    lastvidgcb[0] = lastvidgcb[1] = lastvidgcb[2] = 0.0f;
1537
 
4749 terminx 1538
    return 1;
1539
}
1540
 
1541
void setvideomode_sdlcommonpost(int32_t x, int32_t y, int32_t c, int32_t fs, int32_t regrab)
1542
{
1543
    wm_setapptitle(apptitle);
1544
 
1545
#ifdef USE_OPENGL
6919 pogokeen 1546
    if (!nogl)
4749 terminx 1547
        sdlayer_setvideomode_opengl();
1548
#endif
1549
 
1550
    xres = x;
1551
    yres = y;
1552
    bpp = c;
1553
    fullscreen = fs;
1554
    // bytesperline = sdl_surface->pitch;
1555
    numpages = c > 8 ? 2 : 1;
1556
    frameplace = 0;
1557
    lockcount = 0;
1558
    modechange = 1;
1559
    videomodereset = 0;
1560
 
1561
    // save the current system gamma to determine if gamma is available
5659 terminx 1562
#ifndef EDUKE32_GLES
4749 terminx 1563
    if (!gammabrightness)
342 terminx 1564
    {
4749 terminx 1565
        //        float f = 1.0 + ((float)curbrightness / 10.0);
1566
#if SDL_MAJOR_VERSION != 1
1567
        if (SDL_GetWindowGammaRamp(sdl_window, sysgamma[0], sysgamma[1], sysgamma[2]) == 0)
1568
#else
1569
        if (SDL_GetGammaRamp(sysgamma[0], sysgamma[1], sysgamma[2]) >= 0)
1570
#endif
1571
            gammabrightness = 1;
1572
 
1573
        // see if gamma really is working by trying to set the brightness
6828 terminx 1574
        if (gammabrightness && videoSetGamma() < 0)
4749 terminx 1575
            gammabrightness = 0;  // nope
109 terminx 1576
    }
5659 terminx 1577
#endif
4080 hendricks2 1578
 
6829 terminx 1579
    videoFadePalette(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta);
4749 terminx 1580
 
1581
    if (regrab)
6827 terminx 1582
        mouseGrabInput(g_mouseLockedToWindow);
4749 terminx 1583
}
1584
 
1585
#if SDL_MAJOR_VERSION!=1
5621 terminx 1586
void setrefreshrate(void)
1587
{
8063 terminx 1588
    int const display = r_displayindex < SDL_GetNumVideoDisplays() ? r_displayindex : 0;
1589
 
5621 terminx 1590
    SDL_DisplayMode dispmode;
8063 terminx 1591
    SDL_GetCurrentDisplayMode(display, &dispmode);
5621 terminx 1592
 
1593
    dispmode.refresh_rate = maxrefreshfreq;
1594
 
1595
    SDL_DisplayMode newmode;
8063 terminx 1596
    SDL_GetClosestDisplayMode(display, &dispmode, &newmode);
5621 terminx 1597
 
8050 pogokeen 1598
    char error = 0;
1599
 
5621 terminx 1600
    if (dispmode.refresh_rate != newmode.refresh_rate)
1601
    {
1602
        initprintf("Refresh rate: %dHz\n", newmode.refresh_rate);
8050 pogokeen 1603
        error = SDL_SetWindowDisplayMode(sdl_window, &newmode);
5621 terminx 1604
    }
6689 pogokeen 1605
 
6833 terminx 1606
    if (!newmode.refresh_rate)
1607
        newmode.refresh_rate = 60;
8031 terminx 1608
 
8050 pogokeen 1609
    refreshfreq = error ? -1 : newmode.refresh_rate;
8031 terminx 1610
    currentVBlankInterval = timerGetFreqU64()/(double)newmode.refresh_rate;
5621 terminx 1611
}
1612
 
6828 terminx 1613
int32_t videoSetMode(int32_t x, int32_t y, int32_t c, int32_t fs)
4749 terminx 1614
{
1615
    int32_t regrab = 0, ret;
109 terminx 1616
 
4749 terminx 1617
    ret = setvideomode_sdlcommon(&x, &y, c, fs, &regrab);
6938 pogokeen 1618
    if (ret != 1)
1619
    {
1620
        if (ret == 0)
1621
        {
1622
            setvideomode_sdlcommonpost(x, y, c, fs, regrab);
1623
        }
1624
        return ret;
1625
    }
4749 terminx 1626
 
4089 hendricks2 1627
    // deinit
1628
    destroy_window_resources();
1629
 
4749 terminx 1630
    initprintf("Setting video mode %dx%d (%d-bpp %s)\n", x, y, c, ((fs & 1) ? "fullscreen" : "windowed"));
1631
 
8063 terminx 1632
    int const display = r_displayindex < SDL_GetNumVideoDisplays() ? r_displayindex : 0;
1633
 
7204 terminx 1634
    SDL_DisplayMode desktopmode;
8063 terminx 1635
    SDL_GetDesktopDisplayMode(display, &desktopmode);
7204 terminx 1636
 
8060 terminx 1637
    int const matchedResolution = (desktopmode.w == x && desktopmode.h == y);
8063 terminx 1638
    int const borderless = (r_borderless == 1 || (r_borderless == 2 && matchedResolution)) ? SDL_WINDOW_BORDERLESS : 0;
1820 terminx 1639
#ifdef USE_OPENGL
6919 pogokeen 1640
    if (c > 8 || !nogl)
342 terminx 1641
    {
7045 terminx 1642
        int32_t i;
5526 hendricks2 1643
#ifdef USE_GLEXT
4997 terminx 1644
        int32_t multisamplecheck = (glmultisample > 0);
1645
#else
1646
        int32_t multisamplecheck = 0;
1647
#endif
4749 terminx 1648
        if (nogl)
1649
            return -1;
5 Plagman 1650
 
4755 helixhorne 1651
        struct glattribs
1652
        {
1653
            SDL_GLattr attr;
1654
            int32_t value;
4992 terminx 1655
        } sdlayer_gl_attributes[] =
4755 helixhorne 1656
        {
6603 hendricks2 1657
#ifdef EDUKE32_GLES
4992 terminx 1658
              { SDL_GL_CONTEXT_MAJOR_VERSION, 1 },
1659
              { SDL_GL_CONTEXT_MINOR_VERSION, 1 },
1660
#endif
1661
              { SDL_GL_DOUBLEBUFFER, 1 },
5526 hendricks2 1662
#ifdef USE_GLEXT
4992 terminx 1663
              { SDL_GL_MULTISAMPLEBUFFERS, glmultisample > 0 },
1664
              { SDL_GL_MULTISAMPLESAMPLES, glmultisample },
4997 terminx 1665
#endif
8035 terminx 1666
              { SDL_GL_STENCIL_SIZE, 1 },
4992 terminx 1667
              { SDL_GL_ACCELERATED_VISUAL, 1 },
1668
          };
3221 hendricks2 1669
 
342 terminx 1670
        do
1671
        {
4749 terminx 1672
            SDL_GL_ATTRIBUTES(i, sdlayer_gl_attributes);
109 terminx 1673
 
890 terminx 1674
            /* HACK: changing SDL GL attribs only works before surface creation,
1675
               so we have to create a new surface in a different format first
1676
               to force the surface we WANT to be recreated instead of reused. */
8060 terminx 1677
 
1678
 
8063 terminx 1679
            sdl_window = SDL_CreateWindow("", windowpos ? windowx : (int)SDL_WINDOWPOS_CENTERED_DISPLAY(display),
1680
                                          windowpos ? windowy : (int)SDL_WINDOWPOS_CENTERED_DISPLAY(display), x, y,
8060 terminx 1681
                                          SDL_WINDOW_OPENGL | borderless);
2777 helixhorne 1682
 
4749 terminx 1683
            if (sdl_window)
1684
                sdl_context = SDL_GL_CreateContext(sdl_window);
2777 helixhorne 1685
 
4749 terminx 1686
            if (!sdl_window || !sdl_context)
4089 hendricks2 1687
            {
4749 terminx 1688
                initprintf("Unable to set video mode: %s failed: %s\n", sdl_window ? "SDL_GL_CreateContext" : "SDL_GL_CreateWindow",  SDL_GetError());
8060 terminx 1689
                nogl = 1;
4089 hendricks2 1690
                destroy_window_resources();
2777 helixhorne 1691
                return -1;
4089 hendricks2 1692
            }
4749 terminx 1693
 
6656 pogokeen 1694
            gladLoadGLLoader(SDL_GL_GetProcAddress);
6921 pogokeen 1695
            if (GLVersion.major < 2)
1696
            {
1697
                initprintf("Your computer does not support OpenGL version 2 or greater. GL modes are unavailable.\n");
1698
                nogl = 1;
1699
                destroy_window_resources();
1700
                return -1;
1701
            }
6700 hendricks2 1702
 
8060 terminx 1703
            SDL_SetWindowFullscreen(sdl_window, ((fs & 1) ? (matchedResolution ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN) : 0));
5953 hendricks2 1704
            SDL_GL_SetSwapInterval(vsync_renderlayer);
4089 hendricks2 1705
 
5621 terminx 1706
            setrefreshrate();
4749 terminx 1707
        } while (multisamplecheck--);
342 terminx 1708
    }
1709
    else
2014 helixhorne 1710
#endif  // defined USE_OPENGL
109 terminx 1711
    {
2777 helixhorne 1712
        // init
8063 terminx 1713
        sdl_window = SDL_CreateWindow("", windowpos ? windowx : (int)SDL_WINDOWPOS_CENTERED_DISPLAY(display),
1714
                                      windowpos ? windowy : (int)SDL_WINDOWPOS_CENTERED_DISPLAY(display), x, y,
8060 terminx 1715
                                      borderless);
4089 hendricks2 1716
        if (!sdl_window)
4432 terminx 1717
            SDL2_VIDEO_ERR("SDL_CreateWindow");
2777 helixhorne 1718
 
5621 terminx 1719
        setrefreshrate();
1720
 
4253 hendricks2 1721
        if (!sdl_surface)
1722
        {
1723
            sdl_surface = SDL_GetWindowSurface(sdl_window);
1724
            if (!sdl_surface)
4432 terminx 1725
                SDL2_VIDEO_ERR("SDL_GetWindowSurface");
4253 hendricks2 1726
        }
1727
 
8060 terminx 1728
        SDL_SetWindowFullscreen(sdl_window, ((fs & 1) ? (matchedResolution ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN) : 0));
109 terminx 1729
    }
5 Plagman 1730
 
6544 terminx 1731
    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
4749 terminx 1732
    setvideomode_sdlcommonpost(x, y, c, fs, regrab);
5 Plagman 1733
 
109 terminx 1734
    return 0;
5 Plagman 1735
}
4749 terminx 1736
#endif
5 Plagman 1737
 
1738
//
1739
// resetvideomode() -- resets the video system
1740
//
6828 terminx 1741
void videoResetMode(void)
5 Plagman 1742
{
109 terminx 1743
    videomodereset = 1;
1744
    modeschecked = 0;
5 Plagman 1745
}
1746
 
1747
//
1748
// begindrawing() -- locks the framebuffer for drawing
1749
//
5311 helixhorne 1750
 
1751
#ifdef DEBUG_FRAME_LOCKING
1752
uint32_t begindrawing_line[BEGINDRAWING_SIZE];
1753
const char *begindrawing_file[BEGINDRAWING_SIZE];
1754
void begindrawing_real(void)
1755
#else
6828 terminx 1756
void videoBeginDrawing(void)
5311 helixhorne 1757
#endif
5 Plagman 1758
{
342 terminx 1759
    if (bpp > 8)
1760
    {
109 terminx 1761
        if (offscreenrendering) return;
1762
        frameplace = 0;
1763
        bytesperline = 0;
1764
        modechange = 0;
1765
        return;
1766
    }
6933 pogokeen 1767
 
1768
    // lock the frame
1769
    if (lockcount++ > 0)
1770
        return;
1771
 
7853 pogokeen 1772
    static intptr_t backupFrameplace = 0;
6933 pogokeen 1773
 
7733 pogokeen 1774
    if (inpreparemirror)
1775
    {
7853 pogokeen 1776
        //POGO: if we are offscreenrendering and we need to render a mirror
1777
        //      or we are rendering a mirror and we start offscreenrendering,
1778
        //      backup our offscreen target so we can restore it later
1779
        //      (but only allow one level deep,
1780
        //       i.e. no viewscreen showing a camera showing a mirror that reflects the same viewscreen and recursing)
1781
        if (offscreenrendering)
1782
        {
1783
            if (!backupFrameplace)
1784
                backupFrameplace = frameplace;
1785
            else if (frameplace != (intptr_t)mirrorBuffer &&
1786
                     frameplace != backupFrameplace)
1787
                return;
1788
        }
1789
 
7733 pogokeen 1790
        frameplace = (intptr_t)mirrorBuffer;
7853 pogokeen 1791
 
1792
        if (offscreenrendering)
1793
            return;
7733 pogokeen 1794
    }
7853 pogokeen 1795
    else if (offscreenrendering)
1796
    {
1797
        if (backupFrameplace)
1798
        {
1799
            frameplace = backupFrameplace;
1800
            backupFrameplace = 0;
1801
        }
1802
        return;
1803
    }
7733 pogokeen 1804
    else
6939 pogokeen 1805
#ifdef USE_OPENGL
6933 pogokeen 1806
    if (!nogl)
6919 pogokeen 1807
    {
1808
        frameplace = (intptr_t)glsurface_getBuffer();
1809
    }
7733 pogokeen 1810
    else
6939 pogokeen 1811
#endif
7733 pogokeen 1812
    {
1813
        frameplace = (intptr_t)softsurface_getBuffer();
1814
    }
6919 pogokeen 1815
 
6939 pogokeen 1816
    if (modechange)
342 terminx 1817
    {
6939 pogokeen 1818
        bytesperline = xdim;
3291 helixhorne 1819
        calc_ylookup(bytesperline, ydim);
109 terminx 1820
        modechange=0;
1821
    }
5 Plagman 1822
}
1823
 
1824
 
1825
//
1826
// enddrawing() -- unlocks the framebuffer
1827
//
6828 terminx 1828
void videoEndDrawing(void)
5 Plagman 1829
{
6933 pogokeen 1830
    if (bpp > 8)
342 terminx 1831
    {
109 terminx 1832
        if (!offscreenrendering) frameplace = 0;
1833
        return;
1834
    }
5 Plagman 1835
 
109 terminx 1836
    if (!frameplace) return;
584 terminx 1837
    if (lockcount > 1) { lockcount--; return; }
109 terminx 1838
    if (!offscreenrendering) frameplace = 0;
1839
    if (lockcount == 0) return;
1840
    lockcount = 0;
5 Plagman 1841
}
1842
 
1843
//
1844
// showframe() -- update the display
1845
//
4749 terminx 1846
#if SDL_MAJOR_VERSION != 1
4992 terminx 1847
 
1848
#ifdef __ANDROID__
5652 terminx 1849
extern "C" void AndroidDrawControls();
4992 terminx 1850
#endif
1851
 
6828 terminx 1852
void videoShowFrame(int32_t w)
5 Plagman 1853
{
655 terminx 1854
    UNREFERENCED_PARAMETER(w);
5 Plagman 1855
 
4992 terminx 1856
#ifdef __ANDROID__
1857
    if (mobile_halted) return;
1858
#endif
1859
 
5 Plagman 1860
#ifdef USE_OPENGL
6919 pogokeen 1861
    if (!nogl)
342 terminx 1862
    {
6919 pogokeen 1863
        if (bpp > 8)
1864
        {
1865
            if (palfadedelta)
1866
                fullscreen_tint_gl(palfadergb.r, palfadergb.g, palfadergb.b, palfadedelta);
5 Plagman 1867
 
4992 terminx 1868
#ifdef __ANDROID__
6919 pogokeen 1869
            AndroidDrawControls();
4992 terminx 1870
#endif
6919 pogokeen 1871
        }
1872
        else
1873
        {
6932 pogokeen 1874
            glsurface_blitBuffer();
6919 pogokeen 1875
        }
6700 hendricks2 1876
 
4082 hendricks2 1877
        SDL_GL_SwapWindow(sdl_window);
8031 terminx 1878
 
7977 terminx 1879
        if (vsync)
1880
        {
8031 terminx 1881
            switch (swapcomplete)
1882
            {
1883
                case 1: glFinish(); break;
1884
                case 2:
1885
                {
1886
                    static uint64_t lastSwapTime;
1887
                    // busy loop until we're ready to update again
1888
                    // sit on it and spin
1889
                    uint64_t swapTime = timerGetTicksU64();
1890
                    while ((double)(timerGetTicksU64() - lastSwapTime) < currentVBlankInterval) { }
1891
                    lastSwapTime = swapTime;
1892
                }
1893
                break;
1894
                case 3: glFlush(); break;
1895
            }
7977 terminx 1896
        }
109 terminx 1897
        return;
1898
    }
5 Plagman 1899
#endif
1900
 
109 terminx 1901
    if (offscreenrendering) return;
5 Plagman 1902
 
342 terminx 1903
    if (lockcount)
1904
    {
584 terminx 1905
        printf("Frame still locked %d times when showframe() called.\n", lockcount);
6828 terminx 1906
        while (lockcount) videoEndDrawing();
109 terminx 1907
    }
1908
 
6939 pogokeen 1909
    if (SDL_MUSTLOCK(sdl_surface)) SDL_LockSurface(sdl_surface);
1910
    softsurface_blitBuffer((uint32_t*) sdl_surface->pixels, sdl_surface->format->BitsPerPixel);
1911
    if (SDL_MUSTLOCK(sdl_surface)) SDL_UnlockSurface(sdl_surface);
2221 helixhorne 1912
 
6939 pogokeen 1913
    if (SDL_UpdateWindowSurface(sdl_window))
4089 hendricks2 1914
    {
1915
        // If a fullscreen X11 window is minimized then this may be required.
1916
        // FIXME: What to do if this fails...
1917
        sdl_surface = SDL_GetWindowSurface(sdl_window);
1918
        SDL_UpdateWindowSurface(sdl_window);
1919
    }
4749 terminx 1920
}
2777 helixhorne 1921
#endif
5 Plagman 1922
//
1923
// setpalette() -- set palette values
1924
//
6828 terminx 1925
int32_t videoUpdatePalette(int32_t start, int32_t num)
5 Plagman 1926
{
6939 pogokeen 1927
    UNREFERENCED_PARAMETER(start);
1928
    UNREFERENCED_PARAMETER(num);
1929
 
4749 terminx 1930
    if (bpp > 8)
1931
        return 0;  // no palette in opengl
5 Plagman 1932
 
6939 pogokeen 1933
#ifdef USE_OPENGL
1934
    if (!nogl)
1935
        glsurface_setPalette(curpalettefaded);
1936
    else
4074 hendricks2 1937
#endif
6939 pogokeen 1938
    {
1939
        if (sdl_surface)
1940
            softsurface_setPalette(curpalettefaded,
1941
                                   sdl_surface->format->Rmask,
1942
                                   sdl_surface->format->Gmask,
1943
                                   sdl_surface->format->Bmask);
1944
    }
109 terminx 1945
 
2221 helixhorne 1946
    return 0;
5 Plagman 1947
}
1948
 
1949
//
1950
// setgamma
1951
//
6828 terminx 1952
int32_t videoSetGamma(void)
5 Plagman 1953
{
6828 terminx 1954
    if (novideo)
1955
        return 0;
4440 terminx 1956
 
1205 terminx 1957
    int32_t i;
1958
    uint16_t gammaTable[768];
6828 terminx 1959
    float gamma = max(0.1f, min(4.f, g_videoGamma));
1960
    float contrast = max(0.1f, min(3.f, g_videoContrast));
1961
    float bright = max(-0.8f, min(0.8f, g_videoBrightness));
870 terminx 1962
 
4606 terminx 1963
    float invgamma = 1.f / gamma;
1964
    float norm = powf(255.f, invgamma - 1.f);
872 terminx 1965
 
4749 terminx 1966
    if (lastvidgcb[0] == gamma && lastvidgcb[1] == contrast && lastvidgcb[2] == bright)
2222 helixhorne 1967
        return 0;
1968
 
872 terminx 1969
    // This formula is taken from Doomsday
1970
 
1971
    for (i = 0; i < 256; i++)
1972
    {
4606 terminx 1973
        float val = i * contrast - (contrast - 1.f) * 127.f;
1974
        if (gamma != 1.f)
1975
            val = powf(val, invgamma) / norm;
872 terminx 1976
 
4606 terminx 1977
        val += bright * 128.f;
1978
 
4749 terminx 1979
        gammaTable[i] = gammaTable[i + 256] = gammaTable[i + 512] = (uint16_t)max(0.f, min(65535.f, val * 256.f));
872 terminx 1980
    }
4432 terminx 1981
 
4749 terminx 1982
#if SDL_MAJOR_VERSION == 1
4606 terminx 1983
    i = SDL_SetGammaRamp(&gammaTable[0], &gammaTable[256], &gammaTable[512]);
4432 terminx 1984
    if (i != -1)
2777 helixhorne 1985
#else
1986
    i = INT32_MIN;
4606 terminx 1987
 
2777 helixhorne 1988
    if (sdl_window)
4606 terminx 1989
        i = SDL_SetWindowGammaRamp(sdl_window, &gammaTable[0], &gammaTable[256], &gammaTable[512]);
2222 helixhorne 1990
 
2777 helixhorne 1991
    if (i < 0)
2222 helixhorne 1992
    {
4749 terminx 1993
#ifndef __ANDROID__  // Don't do this check, it is really supported, TODO
5884 terminx 1994
/*
2777 helixhorne 1995
        if (i != INT32_MIN)
1996
            initprintf("Unable to set gamma: SDL_SetWindowGammaRamp failed: %s\n", SDL_GetError());
5884 terminx 1997
*/
5962 hendricks2 1998
#endif
5884 terminx 1999
 
7316 terminx 2000
        OSD_Printf("videoSetGamma(): %s\n", SDL_GetError());
2001
 
5962 hendricks2 2002
#ifndef EDUKE32_GLES
5884 terminx 2003
#if SDL_MAJOR_VERSION == 1
2004
        SDL_SetGammaRamp(&sysgamma[0][0], &sysgamma[1][0], &sysgamma[2][0]);
2005
#else
7316 terminx 2006
 
5884 terminx 2007
        if (sdl_window)
2008
            SDL_SetWindowGammaRamp(sdl_window, &sysgamma[0][0], &sysgamma[1][0], &sysgamma[2][0]);
4440 terminx 2009
#endif
5884 terminx 2010
        gammabrightness = 0;
2011
#endif
2777 helixhorne 2012
    }
2013
    else
2014
#endif
2015
    {
2222 helixhorne 2016
        lastvidgcb[0] = gamma;
2017
        lastvidgcb[1] = contrast;
2018
        lastvidgcb[2] = bright;
5884 terminx 2019
 
2020
        gammabrightness = 1;
2222 helixhorne 2021
    }
2022
 
2023
    return i;
5 Plagman 2024
}
2025
 
4852 hendricks2 2026
#if !defined __APPLE__ && !defined EDUKE32_TOUCH_DEVICES
6982 terminx 2027
extern "C" struct sdlappicon sdlappicon;
4752 terminx 2028
static inline SDL_Surface *loadappicon(void)
5 Plagman 2029
{
4752 terminx 2030
    SDL_Surface *surf = SDL_CreateRGBSurfaceFrom((void *)sdlappicon.pixels, sdlappicon.width, sdlappicon.height, 32,
2031
                                                 sdlappicon.width * 4, 0xffl, 0xff00l, 0xff0000l, 0xff000000l);
109 terminx 2032
    return surf;
5 Plagman 2033
}
2034
#endif
2035
 
2036
//
2037
//
2038
// ---------------------------------------
2039
//
2040
// Miscellany
2041
//
2042
// ---------------------------------------
2043
//
109 terminx 2044
//
5 Plagman 2045
 
3022 helixhorne 2046
int32_t handleevents_peekkeys(void)
2047
{
2048
    SDL_PumpEvents();
4749 terminx 2049
 
4074 hendricks2 2050
#if SDL_MAJOR_VERSION==1
3022 helixhorne 2051
    return SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_EVENTMASK(SDL_KEYDOWN));
2052
#else
4074 hendricks2 2053
    return SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN);
3022 helixhorne 2054
#endif
2055
}
5 Plagman 2056
 
4853 hendricks2 2057
void handleevents_updatemousestate(uint8_t state)
2058
{
6827 terminx 2059
    g_mouseClickState = state == SDL_RELEASED ? MOUSE_RELEASED : MOUSE_PRESSED;
4853 hendricks2 2060
}
3022 helixhorne 2061
 
4853 hendricks2 2062
 
5 Plagman 2063
//
2064
// handleevents() -- process the SDL message queue
2065
//   returns !0 if there was an important event worth checking (like quitting)
2066
//
1593 terminx 2067
 
4749 terminx 2068
int32_t handleevents_sdlcommon(SDL_Event *ev)
5 Plagman 2069
{
4749 terminx 2070
    switch (ev->type)
4200 hendricks2 2071
    {
5169 hendricks2 2072
#if !defined EDUKE32_IOS
4749 terminx 2073
        case SDL_MOUSEMOTION:
4753 terminx 2074
#ifndef GEKKO
6827 terminx 2075
            g_mouseAbs.x = ev->motion.x;
2076
            g_mouseAbs.y = ev->motion.y;
4753 terminx 2077
#endif
4749 terminx 2078
            // SDL <VER> doesn't handle relative mouse movement correctly yet as the cursor still clips to the
2079
            // screen edges
2080
            // so, we call SDL_WarpMouse() to center the cursor and ignore the resulting motion event that occurs
2081
            //  <VER> is 1.3 for PK, 1.2 for tueidj
6827 terminx 2082
            if (appactive && g_mouseGrabbed)
4200 hendricks2 2083
            {
6797 terminx 2084
# if SDL_MAJOR_VERSION==1
4749 terminx 2085
                if (ev->motion.x != xdim >> 1 || ev->motion.y != ydim >> 1)
6797 terminx 2086
# endif
1109 terminx 2087
                {
6827 terminx 2088
                    g_mousePos.x += ev->motion.xrel;
2089
                    g_mousePos.y += ev->motion.yrel;
4754 terminx 2090
# if SDL_MAJOR_VERSION==1
2091
                    SDL_WarpMouse(xdim>>1, ydim>>1);
2092
# endif
4327 terminx 2093
                }
1109 terminx 2094
            }
109 terminx 2095
            break;
5 Plagman 2096
 
109 terminx 2097
        case SDL_MOUSEBUTTONDOWN:
2098
        case SDL_MOUSEBUTTONUP:
5169 hendricks2 2099
        {
2100
            int32_t j;
5768 hendricks2 2101
 
4749 terminx 2102
            // some of these get reordered to match winlayer
2103
            switch (ev->button.button)
342 terminx 2104
            {
4749 terminx 2105
                default: j = -1; break;
4853 hendricks2 2106
                case SDL_BUTTON_LEFT: j = 0; handleevents_updatemousestate(ev->button.state); break;
4749 terminx 2107
                case SDL_BUTTON_RIGHT: j = 1; break;
2108
                case SDL_BUTTON_MIDDLE: j = 2; break;
4190 helixhorne 2109
 
4755 helixhorne 2110
#if SDL_MAJOR_VERSION == 1
4749 terminx 2111
                case SDL_BUTTON_WHEELUP:    // 4
2112
                case SDL_BUTTON_WHEELDOWN:  // 5
2113
                    j = ev->button.button;
2114
                    break;
4190 helixhorne 2115
#endif
4755 helixhorne 2116
                /* Thumb buttons. */
8043 hendricks2 2117
#if SDL_MAJOR_VERSION==1
4755 helixhorne 2118
                // NOTE: SDL1 does have SDL_BUTTON_X1, but that's not what is
8043 hendricks2 2119
                // generated. (Only tested on Linux and Windows.)
4749 terminx 2120
                case 8: j = 3; break;
2121
                case 9: j = 6; break;
4190 helixhorne 2122
#else
8043 hendricks2 2123
                // On SDL2/Windows and SDL >= 2.0.?/Linux, everything is as it should be.
2124
                // If anyone cares about old versions of SDL2 on Linux, patches welcome.
4749 terminx 2125
                case SDL_BUTTON_X1: j = 3; break;
2126
                case SDL_BUTTON_X2: j = 6; break;
4190 helixhorne 2127
#endif
109 terminx 2128
            }
5 Plagman 2129
 
4749 terminx 2130
            if (j < 0)
2131
                break;
2132
 
2133
            if (ev->button.state == SDL_PRESSED)
6827 terminx 2134
                g_mouseBits |= (1 << j);
342 terminx 2135
            else
4775 hendricks2 2136
#if SDL_MAJOR_VERSION==1
2137
                if (j != SDL_BUTTON_WHEELUP && j != SDL_BUTTON_WHEELDOWN)
2138
#endif
6827 terminx 2139
                g_mouseBits &= ~(1 << j);
5 Plagman 2140
 
6827 terminx 2141
            if (g_mouseCallback)
2142
                g_mouseCallback(j+1, ev->button.state == SDL_PRESSED);
109 terminx 2143
            break;
5169 hendricks2 2144
        }
2145
#else
2146
# if SDL_MAJOR_VERSION != 1
2147
        case SDL_FINGERUP:
6827 terminx 2148
            g_mouseClickState = MOUSE_RELEASED;
5169 hendricks2 2149
            break;
2150
        case SDL_FINGERDOWN:
6827 terminx 2151
            g_mouseClickState = MOUSE_PRESSED;
5169 hendricks2 2152
        case SDL_FINGERMOTION:
6827 terminx 2153
            g_mouseAbs.x = Blrintf(ev->tfinger.x * xdim);
2154
            g_mouseAbs.y = Blrintf(ev->tfinger.y * ydim);
5169 hendricks2 2155
            break;
2156
# endif
2157
#endif
8005 terminx 2158
 
109 terminx 2159
        case SDL_JOYAXISMOTION:
7958 hendricks2 2160
#if SDL_MAJOR_VERSION >= 2
2161
            if (joystick.isGameController)
2162
                break;
2163
            fallthrough__;
2164
        case SDL_CONTROLLERAXISMOTION:
2165
#endif
6827 terminx 2166
            if (appactive && ev->jaxis.axis < joystick.numAxes)
1716 plagman 2167
            {
7956 hendricks2 2168
                joystick.pAxis[ev->jaxis.axis] = ev->jaxis.value;
2169
                int32_t const scaledValue = ev->jaxis.value * 10000 / 32767;
2170
                if ((scaledValue < joydead[ev->jaxis.axis]) &&
2171
                    (scaledValue > -joydead[ev->jaxis.axis]))
6827 terminx 2172
                    joystick.pAxis[ev->jaxis.axis] = 0;
7956 hendricks2 2173
                else if (scaledValue >= joysatur[ev->jaxis.axis])
2174
                    joystick.pAxis[ev->jaxis.axis] = 32767;
2175
                else if (scaledValue <= -joysatur[ev->jaxis.axis])
2176
                    joystick.pAxis[ev->jaxis.axis] = -32767;
1716 plagman 2177
                else
6827 terminx 2178
                    joystick.pAxis[ev->jaxis.axis] = joystick.pAxis[ev->jaxis.axis] * 10000 / joysatur[ev->jaxis.axis];
1716 plagman 2179
            }
109 terminx 2180
            break;
5 Plagman 2181
 
342 terminx 2182
        case SDL_JOYHATMOTION:
2183
        {
4749 terminx 2184
            int32_t hatvals[16] = {
2185
                -1,     // centre
2186
                0,      // up 1
2187
                9000,   // right 2
2188
                4500,   // up+right 3
2189
                18000,  // down 4
2190
                -1,     // down+up!! 5
2191
                13500,  // down+right 6
2192
                -1,     // down+right+up!! 7
2193
                27000,  // left 8
2194
                27500,  // left+up 9
2195
                -1,     // left+right!! 10
2196
                -1,     // left+right+up!! 11
2197
                22500,  // left+down 12
2198
                -1,     // left+down+up!! 13
2199
                -1,     // left+down+right!! 14
2200
                -1,     // left+down+right+up!! 15
584 terminx 2201
            };
6827 terminx 2202
            if (appactive && ev->jhat.hat < joystick.numHats)
2203
                joystick.pHat[ev->jhat.hat] = hatvals[ev->jhat.value & 15];
331 terminx 2204
            break;
2205
        }
5 Plagman 2206
 
109 terminx 2207
        case SDL_JOYBUTTONDOWN:
2208
        case SDL_JOYBUTTONUP:
7958 hendricks2 2209
#if SDL_MAJOR_VERSION >= 2
2210
            if (joystick.isGameController)
2211
                break;
2212
            fallthrough__;
2213
        case SDL_CONTROLLERBUTTONDOWN:
2214
        case SDL_CONTROLLERBUTTONUP:
2215
#endif
6827 terminx 2216
            if (appactive && ev->jbutton.button < joystick.numButtons)
342 terminx 2217
            {
4749 terminx 2218
                if (ev->jbutton.state == SDL_PRESSED)
6827 terminx 2219
                    joystick.bits |= 1 << ev->jbutton.button;
109 terminx 2220
                else
6827 terminx 2221
                    joystick.bits &= ~(1 << ev->jbutton.button);
4853 hendricks2 2222
 
2223
#ifdef GEKKO
2224
                if (ev->jbutton.button == 0) // WII_A
2225
                    handleevents_updatemousestate(ev->jbutton.state);
2226
#endif
109 terminx 2227
            }
2228
            break;
5 Plagman 2229
 
109 terminx 2230
        case SDL_QUIT:
2231
            quitevent = 1;
4749 terminx 2232
            return -1;
109 terminx 2233
    }
2234
 
4749 terminx 2235
    return 0;
2236
}
1644 helixhorne 2237
 
4767 hendricks2 2238
int32_t handleevents_pollsdl(void);
4749 terminx 2239
#if SDL_MAJOR_VERSION != 1
2240
// SDL 2.0 specific event handling
2241
int32_t handleevents_pollsdl(void)
2242
{
2243
    int32_t code, rv=0, j;
2244
    SDL_Event ev;
109 terminx 2245
 
4749 terminx 2246
    while (SDL_PollEvent(&ev))
2247
    {
2248
        switch (ev.type)
2249
        {
2250
            case SDL_TEXTINPUT:
2251
                j = 0;
2252
                do
2253
                {
2254
                    code = ev.text.text[j];
2255
 
6827 terminx 2256
                    if (code != g_keyAsciiTable[OSD_OSDKey()] && !keyBufferFull())
4749 terminx 2257
                    {
2258
                        if (OSD_HandleChar(code))
6827 terminx 2259
                            keyBufferInsert(code);
4749 terminx 2260
                    }
7080 terminx 2261
                } while (j < SDL_TEXTINPUTEVENT_TEXT_SIZE-1 && ev.text.text[++j]);
4749 terminx 2262
                break;
2263
 
2264
            case SDL_KEYDOWN:
2265
            case SDL_KEYUP:
5324 helixhorne 2266
            {
7164 terminx 2267
                auto const &sc = ev.key.keysym.scancode;
5324 helixhorne 2268
                code = keytranslation[sc];
4749 terminx 2269
 
5808 helixhorne 2270
                // Modifiers that have to be held down to be effective
2271
                // (excludes KMOD_NUM, for example).
2272
                static const int MODIFIERS =
2273
                    KMOD_LSHIFT|KMOD_RSHIFT|KMOD_LCTRL|KMOD_RCTRL|
2274
                    KMOD_LALT|KMOD_RALT|KMOD_LGUI|KMOD_RGUI;
2275
 
4749 terminx 2276
                // XXX: see osd.c, OSD_HandleChar(), there are more...
6827 terminx 2277
                if (ev.key.type == SDL_KEYDOWN && !keyBufferFull() &&
5324 helixhorne 2278
                    (sc == SDL_SCANCODE_RETURN || sc == SDL_SCANCODE_KP_ENTER ||
2279
                     sc == SDL_SCANCODE_ESCAPE ||
2280
                     sc == SDL_SCANCODE_BACKSPACE ||
2281
                     sc == SDL_SCANCODE_TAB ||
5808 helixhorne 2282
                     (((ev.key.keysym.mod) & MODIFIERS) == KMOD_LCTRL &&
5324 helixhorne 2283
                      (sc >= SDL_SCANCODE_A && sc <= SDL_SCANCODE_Z))))
4749 terminx 2284
                {
2285
                    char keyvalue;
5324 helixhorne 2286
                    switch (sc)
4749 terminx 2287
                    {
2288
                        case SDL_SCANCODE_RETURN: case SDL_SCANCODE_KP_ENTER: keyvalue = '\r'; break;
2289
                        case SDL_SCANCODE_ESCAPE: keyvalue = 27; break;
2290
                        case SDL_SCANCODE_BACKSPACE: keyvalue = '\b'; break;
2291
                        case SDL_SCANCODE_TAB: keyvalue = '\t'; break;
5324 helixhorne 2292
                        default: keyvalue = sc - SDL_SCANCODE_A + 1; break;  // Ctrl+A --> 1, etc.
4749 terminx 2293
                    }
2294
                    if (OSD_HandleChar(keyvalue))
6827 terminx 2295
                        keyBufferInsert(keyvalue);
4749 terminx 2296
                }
6027 hendricks2 2297
                else if (ev.key.type == SDL_KEYDOWN &&
6827 terminx 2298
                         ev.key.keysym.sym != g_keyAsciiTable[OSD_OSDKey()] && !keyBufferFull() &&
5968 hendricks2 2299
                         !SDL_IsTextInputActive())
2300
                {
2301
                    /*
2302
                    Necessary for Duke 3D's method of entering cheats to work without showing IMEs.
2303
                    SDL_TEXTINPUT is preferable overall, but with bitmap fonts it has no advantage.
2304
                    */
6027 hendricks2 2305
                    SDL_Keycode keyvalue = ev.key.keysym.sym;
4749 terminx 2306
 
5968 hendricks2 2307
                    if ('a' <= keyvalue && keyvalue <= 'z')
2308
                    {
2309
                        if (!!(ev.key.keysym.mod & KMOD_SHIFT) ^ !!(ev.key.keysym.mod & KMOD_CAPS))
2310
                            keyvalue -= 'a'-'A';
2311
                    }
2312
                    else if (ev.key.keysym.mod & KMOD_SHIFT)
2313
                    {
2314
                        switch (keyvalue)
2315
                        {
2316
                            case '\'': keyvalue = '"'; break;
2317
 
2318
                            case ',': keyvalue = '<'; break;
2319
                            case '-': keyvalue = '_'; break;
2320
                            case '.': keyvalue = '>'; break;
2321
                            case '/': keyvalue = '?'; break;
2322
                            case '0': keyvalue = ')'; break;
2323
                            case '1': keyvalue = '!'; break;
2324
                            case '2': keyvalue = '@'; break;
2325
                            case '3': keyvalue = '#'; break;
2326
                            case '4': keyvalue = '$'; break;
2327
                            case '5': keyvalue = '%'; break;
2328
                            case '6': keyvalue = '^'; break;
2329
                            case '7': keyvalue = '&'; break;
2330
                            case '8': keyvalue = '*'; break;
2331
                            case '9': keyvalue = '('; break;
2332
 
2333
                            case ';': keyvalue = ':'; break;
2334
 
2335
                            case '=': keyvalue = '+'; break;
2336
 
2337
                            case '[': keyvalue = '{'; break;
2338
                            case '\\': keyvalue = '|'; break;
2339
                            case ']': keyvalue = '}'; break;
2340
 
2341
                            case '`': keyvalue = '~'; break;
2342
                        }
2343
                    }
6027 hendricks2 2344
                    else if (ev.key.keysym.mod & KMOD_NUM) // && !(ev.key.keysym.mod & KMOD_SHIFT)
2345
                    {
2346
                        switch (keyvalue)
2347
                        {
2348
                            case SDLK_KP_1: keyvalue = '1'; break;
2349
                            case SDLK_KP_2: keyvalue = '2'; break;
2350
                            case SDLK_KP_3: keyvalue = '3'; break;
2351
                            case SDLK_KP_4: keyvalue = '4'; break;
2352
                            case SDLK_KP_5: keyvalue = '5'; break;
2353
                            case SDLK_KP_6: keyvalue = '6'; break;
2354
                            case SDLK_KP_7: keyvalue = '7'; break;
2355
                            case SDLK_KP_8: keyvalue = '8'; break;
2356
                            case SDLK_KP_9: keyvalue = '9'; break;
2357
                            case SDLK_KP_0: keyvalue = '0'; break;
2358
                            case SDLK_KP_PERIOD: keyvalue = '.'; break;
2359
                            case SDLK_KP_COMMA: keyvalue = ','; break;
2360
                        }
2361
                    }
5968 hendricks2 2362
 
6027 hendricks2 2363
                    switch (keyvalue)
2364
                    {
2365
                        case SDLK_KP_DIVIDE: keyvalue = '/'; break;
2366
                        case SDLK_KP_MULTIPLY: keyvalue = '*'; break;
2367
                        case SDLK_KP_MINUS: keyvalue = '-'; break;
2368
                        case SDLK_KP_PLUS: keyvalue = '+'; break;
2369
                    }
2370
 
2371
                    if ((unsigned)keyvalue <= 0x7Fu)
2372
                    {
2373
                        if (OSD_HandleChar(keyvalue))
6827 terminx 2374
                            keyBufferInsert(keyvalue);
6027 hendricks2 2375
                    }
5968 hendricks2 2376
                }
2377
 
4749 terminx 2378
                // initprintf("SDL2: got key %d, %d, %u\n", ev.key.keysym.scancode, code, ev.key.type);
2379
 
2380
                // hook in the osd
2381
                if ((j = OSD_HandleScanCode(code, (ev.key.type == SDL_KEYDOWN))) <= 0)
2382
                {
2383
                    if (j == -1)  // osdkey
7164 terminx 2384
                    {
6827 terminx 2385
                        for (j = 0; j < NUMKEYS; ++j)
7164 terminx 2386
                        {
6827 terminx 2387
                            if (keyGetState(j))
4749 terminx 2388
                            {
6827 terminx 2389
                                keySetState(j, 0);
4749 terminx 2390
                                if (keypresscallback)
2391
                                    keypresscallback(j, 0);
2392
                            }
7164 terminx 2393
                        }
2394
                    }
4749 terminx 2395
                    break;
2396
                }
2397
 
2398
                if (ev.key.type == SDL_KEYDOWN)
2399
                {
6827 terminx 2400
                    if (!keyGetState(code))
4749 terminx 2401
                    {
6827 terminx 2402
                        keySetState(code, 1);
4749 terminx 2403
                        if (keypresscallback)
2404
                            keypresscallback(code, 1);
2405
                    }
2406
                }
2407
                else
2408
                {
2409
# if 1
2410
                    // The pause key generates a release event right after
2411
                    // the pressing one. As a result, it gets unseen
2412
                    // by the game most of the time.
2413
                    if (code == 0x59)  // pause
2414
                        break;
2415
# endif
6827 terminx 2416
                    keySetState(code, 0);
4749 terminx 2417
                    if (keypresscallback)
2418
                        keypresscallback(code, 0);
2419
                }
2420
                break;
5324 helixhorne 2421
            }
4749 terminx 2422
 
2423
            case SDL_MOUSEWHEEL:
2424
                // initprintf("wheel y %d\n",ev.wheel.y);
2425
                if (ev.wheel.y > 0)
2426
                {
6827 terminx 2427
                    g_mouseBits |= 16;
2428
                    if (g_mouseCallback)
2429
                        g_mouseCallback(5, 1);
4749 terminx 2430
                }
2431
                if (ev.wheel.y < 0)
2432
                {
6827 terminx 2433
                    g_mouseBits |= 32;
2434
                    if (g_mouseCallback)
2435
                        g_mouseCallback(6, 1);
4749 terminx 2436
                }
2437
                break;
2438
 
2439
            case SDL_WINDOWEVENT:
2440
                switch (ev.window.event)
2441
                {
2442
                    case SDL_WINDOWEVENT_FOCUS_GAINED:
2443
                    case SDL_WINDOWEVENT_FOCUS_LOST:
2444
                        appactive = (ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED);
6827 terminx 2445
                        if (g_mouseGrabbed && g_mouseEnabled)
4749 terminx 2446
                            grabmouse_low(appactive);
2447
#ifdef _WIN32
6708 hendricks2 2448
                        // Win_SetKeyboardLayoutUS(appactive);
5972 hendricks2 2449
 
4749 terminx 2450
                        if (backgroundidle)
2451
                            SetPriorityClass(GetCurrentProcess(), appactive ? NORMAL_PRIORITY_CLASS : IDLE_PRIORITY_CLASS);
3219 hendricks2 2452
#endif
4749 terminx 2453
                        break;
5 Plagman 2454
 
4749 terminx 2455
                    case SDL_WINDOWEVENT_MOVED:
8063 terminx 2456
                    {
4749 terminx 2457
                        if (windowpos)
2458
                        {
2459
                            windowx = ev.window.data1;
2460
                            windowy = ev.window.data2;
2461
                        }
8063 terminx 2462
 
2463
                        r_displayindex = SDL_GetWindowDisplayIndex(sdl_window);
2464
                        modeschecked = 0;
2465
                        videoGetModes();
4749 terminx 2466
                        break;
8063 terminx 2467
                    }
4753 terminx 2468
                    case SDL_WINDOWEVENT_ENTER:
6827 terminx 2469
                        g_mouseInsideWindow = 1;
4753 terminx 2470
                        break;
2471
                    case SDL_WINDOWEVENT_LEAVE:
6827 terminx 2472
                        g_mouseInsideWindow = 0;
4753 terminx 2473
                        break;
4749 terminx 2474
                }
8063 terminx 2475
 
4749 terminx 2476
                break;
5 Plagman 2477
 
4749 terminx 2478
            default:
2479
                rv = handleevents_sdlcommon(&ev);
2480
                break;
2481
        }
2482
    }
2483
 
109 terminx 2484
    return rv;
5 Plagman 2485
}
4749 terminx 2486
#endif
5 Plagman 2487
 
4749 terminx 2488
int32_t handleevents(void)
1644 helixhorne 2489
{
4992 terminx 2490
#ifdef __ANDROID__
2491
    if (mobile_halted) return 0;
2492
#endif
2493
 
4749 terminx 2494
    int32_t rv;
1644 helixhorne 2495
 
6827 terminx 2496
    if (inputchecked && g_mouseEnabled)
1762 terminx 2497
    {
6827 terminx 2498
        if (g_mouseCallback)
1762 terminx 2499
        {
6827 terminx 2500
            if (g_mouseBits & 16)
2501
                g_mouseCallback(5, 0);
2502
            if (g_mouseBits & 32)
2503
                g_mouseCallback(6, 0);
1644 helixhorne 2504
        }
6827 terminx 2505
        g_mouseBits &= ~(16 | 32);
1644 helixhorne 2506
    }
4749 terminx 2507
 
2508
    rv = handleevents_pollsdl();
2509
 
2510
    inputchecked = 0;
6828 terminx 2511
    timerUpdate();
4749 terminx 2512
 
8094 hendricks2 2513
    communityapiRunCallbacks();
2514
 
4749 terminx 2515
#ifndef _WIN32
2516
    startwin_idle(NULL);
1644 helixhorne 2517
#endif
2518
 
4749 terminx 2519
    return rv;
2520
}
109 terminx 2521
 
4749 terminx 2522
#if SDL_MAJOR_VERSION == 1
6056 hendricks2 2523
#include "sdlayer12.cpp"
4749 terminx 2524
#endif