1 // Emacs style mode select -*- C++ -*-
2 //
3 // SONIC ROBO BLAST 2
4 //-----------------------------------------------------------------------------
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
8 // Copyright (C) 2014-2020 by Sonic Team Junior.
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // Changes by Graue <graue@oceanbase.org> are in the public domain.
21 //
22 //-----------------------------------------------------------------------------
23 /// \file
24 /// \brief SRB2 system stuff for SDL
25
26 #ifdef CMAKECONFIG
27 #include "config.h"
28 #else
29 #include "../config.h.in"
30 #endif
31
32 #include <signal.h>
33
34 #ifdef _WIN32
35 #define RPC_NO_WINDOWS_H
36 #include <windows.h>
37 #include "../doomtype.h"
38 typedef BOOL (WINAPI *p_GetDiskFreeSpaceExA)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
39 typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD);
40 typedef DWORD (WINAPI *p_timeGetTime) (void);
41 typedef UINT (WINAPI *p_timeEndPeriod) (UINT);
42 typedef HANDLE (WINAPI *p_OpenFileMappingA) (DWORD, BOOL, LPCSTR);
43 typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
44 #endif
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #ifdef __GNUC__
49 #include <unistd.h>
50 #elif defined (_MSC_VER)
51 #include <direct.h>
52 #endif
53 #if defined (__unix__) || defined (UNIXCOMMON)
54 #include <fcntl.h>
55 #endif
56
57 #include <stdio.h>
58 #ifdef _WIN32
59 #include <conio.h>
60 #endif
61
62 #ifdef _MSC_VER
63 #pragma warning(disable : 4214 4244)
64 #endif
65
66 #ifdef HAVE_SDL
67 #define _MATH_DEFINES_DEFINED
68 #include "SDL.h"
69
70 #ifdef HAVE_TTF
71 #include "i_ttf.h"
72 #endif
73
74 #ifdef _MSC_VER
75 #pragma warning(default : 4214 4244)
76 #endif
77
78 #include "SDL_cpuinfo.h"
79 #define HAVE_SDLCPUINFO
80
81 #if defined (__unix__) || defined(__APPLE__) || (defined (UNIXCOMMON) && !defined (__HAIKU__))
82 #if defined (__linux__)
83 #include <sys/vfs.h>
84 #else
85 #include <sys/param.h>
86 #include <sys/mount.h>
87 /*For meminfo*/
88 #include <sys/types.h>
89 #ifdef FREEBSD
90 #include <kvm.h>
91 #endif
92 #include <nlist.h>
93 #include <sys/vmmeter.h>
94 #endif
95 #endif
96
97 #if defined (__linux__) || (defined (UNIXCOMMON) && !defined (__HAIKU__))
98 #ifndef NOTERMIOS
99 #include <termios.h>
100 #include <sys/ioctl.h> // ioctl
101 #define HAVE_TERMIOS
102 #endif
103 #endif
104
105 #if (defined (__unix__) && !defined (_MSDOS)) || (defined (UNIXCOMMON) && !defined(__APPLE__))
106 #include <errno.h>
107 #include <sys/wait.h>
108 #define NEWSIGNALHANDLER
109 #endif
110
111 #ifndef NOMUMBLE
112 #ifdef __linux__ // need -lrt
113 #include <sys/mman.h>
114 #ifdef MAP_FAILED
115 #define HAVE_SHM
116 #endif
117 #include <wchar.h>
118 #endif
119
120 #ifdef _WIN32
121 #define HAVE_MUMBLE
122 #define WINMUMBLE
123 #elif defined (HAVE_SHM)
124 #define HAVE_MUMBLE
125 #endif
126 #endif // NOMUMBLE
127
128 #ifndef O_BINARY
129 #define O_BINARY 0
130 #endif
131
132 #ifdef __APPLE__
133 #include "macosx/mac_resources.h"
134 #endif
135
136 #ifndef errno
137 #include <errno.h>
138 #endif
139
140 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
141 #include <execinfo.h>
142 #include <time.h>
143 #define UNIXBACKTRACE
144 #endif
145
146 // Locations for searching the srb2.pk3
147 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
148 #define DEFAULTWADLOCATION1 "/usr/local/share/games/SRB2"
149 #define DEFAULTWADLOCATION2 "/usr/local/games/SRB2"
150 #define DEFAULTWADLOCATION3 "/usr/share/games/SRB2"
151 #define DEFAULTWADLOCATION4 "/usr/games/SRB2"
152 #define DEFAULTSEARCHPATH1 "/usr/local/games"
153 #define DEFAULTSEARCHPATH2 "/usr/games"
154 #define DEFAULTSEARCHPATH3 "/usr/local"
155 #elif defined (_WIN32)
156 #define DEFAULTWADLOCATION1 "c:\\games\\srb2"
157 #define DEFAULTWADLOCATION2 "\\games\\srb2"
158 #define DEFAULTSEARCHPATH1 "c:\\games"
159 #define DEFAULTSEARCHPATH2 "\\games"
160 #endif
161
162 /** \brief WAD file to look for
163 */
164 #define WADKEYWORD1 "srb2.pk3"
165 /** \brief holds wad path
166 */
167 static char returnWadPath[256];
168
169 //Alam_GBC: SDL
170
171 #include "../doomdef.h"
172 #include "../m_misc.h"
173 #include "../i_video.h"
174 #include "../i_sound.h"
175 #include "../i_system.h"
176 #include "../i_threads.h"
177 #include "../screen.h" //vid.WndParent
178 #include "../d_net.h"
179 #include "../g_game.h"
180 #include "../filesrch.h"
181 #include "endtxt.h"
182 #include "sdlmain.h"
183
184 #include "../i_joy.h"
185
186 #include "../m_argv.h"
187
188 #include "../m_menu.h"
189
190 #ifdef MAC_ALERT
191 #include "macosx/mac_alert.h"
192 #endif
193
194 #include "../d_main.h"
195
196 #if !defined(NOMUMBLE) && defined(HAVE_MUMBLE)
197 // Mumble context string
198 #include "../d_clisrv.h"
199 #include "../byteptr.h"
200 #endif
201
202 /** \brief The JoyReset function
203
204 \param JoySet Joystick info to reset
205
206 \return void
207 */
JoyReset(SDLJoyInfo_t * JoySet)208 static void JoyReset(SDLJoyInfo_t *JoySet)
209 {
210 if (JoySet->dev)
211 {
212 SDL_JoystickClose(JoySet->dev);
213 }
214 JoySet->dev = NULL;
215 JoySet->oldjoy = -1;
216 JoySet->axises = JoySet->buttons = JoySet->hats = JoySet->balls = 0;
217 //JoySet->scale
218 }
219
220 /** \brief First joystick up and running
221 */
222 static INT32 joystick_started = 0;
223
224 /** \brief SDL info about joystick 1
225 */
226 SDLJoyInfo_t JoyInfo;
227
228
229 /** \brief Second joystick up and running
230 */
231 static INT32 joystick2_started = 0;
232
233 /** \brief SDL inof about joystick 2
234 */
235 SDLJoyInfo_t JoyInfo2;
236
237 #ifdef HAVE_TERMIOS
238 static INT32 fdmouse2 = -1;
239 static INT32 mouse2_started = 0;
240 #endif
241
242 SDL_bool consolevent = SDL_FALSE;
243 SDL_bool framebuffer = SDL_FALSE;
244
245 UINT8 keyboard_started = false;
246
247 #ifdef UNIXBACKTRACE
248 #define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string)
249 #define CRASHLOG_WRITE(string) if (fd != -1) write(fd, string, strlen(string))
250 #define CRASHLOG_STDERR_WRITE(string) \
251 if (fd != -1)\
252 write(fd, string, strlen(string));\
253 I_OutputMsg("%s", string)
254
write_backtrace(INT32 signal)255 static void write_backtrace(INT32 signal)
256 {
257 int fd = -1;
258 size_t size;
259 time_t rawtime;
260 struct tm timeinfo;
261
262 enum { BT_SIZE = 1024, STR_SIZE = 32 };
263 void *array[BT_SIZE];
264 char timestr[STR_SIZE];
265
266 const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n";
267 const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr.
268
269 fd = open(va("%s" PATHSEP "%s", srb2home, "crash-log.txt"), O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR);
270
271 if (fd == -1)
272 I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n");
273
274 // Get the current time as a string.
275 time(&rawtime);
276 localtime_r(&rawtime, &timeinfo);
277 strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo);
278
279 CRASHLOG_WRITE("------------------------\n"); // Nice looking seperator
280
281 CRASHLOG_STDERR_WRITE("\n"); // Newline to look nice for both outputs.
282 CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message
283 STDERR_WRITE(error2); // Tell the user where the crash log is.
284
285 // Tell the log when we crashed.
286 CRASHLOG_WRITE("Time of crash: ");
287 CRASHLOG_WRITE(timestr);
288 CRASHLOG_WRITE("\n");
289
290 // Give the crash log the cause and a nice 'Backtrace:' thing
291 // The signal is given to the user when the parent process sees we crashed.
292 CRASHLOG_WRITE("Cause: ");
293 CRASHLOG_WRITE(strsignal(signal));
294 CRASHLOG_WRITE("\n"); // Newline for the signal name
295
296 CRASHLOG_STDERR_WRITE("\nBacktrace:\n");
297
298 // Flood the output and log with the backtrace
299 size = backtrace(array, BT_SIZE);
300 backtrace_symbols_fd(array, size, fd);
301 backtrace_symbols_fd(array, size, STDERR_FILENO);
302
303 CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :)
304
305 close(fd);
306 }
307 #undef STDERR_WRITE
308 #undef CRASHLOG_WRITE
309 #undef CRASHLOG_STDERR_WRITE
310 #endif // UNIXBACKTRACE
311
I_ReportSignal(int num,int coredumped)312 static void I_ReportSignal(int num, int coredumped)
313 {
314 //static char msg[] = "oh no! back to reality!\r\n";
315 const char * sigmsg;
316 char msg[128];
317
318 switch (num)
319 {
320 // case SIGINT:
321 // sigmsg = "SIGINT - interrupted";
322 // break;
323 case SIGILL:
324 sigmsg = "SIGILL - illegal instruction - invalid function image";
325 break;
326 case SIGFPE:
327 sigmsg = "SIGFPE - mathematical exception";
328 break;
329 case SIGSEGV:
330 sigmsg = "SIGSEGV - segment violation";
331 break;
332 // case SIGTERM:
333 // sigmsg = "SIGTERM - Software termination signal from kill";
334 // break;
335 // case SIGBREAK:
336 // sigmsg = "SIGBREAK - Ctrl-Break sequence";
337 // break;
338 case SIGABRT:
339 sigmsg = "SIGABRT - abnormal termination triggered by abort call";
340 break;
341 default:
342 sprintf(msg,"signal number %d", num);
343 if (coredumped)
344 sigmsg = 0;
345 else
346 sigmsg = msg;
347 }
348
349 if (coredumped)
350 {
351 if (sigmsg)
352 sprintf(msg, "%s (core dumped)", sigmsg);
353 else
354 strcat(msg, " (core dumped)");
355
356 sigmsg = msg;
357 }
358
359 I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg);
360
361 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
362 "Process killed by signal",
363 sigmsg, NULL);
364 }
365
366 #ifndef NEWSIGNALHANDLER
signal_handler(INT32 num)367 FUNCNORETURN static ATTRNORETURN void signal_handler(INT32 num)
368 {
369 D_QuitNetGame(); // Fix server freezes
370 CL_AbortDownloadResume();
371 #ifdef UNIXBACKTRACE
372 write_backtrace(num);
373 #endif
374 I_ReportSignal(num, 0);
375 I_ShutdownSystem();
376 signal(num, SIG_DFL); //default signal action
377 raise(num);
378 I_Quit();
379 }
380 #endif
381
quit_handler(int num)382 FUNCNORETURN static ATTRNORETURN void quit_handler(int num)
383 {
384 signal(num, SIG_DFL); //default signal action
385 raise(num);
386 I_Quit();
387 }
388
389 #ifdef HAVE_TERMIOS
390 // TERMIOS console code from Quake3: thank you!
391 SDL_bool stdin_active = SDL_TRUE;
392
393 typedef struct
394 {
395 size_t cursor;
396 char buffer[256];
397 } feild_t;
398
399 feild_t tty_con;
400
401 // when printing general stuff to stdout stderr (Sys_Printf)
402 // we need to disable the tty console stuff
403 // this increments so we can recursively disable
404 static INT32 ttycon_hide = 0;
405 // some key codes that the terminal may be using
406 // TTimo NOTE: I'm not sure how relevant this is
407 static INT32 tty_erase;
408 static INT32 tty_eof;
409
410 static struct termios tty_tc;
411
412 // =============================================================
413 // tty console routines
414 // NOTE: if the user is editing a line when something gets printed to the early console then it won't look good
415 // so we provide tty_Clear and tty_Show to be called before and after a stdout or stderr output
416 // =============================================================
417
418 // flush stdin, I suspect some terminals are sending a LOT of garbage
419 // FIXME TTimo relevant?
420 #if 0
421 static inline void tty_FlushIn(void)
422 {
423 char key;
424 while (read(STDIN_FILENO, &key, 1)!=-1);
425 }
426 #endif
427
428 // do a backspace
429 // TTimo NOTE: it seems on some terminals just sending '\b' is not enough
430 // so for now, in any case we send "\b \b" .. yeah well ..
431 // (there may be a way to find out if '\b' alone would work though)
tty_Back(void)432 static void tty_Back(void)
433 {
434 char key;
435 ssize_t d;
436 key = '\b';
437 d = write(STDOUT_FILENO, &key, 1);
438 key = ' ';
439 d = write(STDOUT_FILENO, &key, 1);
440 key = '\b';
441 d = write(STDOUT_FILENO, &key, 1);
442 (void)d;
443 }
444
tty_Clear(void)445 static void tty_Clear(void)
446 {
447 size_t i;
448 if (tty_con.cursor>0)
449 {
450 for (i=0; i<tty_con.cursor; i++)
451 {
452 tty_Back();
453 }
454 }
455
456 }
457
458 // clear the display of the line currently edited
459 // bring cursor back to beginning of line
tty_Hide(void)460 static inline void tty_Hide(void)
461 {
462 //I_Assert(consolevent);
463 if (ttycon_hide)
464 {
465 ttycon_hide++;
466 return;
467 }
468 tty_Clear();
469 ttycon_hide++;
470 }
471
472 // show the current line
473 // FIXME TTimo need to position the cursor if needed??
tty_Show(void)474 static inline void tty_Show(void)
475 {
476 size_t i;
477 ssize_t d;
478 //I_Assert(consolevent);
479 I_Assert(ttycon_hide>0);
480 ttycon_hide--;
481 if (ttycon_hide == 0 && tty_con.cursor)
482 {
483 for (i=0; i<tty_con.cursor; i++)
484 {
485 d = write(STDOUT_FILENO, tty_con.buffer+i, 1);
486 }
487 }
488 (void)d;
489 }
490
491 // never exit without calling this, or your terminal will be left in a pretty bad state
I_ShutdownConsole(void)492 static void I_ShutdownConsole(void)
493 {
494 if (consolevent)
495 {
496 I_OutputMsg("Shutdown tty console\n");
497 consolevent = SDL_FALSE;
498 tcsetattr (STDIN_FILENO, TCSADRAIN, &tty_tc);
499 }
500 }
501
I_StartupConsole(void)502 static void I_StartupConsole(void)
503 {
504 struct termios tc;
505
506 // TTimo
507 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=390 (404)
508 // then SIGTTIN or SIGTOU is emitted, if not catched, turns into a SIGSTP
509 signal(SIGTTIN, SIG_IGN);
510 signal(SIGTTOU, SIG_IGN);
511
512 consolevent = !M_CheckParm("-noconsole");
513 framebuffer = M_CheckParm("-framebuffer");
514
515 if (framebuffer)
516 consolevent = SDL_FALSE;
517
518 if (!consolevent) return;
519
520 if (isatty(STDIN_FILENO)!=1)
521 {
522 I_OutputMsg("stdin is not a tty, tty console mode failed\n");
523 consolevent = SDL_FALSE;
524 return;
525 }
526 memset(&tty_con, 0x00, sizeof(tty_con));
527 tcgetattr (0, &tty_tc);
528 tty_erase = tty_tc.c_cc[VERASE];
529 tty_eof = tty_tc.c_cc[VEOF];
530 tc = tty_tc;
531 /*
532 ECHO: don't echo input characters
533 ICANON: enable canonical mode. This enables the special
534 characters EOF, EOL, EOL2, ERASE, KILL, REPRINT,
535 STATUS, and WERASE, and buffers by lines.
536 ISIG: when any of the characters INTR, QUIT, SUSP, or
537 DSUSP are received, generate the corresponding signal
538 */
539 tc.c_lflag &= ~(ECHO | ICANON);
540 /*
541 ISTRIP strip off bit 8
542 INPCK enable input parity checking
543 */
544 tc.c_iflag &= ~(ISTRIP | INPCK);
545 tc.c_cc[VMIN] = 0; //1?
546 tc.c_cc[VTIME] = 0;
547 tcsetattr (0, TCSADRAIN, &tc);
548 }
549
I_GetConsoleEvents(void)550 void I_GetConsoleEvents(void)
551 {
552 // we use this when sending back commands
553 event_t ev = {0,0,0,0};
554 char key = 0;
555 ssize_t d;
556
557 if (!consolevent)
558 return;
559
560 ev.type = ev_console;
561 if (read(STDIN_FILENO, &key, 1) == -1 || !key)
562 return;
563
564 // we have something
565 // backspace?
566 // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
567 if ((key == tty_erase) || (key == 127) || (key == 8))
568 {
569 if (tty_con.cursor > 0)
570 {
571 tty_con.cursor--;
572 tty_con.buffer[tty_con.cursor] = '\0';
573 tty_Back();
574 }
575 ev.data1 = KEY_BACKSPACE;
576 }
577 else if (key < ' ') // check if this is a control char
578 {
579 if (key == '\n')
580 {
581 tty_Clear();
582 tty_con.cursor = 0;
583 ev.data1 = KEY_ENTER;
584 }
585 else return;
586 }
587 else
588 {
589 // push regular character
590 ev.data1 = tty_con.buffer[tty_con.cursor] = key;
591 tty_con.cursor++;
592 // print the current line (this is differential)
593 d = write(STDOUT_FILENO, &key, 1);
594 }
595 if (ev.data1) D_PostEvent(&ev);
596 //tty_FlushIn();
597 (void)d;
598 }
599
600 #elif defined (_WIN32)
I_ReadyConsole(HANDLE ci)601 static BOOL I_ReadyConsole(HANDLE ci)
602 {
603 DWORD gotinput;
604 if (ci == INVALID_HANDLE_VALUE) return FALSE;
605 if (WaitForSingleObject(ci,0) != WAIT_OBJECT_0) return FALSE;
606 if (GetFileType(ci) != FILE_TYPE_CHAR) return FALSE;
607 if (!GetConsoleMode(ci, &gotinput)) return FALSE;
608 return (GetNumberOfConsoleInputEvents(ci, &gotinput) && gotinput);
609 }
610
611 static boolean entering_con_command = false;
612
Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt,HANDLE co)613 static void Impl_HandleKeyboardConsoleEvent(KEY_EVENT_RECORD evt, HANDLE co)
614 {
615 event_t event;
616 CONSOLE_SCREEN_BUFFER_INFO CSBI;
617 DWORD t;
618
619 memset(&event,0x00,sizeof (event));
620
621 if (evt.bKeyDown)
622 {
623 event.type = ev_console;
624 entering_con_command = true;
625 switch (evt.wVirtualKeyCode)
626 {
627 case VK_ESCAPE:
628 case VK_TAB:
629 event.data1 = KEY_NULL;
630 break;
631 case VK_RETURN:
632 entering_con_command = false;
633 /* FALLTHRU */
634 default:
635 //event.data1 = MapVirtualKey(evt.wVirtualKeyCode,2); // convert in to char
636 event.data1 = evt.uChar.AsciiChar;
637 }
638 if (co != INVALID_HANDLE_VALUE && GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &t))
639 {
640 if (event.data1 && event.data1 != KEY_LSHIFT && event.data1 != KEY_RSHIFT)
641 {
642 #ifdef _UNICODE
643 WriteConsole(co, &evt.uChar.UnicodeChar, 1, &t, NULL);
644 #else
645 WriteConsole(co, &evt.uChar.AsciiChar, 1 , &t, NULL);
646 #endif
647 }
648 if (evt.wVirtualKeyCode == VK_BACK
649 && GetConsoleScreenBufferInfo(co,&CSBI))
650 {
651 WriteConsoleOutputCharacterA(co, " ",1, CSBI.dwCursorPosition, &t);
652 }
653 }
654 }
655 if (event.data1) D_PostEvent(&event);
656 }
657
I_GetConsoleEvents(void)658 void I_GetConsoleEvents(void)
659 {
660 HANDLE ci = GetStdHandle(STD_INPUT_HANDLE);
661 HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE);
662 INPUT_RECORD input;
663 DWORD t;
664
665 while (I_ReadyConsole(ci) && ReadConsoleInput(ci, &input, 1, &t) && t)
666 {
667 switch (input.EventType)
668 {
669 case KEY_EVENT:
670 Impl_HandleKeyboardConsoleEvent(input.Event.KeyEvent, co);
671 break;
672 case MOUSE_EVENT:
673 case WINDOW_BUFFER_SIZE_EVENT:
674 case MENU_EVENT:
675 case FOCUS_EVENT:
676 break;
677 }
678 }
679 }
680
I_StartupConsole(void)681 static void I_StartupConsole(void)
682 {
683 HANDLE ci, co;
684 const INT32 ded = M_CheckParm("-dedicated");
685 BOOL gotConsole = FALSE;
686 if (M_CheckParm("-console") || ded)
687 gotConsole = AllocConsole();
688 #ifdef _DEBUG
689 else if (M_CheckParm("-noconsole") && !ded)
690 #else
691 else if (!M_CheckParm("-console") && !ded)
692 #endif
693 {
694 FreeConsole();
695 gotConsole = FALSE;
696 }
697
698 if (gotConsole)
699 {
700 SetConsoleTitleA("SRB2 Console");
701 consolevent = SDL_TRUE;
702 }
703
704 //Let get the real console HANDLE, because Mingw's Bash is bad!
705 ci = CreateFile(TEXT("CONIN$") , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
706 co = CreateFile(TEXT("CONOUT$"), GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
707 if (ci != INVALID_HANDLE_VALUE)
708 {
709 const DWORD CM = ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT;
710 SetStdHandle(STD_INPUT_HANDLE, ci);
711 if (GetFileType(ci) == FILE_TYPE_CHAR)
712 SetConsoleMode(ci, CM); //default mode but no ENABLE_MOUSE_INPUT
713 }
714 if (co != INVALID_HANDLE_VALUE)
715 {
716 SetStdHandle(STD_OUTPUT_HANDLE, co);
717 SetStdHandle(STD_ERROR_HANDLE, co);
718 }
719 }
I_ShutdownConsole(void)720 static inline void I_ShutdownConsole(void){}
721 #else
I_GetConsoleEvents(void)722 void I_GetConsoleEvents(void){}
I_StartupConsole(void)723 static inline void I_StartupConsole(void)
724 {
725 #ifdef _DEBUG
726 consolevent = !M_CheckParm("-noconsole");
727 #else
728 consolevent = M_CheckParm("-console");
729 #endif
730
731 framebuffer = M_CheckParm("-framebuffer");
732
733 if (framebuffer)
734 consolevent = SDL_FALSE;
735 }
I_ShutdownConsole(void)736 static inline void I_ShutdownConsole(void){}
737 #endif
738
739 //
740 // StartupKeyboard
741 //
I_RegisterSignals(void)742 static void I_RegisterSignals (void)
743 {
744 #ifdef SIGINT
745 signal(SIGINT , quit_handler);
746 #endif
747 #ifdef SIGBREAK
748 signal(SIGBREAK , quit_handler);
749 #endif
750 #ifdef SIGTERM
751 signal(SIGTERM , quit_handler);
752 #endif
753
754 // If these defines don't exist,
755 // then compilation would have failed above us...
756 #ifndef NEWSIGNALHANDLER
757 signal(SIGILL , signal_handler);
758 signal(SIGSEGV , signal_handler);
759 signal(SIGABRT , signal_handler);
760 signal(SIGFPE , signal_handler);
761 #endif
762 }
763
764 #ifdef NEWSIGNALHANDLER
signal_handler_child(INT32 num)765 static void signal_handler_child(INT32 num)
766 {
767 #ifdef UNIXBACKTRACE
768 write_backtrace(num);
769 #endif
770
771 signal(num, SIG_DFL); //default signal action
772 raise(num);
773 }
774
I_RegisterChildSignals(void)775 static void I_RegisterChildSignals(void)
776 {
777 // If these defines don't exist,
778 // then compilation would have failed above us...
779 signal(SIGILL , signal_handler_child);
780 signal(SIGSEGV , signal_handler_child);
781 signal(SIGABRT , signal_handler_child);
782 signal(SIGFPE , signal_handler_child);
783 }
784 #endif
785
786 //
787 //I_OutputMsg
788 //
I_OutputMsg(const char * fmt,...)789 void I_OutputMsg(const char *fmt, ...)
790 {
791 size_t len;
792 char txt[8192];
793 va_list argptr;
794
795 va_start(argptr,fmt);
796 vsprintf(txt, fmt, argptr);
797 va_end(argptr);
798
799 #ifdef HAVE_TTF
800 if (TTF_WasInit()) I_TTFDrawText(currentfont, solid, DEFAULTFONTFGR, DEFAULTFONTFGG, DEFAULTFONTFGB, DEFAULTFONTFGA,
801 DEFAULTFONTBGR, DEFAULTFONTBGG, DEFAULTFONTBGB, DEFAULTFONTBGA, txt);
802 #endif
803
804 #if defined (_WIN32) && defined (_MSC_VER)
805 OutputDebugStringA(txt);
806 #endif
807
808 len = strlen(txt);
809
810 #ifdef LOGMESSAGES
811 if (logstream)
812 {
813 size_t d = fwrite(txt, len, 1, logstream);
814 fflush(logstream);
815 (void)d;
816 }
817 #endif
818
819 #if defined (_WIN32)
820 #ifdef DEBUGFILE
821 if (debugfile != stderr)
822 #endif
823 {
824 HANDLE co = GetStdHandle(STD_OUTPUT_HANDLE);
825 DWORD bytesWritten;
826
827 if (co == INVALID_HANDLE_VALUE)
828 return;
829
830 if (GetFileType(co) == FILE_TYPE_CHAR && GetConsoleMode(co, &bytesWritten))
831 {
832 static COORD coordNextWrite = {0,0};
833 LPVOID oldLines = NULL;
834 INT oldLength;
835 CONSOLE_SCREEN_BUFFER_INFO csbi;
836
837 // Save the lines that we're going to obliterate.
838 GetConsoleScreenBufferInfo(co, &csbi);
839 oldLength = csbi.dwSize.X * (csbi.dwCursorPosition.Y - coordNextWrite.Y) + csbi.dwCursorPosition.X - coordNextWrite.X;
840
841 if (oldLength > 0)
842 {
843 LPVOID blank = malloc(oldLength);
844 if (!blank) return;
845 memset(blank, ' ', oldLength); // Blank out.
846 oldLines = malloc(oldLength*sizeof(TCHAR));
847 if (!oldLines)
848 {
849 free(blank);
850 return;
851 }
852
853 ReadConsoleOutputCharacter(co, oldLines, oldLength, coordNextWrite, &bytesWritten);
854
855 // Move to where we what to print - which is where we would've been,
856 // had console input not been in the way,
857 SetConsoleCursorPosition(co, coordNextWrite);
858
859 WriteConsoleA(co, blank, oldLength, &bytesWritten, NULL);
860 free(blank);
861
862 // And back to where we want to print again.
863 SetConsoleCursorPosition(co, coordNextWrite);
864 }
865
866 // Actually write the string now!
867 WriteConsoleA(co, txt, (DWORD)len, &bytesWritten, NULL);
868
869 // Next time, output where we left off.
870 GetConsoleScreenBufferInfo(co, &csbi);
871 coordNextWrite = csbi.dwCursorPosition;
872
873 // Restore what was overwritten.
874 if (oldLines && entering_con_command)
875 WriteConsole(co, oldLines, oldLength, &bytesWritten, NULL);
876 if (oldLines) free(oldLines);
877 }
878 else // Redirected to a file.
879 WriteFile(co, txt, (DWORD)len, &bytesWritten, NULL);
880 }
881 #else
882 #ifdef HAVE_TERMIOS
883 if (consolevent)
884 {
885 tty_Hide();
886 }
887 #endif
888
889 if (!framebuffer)
890 fprintf(stderr, "%s", txt);
891 #ifdef HAVE_TERMIOS
892 if (consolevent)
893 {
894 tty_Show();
895 }
896 #endif
897
898 // 2004-03-03 AJR Since not all messages end in newline, some were getting displayed late.
899 if (!framebuffer)
900 fflush(stderr);
901
902 #endif
903 }
904
905 //
906 // I_GetKey
907 //
I_GetKey(void)908 INT32 I_GetKey (void)
909 {
910 // Warning: I_GetKey empties the event queue till next keypress
911 event_t *ev;
912 INT32 rc = 0;
913
914 // return the first keypress from the event queue
915 for (; eventtail != eventhead; eventtail = (eventtail+1)&(MAXEVENTS-1))
916 {
917 ev = &events[eventtail];
918 if (ev->type == ev_keydown || ev->type == ev_console)
919 {
920 rc = ev->data1;
921 continue;
922 }
923 }
924
925 return rc;
926 }
927
928 //
929 // I_JoyScale
930 //
I_JoyScale(void)931 void I_JoyScale(void)
932 {
933 Joystick.bGamepadStyle = cv_joyscale.value==0;
934 JoyInfo.scale = Joystick.bGamepadStyle?1:cv_joyscale.value;
935 }
936
I_JoyScale2(void)937 void I_JoyScale2(void)
938 {
939 Joystick2.bGamepadStyle = cv_joyscale2.value==0;
940 JoyInfo2.scale = Joystick2.bGamepadStyle?1:cv_joyscale2.value;
941 }
942
943 // Cheat to get the device index for a joystick handle
I_GetJoystickDeviceIndex(SDL_Joystick * dev)944 INT32 I_GetJoystickDeviceIndex(SDL_Joystick *dev)
945 {
946 INT32 i, count = SDL_NumJoysticks();
947
948 for (i = 0; dev && i < count; i++)
949 {
950 SDL_Joystick *test = SDL_JoystickOpen(i);
951 if (test && test == dev)
952 return i;
953 else if (JoyInfo.dev != test && JoyInfo2.dev != test)
954 SDL_JoystickClose(test);
955 }
956
957 return -1;
958 }
959
960 /** \brief Joystick 1 buttons states
961 */
962 static UINT64 lastjoybuttons = 0;
963
964 /** \brief Joystick 1 hats state
965 */
966 static UINT64 lastjoyhats = 0;
967
968 /** \brief Shuts down joystick 1
969
970
971 \return void
972
973
974 */
I_ShutdownJoystick(void)975 void I_ShutdownJoystick(void)
976 {
977 INT32 i;
978 event_t event;
979 event.type=ev_keyup;
980 event.data2 = 0;
981 event.data3 = 0;
982
983 lastjoybuttons = lastjoyhats = 0;
984
985 // emulate the up of all joystick buttons
986 for (i=0;i<JOYBUTTONS;i++)
987 {
988 event.data1=KEY_JOY1+i;
989 D_PostEvent(&event);
990 }
991
992 // emulate the up of all joystick hats
993 for (i=0;i<JOYHATS*4;i++)
994 {
995 event.data1=KEY_HAT1+i;
996 D_PostEvent(&event);
997 }
998
999 // reset joystick position
1000 event.type = ev_joystick;
1001 for (i=0;i<JOYAXISSET; i++)
1002 {
1003 event.data1 = i;
1004 D_PostEvent(&event);
1005 }
1006
1007 joystick_started = 0;
1008 JoyReset(&JoyInfo);
1009
1010 // don't shut down the subsystem here, because hotplugging
1011 }
1012
I_GetJoystickEvents(void)1013 void I_GetJoystickEvents(void)
1014 {
1015 static event_t event = {0,0,0,0};
1016 INT32 i = 0;
1017 UINT64 joyhats = 0;
1018 #if 0
1019 UINT64 joybuttons = 0;
1020 Sint16 axisx, axisy;
1021 #endif
1022
1023 if (!joystick_started) return;
1024
1025 if (!JoyInfo.dev) //I_ShutdownJoystick();
1026 return;
1027
1028 #if 0
1029 //faB: look for as much buttons as g_input code supports,
1030 // we don't use the others
1031 for (i = JoyInfo.buttons - 1; i >= 0; i--)
1032 {
1033 joybuttons <<= 1;
1034 if (SDL_JoystickGetButton(JoyInfo.dev,i))
1035 joybuttons |= 1;
1036 }
1037
1038 if (joybuttons != lastjoybuttons)
1039 {
1040 INT64 j = 1; // keep only bits that changed since last time
1041 INT64 newbuttons = joybuttons ^ lastjoybuttons;
1042 lastjoybuttons = joybuttons;
1043
1044 for (i = 0; i < JOYBUTTONS; i++, j <<= 1)
1045 {
1046 if (newbuttons & j) // button changed state?
1047 {
1048 if (joybuttons & j)
1049 event.type = ev_keydown;
1050 else
1051 event.type = ev_keyup;
1052 event.data1 = KEY_JOY1 + i;
1053 D_PostEvent(&event);
1054 }
1055 }
1056 }
1057 #endif
1058
1059 for (i = JoyInfo.hats - 1; i >= 0; i--)
1060 {
1061 Uint8 hat = SDL_JoystickGetHat(JoyInfo.dev, i);
1062
1063 if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i);
1064 if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i);
1065 if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i);
1066 if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i);
1067 }
1068
1069 if (joyhats != lastjoyhats)
1070 {
1071 INT64 j = 1; // keep only bits that changed since last time
1072 INT64 newhats = joyhats ^ lastjoyhats;
1073 lastjoyhats = joyhats;
1074
1075 for (i = 0; i < JOYHATS*4; i++, j <<= 1)
1076 {
1077 if (newhats & j) // hat changed state?
1078 {
1079 if (joyhats & j)
1080 event.type = ev_keydown;
1081 else
1082 event.type = ev_keyup;
1083 event.data1 = KEY_HAT1 + i;
1084 D_PostEvent(&event);
1085 }
1086 }
1087 }
1088
1089 #if 0
1090 // send joystick axis positions
1091 event.type = ev_joystick;
1092
1093 for (i = JOYAXISSET - 1; i >= 0; i--)
1094 {
1095 event.data1 = i;
1096 if (i*2 + 1 <= JoyInfo.axises)
1097 axisx = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 0);
1098 else axisx = 0;
1099 if (i*2 + 2 <= JoyInfo.axises)
1100 axisy = SDL_JoystickGetAxis(JoyInfo.dev, i*2 + 1);
1101 else axisy = 0;
1102
1103
1104 // -32768 to 32767
1105 axisx = axisx/32;
1106 axisy = axisy/32;
1107
1108
1109 if (Joystick.bGamepadStyle)
1110 {
1111 // gamepad control type, on or off, live or die
1112 if (axisx < -(JOYAXISRANGE/2))
1113 event.data2 = -1;
1114 else if (axisx > (JOYAXISRANGE/2))
1115 event.data2 = 1;
1116 else event.data2 = 0;
1117 if (axisy < -(JOYAXISRANGE/2))
1118 event.data3 = -1;
1119 else if (axisy > (JOYAXISRANGE/2))
1120 event.data3 = 1;
1121 else event.data3 = 0;
1122 }
1123 else
1124 {
1125
1126 axisx = JoyInfo.scale?((axisx/JoyInfo.scale)*JoyInfo.scale):axisx;
1127 axisy = JoyInfo.scale?((axisy/JoyInfo.scale)*JoyInfo.scale):axisy;
1128
1129 #ifdef SDL_JDEADZONE
1130 if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0;
1131 if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0;
1132 #endif
1133
1134 // analog control style , just send the raw data
1135 event.data2 = axisx; // x axis
1136 event.data3 = axisy; // y axis
1137 }
1138 D_PostEvent(&event);
1139 }
1140 #endif
1141 }
1142
1143 /** \brief Open joystick handle
1144
1145 \param fname name of joystick
1146
1147 \return axises
1148
1149
1150 */
joy_open(int joyindex)1151 static int joy_open(int joyindex)
1152 {
1153 SDL_Joystick *newdev = NULL;
1154 int num_joy = 0;
1155
1156 if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
1157 {
1158 CONS_Printf(M_GetText("Joystick subsystem not started\n"));
1159 return -1;
1160 }
1161
1162 if (joyindex <= 0)
1163 return -1;
1164
1165 num_joy = SDL_NumJoysticks();
1166
1167 if (num_joy == 0)
1168 {
1169 CONS_Printf("%s", M_GetText("Found no joysticks on this system\n"));
1170 return -1;
1171 }
1172
1173 newdev = SDL_JoystickOpen(joyindex-1);
1174
1175 // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging
1176 // This indexing is SDL's responsibility and there's not much we can do about it.
1177 //
1178 // Example:
1179 // 1. Plug Controller A -> Index 0 opened
1180 // 2. Plug Controller B -> Index 1 opened
1181 // 3. Unplug Controller A -> Index 0 closed, Index 1 active
1182 // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed
1183 // 5. Plug Controller B -> Index 0 opened
1184 // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B
1185 if (JoyInfo.dev)
1186 {
1187 if (JoyInfo.dev == newdev // same device, nothing to do
1188 || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo.dev))) // we failed, but already have a working device
1189 return JoyInfo.axises;
1190 // Else, we're changing devices, so send neutral joy events
1191 CONS_Debug(DBG_GAMELOGIC, "Joystick1 device is changing; resetting events...\n");
1192 I_ShutdownJoystick();
1193 }
1194
1195 JoyInfo.dev = newdev;
1196
1197 if (JoyInfo.dev == NULL)
1198 {
1199 CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: Couldn't open device - %s\n"), SDL_GetError());
1200 return -1;
1201 }
1202 else
1203 {
1204 CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick1: %s\n"), SDL_JoystickName(JoyInfo.dev));
1205 JoyInfo.axises = SDL_JoystickNumAxes(JoyInfo.dev);
1206 if (JoyInfo.axises > JOYAXISSET*2)
1207 JoyInfo.axises = JOYAXISSET*2;
1208 /* if (joyaxes<2)
1209 {
1210 I_OutputMsg("Not enought axes?\n");
1211 return 0;
1212 }*/
1213
1214 JoyInfo.buttons = SDL_JoystickNumButtons(JoyInfo.dev);
1215 if (JoyInfo.buttons > JOYBUTTONS)
1216 JoyInfo.buttons = JOYBUTTONS;
1217
1218 JoyInfo.hats = SDL_JoystickNumHats(JoyInfo.dev);
1219 if (JoyInfo.hats > JOYHATS)
1220 JoyInfo.hats = JOYHATS;
1221
1222 JoyInfo.balls = SDL_JoystickNumBalls(JoyInfo.dev);
1223
1224 //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo.dev), "pad");
1225
1226 return JoyInfo.axises;
1227 }
1228 }
1229
1230 //Joystick2
1231
1232 /** \brief Joystick 2 buttons states
1233 */
1234 static UINT64 lastjoy2buttons = 0;
1235
1236 /** \brief Joystick 2 hats state
1237 */
1238 static UINT64 lastjoy2hats = 0;
1239
1240 /** \brief Shuts down joystick 2
1241
1242
1243 \return void
1244 */
I_ShutdownJoystick2(void)1245 void I_ShutdownJoystick2(void)
1246 {
1247 INT32 i;
1248 event_t event;
1249 event.type = ev_keyup;
1250 event.data2 = 0;
1251 event.data3 = 0;
1252
1253 lastjoy2buttons = lastjoy2hats = 0;
1254
1255 // emulate the up of all joystick buttons
1256 for (i = 0; i < JOYBUTTONS; i++)
1257 {
1258 event.data1 = KEY_2JOY1 + i;
1259 D_PostEvent(&event);
1260 }
1261
1262 // emulate the up of all joystick hats
1263 for (i = 0; i < JOYHATS*4; i++)
1264 {
1265 event.data1 = KEY_2HAT1 + i;
1266 D_PostEvent(&event);
1267 }
1268
1269 // reset joystick position
1270 event.type = ev_joystick2;
1271 for (i = 0; i < JOYAXISSET; i++)
1272 {
1273 event.data1 = i;
1274 D_PostEvent(&event);
1275 }
1276
1277 joystick2_started = 0;
1278 JoyReset(&JoyInfo2);
1279
1280 // don't shut down the subsystem here, because hotplugging
1281 }
1282
I_GetJoystick2Events(void)1283 void I_GetJoystick2Events(void)
1284 {
1285 static event_t event = {0,0,0,0};
1286 INT32 i = 0;
1287 UINT64 joyhats = 0;
1288 #if 0
1289 INT64 joybuttons = 0;
1290 INT32 axisx, axisy;
1291 #endif
1292
1293 if (!joystick2_started)
1294 return;
1295
1296 if (!JoyInfo2.dev) //I_ShutdownJoystick2();
1297 return;
1298
1299
1300 #if 0
1301 //faB: look for as much buttons as g_input code supports,
1302 // we don't use the others
1303 for (i = JoyInfo2.buttons - 1; i >= 0; i--)
1304 {
1305 joybuttons <<= 1;
1306 if (SDL_JoystickGetButton(JoyInfo2.dev,i))
1307 joybuttons |= 1;
1308 }
1309
1310 if (joybuttons != lastjoy2buttons)
1311 {
1312 INT64 j = 1; // keep only bits that changed since last time
1313 INT64 newbuttons = joybuttons ^ lastjoy2buttons;
1314 lastjoy2buttons = joybuttons;
1315
1316 for (i = 0; i < JOYBUTTONS; i++, j <<= 1)
1317 {
1318 if (newbuttons & j) // button changed state?
1319 {
1320 if (joybuttons & j)
1321 event.type = ev_keydown;
1322 else
1323 event.type = ev_keyup;
1324 event.data1 = KEY_2JOY1 + i;
1325 D_PostEvent(&event);
1326 }
1327 }
1328 }
1329 #endif
1330
1331 for (i = JoyInfo2.hats - 1; i >= 0; i--)
1332 {
1333 Uint8 hat = SDL_JoystickGetHat(JoyInfo2.dev, i);
1334
1335 if (hat & SDL_HAT_UP ) joyhats|=(UINT64)0x1<<(0 + 4*i);
1336 if (hat & SDL_HAT_DOWN ) joyhats|=(UINT64)0x1<<(1 + 4*i);
1337 if (hat & SDL_HAT_LEFT ) joyhats|=(UINT64)0x1<<(2 + 4*i);
1338 if (hat & SDL_HAT_RIGHT) joyhats|=(UINT64)0x1<<(3 + 4*i);
1339 }
1340
1341 if (joyhats != lastjoy2hats)
1342 {
1343 INT64 j = 1; // keep only bits that changed since last time
1344 INT64 newhats = joyhats ^ lastjoy2hats;
1345 lastjoy2hats = joyhats;
1346
1347 for (i = 0; i < JOYHATS*4; i++, j <<= 1)
1348 {
1349 if (newhats & j) // hat changed state?
1350 {
1351 if (joyhats & j)
1352 event.type = ev_keydown;
1353 else
1354 event.type = ev_keyup;
1355 event.data1 = KEY_2HAT1 + i;
1356 D_PostEvent(&event);
1357 }
1358 }
1359 }
1360
1361 #if 0
1362 // send joystick axis positions
1363 event.type = ev_joystick2;
1364
1365 for (i = JOYAXISSET - 1; i >= 0; i--)
1366 {
1367 event.data1 = i;
1368 if (i*2 + 1 <= JoyInfo2.axises)
1369 axisx = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 0);
1370 else axisx = 0;
1371 if (i*2 + 2 <= JoyInfo2.axises)
1372 axisy = SDL_JoystickGetAxis(JoyInfo2.dev, i*2 + 1);
1373 else axisy = 0;
1374
1375 // -32768 to 32767
1376 axisx = axisx/32;
1377 axisy = axisy/32;
1378
1379 if (Joystick2.bGamepadStyle)
1380 {
1381 // gamepad control type, on or off, live or die
1382 if (axisx < -(JOYAXISRANGE/2))
1383 event.data2 = -1;
1384 else if (axisx > (JOYAXISRANGE/2))
1385 event.data2 = 1;
1386 else
1387 event.data2 = 0;
1388 if (axisy < -(JOYAXISRANGE/2))
1389 event.data3 = -1;
1390 else if (axisy > (JOYAXISRANGE/2))
1391 event.data3 = 1;
1392 else
1393 event.data3 = 0;
1394 }
1395 else
1396 {
1397
1398 axisx = JoyInfo2.scale?((axisx/JoyInfo2.scale)*JoyInfo2.scale):axisx;
1399 axisy = JoyInfo2.scale?((axisy/JoyInfo2.scale)*JoyInfo2.scale):axisy;
1400
1401 #ifdef SDL_JDEADZONE
1402 if (-SDL_JDEADZONE <= axisx && axisx <= SDL_JDEADZONE) axisx = 0;
1403 if (-SDL_JDEADZONE <= axisy && axisy <= SDL_JDEADZONE) axisy = 0;
1404 #endif
1405
1406 // analog control style , just send the raw data
1407 event.data2 = axisx; // x axis
1408 event.data3 = axisy; // y axis
1409 }
1410 D_PostEvent(&event);
1411 }
1412 #endif
1413 }
1414
1415 /** \brief Open joystick handle
1416
1417 \param fname name of joystick
1418
1419 \return axises
1420
1421
1422 */
joy_open2(int joyindex)1423 static int joy_open2(int joyindex)
1424 {
1425 SDL_Joystick *newdev = NULL;
1426 int num_joy = 0;
1427
1428 if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
1429 {
1430 CONS_Printf(M_GetText("Joystick subsystem not started\n"));
1431 return -1;
1432 }
1433
1434 if (joyindex <= 0)
1435 return -1;
1436
1437 num_joy = SDL_NumJoysticks();
1438
1439 if (num_joy == 0)
1440 {
1441 CONS_Printf("%s", M_GetText("Found no joysticks on this system\n"));
1442 return -1;
1443 }
1444
1445 newdev = SDL_JoystickOpen(joyindex-1);
1446
1447 // Handle the edge case where the device <-> joystick index assignment can change due to hotplugging
1448 // This indexing is SDL's responsibility and there's not much we can do about it.
1449 //
1450 // Example:
1451 // 1. Plug Controller A -> Index 0 opened
1452 // 2. Plug Controller B -> Index 1 opened
1453 // 3. Unplug Controller A -> Index 0 closed, Index 1 active
1454 // 4. Unplug Controller B -> Index 0 inactive, Index 1 closed
1455 // 5. Plug Controller B -> Index 0 opened
1456 // 6. Plug Controller A -> Index 0 REPLACED, opened as Controller A; Index 1 is now Controller B
1457 if (JoyInfo2.dev)
1458 {
1459 if (JoyInfo2.dev == newdev // same device, nothing to do
1460 || (newdev == NULL && SDL_JoystickGetAttached(JoyInfo2.dev))) // we failed, but already have a working device
1461 return JoyInfo.axises;
1462 // Else, we're changing devices, so send neutral joy events
1463 CONS_Debug(DBG_GAMELOGIC, "Joystick2 device is changing; resetting events...\n");
1464 I_ShutdownJoystick2();
1465 }
1466
1467 JoyInfo2.dev = newdev;
1468
1469 if (JoyInfo2.dev == NULL)
1470 {
1471 CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: couldn't open device - %s\n"), SDL_GetError());
1472 return -1;
1473 }
1474 else
1475 {
1476 CONS_Debug(DBG_GAMELOGIC, M_GetText("Joystick2: %s\n"), SDL_JoystickName(JoyInfo2.dev));
1477 JoyInfo2.axises = SDL_JoystickNumAxes(JoyInfo2.dev);
1478 if (JoyInfo2.axises > JOYAXISSET*2)
1479 JoyInfo2.axises = JOYAXISSET*2;
1480 /* if (joyaxes<2)
1481 {
1482 I_OutputMsg("Not enought axes?\n");
1483 return 0;
1484 }*/
1485
1486 JoyInfo2.buttons = SDL_JoystickNumButtons(JoyInfo2.dev);
1487 if (JoyInfo2.buttons > JOYBUTTONS)
1488 JoyInfo2.buttons = JOYBUTTONS;
1489
1490 JoyInfo2.hats = SDL_JoystickNumHats(JoyInfo2.dev);
1491 if (JoyInfo2.hats > JOYHATS)
1492 JoyInfo2.hats = JOYHATS;
1493
1494 JoyInfo2.balls = SDL_JoystickNumBalls(JoyInfo2.dev);
1495
1496 //Joystick.bGamepadStyle = !stricmp(SDL_JoystickName(JoyInfo2.dev), "pad");
1497
1498 return JoyInfo2.axises;
1499 }
1500 }
1501
1502 //
1503 // I_InitJoystick
1504 //
I_InitJoystick(void)1505 void I_InitJoystick(void)
1506 {
1507 SDL_Joystick *newjoy = NULL;
1508
1509 //I_ShutdownJoystick();
1510 if (M_CheckParm("-nojoy"))
1511 return;
1512
1513 if (M_CheckParm("-noxinput"))
1514 SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
1515
1516 if (M_CheckParm("-nohidapi"))
1517 SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE);
1518
1519 if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
1520 {
1521 CONS_Printf("I_InitJoystick()...\n");
1522
1523 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
1524 {
1525 CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError());
1526 return;
1527 }
1528 }
1529
1530 if (cv_usejoystick.value)
1531 newjoy = SDL_JoystickOpen(cv_usejoystick.value-1);
1532
1533 if (newjoy && JoyInfo2.dev == newjoy) // don't override an active device
1534 cv_usejoystick.value = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1;
1535 else if (newjoy && joy_open(cv_usejoystick.value) != -1)
1536 {
1537 // SDL's device indexes are unstable, so cv_usejoystick may not match
1538 // the actual device index. So let's cheat a bit and find the device's current index.
1539 JoyInfo.oldjoy = I_GetJoystickDeviceIndex(JoyInfo.dev) + 1;
1540 joystick_started = 1;
1541 }
1542 else
1543 {
1544 if (JoyInfo.oldjoy)
1545 I_ShutdownJoystick();
1546 cv_usejoystick.value = 0;
1547 joystick_started = 0;
1548 }
1549
1550 if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy)
1551 SDL_JoystickClose(newjoy);
1552 }
1553
I_InitJoystick2(void)1554 void I_InitJoystick2(void)
1555 {
1556 SDL_Joystick *newjoy = NULL;
1557
1558 //I_ShutdownJoystick2();
1559 if (M_CheckParm("-nojoy"))
1560 return;
1561
1562 if (M_CheckParm("-noxinput"))
1563 SDL_SetHintWithPriority("SDL_XINPUT_ENABLED", "0", SDL_HINT_OVERRIDE);
1564
1565 if (M_CheckParm("-nohidapi"))
1566 SDL_SetHintWithPriority("SDL_JOYSTICK_HIDAPI", "0", SDL_HINT_OVERRIDE);
1567
1568 if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
1569 {
1570 CONS_Printf("I_InitJoystick2()...\n");
1571
1572 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1)
1573 {
1574 CONS_Printf(M_GetText("Couldn't initialize joystick: %s\n"), SDL_GetError());
1575 return;
1576 }
1577 }
1578
1579 if (cv_usejoystick2.value)
1580 newjoy = SDL_JoystickOpen(cv_usejoystick2.value-1);
1581
1582 if (newjoy && JoyInfo.dev == newjoy) // don't override an active device
1583 cv_usejoystick2.value = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1;
1584 else if (newjoy && joy_open2(cv_usejoystick2.value) != -1)
1585 {
1586 // SDL's device indexes are unstable, so cv_usejoystick may not match
1587 // the actual device index. So let's cheat a bit and find the device's current index.
1588 JoyInfo2.oldjoy = I_GetJoystickDeviceIndex(JoyInfo2.dev) + 1;
1589 joystick2_started = 1;
1590 }
1591 else
1592 {
1593 if (JoyInfo2.oldjoy)
1594 I_ShutdownJoystick2();
1595 cv_usejoystick2.value = 0;
1596 joystick2_started = 0;
1597 }
1598
1599 if (JoyInfo.dev != newjoy && JoyInfo2.dev != newjoy)
1600 SDL_JoystickClose(newjoy);
1601 }
1602
I_ShutdownInput(void)1603 static void I_ShutdownInput(void)
1604 {
1605 // Yes, the name is misleading: these send neutral events to
1606 // clean up the unplugged joystick's input
1607 // Note these methods are internal to this file, not called elsewhere.
1608 I_ShutdownJoystick();
1609 I_ShutdownJoystick2();
1610
1611 if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
1612 {
1613 CONS_Printf("Shutting down joy system\n");
1614 SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
1615 I_OutputMsg("I_Joystick: SDL's Joystick system has been shutdown\n");
1616 }
1617 }
1618
I_NumJoys(void)1619 INT32 I_NumJoys(void)
1620 {
1621 INT32 numjoy = 0;
1622 if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
1623 numjoy = SDL_NumJoysticks();
1624 return numjoy;
1625 }
1626
1627 static char joyname[255]; // joystick name is straight from the driver
1628
I_GetJoyName(INT32 joyindex)1629 const char *I_GetJoyName(INT32 joyindex)
1630 {
1631 const char *tempname = NULL;
1632 joyname[0] = 0;
1633 joyindex--; //SDL's Joystick System starts at 0, not 1
1634 if (SDL_WasInit(SDL_INIT_JOYSTICK) == SDL_INIT_JOYSTICK)
1635 {
1636 tempname = SDL_JoystickNameForIndex(joyindex);
1637 if (tempname)
1638 strncpy(joyname, tempname, 255);
1639 }
1640 return joyname;
1641 }
1642
1643 #ifndef NOMUMBLE
1644 #ifdef HAVE_MUMBLE
1645 // Best Mumble positional audio settings:
1646 // Minimum distance 3.0 m
1647 // Bloom 175%
1648 // Maximum distance 80.0 m
1649 // Minimum volume 50%
1650 #define DEG2RAD (0.017453292519943295769236907684883l) // TAU/360 or PI/180
1651 #define MUMBLEUNIT (64.0f) // FRACUNITS in a Meter
1652
1653 static struct {
1654 #ifdef WINMUMBLE
1655 UINT32 uiVersion;
1656 DWORD uiTick;
1657 #else
1658 Uint32 uiVersion;
1659 Uint32 uiTick;
1660 #endif
1661 float fAvatarPosition[3];
1662 float fAvatarFront[3];
1663 float fAvatarTop[3]; // defaults to Y-is-up (only used for leaning)
1664 wchar_t name[256]; // game name
1665 float fCameraPosition[3];
1666 float fCameraFront[3];
1667 float fCameraTop[3]; // defaults to Y-is-up (only used for leaning)
1668 wchar_t identity[256]; // player id
1669 #ifdef WINMUMBLE
1670 UINT32 context_len;
1671 #else
1672 Uint32 context_len;
1673 #endif
1674 unsigned char context[256]; // server/team
1675 wchar_t description[2048]; // game description
1676 } *mumble = NULL;
1677 #endif // HAVE_MUMBLE
1678
I_SetupMumble(void)1679 static void I_SetupMumble(void)
1680 {
1681 #ifdef WINMUMBLE
1682 HANDLE hMap = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, L"MumbleLink");
1683 if (!hMap)
1684 return;
1685
1686 mumble = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(*mumble));
1687 if (!mumble)
1688 CloseHandle(hMap);
1689 #elif defined (HAVE_SHM)
1690 int shmfd;
1691 char memname[256];
1692
1693 snprintf(memname, 256, "/MumbleLink.%d", getuid());
1694 shmfd = shm_open(memname, O_RDWR, S_IRUSR | S_IWUSR);
1695
1696 if(shmfd < 0)
1697 return;
1698
1699 mumble = mmap(NULL, sizeof(*mumble), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
1700 if (mumble == MAP_FAILED)
1701 mumble = NULL;
1702 #endif
1703 }
1704
I_UpdateMumble(const mobj_t * mobj,const listener_t listener)1705 void I_UpdateMumble(const mobj_t *mobj, const listener_t listener)
1706 {
1707 #ifdef HAVE_MUMBLE
1708 double angle;
1709 fixed_t anglef;
1710
1711 if (!mumble)
1712 return;
1713
1714 if(mumble->uiVersion != 2) {
1715 wcsncpy(mumble->name, L"SRB2 "VERSIONSTRINGW, 256);
1716 wcsncpy(mumble->description, L"Sonic Robo Blast 2 with integrated Mumble Link support.", 2048);
1717 mumble->uiVersion = 2;
1718 }
1719 mumble->uiTick++;
1720
1721 if (!netgame || gamestate != GS_LEVEL) { // Zero out, but never delink.
1722 mumble->fAvatarPosition[0] = mumble->fAvatarPosition[1] = mumble->fAvatarPosition[2] = 0.0f;
1723 mumble->fAvatarFront[0] = 1.0f;
1724 mumble->fAvatarFront[1] = mumble->fAvatarFront[2] = 0.0f;
1725 mumble->fCameraPosition[0] = mumble->fCameraPosition[1] = mumble->fCameraPosition[2] = 0.0f;
1726 mumble->fCameraFront[0] = 1.0f;
1727 mumble->fCameraFront[1] = mumble->fCameraFront[2] = 0.0f;
1728 return;
1729 }
1730
1731 {
1732 UINT8 *p = mumble->context;
1733 WRITEMEM(p, server_context, 8);
1734 WRITEINT16(p, gamemap);
1735 mumble->context_len = (UINT32)(p - mumble->context);
1736 }
1737
1738 if (mobj) {
1739 mumble->fAvatarPosition[0] = FIXED_TO_FLOAT(mobj->x) / MUMBLEUNIT;
1740 mumble->fAvatarPosition[1] = FIXED_TO_FLOAT(mobj->z) / MUMBLEUNIT;
1741 mumble->fAvatarPosition[2] = FIXED_TO_FLOAT(mobj->y) / MUMBLEUNIT;
1742
1743 anglef = AngleFixed(mobj->angle);
1744 angle = FIXED_TO_FLOAT(anglef)*DEG2RAD;
1745 mumble->fAvatarFront[0] = (float)cos(angle);
1746 mumble->fAvatarFront[1] = 0.0f;
1747 mumble->fAvatarFront[2] = (float)sin(angle);
1748 } else {
1749 mumble->fAvatarPosition[0] = mumble->fAvatarPosition[1] = mumble->fAvatarPosition[2] = 0.0f;
1750 mumble->fAvatarFront[0] = 1.0f;
1751 mumble->fAvatarFront[1] = mumble->fAvatarFront[2] = 0.0f;
1752 }
1753
1754 mumble->fCameraPosition[0] = FIXED_TO_FLOAT(listener.x) / MUMBLEUNIT;
1755 mumble->fCameraPosition[1] = FIXED_TO_FLOAT(listener.z) / MUMBLEUNIT;
1756 mumble->fCameraPosition[2] = FIXED_TO_FLOAT(listener.y) / MUMBLEUNIT;
1757
1758 anglef = AngleFixed(listener.angle);
1759 angle = FIXED_TO_FLOAT(anglef)*DEG2RAD;
1760 mumble->fCameraFront[0] = (float)cos(angle);
1761 mumble->fCameraFront[1] = 0.0f;
1762 mumble->fCameraFront[2] = (float)sin(angle);
1763 #else
1764 (void)mobj;
1765 (void)listener;
1766 #endif // HAVE_MUMBLE
1767 }
1768 #undef WINMUMBLE
1769 #endif // NOMUMBLE
1770
1771 #ifdef HAVE_TERMIOS
1772
I_GetMouseEvents(void)1773 void I_GetMouseEvents(void)
1774 {
1775 static UINT8 mdata[5];
1776 static INT32 i = 0,om2b = 0;
1777 INT32 di, j, mlp, button;
1778 event_t event;
1779 const INT32 mswap[8] = {0, 4, 1, 5, 2, 6, 3, 7};
1780
1781 if (!mouse2_started) return;
1782 for (mlp = 0; mlp < 20; mlp++)
1783 {
1784 for (; i < 5; i++)
1785 {
1786 di = read(fdmouse2, mdata+i, 1);
1787 if (di == -1) return;
1788 }
1789 if ((mdata[0] & 0xf8) != 0x80)
1790 {
1791 for (j = 1; j < 5; j++)
1792 if ((mdata[j] & 0xf8) == 0x80)
1793 for (i = 0; i < 5-j; i++) // shift
1794 mdata[i] = mdata[i+j];
1795 if (i < 5) continue;
1796 }
1797 else
1798 {
1799 button = mswap[~mdata[0] & 0x07];
1800 for (j = 0; j < MOUSEBUTTONS; j++)
1801 {
1802 if (om2b & (1<<j))
1803 {
1804 if (!(button & (1<<j))) //keyup
1805 {
1806 event.type = ev_keyup;
1807 event.data1 = KEY_2MOUSE1+j;
1808 D_PostEvent(&event);
1809 om2b ^= 1 << j;
1810 }
1811 }
1812 else
1813 {
1814 if (button & (1<<j))
1815 {
1816 event.type = ev_keydown;
1817 event.data1 = KEY_2MOUSE1+j;
1818 D_PostEvent(&event);
1819 om2b ^= 1 << j;
1820 }
1821 }
1822 }
1823 event.data2 = ((SINT8)mdata[1])+((SINT8)mdata[3]);
1824 event.data3 = ((SINT8)mdata[2])+((SINT8)mdata[4]);
1825 if (event.data2 && event.data3)
1826 {
1827 event.type = ev_mouse2;
1828 event.data1 = 0;
1829 D_PostEvent(&event);
1830 }
1831 }
1832 i = 0;
1833 }
1834 }
1835
1836 //
1837 // I_ShutdownMouse2
1838 //
I_ShutdownMouse2(void)1839 static void I_ShutdownMouse2(void)
1840 {
1841 if (fdmouse2 != -1) close(fdmouse2);
1842 mouse2_started = 0;
1843 }
1844 #elif defined (_WIN32)
1845
1846 static HANDLE mouse2filehandle = INVALID_HANDLE_VALUE;
1847
I_ShutdownMouse2(void)1848 static void I_ShutdownMouse2(void)
1849 {
1850 event_t event;
1851 INT32 i;
1852
1853 if (mouse2filehandle == INVALID_HANDLE_VALUE)
1854 return;
1855
1856 SetCommMask(mouse2filehandle, 0);
1857
1858 EscapeCommFunction(mouse2filehandle, CLRDTR);
1859 EscapeCommFunction(mouse2filehandle, CLRRTS);
1860
1861 PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT |
1862 PURGE_TXCLEAR | PURGE_RXCLEAR);
1863
1864 CloseHandle(mouse2filehandle);
1865
1866 // emulate the up of all mouse buttons
1867 for (i = 0; i < MOUSEBUTTONS; i++)
1868 {
1869 event.type = ev_keyup;
1870 event.data1 = KEY_2MOUSE1+i;
1871 D_PostEvent(&event);
1872 }
1873
1874 mouse2filehandle = INVALID_HANDLE_VALUE;
1875 }
1876
1877 #define MOUSECOMBUFFERSIZE 256
1878 static INT32 handlermouse2x,handlermouse2y,handlermouse2buttons;
1879
I_PoolMouse2(void)1880 static void I_PoolMouse2(void)
1881 {
1882 UINT8 buffer[MOUSECOMBUFFERSIZE];
1883 COMSTAT ComStat;
1884 DWORD dwErrorFlags;
1885 DWORD dwLength;
1886 char dx,dy;
1887
1888 static INT32 bytenum;
1889 static UINT8 combytes[4];
1890 DWORD i;
1891
1892 ClearCommError(mouse2filehandle, &dwErrorFlags, &ComStat);
1893 dwLength = min(MOUSECOMBUFFERSIZE, ComStat.cbInQue);
1894
1895 if (dwLength <= 0)
1896 return;
1897
1898 if (!ReadFile(mouse2filehandle, buffer, dwLength, &dwLength, NULL))
1899 {
1900 CONS_Alert(CONS_WARNING, "%s", M_GetText("Read Error on secondary mouse port\n"));
1901 return;
1902 }
1903
1904 // parse the mouse packets
1905 for (i = 0; i < dwLength; i++)
1906 {
1907 if ((buffer[i] & 64)== 64)
1908 bytenum = 0;
1909
1910 if (bytenum < 4)
1911 combytes[bytenum] = buffer[i];
1912 bytenum++;
1913
1914 if (bytenum == 1)
1915 {
1916 handlermouse2buttons &= ~3;
1917 handlermouse2buttons |= ((combytes[0] & (32+16)) >> 4);
1918 }
1919 else if (bytenum == 3)
1920 {
1921 dx = (char)((combytes[0] & 3) << 6);
1922 dy = (char)((combytes[0] & 12) << 4);
1923 dx = (char)(dx + combytes[1]);
1924 dy = (char)(dy + combytes[2]);
1925 handlermouse2x+= dx;
1926 handlermouse2y+= dy;
1927 }
1928 else if (bytenum == 4) // fourth UINT8 (logitech mouses)
1929 {
1930 if (buffer[i] & 32)
1931 handlermouse2buttons |= 4;
1932 else
1933 handlermouse2buttons &= ~4;
1934 }
1935 }
1936 }
1937
I_GetMouseEvents(void)1938 void I_GetMouseEvents(void)
1939 {
1940 static UINT8 lastbuttons2 = 0; //mouse movement
1941 event_t event;
1942
1943 if (mouse2filehandle == INVALID_HANDLE_VALUE)
1944 return;
1945
1946 I_PoolMouse2();
1947 // post key event for buttons
1948 if (handlermouse2buttons != lastbuttons2)
1949 {
1950 INT32 i, j = 1, k;
1951 k = (handlermouse2buttons ^ lastbuttons2); // only changed bit to 1
1952 lastbuttons2 = (UINT8)handlermouse2buttons;
1953
1954 for (i = 0; i < MOUSEBUTTONS; i++, j <<= 1)
1955 if (k & j)
1956 {
1957 if (handlermouse2buttons & j)
1958 event.type = ev_keydown;
1959 else
1960 event.type = ev_keyup;
1961 event.data1 = KEY_2MOUSE1+i;
1962 D_PostEvent(&event);
1963 }
1964 }
1965
1966 if (handlermouse2x != 0 || handlermouse2y != 0)
1967 {
1968 event.type = ev_mouse2;
1969 event.data1 = 0;
1970 // event.data1 = buttons; // not needed
1971 event.data2 = handlermouse2x << 1;
1972 event.data3 = -handlermouse2y << 1;
1973 handlermouse2x = 0;
1974 handlermouse2y = 0;
1975
1976 D_PostEvent(&event);
1977 }
1978 }
1979 #else
I_GetMouseEvents(void)1980 void I_GetMouseEvents(void){};
1981 #endif
1982
1983 //
1984 // I_StartupMouse2
1985 //
I_StartupMouse2(void)1986 void I_StartupMouse2(void)
1987 {
1988 #ifdef HAVE_TERMIOS
1989 struct termios m2tio;
1990 size_t i;
1991 INT32 dtr = -1, rts = -1;;
1992 I_ShutdownMouse2();
1993 if (cv_usemouse2.value == 0) return;
1994 if ((fdmouse2 = open(cv_mouse2port.string, O_RDONLY|O_NONBLOCK|O_NOCTTY)) == -1)
1995 {
1996 CONS_Printf(M_GetText("Error opening %s!\n"), cv_mouse2port.string);
1997 return;
1998 }
1999 tcflush(fdmouse2, TCIOFLUSH);
2000 m2tio.c_iflag = IGNBRK;
2001 m2tio.c_oflag = 0;
2002 m2tio.c_cflag = CREAD|CLOCAL|HUPCL|CS8|CSTOPB|B1200;
2003 m2tio.c_lflag = 0;
2004 m2tio.c_cc[VTIME] = 0;
2005 m2tio.c_cc[VMIN] = 1;
2006 tcsetattr(fdmouse2, TCSANOW, &m2tio);
2007 for (i = 0; i < strlen(cv_mouse2opt.string); i++)
2008 {
2009 if (toupper(cv_mouse2opt.string[i]) == 'D')
2010 {
2011 if (cv_mouse2opt.string[i+1] == '-')
2012 dtr = 0;
2013 else
2014 dtr = 1;
2015 }
2016 if (toupper(cv_mouse2opt.string[i]) == 'R')
2017 {
2018 if (cv_mouse2opt.string[i+1] == '-')
2019 rts = 0;
2020 else
2021 rts = 1;
2022 }
2023 if (dtr != -1 || rts != -1)
2024 {
2025 INT32 c;
2026 if (!ioctl(fdmouse2, TIOCMGET, &c))
2027 {
2028 if (!dtr)
2029 c &= ~TIOCM_DTR;
2030 else if (dtr > 0)
2031 c |= TIOCM_DTR;
2032 }
2033 if (!rts)
2034 c &= ~TIOCM_RTS;
2035 else if (rts > 0)
2036 c |= TIOCM_RTS;
2037 ioctl(fdmouse2, TIOCMSET, &c);
2038 }
2039 }
2040 mouse2_started = 1;
2041 I_AddExitFunc(I_ShutdownMouse2);
2042 #elif defined (_WIN32)
2043 DCB dcb;
2044
2045 if (mouse2filehandle != INVALID_HANDLE_VALUE)
2046 I_ShutdownMouse2();
2047
2048 if (cv_usemouse2.value == 0)
2049 return;
2050
2051 if (mouse2filehandle == INVALID_HANDLE_VALUE)
2052 {
2053 // COM file handle
2054 mouse2filehandle = CreateFileA(cv_mouse2port.string, GENERIC_READ | GENERIC_WRITE,
2055 0, // exclusive access
2056 NULL, // no security attrs
2057 OPEN_EXISTING,
2058 FILE_ATTRIBUTE_NORMAL,
2059 NULL);
2060 if (mouse2filehandle == INVALID_HANDLE_VALUE)
2061 {
2062 INT32 e = GetLastError();
2063 if (e == 5)
2064 CONS_Alert(CONS_ERROR, M_GetText("Can't open %s: Access denied\n"), cv_mouse2port.string);
2065 else
2066 CONS_Alert(CONS_ERROR, M_GetText("Can't open %s: error %d\n"), cv_mouse2port.string, e);
2067 return;
2068 }
2069 }
2070
2071 // getevent when somthing happens
2072 //SetCommMask(mouse2filehandle, EV_RXCHAR);
2073
2074 // buffers
2075 SetupComm(mouse2filehandle, MOUSECOMBUFFERSIZE, MOUSECOMBUFFERSIZE);
2076
2077 // purge buffers
2078 PurgeComm(mouse2filehandle, PURGE_TXABORT | PURGE_RXABORT
2079 | PURGE_TXCLEAR | PURGE_RXCLEAR);
2080
2081 // setup port to 1200 7N1
2082 dcb.DCBlength = sizeof (DCB);
2083
2084 GetCommState(mouse2filehandle, &dcb);
2085
2086 dcb.BaudRate = CBR_1200;
2087 dcb.ByteSize = 7;
2088 dcb.Parity = NOPARITY;
2089 dcb.StopBits = ONESTOPBIT;
2090
2091 dcb.fDtrControl = DTR_CONTROL_ENABLE;
2092 dcb.fRtsControl = RTS_CONTROL_ENABLE;
2093
2094 dcb.fBinary = TRUE;
2095 dcb.fParity = TRUE;
2096
2097 SetCommState(mouse2filehandle, &dcb);
2098 I_AddExitFunc(I_ShutdownMouse2);
2099 #endif
2100 }
2101
2102 //
2103 // I_Tactile
2104 //
I_Tactile(FFType pFFType,const JoyFF_t * FFEffect)2105 void I_Tactile(FFType pFFType, const JoyFF_t *FFEffect)
2106 {
2107 // UNUSED.
2108 (void)pFFType;
2109 (void)FFEffect;
2110 }
2111
I_Tactile2(FFType pFFType,const JoyFF_t * FFEffect)2112 void I_Tactile2(FFType pFFType, const JoyFF_t *FFEffect)
2113 {
2114 // UNUSED.
2115 (void)pFFType;
2116 (void)FFEffect;
2117 }
2118
2119 /** \brief empty ticcmd for player 1
2120 */
2121 static ticcmd_t emptycmd;
2122
I_BaseTiccmd(void)2123 ticcmd_t *I_BaseTiccmd(void)
2124 {
2125 return &emptycmd;
2126 }
2127
2128 /** \brief empty ticcmd for player 2
2129 */
2130 static ticcmd_t emptycmd2;
2131
I_BaseTiccmd2(void)2132 ticcmd_t *I_BaseTiccmd2(void)
2133 {
2134 return &emptycmd2;
2135 }
2136
2137 //
2138 // I_GetTime
2139 // returns time in 1/TICRATE second tics
2140 //
2141
2142 static Uint64 timer_frequency;
2143
2144 static double tic_frequency;
2145 static Uint64 tic_epoch;
2146
I_GetTime(void)2147 tic_t I_GetTime(void)
2148 {
2149 static double elapsed;
2150
2151 const Uint64 now = SDL_GetPerformanceCounter();
2152
2153 elapsed += (now - tic_epoch) / tic_frequency;
2154 tic_epoch = now; // moving epoch
2155
2156 return (tic_t)elapsed;
2157 }
2158
I_GetPreciseTime(void)2159 precise_t I_GetPreciseTime(void)
2160 {
2161 return SDL_GetPerformanceCounter();
2162 }
2163
I_PreciseToMicros(precise_t d)2164 int I_PreciseToMicros(precise_t d)
2165 {
2166 return (int)(d / (timer_frequency / 1000000.0));
2167 }
2168
2169 //
2170 //I_StartupTimer
2171 //
I_StartupTimer(void)2172 void I_StartupTimer(void)
2173 {
2174 timer_frequency = SDL_GetPerformanceFrequency();
2175 tic_epoch = SDL_GetPerformanceCounter();
2176
2177 tic_frequency = timer_frequency / (double)NEWTICRATE;
2178 }
2179
I_Sleep(void)2180 void I_Sleep(void)
2181 {
2182 if (cv_sleep.value != -1)
2183 SDL_Delay(cv_sleep.value);
2184 }
2185
2186 #ifdef NEWSIGNALHANDLER
newsignalhandler_Warn(const char * pr)2187 static void newsignalhandler_Warn(const char *pr)
2188 {
2189 char text[128];
2190
2191 snprintf(text, sizeof text,
2192 "Error while setting up signal reporting: %s: %s",
2193 pr,
2194 strerror(errno)
2195 );
2196
2197 I_OutputMsg("%s\n", text);
2198
2199 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
2200 "Startup error",
2201 text, NULL);
2202
2203 I_ShutdownConsole();
2204 exit(-1);
2205 }
2206
I_Fork(void)2207 static void I_Fork(void)
2208 {
2209 int child;
2210 int status;
2211 int signum;
2212 int c;
2213
2214 child = fork();
2215
2216 switch (child)
2217 {
2218 case -1:
2219 newsignalhandler_Warn("fork()");
2220 break;
2221 case 0:
2222 I_RegisterChildSignals();
2223 break;
2224 default:
2225 if (logstream)
2226 fclose(logstream);/* the child has this */
2227
2228 c = wait(&status);
2229
2230 #ifdef LOGMESSAGES
2231 /* By the way, exit closes files. */
2232 logstream = fopen(logfilename, "at");
2233 #else
2234 logstream = 0;
2235 #endif
2236
2237 if (c == -1)
2238 {
2239 kill(child, SIGKILL);
2240 newsignalhandler_Warn("wait()");
2241 }
2242 else
2243 {
2244 if (WIFSIGNALED (status))
2245 {
2246 signum = WTERMSIG (status);
2247 #ifdef WCOREDUMP
2248 I_ReportSignal(signum, WCOREDUMP (status));
2249 #else
2250 I_ReportSignal(signum, 0);
2251 #endif
2252 status = 128 + signum;
2253 }
2254 else if (WIFEXITED (status))
2255 {
2256 status = WEXITSTATUS (status);
2257 }
2258
2259 I_ShutdownConsole();
2260 exit(status);
2261 }
2262 }
2263 }
2264 #endif/*NEWSIGNALHANDLER*/
2265
I_StartupSystem(void)2266 INT32 I_StartupSystem(void)
2267 {
2268 SDL_version SDLcompiled;
2269 SDL_version SDLlinked;
2270 SDL_VERSION(&SDLcompiled)
2271 SDL_GetVersion(&SDLlinked);
2272 #ifdef HAVE_THREADS
2273 I_start_threads();
2274 I_AddExitFunc(I_stop_threads);
2275 #endif
2276 I_StartupConsole();
2277 #ifdef NEWSIGNALHANDLER
2278 I_Fork();
2279 #endif
2280 I_RegisterSignals();
2281 I_OutputMsg("Compiled for SDL version: %d.%d.%d\n",
2282 SDLcompiled.major, SDLcompiled.minor, SDLcompiled.patch);
2283 I_OutputMsg("Linked with SDL version: %d.%d.%d\n",
2284 SDLlinked.major, SDLlinked.minor, SDLlinked.patch);
2285 if (SDL_Init(0) < 0)
2286 I_Error("SRB2: SDL System Error: %s", SDL_GetError()); //Alam: Oh no....
2287 #ifndef NOMUMBLE
2288 I_SetupMumble();
2289 #endif
2290 return 0;
2291 }
2292
2293 //
2294 // I_Quit
2295 //
I_Quit(void)2296 void I_Quit(void)
2297 {
2298 static SDL_bool quiting = SDL_FALSE;
2299
2300 /* prevent recursive I_Quit() */
2301 if (quiting) goto death;
2302 SDLforceUngrabMouse();
2303 quiting = SDL_FALSE;
2304 M_SaveConfig(NULL); //save game config, cvars..
2305 #ifndef NONET
2306 D_SaveBan(); // save the ban list
2307 #endif
2308 G_SaveGameData(); // Tails 12-08-2002
2309 //added:16-02-98: when recording a demo, should exit using 'q' key,
2310 // but sometimes we forget and use 'F10'.. so save here too.
2311
2312 if (demorecording)
2313 G_CheckDemoStatus();
2314 if (metalrecording)
2315 G_StopMetalRecording(false);
2316
2317 D_QuitNetGame();
2318 CL_AbortDownloadResume();
2319 M_FreePlayerSetupColors();
2320 I_ShutdownMusic();
2321 I_ShutdownSound();
2322 // use this for 1.28 19990220 by Kin
2323 I_ShutdownGraphics();
2324 I_ShutdownInput();
2325 I_ShutdownSystem();
2326 SDL_Quit();
2327 /* if option -noendtxt is set, don't print the text */
2328 if (!M_CheckParm("-noendtxt") && W_CheckNumForName("ENDOOM") != LUMPERROR)
2329 {
2330 printf("\r");
2331 ShowEndTxt();
2332 }
2333 if (myargmalloc)
2334 free(myargv); // Deallocate allocated memory
2335 death:
2336 W_Shutdown();
2337 exit(0);
2338 }
2339
I_WaitVBL(INT32 count)2340 void I_WaitVBL(INT32 count)
2341 {
2342 count = 1;
2343 SDL_Delay(count);
2344 }
2345
I_BeginRead(void)2346 void I_BeginRead(void)
2347 {
2348 }
2349
I_EndRead(void)2350 void I_EndRead(void)
2351 {
2352 }
2353
2354 //
2355 // I_Error
2356 //
2357 /** \brief phuck recursive errors
2358 */
2359 static INT32 errorcount = 0;
2360
2361 /** \brief recursive error detecting
2362 */
2363 static boolean shutdowning = false;
2364
I_Error(const char * error,...)2365 void I_Error(const char *error, ...)
2366 {
2367 va_list argptr;
2368 char buffer[8192];
2369
2370 // recursive error detecting
2371 if (shutdowning)
2372 {
2373 errorcount++;
2374 if (errorcount == 1)
2375 SDLforceUngrabMouse();
2376 // try to shutdown each subsystem separately
2377 if (errorcount == 2)
2378 I_ShutdownMusic();
2379 if (errorcount == 3)
2380 I_ShutdownSound();
2381 if (errorcount == 4)
2382 I_ShutdownGraphics();
2383 if (errorcount == 5)
2384 I_ShutdownInput();
2385 if (errorcount == 6)
2386 I_ShutdownSystem();
2387 if (errorcount == 7)
2388 SDL_Quit();
2389 if (errorcount == 8)
2390 {
2391 M_SaveConfig(NULL);
2392 G_SaveGameData();
2393 }
2394 if (errorcount > 20)
2395 {
2396 va_start(argptr, error);
2397 vsprintf(buffer, error, argptr);
2398 va_end(argptr);
2399 // Implement message box with SDL_ShowSimpleMessageBox,
2400 // which should fail gracefully if it can't put a message box up
2401 // on the target system
2402 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
2403 "SRB2 "VERSIONSTRING" Recursive Error",
2404 buffer, NULL);
2405
2406 W_Shutdown();
2407 exit(-1); // recursive errors detected
2408 }
2409 }
2410
2411 shutdowning = true;
2412
2413 // Display error message in the console before we start shutting it down
2414 va_start(argptr, error);
2415 vsprintf(buffer, error, argptr);
2416 va_end(argptr);
2417 I_OutputMsg("\nI_Error(): %s\n", buffer);
2418 // ---
2419
2420 M_SaveConfig(NULL); // save game config, cvars..
2421 #ifndef NONET
2422 D_SaveBan(); // save the ban list
2423 #endif
2424 G_SaveGameData(); // Tails 12-08-2002
2425
2426 // Shutdown. Here might be other errors.
2427 if (demorecording)
2428 G_CheckDemoStatus();
2429 if (metalrecording)
2430 G_StopMetalRecording(false);
2431
2432 D_QuitNetGame();
2433 CL_AbortDownloadResume();
2434 M_FreePlayerSetupColors();
2435 I_ShutdownMusic();
2436 I_ShutdownSound();
2437 // use this for 1.28 19990220 by Kin
2438 I_ShutdownGraphics();
2439 I_ShutdownInput();
2440 I_ShutdownSystem();
2441 SDL_Quit();
2442
2443 // Implement message box with SDL_ShowSimpleMessageBox,
2444 // which should fail gracefully if it can't put a message box up
2445 // on the target system
2446 SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
2447 "SRB2 "VERSIONSTRING" Error",
2448 buffer, NULL);
2449 // Note that SDL_ShowSimpleMessageBox does *not* require SDL to be
2450 // initialized at the time, so calling it after SDL_Quit() is
2451 // perfectly okay! In addition, we do this on purpose so the
2452 // fullscreen window is closed before displaying the error message
2453 // in case the fullscreen window blocks it for some absurd reason.
2454
2455 W_Shutdown();
2456
2457 #if defined (PARANOIA) && defined (__CYGWIN__)
2458 *(INT32 *)2 = 4; //Alam: Debug!
2459 #endif
2460
2461 exit(-1);
2462 }
2463
2464 /** \brief quit function table
2465 */
2466 static quitfuncptr quit_funcs[MAX_QUIT_FUNCS]; /* initialized to all bits 0 */
2467
2468 //
2469 // Adds a function to the list that need to be called by I_SystemShutdown().
2470 //
I_AddExitFunc(void (* func)())2471 void I_AddExitFunc(void (*func)())
2472 {
2473 INT32 c;
2474
2475 for (c = 0; c < MAX_QUIT_FUNCS; c++)
2476 {
2477 if (!quit_funcs[c])
2478 {
2479 quit_funcs[c] = func;
2480 break;
2481 }
2482 }
2483 }
2484
2485
2486 //
2487 // Removes a function from the list that need to be called by
2488 // I_SystemShutdown().
2489 //
I_RemoveExitFunc(void (* func)())2490 void I_RemoveExitFunc(void (*func)())
2491 {
2492 INT32 c;
2493
2494 for (c = 0; c < MAX_QUIT_FUNCS; c++)
2495 {
2496 if (quit_funcs[c] == func)
2497 {
2498 while (c < MAX_QUIT_FUNCS-1)
2499 {
2500 quit_funcs[c] = quit_funcs[c+1];
2501 c++;
2502 }
2503 quit_funcs[MAX_QUIT_FUNCS-1] = NULL;
2504 break;
2505 }
2506 }
2507 }
2508
2509 #if !(defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON))
Shittycopyerror(const char * name)2510 static void Shittycopyerror(const char *name)
2511 {
2512 I_OutputMsg(
2513 "Error copying log file: %s: %s\n",
2514 name,
2515 strerror(errno)
2516 );
2517 }
2518
Shittylogcopy(void)2519 static void Shittylogcopy(void)
2520 {
2521 char buf[8192];
2522 FILE *fp;
2523 size_t r;
2524 if (fseek(logstream, 0, SEEK_SET) == -1)
2525 {
2526 Shittycopyerror("fseek");
2527 }
2528 else if (( fp = fopen(logfilename, "wt") ))
2529 {
2530 while (( r = fread(buf, 1, sizeof buf, logstream) ))
2531 {
2532 if (fwrite(buf, 1, r, fp) < r)
2533 {
2534 Shittycopyerror("fwrite");
2535 break;
2536 }
2537 }
2538 if (ferror(logstream))
2539 {
2540 Shittycopyerror("fread");
2541 }
2542 fclose(fp);
2543 }
2544 else
2545 {
2546 Shittycopyerror(logfilename);
2547 }
2548 }
2549 #endif/*!(defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON))*/
2550
2551 //
2552 // Closes down everything. This includes restoring the initial
2553 // palette and video mode, and removing whatever mouse, keyboard, and
2554 // timer routines have been installed.
2555 //
2556 // NOTE: Shutdown user funcs are effectively called in reverse order.
2557 //
I_ShutdownSystem(void)2558 void I_ShutdownSystem(void)
2559 {
2560 INT32 c;
2561
2562 #ifndef NEWSIGNALHANDLER
2563 I_ShutdownConsole();
2564 #endif
2565
2566 for (c = MAX_QUIT_FUNCS-1; c >= 0; c--)
2567 if (quit_funcs[c])
2568 (*quit_funcs[c])();
2569 #ifdef LOGMESSAGES
2570 if (logstream)
2571 {
2572 I_OutputMsg("I_ShutdownSystem(): end of logstream.\n");
2573 #if !(defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON))
2574 Shittylogcopy();
2575 #endif
2576 fclose(logstream);
2577 logstream = NULL;
2578 }
2579 #endif
2580
2581 }
2582
I_GetDiskFreeSpace(INT64 * freespace)2583 void I_GetDiskFreeSpace(INT64 *freespace)
2584 {
2585 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
2586 #if defined (SOLARIS) || defined (__HAIKU__)
2587 *freespace = INT32_MAX;
2588 return;
2589 #else // Both Linux and BSD have this, apparently.
2590 struct statfs stfs;
2591 if (statfs(srb2home, &stfs) == -1)
2592 {
2593 *freespace = INT32_MAX;
2594 return;
2595 }
2596 *freespace = stfs.f_bavail * stfs.f_bsize;
2597 #endif
2598 #elif defined (_WIN32)
2599 static p_GetDiskFreeSpaceExA pfnGetDiskFreeSpaceEx = NULL;
2600 static boolean testwin95 = false;
2601 ULARGE_INTEGER usedbytes, lfreespace;
2602
2603 if (!testwin95)
2604 {
2605 pfnGetDiskFreeSpaceEx = (p_GetDiskFreeSpaceExA)(LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetDiskFreeSpaceExA");
2606 testwin95 = true;
2607 }
2608 if (pfnGetDiskFreeSpaceEx)
2609 {
2610 if (pfnGetDiskFreeSpaceEx(srb2home, &lfreespace, &usedbytes, NULL))
2611 *freespace = lfreespace.QuadPart;
2612 else
2613 *freespace = INT32_MAX;
2614 }
2615 else
2616 {
2617 DWORD SectorsPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters;
2618 GetDiskFreeSpace(NULL, &SectorsPerCluster, &BytesPerSector,
2619 &NumberOfFreeClusters, &TotalNumberOfClusters);
2620 *freespace = BytesPerSector*SectorsPerCluster*NumberOfFreeClusters;
2621 }
2622 #else // Dummy for platform independent; 1GB should be enough
2623 *freespace = 1024*1024*1024;
2624 #endif
2625 }
2626
I_GetUserName(void)2627 char *I_GetUserName(void)
2628 {
2629 static char username[MAXPLAYERNAME+1];
2630 char *p;
2631 #ifdef _WIN32
2632 DWORD i = MAXPLAYERNAME;
2633
2634 if (!GetUserNameA(username, &i))
2635 #endif
2636 {
2637 p = I_GetEnv("USER");
2638 if (!p)
2639 {
2640 p = I_GetEnv("user");
2641 if (!p)
2642 {
2643 p = I_GetEnv("USERNAME");
2644 if (!p)
2645 {
2646 p = I_GetEnv("username");
2647 if (!p)
2648 {
2649 return NULL;
2650 }
2651 }
2652 }
2653 }
2654 strncpy(username, p, MAXPLAYERNAME);
2655 }
2656
2657
2658 if (strcmp(username, "") != 0)
2659 return username;
2660 return NULL; // dummy for platform independent version
2661 }
2662
I_mkdir(const char * dirname,INT32 unixright)2663 INT32 I_mkdir(const char *dirname, INT32 unixright)
2664 {
2665 //[segabor]
2666 #if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON) || defined (__CYGWIN__)
2667 return mkdir(dirname, unixright);
2668 #elif defined (_WIN32)
2669 UNREFERENCED_PARAMETER(unixright); /// \todo should implement ntright under nt...
2670 return CreateDirectoryA(dirname, NULL);
2671 #else
2672 (void)dirname;
2673 (void)unixright;
2674 return false;
2675 #endif
2676 }
2677
I_GetEnv(const char * name)2678 char *I_GetEnv(const char *name)
2679 {
2680 #ifdef NEED_SDL_GETENV
2681 return SDL_getenv(name);
2682 #else
2683 return getenv(name);
2684 #endif
2685 }
2686
I_PutEnv(char * variable)2687 INT32 I_PutEnv(char *variable)
2688 {
2689 #ifdef NEED_SDL_GETENV
2690 return SDL_putenv(variable);
2691 #else
2692 return putenv(variable);
2693 #endif
2694 }
2695
I_ClipboardCopy(const char * data,size_t size)2696 INT32 I_ClipboardCopy(const char *data, size_t size)
2697 {
2698 char storage[256];
2699 if (size > 255)
2700 size = 255;
2701 memcpy(storage, data, size);
2702 storage[size] = 0;
2703
2704 if (SDL_SetClipboardText(storage))
2705 return 0;
2706 return -1;
2707 }
2708
I_ClipboardPaste(void)2709 const char *I_ClipboardPaste(void)
2710 {
2711 static char clipboard_modified[256];
2712 char *clipboard_contents, *i = clipboard_modified;
2713
2714 if (!SDL_HasClipboardText())
2715 return NULL;
2716
2717 clipboard_contents = SDL_GetClipboardText();
2718 strlcpy(clipboard_modified, clipboard_contents, 256);
2719 SDL_free(clipboard_contents);
2720
2721 while (*i)
2722 {
2723 if (*i == '\n' || *i == '\r')
2724 { // End on newline
2725 *i = 0;
2726 break;
2727 }
2728 else if (*i == '\t')
2729 *i = ' '; // Tabs become spaces
2730 else if (*i < 32 || (unsigned)*i > 127)
2731 *i = '?'; // Nonprintable chars become question marks
2732 ++i;
2733 }
2734 return (const char *)&clipboard_modified;
2735 }
2736
2737 /** \brief The isWadPathOk function
2738
2739 \param path string path to check
2740
2741 \return if true, wad file found
2742
2743
2744 */
isWadPathOk(const char * path)2745 static boolean isWadPathOk(const char *path)
2746 {
2747 char *wad3path = malloc(256);
2748
2749 if (!wad3path)
2750 return false;
2751
2752 sprintf(wad3path, pandf, path, WADKEYWORD1);
2753
2754 if (FIL_ReadFileOK(wad3path))
2755 {
2756 free(wad3path);
2757 return true;
2758 }
2759
2760 free(wad3path);
2761 return false;
2762 }
2763
pathonly(char * s)2764 static void pathonly(char *s)
2765 {
2766 size_t j;
2767
2768 for (j = strlen(s); j != (size_t)-1; j--)
2769 if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
2770 {
2771 if (s[j] == ':') s[j+1] = 0;
2772 else s[j] = 0;
2773 return;
2774 }
2775 }
2776
2777 /** \brief search for srb2.pk3 in the given path
2778
2779 \param searchDir starting path
2780
2781 \return WAD path if not NULL
2782
2783
2784 */
searchWad(const char * searchDir)2785 static const char *searchWad(const char *searchDir)
2786 {
2787 static char tempsw[256] = "";
2788 filestatus_t fstemp;
2789
2790 strcpy(tempsw, WADKEYWORD1);
2791 fstemp = filesearch(tempsw,searchDir,NULL,true,20);
2792 if (fstemp == FS_FOUND)
2793 {
2794 pathonly(tempsw);
2795 return tempsw;
2796 }
2797
2798 return NULL;
2799 }
2800
2801 /** \brief go through all possible paths and look for srb2.pk3
2802
2803 \return path to srb2.pk3 if any
2804 */
locateWad(void)2805 static const char *locateWad(void)
2806 {
2807 const char *envstr;
2808 const char *WadPath;
2809
2810 I_OutputMsg("SRB2WADDIR");
2811 // does SRB2WADDIR exist?
2812 if (((envstr = I_GetEnv("SRB2WADDIR")) != NULL) && isWadPathOk(envstr))
2813 return envstr;
2814
2815 #ifndef NOCWD
2816 I_OutputMsg(",.");
2817 // examine current dir
2818 strcpy(returnWadPath, ".");
2819 if (isWadPathOk(returnWadPath))
2820 return NULL;
2821 #endif
2822
2823
2824 #ifdef CMAKECONFIG
2825 #ifndef NDEBUG
2826 I_OutputMsg(","CMAKE_ASSETS_DIR);
2827 strcpy(returnWadPath, CMAKE_ASSETS_DIR);
2828 if (isWadPathOk(returnWadPath))
2829 {
2830 return returnWadPath;
2831 }
2832 #endif
2833 #endif
2834
2835 #ifdef __APPLE__
2836 OSX_GetResourcesPath(returnWadPath);
2837 I_OutputMsg(",%s", returnWadPath);
2838 if (isWadPathOk(returnWadPath))
2839 {
2840 return returnWadPath;
2841 }
2842 #endif
2843
2844 // examine default dirs
2845 #ifdef DEFAULTWADLOCATION1
2846 I_OutputMsg(","DEFAULTWADLOCATION1);
2847 strcpy(returnWadPath, DEFAULTWADLOCATION1);
2848 if (isWadPathOk(returnWadPath))
2849 return returnWadPath;
2850 #endif
2851 #ifdef DEFAULTWADLOCATION2
2852 I_OutputMsg(","DEFAULTWADLOCATION2);
2853 strcpy(returnWadPath, DEFAULTWADLOCATION2);
2854 if (isWadPathOk(returnWadPath))
2855 return returnWadPath;
2856 #endif
2857 #ifdef DEFAULTWADLOCATION3
2858 I_OutputMsg(","DEFAULTWADLOCATION3);
2859 strcpy(returnWadPath, DEFAULTWADLOCATION3);
2860 if (isWadPathOk(returnWadPath))
2861 return returnWadPath;
2862 #endif
2863 #ifdef DEFAULTWADLOCATION4
2864 I_OutputMsg(","DEFAULTWADLOCATION4);
2865 strcpy(returnWadPath, DEFAULTWADLOCATION4);
2866 if (isWadPathOk(returnWadPath))
2867 return returnWadPath;
2868 #endif
2869 #ifdef DEFAULTWADLOCATION5
2870 I_OutputMsg(","DEFAULTWADLOCATION5);
2871 strcpy(returnWadPath, DEFAULTWADLOCATION5);
2872 if (isWadPathOk(returnWadPath))
2873 return returnWadPath;
2874 #endif
2875 #ifdef DEFAULTWADLOCATION6
2876 I_OutputMsg(","DEFAULTWADLOCATION6);
2877 strcpy(returnWadPath, DEFAULTWADLOCATION6);
2878 if (isWadPathOk(returnWadPath))
2879 return returnWadPath;
2880 #endif
2881 #ifdef DEFAULTWADLOCATION7
2882 I_OutputMsg(","DEFAULTWADLOCATION7);
2883 strcpy(returnWadPath, DEFAULTWADLOCATION7);
2884 if (isWadPathOk(returnWadPath))
2885 return returnWadPath;
2886 #endif
2887 #ifndef NOHOME
2888 // find in $HOME
2889 I_OutputMsg(",HOME");
2890 if ((envstr = I_GetEnv("HOME")) != NULL)
2891 {
2892 WadPath = searchWad(envstr);
2893 if (WadPath)
2894 return WadPath;
2895 }
2896 #endif
2897 #ifdef DEFAULTSEARCHPATH1
2898 // find in /usr/local
2899 I_OutputMsg(", in:"DEFAULTSEARCHPATH1);
2900 WadPath = searchWad(DEFAULTSEARCHPATH1);
2901 if (WadPath)
2902 return WadPath;
2903 #endif
2904 #ifdef DEFAULTSEARCHPATH2
2905 // find in /usr/games
2906 I_OutputMsg(", in:"DEFAULTSEARCHPATH2);
2907 WadPath = searchWad(DEFAULTSEARCHPATH2);
2908 if (WadPath)
2909 return WadPath;
2910 #endif
2911 #ifdef DEFAULTSEARCHPATH3
2912 // find in ???
2913 I_OutputMsg(", in:"DEFAULTSEARCHPATH3);
2914 WadPath = searchWad(DEFAULTSEARCHPATH3);
2915 if (WadPath)
2916 return WadPath;
2917 #endif
2918 // if nothing was found
2919 return NULL;
2920 }
2921
I_LocateWad(void)2922 const char *I_LocateWad(void)
2923 {
2924 const char *waddir;
2925
2926 I_OutputMsg("Looking for WADs in: ");
2927 waddir = locateWad();
2928 I_OutputMsg("\n");
2929
2930 if (waddir)
2931 {
2932 // change to the directory where we found srb2.pk3
2933 #if defined (_WIN32)
2934 SetCurrentDirectoryA(waddir);
2935 #else
2936 if (chdir(waddir) == -1)
2937 I_OutputMsg("Couldn't change working directory\n");
2938 #endif
2939 }
2940 return waddir;
2941 }
2942
2943 #ifdef __linux__
2944 #define MEMINFO_FILE "/proc/meminfo"
2945 #define MEMTOTAL "MemTotal:"
2946 #define MEMAVAILABLE "MemAvailable:"
2947 #define MEMFREE "MemFree:"
2948 #define CACHED "Cached:"
2949 #define BUFFERS "Buffers:"
2950 #define SHMEM "Shmem:"
2951
2952 /* Parse the contents of /proc/meminfo (in buf), return value of "name"
2953 * (example: MemTotal) */
get_entry(const char * name,const char * buf)2954 static long get_entry(const char* name, const char* buf)
2955 {
2956 long val;
2957 char* hit = strstr(buf, name);
2958 if (hit == NULL) {
2959 return -1;
2960 }
2961
2962 errno = 0;
2963 val = strtol(hit + strlen(name), NULL, 10);
2964 if (errno != 0) {
2965 CONS_Alert(CONS_ERROR, M_GetText("get_entry: strtol() failed: %s\n"), strerror(errno));
2966 return -1;
2967 }
2968 return val;
2969 }
2970 #endif
2971
2972 // quick fix for compil
I_GetFreeMem(UINT32 * total)2973 UINT32 I_GetFreeMem(UINT32 *total)
2974 {
2975 #ifdef FREEBSD
2976 struct vmmeter sum;
2977 kvm_t *kd;
2978 struct nlist namelist[] =
2979 {
2980 #define X_SUM 0
2981 {"_cnt"},
2982 {NULL}
2983 };
2984 if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
2985 {
2986 if (total)
2987 *total = 0L;
2988 return 0;
2989 }
2990 if (kvm_nlist(kd, namelist) != 0)
2991 {
2992 kvm_close (kd);
2993 if (total)
2994 *total = 0L;
2995 return 0;
2996 }
2997 if (kvm_read(kd, namelist[X_SUM].n_value, &sum,
2998 sizeof (sum)) != sizeof (sum))
2999 {
3000 kvm_close(kd);
3001 if (total)
3002 *total = 0L;
3003 return 0;
3004 }
3005 kvm_close(kd);
3006
3007 if (total)
3008 *total = sum.v_page_count * sum.v_page_size;
3009 return sum.v_free_count * sum.v_page_size;
3010 #elif defined (SOLARIS)
3011 /* Just guess */
3012 if (total)
3013 *total = 32 << 20;
3014 return 32 << 20;
3015 #elif defined (_WIN32)
3016 MEMORYSTATUS info;
3017
3018 info.dwLength = sizeof (MEMORYSTATUS);
3019 GlobalMemoryStatus( &info );
3020 if (total)
3021 *total = (UINT32)info.dwTotalPhys;
3022 return (UINT32)info.dwAvailPhys;
3023 #elif defined (__linux__)
3024 /* Linux */
3025 char buf[1024];
3026 char *memTag;
3027 UINT32 freeKBytes;
3028 UINT32 totalKBytes;
3029 INT32 n;
3030 INT32 meminfo_fd = -1;
3031 long Cached;
3032 long MemFree;
3033 long Buffers;
3034 long Shmem;
3035 long MemAvailable = -1;
3036
3037 meminfo_fd = open(MEMINFO_FILE, O_RDONLY);
3038 n = read(meminfo_fd, buf, 1023);
3039 close(meminfo_fd);
3040
3041 if (n < 0)
3042 {
3043 // Error
3044 if (total)
3045 *total = 0L;
3046 return 0;
3047 }
3048
3049 buf[n] = '\0';
3050 if ((memTag = strstr(buf, MEMTOTAL)) == NULL)
3051 {
3052 // Error
3053 if (total)
3054 *total = 0L;
3055 return 0;
3056 }
3057
3058 memTag += sizeof (MEMTOTAL);
3059 totalKBytes = atoi(memTag);
3060
3061 if ((memTag = strstr(buf, MEMAVAILABLE)) == NULL)
3062 {
3063 Cached = get_entry(CACHED, buf);
3064 MemFree = get_entry(MEMFREE, buf);
3065 Buffers = get_entry(BUFFERS, buf);
3066 Shmem = get_entry(SHMEM, buf);
3067 MemAvailable = Cached + MemFree + Buffers - Shmem;
3068
3069 if (MemAvailable == -1)
3070 {
3071 // Error
3072 if (total)
3073 *total = 0L;
3074 return 0;
3075 }
3076 freeKBytes = MemAvailable;
3077 }
3078 else
3079 {
3080 memTag += sizeof (MEMAVAILABLE);
3081 freeKBytes = atoi(memTag);
3082 }
3083
3084 if (total)
3085 *total = totalKBytes << 10;
3086 return freeKBytes << 10;
3087 #else
3088 // Guess 48 MB.
3089 if (total)
3090 *total = 48<<20;
3091 return 48<<20;
3092 #endif
3093 }
3094
I_CPUInfo(void)3095 const CPUInfoFlags *I_CPUInfo(void)
3096 {
3097 #if defined (_WIN32)
3098 static CPUInfoFlags WIN_CPUInfo;
3099 SYSTEM_INFO SI;
3100 p_IsProcessorFeaturePresent pfnCPUID = (p_IsProcessorFeaturePresent)(LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsProcessorFeaturePresent");
3101
3102 ZeroMemory(&WIN_CPUInfo,sizeof (WIN_CPUInfo));
3103 if (pfnCPUID)
3104 {
3105 WIN_CPUInfo.FPPE = pfnCPUID( 0); //PF_FLOATING_POINT_PRECISION_ERRATA
3106 WIN_CPUInfo.FPE = pfnCPUID( 1); //PF_FLOATING_POINT_EMULATED
3107 WIN_CPUInfo.cmpxchg = pfnCPUID( 2); //PF_COMPARE_EXCHANGE_DOUBLE
3108 WIN_CPUInfo.MMX = pfnCPUID( 3); //PF_MMX_INSTRUCTIONS_AVAILABLE
3109 WIN_CPUInfo.PPCMM64 = pfnCPUID( 4); //PF_PPC_MOVEMEM_64BIT_OK
3110 WIN_CPUInfo.ALPHAbyte = pfnCPUID( 5); //PF_ALPHA_BYTE_INSTRUCTIONS
3111 WIN_CPUInfo.SSE = pfnCPUID( 6); //PF_XMMI_INSTRUCTIONS_AVAILABLE
3112 WIN_CPUInfo.AMD3DNow = pfnCPUID( 7); //PF_3DNOW_INSTRUCTIONS_AVAILABLE
3113 WIN_CPUInfo.RDTSC = pfnCPUID( 8); //PF_RDTSC_INSTRUCTION_AVAILABLE
3114 WIN_CPUInfo.PAE = pfnCPUID( 9); //PF_PAE_ENABLED
3115 WIN_CPUInfo.SSE2 = pfnCPUID(10); //PF_XMMI64_INSTRUCTIONS_AVAILABLE
3116 //WIN_CPUInfo.blank = pfnCPUID(11); //PF_SSE_DAZ_MODE_AVAILABLE
3117 WIN_CPUInfo.DEP = pfnCPUID(12); //PF_NX_ENABLED
3118 WIN_CPUInfo.SSE3 = pfnCPUID(13); //PF_SSE3_INSTRUCTIONS_AVAILABLE
3119 WIN_CPUInfo.cmpxchg16b = pfnCPUID(14); //PF_COMPARE_EXCHANGE128
3120 WIN_CPUInfo.cmp8xchg16 = pfnCPUID(15); //PF_COMPARE64_EXCHANGE128
3121 WIN_CPUInfo.PFC = pfnCPUID(16); //PF_CHANNELS_ENABLED
3122 }
3123 #ifdef HAVE_SDLCPUINFO
3124 else
3125 {
3126 WIN_CPUInfo.RDTSC = SDL_HasRDTSC();
3127 WIN_CPUInfo.MMX = SDL_HasMMX();
3128 WIN_CPUInfo.AMD3DNow = SDL_Has3DNow();
3129 WIN_CPUInfo.SSE = SDL_HasSSE();
3130 WIN_CPUInfo.SSE2 = SDL_HasSSE2();
3131 WIN_CPUInfo.AltiVec = SDL_HasAltiVec();
3132 }
3133 WIN_CPUInfo.MMXExt = SDL_FALSE; //SDL_HasMMXExt(); No longer in SDL2
3134 WIN_CPUInfo.AMD3DNowExt = SDL_FALSE; //SDL_Has3DNowExt(); No longer in SDL2
3135 #endif
3136 GetSystemInfo(&SI);
3137 WIN_CPUInfo.CPUs = SI.dwNumberOfProcessors;
3138 WIN_CPUInfo.IA64 = (SI.dwProcessorType == 2200); // PROCESSOR_INTEL_IA64
3139 WIN_CPUInfo.AMD64 = (SI.dwProcessorType == 8664); // PROCESSOR_AMD_X8664
3140 return &WIN_CPUInfo;
3141 #elif defined (HAVE_SDLCPUINFO)
3142 static CPUInfoFlags SDL_CPUInfo;
3143 memset(&SDL_CPUInfo,0,sizeof (CPUInfoFlags));
3144 SDL_CPUInfo.RDTSC = SDL_HasRDTSC();
3145 SDL_CPUInfo.MMX = SDL_HasMMX();
3146 SDL_CPUInfo.MMXExt = SDL_FALSE; //SDL_HasMMXExt(); No longer in SDL2
3147 SDL_CPUInfo.AMD3DNow = SDL_Has3DNow();
3148 SDL_CPUInfo.AMD3DNowExt = SDL_FALSE; //SDL_Has3DNowExt(); No longer in SDL2
3149 SDL_CPUInfo.SSE = SDL_HasSSE();
3150 SDL_CPUInfo.SSE2 = SDL_HasSSE2();
3151 SDL_CPUInfo.AltiVec = SDL_HasAltiVec();
3152 return &SDL_CPUInfo;
3153 #else
3154 return NULL; /// \todo CPUID asm
3155 #endif
3156 }
3157
3158 // note CPUAFFINITY code used to reside here
I_RegisterSysCommands(void)3159 void I_RegisterSysCommands(void) {}
3160 #endif
3161