1 #include "baselayer.h"
2 
3 #include "a.h"
4 #include "build.h"
5 #include "cache1d.h"
6 #include "communityapi.h"
7 #include "compat.h"
8 #include "osd.h"
9 #include "polymost.h"
10 #include "renderlayer.h"
11 
12 // video
13 #ifdef _WIN32
14 #include "winbits.h"
15 extern "C"
16 {
17     __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 0x00000001;
18     __declspec(dllexport) DWORD NvOptimusEnablement                = 0x00000001;
19 }
20 #endif // _WIN32
21 
22 int32_t g_borderless=2;
23 
24 // input
25 char    inputdevices = 0;
26 
27 char    keystatus[NUMKEYS];
28 char    g_keyFIFO[KEYFIFOSIZ];
29 char    g_keyAsciiFIFO[KEYFIFOSIZ];
30 uint8_t g_keyFIFOpos;
31 uint8_t g_keyFIFOend;
32 uint8_t g_keyAsciiPos;
33 uint8_t g_keyAsciiEnd;
34 char    g_keyRemapTable[NUMKEYS];
35 char    g_keyNameTable[NUMKEYS][24];
36 
37 int32_t r_maxfps = -1;
38 int32_t r_maxfpsoffset;
39 uint64_t g_frameDelay;
40 
41 void (*keypresscallback)(int32_t, int32_t);
42 
keySetCallback(void (* callback)(int32_t,int32_t))43 void keySetCallback(void (*callback)(int32_t, int32_t)) { keypresscallback = callback; }
44 
keyGetState(int32_t key)45 int32_t keyGetState(int32_t key) { return keystatus[g_keyRemapTable[key]]; }
46 
keySetState(int32_t key,int32_t state)47 void keySetState(int32_t key, int32_t state)
48 {
49     keystatus[g_keyRemapTable[key]] = state;
50 
51     if (state)
52     {
53         g_keyFIFO[g_keyFIFOend] = g_keyRemapTable[key];
54         g_keyFIFO[(g_keyFIFOend+1)&(KEYFIFOSIZ-1)] = state;
55         g_keyFIFOend = ((g_keyFIFOend+2)&(KEYFIFOSIZ-1));
56     }
57 }
58 
keyGetScan(void)59 char keyGetScan(void)
60 {
61     if (g_keyFIFOpos == g_keyFIFOend)
62         return 0;
63 
64     char const c    = g_keyFIFO[g_keyFIFOpos];
65     g_keyFIFOpos = ((g_keyFIFOpos + 2) & (KEYFIFOSIZ - 1));
66 
67     return c;
68 }
69 
keyFlushScans(void)70 void keyFlushScans(void)
71 {
72     Bmemset(&g_keyFIFO,0,sizeof(g_keyFIFO));
73     g_keyFIFOpos = g_keyFIFOend = 0;
74 }
75 
76 //
77 // character-based input functions
78 //
keyGetChar(void)79 char keyGetChar(void)
80 {
81     if (g_keyAsciiPos == g_keyAsciiEnd)
82         return 0;
83 
84     char const c    = g_keyAsciiFIFO[g_keyAsciiPos];
85     g_keyAsciiPos = ((g_keyAsciiPos + 1) & (KEYFIFOSIZ - 1));
86 
87     return c;
88 }
89 
keyFlushChars(void)90 void keyFlushChars(void)
91 {
92     Bmemset(&g_keyAsciiFIFO,0,sizeof(g_keyAsciiFIFO));
93     g_keyAsciiPos = g_keyAsciiEnd = 0;
94 }
95 
keyGetName(int32_t num)96 const char *keyGetName(int32_t num) { return ((unsigned)num >= NUMKEYS) ? NULL : g_keyNameTable[num]; }
97 
98 vec2_t  g_mousePos;
99 vec2_t  g_mouseAbs;
100 int32_t g_mouseBits;
101 uint8_t g_mouseClickState;
102 
103 bool g_mouseEnabled;
104 bool g_mouseGrabbed;
105 bool g_mouseInsideWindow   = 1;
106 bool g_mouseLockedToWindow = 1;
107 
108 void (*g_mouseCallback)(int32_t, int32_t);
mouseSetCallback(void (* callback)(int32_t,int32_t))109 void mouseSetCallback(void(*callback)(int32_t, int32_t)) { g_mouseCallback = callback; }
110 
mouseAdvanceClickState(void)111 int32_t mouseAdvanceClickState(void)
112 {
113     switch (g_mouseClickState)
114     {
115         case MOUSE_PRESSED: g_mouseClickState  = MOUSE_HELD; return 1;
116         case MOUSE_RELEASED: g_mouseClickState = MOUSE_IDLE; return 1;
117         case MOUSE_HELD: return 1;
118     }
119     return 0;
120 }
121 
mouseReadPos(int32_t * x,int32_t * y)122 void mouseReadPos(int32_t *x, int32_t *y)
123 {
124     if (!g_mouseEnabled || !g_mouseGrabbed || !appactive)
125     {
126         *x = *y = 0;
127         return;
128     }
129 
130     *x = g_mousePos.x;
131     *y = g_mousePos.y;
132     g_mousePos.x = g_mousePos.y = 0;
133 }
134 
mouseReadAbs(vec2_t * const pResult,vec2_t const * const pInput)135 int32_t mouseReadAbs(vec2_t * const pResult, vec2_t const * const pInput)
136 {
137     if (!g_mouseEnabled || !appactive || !g_mouseInsideWindow || (osd && osd->flags & OSD_CAPTURE))
138         return 0;
139 
140     int32_t const xwidth = max(scale(240<<16, xdim, ydim), 320<<16);
141 
142     pResult->x = scale(pInput->x, xwidth, xres) - ((xwidth>>1) - (320<<15));
143     pResult->y = scale(pInput->y, 200<<16, yres);
144 
145     pResult->y = divscale16(pResult->y - (200<<15), rotatesprite_yxaspect) + (200<<15) - rotatesprite_y_offset;
146 
147     return 1;
148 }
149 
mouseReadButtons(void)150 int32_t mouseReadButtons(void)
151 {
152     return (!g_mouseEnabled || !appactive || !g_mouseInsideWindow || (osd && osd->flags & OSD_CAPTURE)) ? 0 : g_mouseBits;
153 }
154 
155 controllerinput_t joystick;
156 
joySetCallback(void (* callback)(int32_t,int32_t))157 void joySetCallback(void (*callback)(int32_t, int32_t)) { joystick.pCallback = callback; }
joyReadButtons(int32_t * pResult)158 void joyReadButtons(int32_t *pResult) { *pResult = appactive ? joystick.bits : 0; }
159 
160 #if defined __linux || defined EDUKE32_BSD || defined __APPLE__
161 # include <sys/mman.h>
162 #endif
163 
164 #if !defined(NOASM) && !defined(GEKKO) && !defined(__ANDROID__)
165 #ifdef __cplusplus
166 extern "C" {
167 #endif
168     extern intptr_t dep_begin, dep_end;
169 #ifdef __cplusplus
170 }
171 #endif
172 #endif
173 
174 #if !defined(NOASM) && !defined(GEKKO) && !defined(__ANDROID__)
nx_unprotect(intptr_t beg,intptr_t end,int prot)175 static int32_t nx_unprotect(intptr_t beg, intptr_t end, int prot)
176 {
177 # if defined _WIN32
178 #  define B_PROT_RW PAGE_READWRITE
179 #  define B_PROT_RX PAGE_EXECUTE_READ
180 #  define B_PROT_RWX PAGE_EXECUTE_READWRITE
181 
182     DWORD oldprot;
183 
184     if (!VirtualProtect((LPVOID) beg, (SIZE_T)end - (SIZE_T)beg, prot, &oldprot))
185     {
186         initprintf("VirtualProtect() error! Crashing in 3... 2... 1...\n");
187         return 1;
188     }
189 # elif defined __linux || defined EDUKE32_BSD || defined __APPLE__
190 #  define B_PROT_RW (PROT_READ|PROT_WRITE)
191 #  define B_PROT_RX (PROT_READ|PROT_EXEC)
192 #  define B_PROT_RWX (PROT_READ|PROT_WRITE|PROT_EXEC)
193 
194     int32_t pagesize;
195     size_t dep_begin_page;
196     pagesize = sysconf(_SC_PAGE_SIZE);
197     if (pagesize == -1)
198     {
199         initprintf("Error getting system page size\n");
200         return 1;
201     }
202     dep_begin_page = ((size_t)beg) & ~(pagesize-1);
203     if (mprotect((void *) dep_begin_page, (size_t)end - dep_begin_page, prot) < 0)
204     {
205         initprintf("Error making code writeable (errno=%d)\n", errno);
206         return 1;
207     }
208 # else
209 #  error "Don't know how to unprotect the self-modifying assembly on this platform!"
210 # endif
211 
212     return 0;
213 }
214 #endif
215 
216 
217 // Calculate ylookup[] and call setvlinebpl()
calc_ylookup(int32_t bpl,int32_t lastyidx)218 void calc_ylookup(int32_t bpl, int32_t lastyidx)
219 {
220     int32_t i, j=0;
221     static int32_t ylookupsiz;
222 
223     Bassert(lastyidx <= MAXYDIM);
224 
225     lastyidx++;
226 
227     if (lastyidx > ylookupsiz)
228     {
229         Xaligned_free(ylookup);
230 
231         ylookup = (intptr_t *)Xaligned_alloc(16, lastyidx * sizeof(intptr_t));
232         ylookupsiz = lastyidx;
233     }
234 
235     for (i=0; i<=lastyidx-4; i+=4)
236     {
237         ylookup[i] = j;
238         ylookup[i + 1] = j + bpl;
239         ylookup[i + 2] = j + (bpl << 1);
240         ylookup[i + 3] = j + (bpl * 3);
241         j += (bpl << 2);
242     }
243 
244     for (; i<lastyidx; i++)
245     {
246         ylookup[i] = j;
247         j += bpl;
248     }
249 
250     setvlinebpl(bpl);
251 }
252 
253 
makeasmwriteable(void)254 void makeasmwriteable(void)
255 {
256 #if !defined(NOASM) && !defined(GEKKO) && !defined(__ANDROID__)
257     nx_unprotect((intptr_t)&dep_begin, (intptr_t)&dep_end, B_PROT_RWX);
258 #endif
259 }
260 
261 int32_t vsync=0;
262 int32_t r_finishbeforeswap=0;
263 int32_t r_glfinish=0;
264 int32_t g_logFlushWindow = 1;
265 
266 #ifdef USE_OPENGL
267 struct glinfo_t glinfo =
268 {
269     "Unknown",  // vendor
270     "Unknown",  // renderer
271     "0.0.0",    // version
272     "",         // extensions
273 
274     1.0,        // max anisotropy
275     0,          // structure filled
276     0,          // supported extensions
277 };
278 
fill_glinfo(void)279 void fill_glinfo(void)
280 {
281     glinfo.extensions = (const char *)glGetString(GL_EXTENSIONS);
282     glinfo.renderer   = (const char *)glGetString(GL_RENDERER);
283     glinfo.vendor     = (const char *)glGetString(GL_VENDOR);
284     glinfo.version    = (const char *)glGetString(GL_VERSION);
285 
286 #ifdef POLYMER
287     if (!Bstrcmp(glinfo.vendor, "ATI Technologies Inc."))
288     {
289         pr_ati_fboworkaround = 1;
290         initprintf("Enabling ATI FBO color attachment workaround.\n");
291 
292         if (Bstrstr(glinfo.renderer, "Radeon X1"))
293         {
294             pr_ati_nodepthoffset = 1;
295             initprintf("Enabling ATI R520 polygon offset workaround.\n");
296         }
297 # ifdef __APPLE__
298         // See bug description at http://lists.apple.com/archives/mac-opengl/2005/Oct/msg00169.html
299         if (!Bstrncmp(glinfo.renderer, "ATI Radeon 9600", 15))
300         {
301             pr_ati_textureformat_one = 1;
302             initprintf("Enabling ATI Radeon 9600 texture format workaround.\n");
303         }
304 # endif
305     }
306 #endif  // defined POLYMER
307 
308     // process the extensions string and flag stuff we recognize
309     glinfo.depthtex = !!Bstrstr(glinfo.extensions, "GL_ARB_depth_texture");
310     glinfo.fbos     = !!Bstrstr(glinfo.extensions, "GL_EXT_framebuffer_object") || !!Bstrstr(glinfo.extensions, "GL_OES_framebuffer_object");
311     glinfo.shadow   = !!Bstrstr(glinfo.extensions, "GL_ARB_shadow");
312     glinfo.texnpot  = !!Bstrstr(glinfo.extensions, "GL_ARB_texture_non_power_of_two") || !!Bstrstr(glinfo.extensions, "GL_OES_texture_npot");
313 
314 #if !defined EDUKE32_GLES
315     glinfo.bgra             = !!Bstrstr(glinfo.extensions, "GL_EXT_bgra");
316     glinfo.bufferstorage    = !!Bstrstr(glinfo.extensions, "GL_ARB_buffer_storage");
317     glinfo.clamptoedge      = !!Bstrstr(glinfo.extensions, "GL_EXT_texture_edge_clamp") || !!Bstrstr(glinfo.extensions, "GL_SGIS_texture_edge_clamp");
318     glinfo.debugoutput      = !!Bstrstr(glinfo.extensions, "GL_ARB_debug_output");
319     glinfo.depthclamp       = !!Bstrstr(glinfo.extensions, "GL_ARB_depth_clamp");
320     glinfo.glsl             = !!Bstrstr(glinfo.extensions, "GL_ARB_shader_objects");
321     glinfo.multitex         = !!Bstrstr(glinfo.extensions, "GL_ARB_multitexture");
322     glinfo.occlusionqueries = !!Bstrstr(glinfo.extensions, "GL_ARB_occlusion_query");
323     glinfo.rect             = !!Bstrstr(glinfo.extensions, "GL_NV_texture_rectangle") || !!Bstrstr(glinfo.extensions, "GL_EXT_texture_rectangle");
324     glinfo.sync             = !!Bstrstr(glinfo.extensions, "GL_ARB_sync");
325     glinfo.texcompr         = !!Bstrstr(glinfo.extensions, "GL_ARB_texture_compression") && Bstrcmp(glinfo.vendor, "ATI Technologies Inc.");
326     glinfo.vbos             = !!Bstrstr(glinfo.extensions, "GL_ARB_vertex_buffer_object");
327     glinfo.vsync            = !!Bstrstr(glinfo.extensions, "WGL_EXT_swap_control") || !!Bstrstr(glinfo.extensions, "GLX_EXT_swap_control");
328 
329 # ifdef DYNAMIC_GLEXT
330     if (glinfo.texcompr && (!glCompressedTexImage2D || !glGetCompressedTexImage))
331     {
332         // lacking the necessary extensions to do this
333         initprintf("Warning: the GL driver lacks necessary functions to use caching\n");
334         glinfo.texcompr = 0;
335     }
336 # endif
337 #else
338     // don't bother checking because ETC2 et al. are not listed in extensions anyway
339     glinfo.texcompr = 1; // !!Bstrstr(glinfo.extensions, "GL_OES_compressed_ETC1_RGB8_texture");
340 #endif
341 
342     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glinfo.maxanisotropy);
343 
344     if (!glinfo.filled)
345     {
346         int32_t oldbpp = bpp;
347         bpp = 32;
348         osdcmd_glinfo(NULL);
349         glinfo.filled = 1;
350         bpp = oldbpp;
351     }
352 }
353 
354 // Used to register the game's / editor's osdcmd_vidmode() functions here.
355 int32_t (*baselayer_osdcmd_vidmode_func)(osdcmdptr_t parm);
356 
osdfunc_setrendermode(osdcmdptr_t parm)357 static int osdfunc_setrendermode(osdcmdptr_t parm)
358 {
359     if (parm->numparms != 1)
360         return OSDCMD_SHOWHELP;
361 
362     int32_t m = Bstrtol(parm->parms[0], NULL, 10);
363 
364     if (m != REND_CLASSIC && m != REND_POLYMOST && m != REND_POLYMER)
365         return OSDCMD_SHOWHELP;
366 
367     if ((m==REND_CLASSIC) != (bpp==8) && baselayer_osdcmd_vidmode_func)
368     {
369         // Mismatch between video mode and requested renderer, do auto switch.
370         osdfuncparm_t parm;
371         char arg[4];
372 
373         const char *ptrptr[1];
374         ptrptr[0] = arg;
375 
376         Bmemset(&parm, 0, sizeof(parm));
377 
378         if (m==REND_CLASSIC)
379             Bmemcpy(&arg, "8", 2);
380         else
381             Bmemcpy(&arg, "32", 3);
382 
383         // CAUTION: we assume that the osdcmd_vidmode function doesn't use any
384         // other member!
385         parm.numparms = 1;
386         parm.parms = ptrptr;
387 
388         baselayer_osdcmd_vidmode_func(&parm);
389     }
390 
391     videoSetRenderMode(m);
392 
393     char const *renderer = "other";
394 
395     switch (videoGetRenderMode())
396     {
397     case REND_CLASSIC:
398 #ifdef NOASM
399         renderer = "classic software (C)";
400 #else
401         renderer = "classic software (ASM)";
402 #endif
403         break;
404     case REND_POLYMOST:
405         renderer = "polygonal OpenGL";
406         break;
407 #ifdef POLYMER
408     case REND_POLYMER:
409         renderer = "great justice (Polymer)";
410         break;
411 #endif
412     }
413 
414     OSD_Printf("Rendering method changed to %s\n", renderer);
415 
416     return OSDCMD_OK;
417 }
418 
419 #ifdef DEBUGGINGAIDS
osdcmd_hicsetpalettetint(osdcmdptr_t parm)420 static int osdcmd_hicsetpalettetint(osdcmdptr_t parm)
421 {
422     int32_t parms[8];
423 
424     if (parm->numparms < 1 || (int32_t)ARRAY_SIZE(parms) < parm->numparms) return OSDCMD_SHOWHELP;
425 
426     size_t i;
427     for (i = 0; (int32_t)i < parm->numparms; ++i)
428         parms[i] = Batol(parm->parms[i]);
429     for (; i < ARRAY_SIZE(parms); ++i)
430         parms[i] = 0;
431 
432     // order is intentional
433     hicsetpalettetint(parms[0],parms[1],parms[2],parms[3],parms[5],parms[6],parms[7],parms[4]);
434 
435     return OSDCMD_OK;
436 }
437 #endif
438 
osdcmd_glinfo(osdcmdptr_t UNUSED (parm))439 int osdcmd_glinfo(osdcmdptr_t UNUSED(parm))
440 {
441     UNREFERENCED_CONST_PARAMETER(parm);
442 
443     if (bpp == 8)
444     {
445         initprintf("glinfo: not in OpenGL mode!\n");
446         return OSDCMD_OK;
447     }
448 
449     initprintf("OpenGL information\n %s %s %s\n",
450                glinfo.vendor, glinfo.renderer, glinfo.version);
451 
452     if (!glinfo.filled)
453         return OSDCMD_OK;
454 
455     char const *s[] = { "supported", "not supported" };
456 
457 #define SUPPORTED(x) (x ? s[0] : s[1])
458 
459     initprintf(" BGRA textures:           %s\n", SUPPORTED(glinfo.bgra));
460     initprintf(" Clamp-to-edge:           %s\n", SUPPORTED(glinfo.clamptoedge));
461     initprintf(" Framebuffer objects:     %s\n", SUPPORTED(glinfo.fbos));
462     initprintf(" Multi-texturing:         %s\n", SUPPORTED(glinfo.multitex));
463     initprintf(" Non-power-of-2 textures: %s\n", SUPPORTED(glinfo.texnpot));
464 #ifndef EDUKE32_GLES
465     initprintf(" Buffer storage:          %s\n", SUPPORTED(glinfo.bufferstorage));
466     initprintf(" Debug output:            %s\n", SUPPORTED(glinfo.debugoutput));
467     initprintf(" Depth textures:          %s\n", SUPPORTED(glinfo.depthtex));
468     initprintf(" GLSL:                    %s\n", SUPPORTED(glinfo.glsl));
469     initprintf(" Occlusion queries:       %s\n", SUPPORTED(glinfo.occlusionqueries));
470     initprintf(" Rectangle textures:      %s\n", SUPPORTED(glinfo.rect));
471     initprintf(" Shadow textures:         %s\n", SUPPORTED(glinfo.shadow));
472     initprintf(" Sync:                    %s\n", SUPPORTED(glinfo.sync));
473     initprintf(" Texture compression:     %s\n", SUPPORTED(glinfo.texcompr));
474     initprintf(" Vertex buffer objects:   %s\n", SUPPORTED(glinfo.vbos));
475 #endif
476     initprintf(" Maximum anisotropy:      %.1f%s\n", glinfo.maxanisotropy, glinfo.maxanisotropy > 1.0 ? "" : " (no anisotropic filtering)");
477 
478 #undef SUPPORTED
479 
480     initprintf(" Extensions:\n%s", glinfo.extensions);
481 
482     return OSDCMD_OK;
483 }
484 #endif
485 
osdcmd_cvar_set_baselayer(osdcmdptr_t parm)486 static int osdcmd_cvar_set_baselayer(osdcmdptr_t parm)
487 {
488     int32_t r = osdcmd_cvar_set(parm);
489 
490     if (r != OSDCMD_OK) return r;
491 
492     if (!Bstrcasecmp(parm->name, "vid_gamma") || !Bstrcasecmp(parm->name, "vid_brightness") || !Bstrcasecmp(parm->name, "vid_contrast"))
493     {
494         videoSetPalette(GAMMA_CALC,0,0);
495         return r;
496     }
497     else if (!Bstrcasecmp(parm->name, "r_maxfps") || !Bstrcasecmp(parm->name, "r_maxfpsoffset"))
498     {
499         if (r_maxfps > 0) r_maxfps = clamp(r_maxfps, 30, 1000);
500         g_frameDelay = calcFrameDelay(r_maxfps, r_maxfpsoffset);
501     }
502     return r;
503 }
504 
baselayer_init(void)505 int32_t baselayer_init(void)
506 {
507 #ifdef _WIN32
508 // on Windows, don't save the "r_screenaspect" cvar because the physical screen size is
509 // determined at startup
510 # define SCREENASPECT_CVAR_TYPE (CVAR_UINT|CVAR_NOSAVE)
511 #else
512 # define SCREENASPECT_CVAR_TYPE (CVAR_UINT)
513 #endif
514     static osdcvardata_t cvars_engine[] =
515     {
516         { "lz4compressionlevel","adjust LZ4 compression level used for savegames",(void *) &lz4CompressionLevel, CVAR_INT, 1, 32 },
517         { "r_borderless", "borderless windowed mode: 0: never  1: always  2: if resolution matches desktop", (void *) &r_borderless, CVAR_INT|CVAR_RESTARTVID, 0, 2 },
518         { "r_displayindex","index of output display",(void *)&r_displayindex, CVAR_INT|CVAR_RESTARTVID, 0, 10 },
519         { "r_usenewaspect","enable/disable new screen aspect ratio determination code",(void *) &r_usenewaspect, CVAR_BOOL, 0, 1 },
520         { "r_screenaspect","if using r_usenewaspect and in fullscreen, screen aspect ratio in the form XXYY, e.g. 1609 for 16:9",
521           (void *) &r_screenxy, SCREENASPECT_CVAR_TYPE, 0, 9999 },
522         { "r_fpgrouscan","use floating-point numbers for slope rendering",(void *) &r_fpgrouscan, CVAR_BOOL, 0, 1 },
523         { "r_novoxmips","turn off/on the use of mipmaps when rendering 8-bit voxels",(void *) &novoxmips, CVAR_BOOL, 0, 1 },
524         { "r_voxels","enable/disable automatic sprite->voxel rendering",(void *) &usevoxels, CVAR_BOOL, 0, 1 },
525         { "r_maxfps", "limit the frame rate", (void *)&r_maxfps, CVAR_INT | CVAR_FUNCPTR, -1, 1000 },
526         { "r_maxfpsoffset", "menu-controlled offset for r_maxfps", (void *)&r_maxfpsoffset, CVAR_INT | CVAR_FUNCPTR, -10, 10 },
527 #ifdef YAX_ENABLE
528         { "r_tror_nomaskpass", "enable/disable additional pass in TROR software rendering", (void *)&r_tror_nomaskpass, CVAR_BOOL, 0, 1 },
529 #endif
530         { "r_windowpositioning", "enable/disable window position memory", (void *) &windowpos, CVAR_BOOL, 0, 1 },
531         { "vid_gamma","adjusts gamma component of gamma ramp",(void *) &g_videoGamma, CVAR_FLOAT|CVAR_FUNCPTR, 0, 10 },
532         { "vid_contrast","adjusts contrast component of gamma ramp",(void *) &g_videoContrast, CVAR_FLOAT|CVAR_FUNCPTR, 0, 10 },
533         { "vid_brightness","adjusts brightness component of gamma ramp",(void *) &g_videoBrightness, CVAR_FLOAT|CVAR_FUNCPTR, -10, 10 },
534 #ifdef DEBUGGINGAIDS
535         { "debug1","debug counter",(void *) &debug1, CVAR_FLOAT, -100000, 100000 },
536         { "debug2","debug counter",(void *) &debug2, CVAR_FLOAT, -100000, 100000 },
537 #endif
538 #ifdef DEBUG_MASK_DRAWING
539         { "debug_maskdrawmode", "Show mask draw orders", (void *)&g_maskDrawMode, CVAR_BOOL, 0, 1 },
540 #endif
541     };
542 
543     for (auto & i : cvars_engine)
544         OSD_RegisterCvar(&i, (i.flags & CVAR_FUNCPTR) ? osdcmd_cvar_set_baselayer : osdcmd_cvar_set);
545 
546 #ifdef USE_OPENGL
547     OSD_RegisterFunction("setrendermode","setrendermode <number>: sets the engine's rendering mode.\n"
548                          "Mode numbers are:\n"
549                          "   0 - Classic Build software\n"
550                          "   3 - Polygonal OpenGL\n"
551 #ifdef POLYMER
552                          "   4 - Great justice renderer (Polymer)\n"
553 #endif
554                          ,
555                          osdfunc_setrendermode);
556 
557 # ifdef DEBUGGINGAIDS
558     OSD_RegisterFunction("hicsetpalettetint","hicsetpalettetint: sets palette tinting values",osdcmd_hicsetpalettetint);
559 # endif
560 
561     OSD_RegisterFunction("glinfo","glinfo: shows OpenGL information about the current OpenGL mode",osdcmd_glinfo);
562 
563     polymost_initosdfuncs();
564 #endif
565 
566     for (native_t i = 0; i < NUMKEYS; i++) g_keyRemapTable[i] = i;
567 
568     return 0;
569 }
570 
maybe_redirect_outputs(void)571 void maybe_redirect_outputs(void)
572 {
573 #if !(defined __APPLE__ && defined __BIG_ENDIAN__) && !defined(__DragonFly__)
574     char *argp;
575 
576     // pipe standard outputs to files
577     if ((argp = Bgetenv("EDUKE32_LOGSTDOUT")) == NULL || Bstrcasecmp(argp, "TRUE"))
578         return;
579 
580     FILE *fp = freopen("stdout.txt", "w", stdout);
581 
582     if (!fp)
583         fp = fopen("stdout.txt", "w");
584 
585     if (fp)
586     {
587         setvbuf(fp, 0, _IONBF, 0);
588         *stdout = *fp;
589         *stderr = *fp;
590     }
591 #endif
592 }
593 
engineFPSLimit(void)594 int engineFPSLimit(void)
595 {
596     if (!r_maxfps)
597         return true;
598 
599     g_frameDelay = calcFrameDelay(r_maxfps, r_maxfpsoffset);
600 
601     uint64_t        frameTicks;
602     static uint64_t nextFrameTicks;
603     static uint64_t frameDelay;
604 
605     if (g_frameDelay != frameDelay)
606     {
607         nextFrameTicks = timerGetPerformanceCounter() + g_frameDelay;
608         frameDelay = g_frameDelay;
609     }
610     handleevents();
611     frameTicks = timerGetPerformanceCounter();
612 
613     if (nextFrameTicks - frameTicks > g_frameDelay)
614     {
615         while (nextFrameTicks - frameTicks > g_frameDelay)
616             nextFrameTicks += g_frameDelay;
617 
618         return true;
619     }
620 
621     return false;
622 }
623