doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
win_main.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include <errno.h>
33 #include <float.h>
34 #include <fcntl.h>
35 #include <direct.h>
36 #include <io.h>
37 #include <conio.h>
38 #include <mapi.h>
39 #include <ShellAPI.h>
40 
41 #ifndef __MRC__
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #endif
45 
46 #include "../sys_local.h"
47 #include "win_local.h"
48 #include "rc/CreateResourceIDs.h"
49 #include "../../renderer/tr_local.h"
50 
51 idCVar Win32Vars_t::sys_arch( "sys_arch", "", CVAR_SYSTEM | CVAR_INIT, "" );
52 idCVar Win32Vars_t::sys_cpustring( "sys_cpustring", "detect", CVAR_SYSTEM | CVAR_INIT, "" );
53 idCVar Win32Vars_t::in_mouse( "in_mouse", "1", CVAR_SYSTEM | CVAR_BOOL, "enable mouse input" );
54 idCVar Win32Vars_t::win_allowAltTab( "win_allowAltTab", "0", CVAR_SYSTEM | CVAR_BOOL, "allow Alt-Tab when fullscreen" );
55 idCVar Win32Vars_t::win_notaskkeys( "win_notaskkeys", "0", CVAR_SYSTEM | CVAR_INTEGER, "disable windows task keys" );
56 idCVar Win32Vars_t::win_username( "win_username", "", CVAR_SYSTEM | CVAR_INIT, "windows user name" );
57 idCVar Win32Vars_t::win_xpos( "win_xpos", "3", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "horizontal position of window" );
58 idCVar Win32Vars_t::win_ypos( "win_ypos", "22", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_INTEGER, "vertical position of window" );
59 idCVar Win32Vars_t::win_outputDebugString( "win_outputDebugString", "0", CVAR_SYSTEM | CVAR_BOOL, "" );
60 idCVar Win32Vars_t::win_outputEditString( "win_outputEditString", "1", CVAR_SYSTEM | CVAR_BOOL, "" );
61 idCVar Win32Vars_t::win_viewlog( "win_viewlog", "0", CVAR_SYSTEM | CVAR_INTEGER, "" );
62 idCVar Win32Vars_t::win_timerUpdate( "win_timerUpdate", "0", CVAR_SYSTEM | CVAR_BOOL, "allows the game to be updated while dragging the window" );
63 idCVar Win32Vars_t::win_allowMultipleInstances( "win_allowMultipleInstances", "0", CVAR_SYSTEM | CVAR_BOOL, "allow multiple instances running concurrently" );
64 
66 
67 static char sys_cmdline[MAX_STRING_CHARS];
68 
69 // not a hard limit, just what we keep track of for debugging
71 
73 
74 static sysMemoryStats_t exeLaunchMemoryStats;
75 
76 static xthreadInfo threadInfo;
77 static HANDLE hTimer;
78 
79 /*
80 ================
81 Sys_GetExeLaunchMemoryStatus
82 ================
83 */
85  stats = exeLaunchMemoryStats;
86 }
87 
88 /*
89 ==================
90 Sys_Createthread
91 ==================
92 */
93 void Sys_CreateThread( xthread_t function, void *parms, xthreadPriority priority, xthreadInfo &info, const char *name, xthreadInfo *threads[MAX_THREADS], int *thread_count ) {
94  HANDLE temp = CreateThread( NULL, // LPSECURITY_ATTRIBUTES lpsa,
95  0, // DWORD cbStack,
96  (LPTHREAD_START_ROUTINE)function, // LPTHREAD_START_ROUTINE lpStartAddr,
97  parms, // LPVOID lpvThreadParm,
98  0, // DWORD fdwCreate,
99  &info.threadId);
100  info.threadHandle = (int) temp;
101  if (priority == THREAD_HIGHEST) {
102  SetThreadPriority( (HANDLE)info.threadHandle, THREAD_PRIORITY_HIGHEST ); // we better sleep enough to do this
103  } else if (priority == THREAD_ABOVE_NORMAL ) {
104  SetThreadPriority( (HANDLE)info.threadHandle, THREAD_PRIORITY_ABOVE_NORMAL );
105  }
106  info.name = name;
107  if ( *thread_count < MAX_THREADS ) {
108  threads[(*thread_count)++] = &info;
109  } else {
110  common->DPrintf("WARNING: MAX_THREADS reached\n");
111  }
112 }
113 
114 /*
115 ==================
116 Sys_DestroyThread
117 ==================
118 */
120  WaitForSingleObject( (HANDLE)info.threadHandle, INFINITE);
121  CloseHandle( (HANDLE)info.threadHandle );
122  info.threadHandle = 0;
123 }
124 
125 /*
126 ==================
127 Sys_Sentry
128 ==================
129 */
130 void Sys_Sentry() {
131  int j = 0;
132 }
133 
134 /*
135 ==================
136 Sys_GetThreadName
137 ==================
138 */
139 const char* Sys_GetThreadName(int *index) {
140  int id = GetCurrentThreadId();
141  for( int i = 0; i < g_thread_count; i++ ) {
142  if ( id == g_threads[i]->threadId ) {
143  if ( index ) {
144  *index = i;
145  }
146  return g_threads[i]->name;
147  }
148  }
149  if ( index ) {
150  *index = -1;
151  }
152  return "main";
153 }
154 
155 
156 /*
157 ==================
158 Sys_EnterCriticalSection
159 ==================
160 */
162  assert( index >= 0 && index < MAX_CRITICAL_SECTIONS );
163  if ( TryEnterCriticalSection( &win32.criticalSections[index] ) == 0 ) {
164  EnterCriticalSection( &win32.criticalSections[index] );
165 // Sys_DebugPrintf( "busy lock '%s' in thread '%s'\n", lock->name, Sys_GetThreadName() );
166  }
167 }
168 
169 /*
170 ==================
171 Sys_LeaveCriticalSection
172 ==================
173 */
175  assert( index >= 0 && index < MAX_CRITICAL_SECTIONS );
176  LeaveCriticalSection( &win32.criticalSections[index] );
177 }
178 
179 /*
180 ==================
181 Sys_WaitForEvent
182 ==================
183 */
184 void Sys_WaitForEvent( int index ) {
185  assert( index == 0 );
186  if ( !win32.backgroundDownloadSemaphore ) {
187  win32.backgroundDownloadSemaphore = CreateEvent( NULL, TRUE, FALSE, NULL );
188  }
189  WaitForSingleObject( win32.backgroundDownloadSemaphore, INFINITE );
190  ResetEvent( win32.backgroundDownloadSemaphore );
191 }
192 
193 /*
194 ==================
195 Sys_TriggerEvent
196 ==================
197 */
198 void Sys_TriggerEvent( int index ) {
199  assert( index == 0 );
200  SetEvent( win32.backgroundDownloadSemaphore );
201 }
202 
203 
204 
205 #pragma optimize( "", on )
206 
207 #ifdef DEBUG
208 
209 
210 static unsigned int debug_total_alloc = 0;
211 static unsigned int debug_total_alloc_count = 0;
212 static unsigned int debug_current_alloc = 0;
213 static unsigned int debug_current_alloc_count = 0;
214 static unsigned int debug_frame_alloc = 0;
215 static unsigned int debug_frame_alloc_count = 0;
216 
217 idCVar sys_showMallocs( "sys_showMallocs", "0", CVAR_SYSTEM, "" );
218 
219 // _HOOK_ALLOC, _HOOK_REALLOC, _HOOK_FREE
220 
221 typedef struct CrtMemBlockHeader
222 {
223  struct _CrtMemBlockHeader *pBlockHeaderNext; // Pointer to the block allocated just before this one:
224  struct _CrtMemBlockHeader *pBlockHeaderPrev; // Pointer to the block allocated just after this one
225  char *szFileName; // File name
226  int nLine; // Line number
227  size_t nDataSize; // Size of user block
228  int nBlockUse; // Type of block
229  long lRequest; // Allocation number
230  byte gap[4]; // Buffer just before (lower than) the user's memory:
231 } CrtMemBlockHeader;
232 
233 #include <crtdbg.h>
234 
235 /*
236 ==================
237 Sys_AllocHook
238 
239  called for every malloc/new/free/delete
240 ==================
241 */
242 int Sys_AllocHook( int nAllocType, void *pvData, size_t nSize, int nBlockUse, long lRequest, const unsigned char * szFileName, int nLine )
243 {
244  CrtMemBlockHeader *pHead;
245  byte *temp;
246 
247  if ( nBlockUse == _CRT_BLOCK )
248  {
249  return( TRUE );
250  }
251 
252  // get a pointer to memory block header
253  temp = ( byte * )pvData;
254  temp -= 32;
255  pHead = ( CrtMemBlockHeader * )temp;
256 
257  switch( nAllocType ) {
258  case _HOOK_ALLOC:
259  debug_total_alloc += nSize;
260  debug_current_alloc += nSize;
261  debug_frame_alloc += nSize;
262  debug_total_alloc_count++;
263  debug_current_alloc_count++;
264  debug_frame_alloc_count++;
265  break;
266 
267  case _HOOK_FREE:
268  assert( pHead->gap[0] == 0xfd && pHead->gap[1] == 0xfd && pHead->gap[2] == 0xfd && pHead->gap[3] == 0xfd );
269 
270  debug_current_alloc -= pHead->nDataSize;
271  debug_current_alloc_count--;
272  debug_total_alloc_count++;
273  debug_frame_alloc_count++;
274  break;
275 
276  case _HOOK_REALLOC:
277  assert( pHead->gap[0] == 0xfd && pHead->gap[1] == 0xfd && pHead->gap[2] == 0xfd && pHead->gap[3] == 0xfd );
278 
279  debug_current_alloc -= pHead->nDataSize;
280  debug_total_alloc += nSize;
281  debug_current_alloc += nSize;
282  debug_frame_alloc += nSize;
283  debug_total_alloc_count++;
284  debug_current_alloc_count--;
285  debug_frame_alloc_count++;
286  break;
287  }
288  return( TRUE );
289 }
290 
291 /*
292 ==================
293 Sys_DebugMemory_f
294 ==================
295 */
296 void Sys_DebugMemory_f( void ) {
297  common->Printf( "Total allocation %8dk in %d blocks\n", debug_total_alloc / 1024, debug_total_alloc_count );
298  common->Printf( "Current allocation %8dk in %d blocks\n", debug_current_alloc / 1024, debug_current_alloc_count );
299 }
300 
301 /*
302 ==================
303 Sys_MemFrame
304 ==================
305 */
306 void Sys_MemFrame( void ) {
307  if( sys_showMallocs.GetInteger() ) {
308  common->Printf("Frame: %8dk in %5d blocks\n", debug_frame_alloc / 1024, debug_frame_alloc_count );
309  }
310 
311  debug_frame_alloc = 0;
312  debug_frame_alloc_count = 0;
313 }
314 
315 #endif
316 
317 /*
318 ==================
319 Sys_FlushCacheMemory
320 
321 On windows, the vertex buffers are write combined, so they
322 don't need to be flushed from the cache
323 ==================
324 */
325 void Sys_FlushCacheMemory( void *base, int bytes ) {
326 }
327 
328 /*
329 =============
330 Sys_Error
331 
332 Show the early console as an error dialog
333 =============
334 */
335 void Sys_Error( const char *error, ... ) {
336  va_list argptr;
337  char text[4096];
338  MSG msg;
339 
340  va_start( argptr, error );
341  vsprintf( text, error, argptr );
342  va_end( argptr);
343 
344  Conbuf_AppendText( text );
345  Conbuf_AppendText( "\n" );
346 
347  Win_SetErrorText( text );
348  Sys_ShowConsole( 1, true );
349 
350  timeEndPeriod( 1 );
351 
353 
354  GLimp_Shutdown();
355 
356  // wait for the user to quit
357  while ( 1 ) {
358  if ( !GetMessage( &msg, NULL, 0, 0 ) ) {
359  common->Quit();
360  }
361  TranslateMessage( &msg );
362  DispatchMessage( &msg );
363  }
364 
366 
367  exit (1);
368 }
369 
370 /*
371 ==============
372 Sys_Quit
373 ==============
374 */
375 void Sys_Quit( void ) {
376  timeEndPeriod( 1 );
379  ExitProcess( 0 );
380 }
381 
382 
383 /*
384 ==============
385 Sys_Printf
386 ==============
387 */
388 #define MAXPRINTMSG 4096
389 void Sys_Printf( const char *fmt, ... ) {
390  char msg[MAXPRINTMSG];
391 
392  va_list argptr;
393  va_start(argptr, fmt);
394  idStr::vsnPrintf( msg, MAXPRINTMSG-1, fmt, argptr );
395  va_end(argptr);
396  msg[sizeof(msg)-1] = '\0';
397 
398  if ( win32.win_outputDebugString.GetBool() ) {
399  OutputDebugString( msg );
400  }
401  if ( win32.win_outputEditString.GetBool() ) {
402  Conbuf_AppendText( msg );
403  }
404 }
405 
406 /*
407 ==============
408 Sys_DebugPrintf
409 ==============
410 */
411 #define MAXPRINTMSG 4096
412 void Sys_DebugPrintf( const char *fmt, ... ) {
413  char msg[MAXPRINTMSG];
414 
415  va_list argptr;
416  va_start( argptr, fmt );
417  idStr::vsnPrintf( msg, MAXPRINTMSG-1, fmt, argptr );
418  msg[ sizeof(msg)-1 ] = '\0';
419  va_end( argptr );
420 
421  OutputDebugString( msg );
422 }
423 
424 /*
425 ==============
426 Sys_DebugVPrintf
427 ==============
428 */
429 void Sys_DebugVPrintf( const char *fmt, va_list arg ) {
430  char msg[MAXPRINTMSG];
431 
432  idStr::vsnPrintf( msg, MAXPRINTMSG-1, fmt, arg );
433  msg[ sizeof(msg)-1 ] = '\0';
434 
435  OutputDebugString( msg );
436 }
437 
438 /*
439 ==============
440 Sys_Sleep
441 ==============
442 */
443 void Sys_Sleep( int msec ) {
444  Sleep( msec );
445 }
446 
447 /*
448 ==============
449 Sys_ShowWindow
450 ==============
451 */
452 void Sys_ShowWindow( bool show ) {
453  ::ShowWindow( win32.hWnd, show ? SW_SHOW : SW_HIDE );
454 }
455 
456 /*
457 ==============
458 Sys_IsWindowVisible
459 ==============
460 */
461 bool Sys_IsWindowVisible( void ) {
462  return ( ::IsWindowVisible( win32.hWnd ) != 0 );
463 }
464 
465 /*
466 ==============
467 Sys_Mkdir
468 ==============
469 */
470 void Sys_Mkdir( const char *path ) {
471  _mkdir (path);
472 }
473 
474 /*
475 =================
476 Sys_FileTimeStamp
477 =================
478 */
479 ID_TIME_T Sys_FileTimeStamp( FILE *fp ) {
480  struct _stat st;
481  _fstat( _fileno( fp ), &st );
482  return (long) st.st_mtime;
483 }
484 
485 /*
486 ==============
487 Sys_Cwd
488 ==============
489 */
490 const char *Sys_Cwd( void ) {
491  static char cwd[MAX_OSPATH];
492 
493  _getcwd( cwd, sizeof( cwd ) - 1 );
494  cwd[MAX_OSPATH-1] = 0;
495 
496  return cwd;
497 }
498 
499 /*
500 ==============
501 Sys_DefaultCDPath
502 ==============
503 */
504 const char *Sys_DefaultCDPath( void ) {
505  return "";
506 }
507 
508 /*
509 ==============
510 Sys_DefaultBasePath
511 ==============
512 */
513 const char *Sys_DefaultBasePath( void ) {
514  return Sys_Cwd();
515 }
516 
517 /*
518 ==============
519 Sys_DefaultSavePath
520 ==============
521 */
522 const char *Sys_DefaultSavePath( void ) {
523  return cvarSystem->GetCVarString( "fs_basepath" );
524 }
525 
526 /*
527 ==============
528 Sys_EXEPath
529 ==============
530 */
531 const char *Sys_EXEPath( void ) {
532  static char exe[ MAX_OSPATH ];
533  GetModuleFileName( NULL, exe, sizeof( exe ) - 1 );
534  return exe;
535 }
536 
537 /*
538 ==============
539 Sys_ListFiles
540 ==============
541 */
542 int Sys_ListFiles( const char *directory, const char *extension, idStrList &list ) {
543  idStr search;
544  struct _finddata_t findinfo;
545  int findhandle;
546  int flag;
547 
548  if ( !extension) {
549  extension = "";
550  }
551 
552  // passing a slash as extension will find directories
553  if ( extension[0] == '/' && extension[1] == 0 ) {
554  extension = "";
555  flag = 0;
556  } else {
557  flag = _A_SUBDIR;
558  }
559 
560  sprintf( search, "%s\\*%s", directory, extension );
561 
562  // search
563  list.Clear();
564 
565  findhandle = _findfirst( search, &findinfo );
566  if ( findhandle == -1 ) {
567  return -1;
568  }
569 
570  do {
571  if ( flag ^ ( findinfo.attrib & _A_SUBDIR ) ) {
572  list.Append( findinfo.name );
573  }
574  } while ( _findnext( findhandle, &findinfo ) != -1 );
575 
576  _findclose( findhandle );
577 
578  return list.Num();
579 }
580 
581 
582 /*
583 ================
584 Sys_GetClipboardData
585 ================
586 */
587 char *Sys_GetClipboardData( void ) {
588  char *data = NULL;
589  char *cliptext;
590 
591  if ( OpenClipboard( NULL ) != 0 ) {
592  HANDLE hClipboardData;
593 
594  if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {
595  if ( ( cliptext = (char *)GlobalLock( hClipboardData ) ) != 0 ) {
596  data = (char *)Mem_Alloc( GlobalSize( hClipboardData ) + 1 );
597  strcpy( data, cliptext );
598  GlobalUnlock( hClipboardData );
599 
600  strtok( data, "\n\r\b" );
601  }
602  }
603  CloseClipboard();
604  }
605  return data;
606 }
607 
608 /*
609 ================
610 Sys_SetClipboardData
611 ================
612 */
613 void Sys_SetClipboardData( const char *string ) {
614  HGLOBAL HMem;
615  char *PMem;
616 
617  // allocate memory block
618  HMem = (char *)::GlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE, strlen( string ) + 1 );
619  if ( HMem == NULL ) {
620  return;
621  }
622  // lock allocated memory and obtain a pointer
623  PMem = (char *)::GlobalLock( HMem );
624  if ( PMem == NULL ) {
625  return;
626  }
627  // copy text into allocated memory block
628  lstrcpy( PMem, string );
629  // unlock allocated memory
630  ::GlobalUnlock( HMem );
631  // open Clipboard
632  if ( !OpenClipboard( 0 ) ) {
633  ::GlobalFree( HMem );
634  return;
635  }
636  // remove current Clipboard contents
637  EmptyClipboard();
638  // supply the memory handle to the Clipboard
639  SetClipboardData( CF_TEXT, HMem );
640  HMem = 0;
641  // close Clipboard
642  CloseClipboard();
643 }
644 
645 /*
646 ========================================================================
647 
648 DLL Loading
649 
650 ========================================================================
651 */
652 
653 /*
654 =====================
655 Sys_DLL_Load
656 =====================
657 */
658 int Sys_DLL_Load( const char *dllName ) {
659  HINSTANCE libHandle;
660  libHandle = LoadLibrary( dllName );
661  if ( libHandle ) {
662  // since we can't have LoadLibrary load only from the specified path, check it did the right thing
663  char loadedPath[ MAX_OSPATH ];
664  GetModuleFileName( libHandle, loadedPath, sizeof( loadedPath ) - 1 );
665  if ( idStr::IcmpPath( dllName, loadedPath ) ) {
666  Sys_Printf( "ERROR: LoadLibrary '%s' wants to load '%s'\n", dllName, loadedPath );
667  Sys_DLL_Unload( (int)libHandle );
668  return 0;
669  }
670  }
671  return (int)libHandle;
672 }
673 
674 /*
675 =====================
676 Sys_DLL_GetProcAddress
677 =====================
678 */
679 void *Sys_DLL_GetProcAddress( int dllHandle, const char *procName ) {
680  return GetProcAddress( (HINSTANCE)dllHandle, procName );
681 }
682 
683 /*
684 =====================
685 Sys_DLL_Unload
686 =====================
687 */
688 void Sys_DLL_Unload( int dllHandle ) {
689  if ( !dllHandle ) {
690  return;
691  }
692  if ( FreeLibrary( (HINSTANCE)dllHandle ) == 0 ) {
693  int lastError = GetLastError();
694  LPVOID lpMsgBuf;
695  FormatMessage(
696  FORMAT_MESSAGE_ALLOCATE_BUFFER,
697  NULL,
698  lastError,
699  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
700  (LPTSTR) &lpMsgBuf,
701  0,
702  NULL
703  );
704  Sys_Error( "Sys_DLL_Unload: FreeLibrary failed - %s (%d)", lpMsgBuf, lastError );
705  }
706 }
707 
708 /*
709 ========================================================================
710 
711 EVENT LOOP
712 
713 ========================================================================
714 */
715 
716 #define MAX_QUED_EVENTS 256
717 #define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
718 
720 int eventHead = 0;
721 int eventTail = 0;
722 
723 /*
724 ================
725 Sys_QueEvent
726 
727 Ptr should either be null, or point to a block of data that can
728 be freed by the game later.
729 ================
730 */
731 void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
732  sysEvent_t *ev;
733 
734  ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
735 
736  if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
737  common->Printf("Sys_QueEvent: overflow\n");
738  // we are discarding an event, but don't leak memory
739  if ( ev->evPtr ) {
740  Mem_Free( ev->evPtr );
741  }
742  eventTail++;
743  }
744 
745  eventHead++;
746 
747  ev->evType = type;
748  ev->evValue = value;
749  ev->evValue2 = value2;
750  ev->evPtrLength = ptrLength;
751  ev->evPtr = ptr;
752 }
753 
754 /*
755 =============
756 Sys_PumpEvents
757 
758 This allows windows to be moved during renderbump
759 =============
760 */
761 void Sys_PumpEvents( void ) {
762  MSG msg;
763 
764  // pump the message loop
765  while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) {
766  if ( !GetMessage( &msg, NULL, 0, 0 ) ) {
767  common->Quit();
768  }
769 
770  // save the msg time, because wndprocs don't have access to the timestamp
771  if ( win32.sysMsgTime && win32.sysMsgTime > (int)msg.time ) {
772  // don't ever let the event times run backwards
773 // common->Printf( "Sys_PumpEvents: win32.sysMsgTime (%i) > msg.time (%i)\n", win32.sysMsgTime, msg.time );
774  } else {
775  win32.sysMsgTime = msg.time;
776  }
777 
778 #ifdef ID_ALLOW_TOOLS
779  if ( GUIEditorHandleMessage ( &msg ) ) {
780  continue;
781  }
782 #endif
783 
784  TranslateMessage (&msg);
785  DispatchMessage (&msg);
786  }
787 }
788 
789 /*
790 ================
791 Sys_GenerateEvents
792 ================
793 */
794 void Sys_GenerateEvents( void ) {
795  static int entered = false;
796  char *s;
797 
798  if ( entered ) {
799  return;
800  }
801  entered = true;
802 
803  // pump the message loop
804  Sys_PumpEvents();
805 
806  // make sure mouse and joystick are only called once a frame
807  IN_Frame();
808 
809  // check for console commands
810  s = Sys_ConsoleInput();
811  if ( s ) {
812  char *b;
813  int len;
814 
815  len = strlen( s ) + 1;
816  b = (char *)Mem_Alloc( len );
817  strcpy( b, s );
818  Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
819  }
820 
821  entered = false;
822 }
823 
824 /*
825 ================
826 Sys_ClearEvents
827 ================
828 */
829 void Sys_ClearEvents( void ) {
830  eventHead = eventTail = 0;
831 }
832 
833 /*
834 ================
835 Sys_GetEvent
836 ================
837 */
839  sysEvent_t ev;
840 
841  // return if we have data
842  if ( eventHead > eventTail ) {
843  eventTail++;
844  return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
845  }
846 
847  // return the empty event
848  memset( &ev, 0, sizeof( ev ) );
849 
850  return ev;
851 }
852 
853 //================================================================
854 
855 /*
856 =================
857 Sys_In_Restart_f
858 
859 Restart the input subsystem
860 =================
861 */
862 void Sys_In_Restart_f( const idCmdArgs &args ) {
864  Sys_InitInput();
865 }
866 
867 
868 /*
869 ==================
870 Sys_AsyncThread
871 ==================
872 */
873 static void Sys_AsyncThread( void *parm ) {
874  int wakeNumber;
875  int startTime;
876 
877  startTime = Sys_Milliseconds();
878  wakeNumber = 0;
879 
880  while ( 1 ) {
881 #ifdef WIN32
882  // this will trigger 60 times a second
883  int r = WaitForSingleObject( hTimer, 100 );
884  if ( r != WAIT_OBJECT_0 ) {
885  OutputDebugString( "idPacketServer::PacketServerInterrupt: bad wait return" );
886  }
887 #endif
888 
889 #if 0
890  wakeNumber++;
891  int msec = Sys_Milliseconds();
892  int deltaTime = msec - startTime;
893  startTime = msec;
894 
895  char str[1024];
896  sprintf( str, "%i ", deltaTime );
897  OutputDebugString( str );
898 #endif
899 
900 
901  common->Async();
902  }
903 }
904 
905 /*
906 ==============
907 Sys_StartAsyncThread
908 
909 Start the thread that will call idCommon::Async()
910 ==============
911 */
912 void Sys_StartAsyncThread( void ) {
913  // create an auto-reset event that happens 60 times a second
914  hTimer = CreateWaitableTimer( NULL, false, NULL );
915  if ( !hTimer ) {
916  common->Error( "idPacketServer::Spawn: CreateWaitableTimer failed" );
917  }
918 
919  LARGE_INTEGER t;
920  t.HighPart = t.LowPart = 0;
921  SetWaitableTimer( hTimer, &t, USERCMD_MSEC, NULL, NULL, TRUE );
922 
923  Sys_CreateThread( (xthread_t)Sys_AsyncThread, NULL, THREAD_ABOVE_NORMAL, threadInfo, "Async", g_threads, &g_thread_count );
924 
925 #ifdef SET_THREAD_AFFINITY
926  // give the async thread an affinity for the second cpu
927  SetThreadAffinityMask( (HANDLE)threadInfo.threadHandle, 2 );
928 #endif
929 
930  if ( !threadInfo.threadHandle ) {
931  common->Error( "Sys_StartAsyncThread: failed" );
932  }
933 }
934 
935 /*
936 ================
937 Sys_AlreadyRunning
938 
939 returns true if there is a copy of D3 running already
940 ================
941 */
942 bool Sys_AlreadyRunning( void ) {
943 #ifndef DEBUG
944  if ( !win32.win_allowMultipleInstances.GetBool() ) {
945  HANDLE hMutexOneInstance = ::CreateMutex( NULL, FALSE, "DOOM3" );
946  if ( ::GetLastError() == ERROR_ALREADY_EXISTS || ::GetLastError() == ERROR_ACCESS_DENIED ) {
947  return true;
948  }
949  }
950 #endif
951  return false;
952 }
953 
954 /*
955 ================
956 Sys_Init
957 
958 The cvar system must already be setup
959 ================
960 */
961 #define OSR2_BUILD_NUMBER 1111
962 #define WIN98_BUILD_NUMBER 1998
963 
964 void Sys_Init( void ) {
965 
966  CoInitialize( NULL );
967 
968  // make sure the timer is high precision, otherwise
969  // NT gets 18ms resolution
970  timeBeginPeriod( 1 );
971 
972  // get WM_TIMER messages pumped every millisecond
973 // SetTimer( NULL, 0, 100, NULL );
974 
975  cmdSystem->AddCommand( "in_restart", Sys_In_Restart_f, CMD_FL_SYSTEM, "restarts the input system" );
976 #ifdef DEBUG
977  cmdSystem->AddCommand( "createResourceIDs", CreateResourceIDs_f, CMD_FL_TOOL, "assigns resource IDs in _resouce.h files" );
978 #endif
979 #if 0
980  cmdSystem->AddCommand( "setAsyncSound", Sys_SetAsyncSound_f, CMD_FL_SYSTEM, "set the async sound option" );
981 #endif
982 
983  //
984  // Windows user name
985  //
987 
988  //
989  // Windows version
990  //
991  win32.osversion.dwOSVersionInfoSize = sizeof( win32.osversion );
992 
993  if ( !GetVersionEx( (LPOSVERSIONINFO)&win32.osversion ) )
994  Sys_Error( "Couldn't get OS info" );
995 
996  if ( win32.osversion.dwMajorVersion < 4 ) {
997  Sys_Error( GAME_NAME " requires Windows version 4 (NT) or greater" );
998  }
999  if ( win32.osversion.dwPlatformId == VER_PLATFORM_WIN32s ) {
1000  Sys_Error( GAME_NAME " doesn't run on Win32s" );
1001  }
1002 
1003  if( win32.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
1004  if( win32.osversion.dwMajorVersion <= 4 ) {
1005  win32.sys_arch.SetString( "WinNT (NT)" );
1006  } else if( win32.osversion.dwMajorVersion == 5 && win32.osversion.dwMinorVersion == 0 ) {
1007  win32.sys_arch.SetString( "Win2K (NT)" );
1008  } else if( win32.osversion.dwMajorVersion == 5 && win32.osversion.dwMinorVersion == 1 ) {
1009  win32.sys_arch.SetString( "WinXP (NT)" );
1010  } else if ( win32.osversion.dwMajorVersion == 6 ) {
1011  win32.sys_arch.SetString( "Vista" );
1012  } else {
1013  win32.sys_arch.SetString( "Unknown NT variant" );
1014  }
1015  } else if( win32.osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) {
1016  if( win32.osversion.dwMajorVersion == 4 && win32.osversion.dwMinorVersion == 0 ) {
1017  // Win95
1018  if( win32.osversion.szCSDVersion[1] == 'C' ) {
1019  win32.sys_arch.SetString( "Win95 OSR2 (95)" );
1020  } else {
1021  win32.sys_arch.SetString( "Win95 (95)" );
1022  }
1023  } else if( win32.osversion.dwMajorVersion == 4 && win32.osversion.dwMinorVersion == 10 ) {
1024  // Win98
1025  if( win32.osversion.szCSDVersion[1] == 'A' ) {
1026  win32.sys_arch.SetString( "Win98SE (95)" );
1027  } else {
1028  win32.sys_arch.SetString( "Win98 (95)" );
1029  }
1030  } else if( win32.osversion.dwMajorVersion == 4 && win32.osversion.dwMinorVersion == 90 ) {
1031  // WinMe
1032  win32.sys_arch.SetString( "WinMe (95)" );
1033  } else {
1034  win32.sys_arch.SetString( "Unknown 95 variant" );
1035  }
1036  } else {
1037  win32.sys_arch.SetString( "unknown Windows variant" );
1038  }
1039 
1040  //
1041  // CPU type
1042  //
1043  if ( !idStr::Icmp( win32.sys_cpustring.GetString(), "detect" ) ) {
1044  idStr string;
1045 
1046  common->Printf( "%1.0f MHz ", Sys_ClockTicksPerSecond() / 1000000.0f );
1047 
1048  win32.cpuid = Sys_GetCPUId();
1049 
1050  string.Clear();
1051 
1052  if ( win32.cpuid & CPUID_AMD ) {
1053  string += "AMD CPU";
1054  } else if ( win32.cpuid & CPUID_INTEL ) {
1055  string += "Intel CPU";
1056  } else if ( win32.cpuid & CPUID_UNSUPPORTED ) {
1057  string += "unsupported CPU";
1058  } else {
1059  string += "generic CPU";
1060  }
1061 
1062  string += " with ";
1063  if ( win32.cpuid & CPUID_MMX ) {
1064  string += "MMX & ";
1065  }
1066  if ( win32.cpuid & CPUID_3DNOW ) {
1067  string += "3DNow! & ";
1068  }
1069  if ( win32.cpuid & CPUID_SSE ) {
1070  string += "SSE & ";
1071  }
1072  if ( win32.cpuid & CPUID_SSE2 ) {
1073  string += "SSE2 & ";
1074  }
1075  if ( win32.cpuid & CPUID_SSE3 ) {
1076  string += "SSE3 & ";
1077  }
1078  if ( win32.cpuid & CPUID_HTT ) {
1079  string += "HTT & ";
1080  }
1081  string.StripTrailing( " & " );
1082  string.StripTrailing( " with " );
1083  win32.sys_cpustring.SetString( string );
1084  } else {
1085  common->Printf( "forcing CPU type to " );
1086  idLexer src( win32.sys_cpustring.GetString(), idStr::Length( win32.sys_cpustring.GetString() ), "sys_cpustring" );
1087  idToken token;
1088 
1089  int id = CPUID_NONE;
1090  while( src.ReadToken( &token ) ) {
1091  if ( token.Icmp( "generic" ) == 0 ) {
1092  id |= CPUID_GENERIC;
1093  } else if ( token.Icmp( "intel" ) == 0 ) {
1094  id |= CPUID_INTEL;
1095  } else if ( token.Icmp( "amd" ) == 0 ) {
1096  id |= CPUID_AMD;
1097  } else if ( token.Icmp( "mmx" ) == 0 ) {
1098  id |= CPUID_MMX;
1099  } else if ( token.Icmp( "3dnow" ) == 0 ) {
1100  id |= CPUID_3DNOW;
1101  } else if ( token.Icmp( "sse" ) == 0 ) {
1102  id |= CPUID_SSE;
1103  } else if ( token.Icmp( "sse2" ) == 0 ) {
1104  id |= CPUID_SSE2;
1105  } else if ( token.Icmp( "sse3" ) == 0 ) {
1106  id |= CPUID_SSE3;
1107  } else if ( token.Icmp( "htt" ) == 0 ) {
1108  id |= CPUID_HTT;
1109  }
1110  }
1111  if ( id == CPUID_NONE ) {
1112  common->Printf( "WARNING: unknown sys_cpustring '%s'\n", win32.sys_cpustring.GetString() );
1113  id = CPUID_GENERIC;
1114  }
1115  win32.cpuid = (cpuid_t) id;
1116  }
1117 
1118  common->Printf( "%s\n", win32.sys_cpustring.GetString() );
1119  common->Printf( "%d MB System Memory\n", Sys_GetSystemRam() );
1120  common->Printf( "%d MB Video Memory\n", Sys_GetVideoRam() );
1121 }
1122 
1123 /*
1124 ================
1125 Sys_Shutdown
1126 ================
1127 */
1128 void Sys_Shutdown( void ) {
1129  CoUninitialize();
1130 }
1131 
1132 /*
1133 ================
1134 Sys_GetProcessorId
1135 ================
1136 */
1138  return win32.cpuid;
1139 }
1140 
1141 /*
1142 ================
1143 Sys_GetProcessorString
1144 ================
1145 */
1146 const char *Sys_GetProcessorString( void ) {
1147  return win32.sys_cpustring.GetString();
1148 }
1149 
1150 //=======================================================================
1151 
1152 //#define SET_THREAD_AFFINITY
1153 
1154 
1155 /*
1156 ====================
1157 Win_Frame
1158 ====================
1159 */
1160 void Win_Frame( void ) {
1161  // if "viewlog" has been modified, show or hide the log console
1162  if ( win32.win_viewlog.IsModified() ) {
1164  Sys_ShowConsole( win32.win_viewlog.GetInteger(), false );
1165  }
1166  win32.win_viewlog.ClearModified();
1167  }
1168 }
1169 
1170 extern "C" { void _chkstk( int size ); };
1171 void clrstk( void );
1172 
1173 /*
1174 ====================
1175 TestChkStk
1176 ====================
1177 */
1178 void TestChkStk( void ) {
1179  int buffer[0x1000];
1180 
1181  buffer[0] = 1;
1182 }
1183 
1184 /*
1185 ====================
1186 HackChkStk
1187 ====================
1188 */
1189 void HackChkStk( void ) {
1190  DWORD old;
1191  VirtualProtect( _chkstk, 6, PAGE_EXECUTE_READWRITE, &old );
1192  *(byte *)_chkstk = 0xe9;
1193  *(int *)((int)_chkstk+1) = (int)clrstk - (int)_chkstk - 5;
1194 
1195  TestChkStk();
1196 }
1197 
1198 /*
1199 ====================
1200 GetExceptionCodeInfo
1201 ====================
1202 */
1203 const char *GetExceptionCodeInfo( UINT code ) {
1204  switch( code ) {
1205  case EXCEPTION_ACCESS_VIOLATION: return "The thread tried to read from or write to a virtual address for which it does not have the appropriate access.";
1206  case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "The thread tried to access an array element that is out of bounds and the underlying hardware supports bounds checking.";
1207  case EXCEPTION_BREAKPOINT: return "A breakpoint was encountered.";
1208  case EXCEPTION_DATATYPE_MISALIGNMENT: return "The thread tried to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries; 32-bit values on 4-byte boundaries, and so on.";
1209  case EXCEPTION_FLT_DENORMAL_OPERAND: return "One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value.";
1210  case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "The thread tried to divide a floating-point value by a floating-point divisor of zero.";
1211  case EXCEPTION_FLT_INEXACT_RESULT: return "The result of a floating-point operation cannot be represented exactly as a decimal fraction.";
1212  case EXCEPTION_FLT_INVALID_OPERATION: return "This exception represents any floating-point exception not included in this list.";
1213  case EXCEPTION_FLT_OVERFLOW: return "The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type.";
1214  case EXCEPTION_FLT_STACK_CHECK: return "The stack overflowed or underflowed as the result of a floating-point operation.";
1215  case EXCEPTION_FLT_UNDERFLOW: return "The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type.";
1216  case EXCEPTION_ILLEGAL_INSTRUCTION: return "The thread tried to execute an invalid instruction.";
1217  case EXCEPTION_IN_PAGE_ERROR: return "The thread tried to access a page that was not present, and the system was unable to load the page. For example, this exception might occur if a network connection is lost while running a program over the network.";
1218  case EXCEPTION_INT_DIVIDE_BY_ZERO: return "The thread tried to divide an integer value by an integer divisor of zero.";
1219  case EXCEPTION_INT_OVERFLOW: return "The result of an integer operation caused a carry out of the most significant bit of the result.";
1220  case EXCEPTION_INVALID_DISPOSITION: return "An exception handler returned an invalid disposition to the exception dispatcher. Programmers using a high-level language such as C should never encounter this exception.";
1221  case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "The thread tried to continue execution after a noncontinuable exception occurred.";
1222  case EXCEPTION_PRIV_INSTRUCTION: return "The thread tried to execute an instruction whose operation is not allowed in the current machine mode.";
1223  case EXCEPTION_SINGLE_STEP: return "A trace trap or other single-instruction mechanism signaled that one instruction has been executed.";
1224  case EXCEPTION_STACK_OVERFLOW: return "The thread used up its stack.";
1225  default: return "Unknown exception";
1226  }
1227 }
1228 
1229 /*
1230 ====================
1231 EmailCrashReport
1232 
1233  emailer originally from Raven/Quake 4
1234 ====================
1235 */
1236 void EmailCrashReport( LPSTR messageText ) {
1237  LPMAPISENDMAIL MAPISendMail;
1238  MapiMessage message;
1239  static int lastEmailTime = 0;
1240 
1241  if ( Sys_Milliseconds() < lastEmailTime + 10000 ) {
1242  return;
1243  }
1244 
1245  lastEmailTime = Sys_Milliseconds();
1246 
1247  HINSTANCE mapi = LoadLibrary( "MAPI32.DLL" );
1248  if( mapi ) {
1249  MAPISendMail = ( LPMAPISENDMAIL )GetProcAddress( mapi, "MAPISendMail" );
1250  if( MAPISendMail ) {
1251  MapiRecipDesc toProgrammers =
1252  {
1253  0, // ulReserved
1254  MAPI_TO, // ulRecipClass
1255  "DOOM 3 Crash", // lpszName
1256  "SMTP:programmers@idsoftware.com", // lpszAddress
1257  0, // ulEIDSize
1258  0 // lpEntry
1259  };
1260 
1261  memset( &message, 0, sizeof( message ) );
1262  message.lpszSubject = "DOOM 3 Fatal Error";
1263  message.lpszNoteText = messageText;
1264  message.nRecipCount = 1;
1265  message.lpRecips = &toProgrammers;
1266 
1267  MAPISendMail(
1268  0, // LHANDLE lhSession
1269  0, // ULONG ulUIParam
1270  &message, // lpMapiMessage lpMessage
1271  MAPI_DIALOG, // FLAGS flFlags
1272  0 // ULONG ulReserved
1273  );
1274  }
1275  FreeLibrary( mapi );
1276  }
1277 }
1278 
1279 int Sys_FPU_PrintStateFlags( char *ptr, int ctrl, int stat, int tags, int inof, int inse, int opof, int opse );
1280 
1281 /*
1282 ====================
1283 _except_handler
1284 ====================
1285 */
1286 EXCEPTION_DISPOSITION __cdecl _except_handler( struct _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame,
1287  struct _CONTEXT *ContextRecord, void * DispatcherContext ) {
1288 
1289  static char msg[ 8192 ];
1290  char FPUFlags[2048];
1291 
1292  Sys_FPU_PrintStateFlags( FPUFlags, ContextRecord->FloatSave.ControlWord,
1293  ContextRecord->FloatSave.StatusWord,
1294  ContextRecord->FloatSave.TagWord,
1295  ContextRecord->FloatSave.ErrorOffset,
1296  ContextRecord->FloatSave.ErrorSelector,
1297  ContextRecord->FloatSave.DataOffset,
1298  ContextRecord->FloatSave.DataSelector );
1299 
1300 
1301  sprintf( msg,
1302  "Please describe what you were doing when DOOM 3 crashed!\n"
1303  "If this text did not pop into your email client please copy and email it to programmers@idsoftware.com\n"
1304  "\n"
1305  "-= FATAL EXCEPTION =-\n"
1306  "\n"
1307  "%s\n"
1308  "\n"
1309  "0x%x at address 0x%08x\n"
1310  "\n"
1311  "%s\n"
1312  "\n"
1313  "EAX = 0x%08x EBX = 0x%08x\n"
1314  "ECX = 0x%08x EDX = 0x%08x\n"
1315  "ESI = 0x%08x EDI = 0x%08x\n"
1316  "EIP = 0x%08x ESP = 0x%08x\n"
1317  "EBP = 0x%08x EFL = 0x%08x\n"
1318  "\n"
1319  "CS = 0x%04x\n"
1320  "SS = 0x%04x\n"
1321  "DS = 0x%04x\n"
1322  "ES = 0x%04x\n"
1323  "FS = 0x%04x\n"
1324  "GS = 0x%04x\n"
1325  "\n"
1326  "%s\n",
1328  ExceptionRecord->ExceptionCode,
1329  ExceptionRecord->ExceptionAddress,
1330  GetExceptionCodeInfo( ExceptionRecord->ExceptionCode ),
1331  ContextRecord->Eax, ContextRecord->Ebx,
1332  ContextRecord->Ecx, ContextRecord->Edx,
1333  ContextRecord->Esi, ContextRecord->Edi,
1334  ContextRecord->Eip, ContextRecord->Esp,
1335  ContextRecord->Ebp, ContextRecord->EFlags,
1336  ContextRecord->SegCs,
1337  ContextRecord->SegSs,
1338  ContextRecord->SegDs,
1339  ContextRecord->SegEs,
1340  ContextRecord->SegFs,
1341  ContextRecord->SegGs,
1342  FPUFlags
1343  );
1344 
1345  EmailCrashReport( msg );
1346  common->FatalError( msg );
1347 
1348  // Tell the OS to restart the faulting instruction
1349  return ExceptionContinueExecution;
1350 }
1351 
1352 #define TEST_FPU_EXCEPTIONS /* FPU_EXCEPTION_INVALID_OPERATION | */ \
1353  /* FPU_EXCEPTION_DENORMALIZED_OPERAND | */ \
1354  /* FPU_EXCEPTION_DIVIDE_BY_ZERO | */ \
1355  /* FPU_EXCEPTION_NUMERIC_OVERFLOW | */ \
1356  /* FPU_EXCEPTION_NUMERIC_UNDERFLOW | */ \
1357  /* FPU_EXCEPTION_INEXACT_RESULT | */ \
1358  0
1359 
1360 /*
1361 ==================
1362 WinMain
1363 ==================
1364 */
1365 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
1366 
1367  const HCURSOR hcurSave = ::SetCursor( LoadCursor( 0, IDC_WAIT ) );
1368 
1369  Sys_SetPhysicalWorkMemory( 192 << 20, 1024 << 20 );
1370 
1371  Sys_GetCurrentMemoryStatus( exeLaunchMemoryStats );
1372 
1373 #if 0
1375  __asm
1376  { // Build EXCEPTION_REGISTRATION record:
1377  push handler // Address of handler function
1378  push FS:[0] // Address of previous handler
1379  mov FS:[0],ESP // Install new EXECEPTION_REGISTRATION
1380  }
1381 #endif
1382 
1383  win32.hInstance = hInstance;
1384  idStr::Copynz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) );
1385 
1386  // done before Com/Sys_Init since we need this for error output
1388 
1389  // no abort/retry/fail errors
1390  SetErrorMode( SEM_FAILCRITICALERRORS );
1391 
1392  for ( int i = 0; i < MAX_CRITICAL_SECTIONS; i++ ) {
1393  InitializeCriticalSection( &win32.criticalSections[i] );
1394  }
1395 
1396  // get the initial time base
1397  Sys_Milliseconds();
1398 
1399 #ifdef DEBUG
1400  // disable the painfully slow MS heap check every 1024 allocs
1401  _CrtSetDbgFlag( 0 );
1402 #endif
1403 
1404 // Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS );
1406 
1407  common->Init( 0, NULL, lpCmdLine );
1408 
1409 #if TEST_FPU_EXCEPTIONS != 0
1411 #endif
1412 
1413 #ifndef ID_DEDICATED
1414  if ( win32.win_notaskkeys.GetInteger() ) {
1415  DisableTaskKeys( TRUE, FALSE, /*( win32.win_notaskkeys.GetInteger() == 2 )*/ FALSE );
1416  }
1417 #endif
1418 
1420 
1421  // hide or show the early console as necessary
1423  Sys_ShowConsole( 1, true );
1424  } else {
1425  Sys_ShowConsole( 0, false );
1426  }
1427 
1428 #ifdef SET_THREAD_AFFINITY
1429  // give the main thread an affinity for the first cpu
1430  SetThreadAffinityMask( GetCurrentThread(), 1 );
1431 #endif
1432 
1433  ::SetCursor( hcurSave );
1434 
1435  // Launch the script debugger
1436  if ( strstr( lpCmdLine, "+debugger" ) ) {
1437  // DebuggerClientInit( lpCmdLine );
1438  return 0;
1439  }
1440 
1441  ::SetFocus( win32.hWnd );
1442 
1443  // main game loop
1444  while( 1 ) {
1445 
1446  Win_Frame();
1447 
1448 #ifdef DEBUG
1449  Sys_MemFrame();
1450 #endif
1451 
1452  // set exceptions, even if some crappy syscall changes them!
1454 
1455 #ifdef ID_ALLOW_TOOLS
1456  if ( com_editors ) {
1457  if ( com_editors & EDITOR_GUI ) {
1458  // GUI editor
1459  GUIEditorRun();
1460  } else if ( com_editors & EDITOR_RADIANT ) {
1461  // Level Editor
1462  RadiantRun();
1463  }
1464  else if (com_editors & EDITOR_MATERIAL ) {
1465  //BSM Nerve: Add support for the material editor
1467  }
1468  else {
1469  if ( com_editors & EDITOR_LIGHT ) {
1470  // in-game Light Editor
1471  LightEditorRun();
1472  }
1473  if ( com_editors & EDITOR_SOUND ) {
1474  // in-game Sound Editor
1475  SoundEditorRun();
1476  }
1477  if ( com_editors & EDITOR_DECL ) {
1478  // in-game Declaration Browser
1479  DeclBrowserRun();
1480  }
1481  if ( com_editors & EDITOR_AF ) {
1482  // in-game Articulated Figure Editor
1483  AFEditorRun();
1484  }
1485  if ( com_editors & EDITOR_PARTICLE ) {
1486  // in-game Particle Editor
1488  }
1489  if ( com_editors & EDITOR_SCRIPT ) {
1490  // in-game Script Editor
1491  ScriptEditorRun();
1492  }
1493  if ( com_editors & EDITOR_PDA ) {
1494  // in-game PDA Editor
1495  PDAEditorRun();
1496  }
1497  }
1498  }
1499 #endif
1500  // run the game
1501  common->Frame();
1502  }
1503 
1504  // never gets here
1505  return 0;
1506 }
1507 
1508 /*
1509 ====================
1510 clrstk
1511 
1512 I tried to get the run time to call this at every function entry, but
1513 ====================
1514 */
1515 static int parmBytes;
1516 __declspec( naked ) void clrstk( void ) {
1517  // eax = bytes to add to stack
1518  __asm {
1519  mov [parmBytes],eax
1520  neg eax ; compute new stack pointer in eax
1521  add eax,esp
1522  add eax,4
1523  xchg eax,esp
1524  mov eax,dword ptr [eax] ; copy the return address
1525  push eax
1526 
1527  ; clear to zero
1528  push edi
1529  push ecx
1530  mov edi,esp
1531  add edi,12
1532  mov ecx,[parmBytes]
1533  shr ecx,2
1534  xor eax,eax
1535  cld
1536  rep stosd
1537  pop ecx
1538  pop edi
1539 
1540  ret
1541  }
1542 }
1543 
1544 /*
1545 ==================
1546 idSysLocal::OpenURL
1547 ==================
1548 */
1549 void idSysLocal::OpenURL( const char *url, bool doexit ) {
1550  static bool doexit_spamguard = false;
1551  HWND wnd;
1552 
1553  if (doexit_spamguard) {
1554  common->DPrintf( "OpenURL: already in an exit sequence, ignoring %s\n", url );
1555  return;
1556  }
1557 
1558  common->Printf("Open URL: %s\n", url);
1559 
1560  if ( !ShellExecute( NULL, "open", url, NULL, NULL, SW_RESTORE ) ) {
1561  common->Error( "Could not open url: '%s' ", url );
1562  return;
1563  }
1564 
1565  wnd = GetForegroundWindow();
1566  if ( wnd ) {
1567  ShowWindow( wnd, SW_MAXIMIZE );
1568  }
1569 
1570  if ( doexit ) {
1571  doexit_spamguard = true;
1573  }
1574 }
1575 
1576 /*
1577 ==================
1578 idSysLocal::StartProcess
1579 ==================
1580 */
1581 void idSysLocal::StartProcess( const char *exePath, bool doexit ) {
1582  TCHAR szPathOrig[_MAX_PATH];
1583  STARTUPINFO si;
1584  PROCESS_INFORMATION pi;
1585 
1586  ZeroMemory( &si, sizeof(si) );
1587  si.cb = sizeof(si);
1588 
1589  strncpy( szPathOrig, exePath, _MAX_PATH );
1590 
1591  if( !CreateProcess( NULL, szPathOrig, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ) ) {
1592  common->Error( "Could not start process: '%s' ", szPathOrig );
1593  return;
1594  }
1595 
1596  if ( doexit ) {
1598  }
1599 }
1600 
1601 /*
1602 ==================
1603 Sys_SetFatalError
1604 ==================
1605 */
1606 void Sys_SetFatalError( const char *error ) {
1607 }
1608 
1609 /*
1610 ==================
1611 Sys_DoPreferences
1612 ==================
1613 */
1614 void Sys_DoPreferences( void ) {
1615 }
void Sys_PumpEvents(void)
Definition: win_main.cpp:761
CRITICAL_SECTION criticalSections[MAX_CRITICAL_SECTIONS]
Definition: win_local.h:152
unsigned int dword
Definition: Lib.h:77
void Sys_AsyncThread(void)
Definition: main.cpp:61
GLsizei const GLfloat * value
Definition: glext.h:3614
HANDLE backgroundDownloadSemaphore
Definition: win_local.h:153
double Sys_ClockTicksPerSecond(void)
Definition: main.cpp:283
int evPtrLength
Definition: sys_public.h:219
assert(prefInfo.fullscreenBtn)
idCVar com_skipRenderer("com_skipRenderer","0", CVAR_BOOL|CVAR_SYSTEM,"skip the renderer completely")
void * Sys_DLL_GetProcAddress(int dllHandle, const char *procName)
Definition: win_main.cpp:679
idCVarSystem * cvarSystem
Definition: CVarSystem.cpp:487
void Sys_SetClipboardData(const char *string)
Definition: win_main.cpp:613
void Sys_CreateConsole(void)
Definition: win_syscon.cpp:283
#define MASK_QUED_EVENTS
Definition: win_main.cpp:717
void LightEditorRun(void)
Definition: edit_stub.cpp:40
static idCVar in_mouse
Definition: win_local.h:140
static idCVar win_outputEditString
Definition: win_local.h:147
xthreadPriority
Definition: sys_public.h:482
bool Sys_IsWindowVisible(void)
Definition: win_main.cpp:461
void Sys_FPU_EnableExceptions(int exceptions)
Definition: main.cpp:227
CONST PIXELFORMATDESCRIPTOR UINT
Definition: win_qgl.cpp:47
#define GAME_NAME
Definition: Licensee.h:37
cpuid_t cpuid
Definition: win_local.h:111
Win32Vars_t win32
Definition: win_main.cpp:65
char * Sys_GetClipboardData(void)
Definition: win_main.cpp:587
int Length(void) const
Definition: Str.h:702
const char * name
Definition: sys_public.h:489
void Sys_ShutdownInput(void)
Definition: dedicated.cpp:41
DWORD
Definition: win_qgl.cpp:61
void Sys_Error(const char *error,...)
Definition: win_main.cpp:335
int Sys_Milliseconds(void)
case const int
Definition: Callbacks.cpp:52
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC
void Conbuf_AppendText(const char *msg)
Definition: win_syscon.cpp:474
static idCVar win_username
Definition: win_local.h:143
void Sys_WaitForEvent(int index)
Definition: win_main.cpp:184
const int MAX_CRITICAL_SECTIONS
Definition: sys_public.h:505
__declspec(naked) void clrstk(void)
Definition: win_main.cpp:1516
#define WINAPI
Definition: qgl.h:64
int g_thread_count
Definition: win_main.cpp:72
void Sys_Printf(const char *fmt,...)
Definition: win_main.cpp:389
OSVERSIONINFOEX osversion
Definition: win_local.h:109
char * Sys_ConsoleInput(void)
Definition: win_syscon.cpp:459
void PDAEditorRun(void)
#define MAX_QUED_EVENTS
Definition: win_main.cpp:716
void GUIEditorRun(void)
Definition: edit_stub.cpp:65
unsigned long threadId
Definition: sys_public.h:491
GLenum GLsizei const GLvoid * string
Definition: glext.h:3472
void Win_SetErrorText(const char *text)
Definition: win_syscon.cpp:543
void Sys_LeaveCriticalSection(int index)
Definition: win_main.cpp:174
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
idCmdSystem * cmdSystem
Definition: CmdSystem.cpp:116
Definition: Token.h:71
void Sys_SetFatalError(const char *error)
Definition: win_main.cpp:1606
cpuid_t Sys_GetProcessorId(void)
Definition: win_main.cpp:1137
bool Sys_AlreadyRunning(void)
Definition: win_main.cpp:942
GLdouble s
Definition: glext.h:2935
GLuint src
Definition: glext.h:5390
void Sys_DLL_Unload(int dllHandle)
Definition: win_main.cpp:688
GLenum GLsizei len
Definition: glext.h:3472
void Sleep(const int time)
int i
Definition: process.py:33
void Sys_In_Restart_f(const idCmdArgs &args)
Definition: win_main.cpp:862
const char * Sys_FPU_GetState(void)
Definition: posix_main.cpp:478
virtual void Async(void)=0
int Icmp(const char *text) const
Definition: Str.h:667
void Sys_StartAsyncThread(void)
Definition: win_main.cpp:912
static idCVar win_ypos
Definition: win_local.h:145
static idCVar win_viewlog
Definition: win_local.h:148
virtual void Frame(void)=0
int sysMsgTime
Definition: win_local.h:115
void MaterialEditorRun(void)
Called every frame by the doom engine to allow the material editor to process messages.
void * evPtr
Definition: sys_public.h:220
int com_editors
Definition: Common.cpp:97
virtual void BufferCommandText(cmdExecution_t exec, const char *text)=0
void Sys_DestroyConsole(void)
Definition: win_syscon.cpp:419
static idCVar sys_arch
Definition: win_local.h:138
const int USERCMD_MSEC
Definition: UsercmdGen.h:41
Definition: Lexer.h:137
GLsizei const GLvoid * pointer
Definition: glext.h:3035
void Sys_Sleep(int msec)
Definition: win_main.cpp:443
void Sys_CreateThread(xthread_t function, void *parms, xthreadPriority priority, xthreadInfo &info, const char *name, xthreadInfo *threads[MAX_THREADS], int *thread_count)
Definition: win_main.cpp:93
sysEventType_t
Definition: sys_public.h:192
cpuid_t Sys_GetCPUId(void)
Definition: win_cpu.cpp:534
void SetString(const char *value)
Definition: CVarSystem.h:146
void HackChkStk(void)
Definition: win_main.cpp:1189
void Sys_InitInput(void)
Definition: dedicated.cpp:39
void Sys_DebugPrintf(const char *fmt,...)
Definition: win_main.cpp:412
GLuint index
Definition: glext.h:3476
void Sys_ShowConsole(int visLevel, bool quitOnClose)
Definition: posix_main.cpp:424
#define MAX_STRING_CHARS
Definition: Lib.h:95
static idCVar win_xpos
Definition: win_local.h:144
#define TEST_FPU_EXCEPTIONS
Definition: win_main.cpp:1352
void Sys_Init(void)
Definition: win_main.cpp:964
idCommon * common
Definition: Common.cpp:206
bool GUIEditorHandleMessage(void *msg)
Definition: edit_stub.cpp:66
#define NULL
Definition: Lib.h:88
virtual const char * GetCVarString(const char *name) const =0
static idCVar win_allowAltTab
Definition: win_local.h:141
cpuid_t
Definition: sys_public.h:142
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
int evValue2
Definition: sys_public.h:218
GLuint buffer
Definition: glext.h:3108
const char * Sys_DefaultBasePath(void)
Definition: win_main.cpp:513
void Sys_ShowWindow(bool show)
Definition: win_main.cpp:452
int GetInteger(void) const
Definition: CVarSystem.h:143
int Sys_GetSystemRam(void)
Definition: main.cpp:339
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
void clrstk(void)
static void Copynz(char *dest, const char *src, int destsize)
Definition: Str.cpp:1376
static idCVar win_allowMultipleInstances
Definition: win_local.h:150
void EmailCrashReport(LPSTR messageText)
Definition: win_main.cpp:1236
const char * path
Definition: sws.c:117
void Sys_DoPreferences(void)
Definition: win_main.cpp:1614
char * Sys_GetCurrentUser(void)
Definition: win_shared.cpp:239
static idCVar serverDedicated
Definition: AsyncNetwork.h:172
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
void IN_Frame(void)
Definition: win_input.cpp:764
void _chkstk(int size)
const char * Sys_EXEPath(void)
Definition: win_main.cpp:531
void SoundEditorRun(void)
Definition: edit_stub.cpp:44
void RadiantRun(void)
Definition: edit_stub.cpp:34
void Sys_TriggerEvent(int index)
Definition: win_main.cpp:198
unsigned int(* xthread_t)(void *)
Definition: sys_public.h:480
virtual void Printf(const char *fmt,...) id_attribute((format(printf
xthreadInfo * g_threads[MAX_THREADS]
Definition: win_main.cpp:70
static idCVar win_outputDebugString
Definition: win_local.h:146
void Sys_FlushCacheMemory(void *base, int bytes)
Definition: win_main.cpp:325
#define MAX_OSPATH
Definition: posix_main.cpp:47
void Sys_Sentry()
Definition: win_main.cpp:130
sysEventType_t evType
Definition: sys_public.h:216
const char * Sys_DefaultCDPath(void)
Definition: win_main.cpp:504
sysEvent_t Sys_GetEvent(void)
Definition: win_main.cpp:838
void AFEditorRun(void)
Definition: DialogAF.cpp:346
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
Definition: win_main.cpp:1365
void Win_Frame(void)
Definition: win_main.cpp:1160
int eventHead
Definition: win_main.cpp:720
void Sys_ClearEvents(void)
Definition: win_main.cpp:829
virtual void OpenURL(const char *url, bool quit)
Definition: main.cpp:421
GLubyte GLubyte b
Definition: glext.h:4662
void TestChkStk(void)
Definition: win_main.cpp:1178
const char * GetString(void) const
Definition: CVarSystem.h:141
const char * Sys_Cwd(void)
Definition: win_main.cpp:490
void Sys_DestroyThread(xthreadInfo &info)
Definition: win_main.cpp:119
int Append(const type &obj)
Definition: List.h:646
GLdouble GLdouble GLdouble r
Definition: glext.h:2951
void Sys_DebugVPrintf(const char *fmt, va_list arg)
Definition: win_main.cpp:429
static int static int vsnPrintf(char *dest, int size, const char *fmt, va_list argptr)
Definition: Str.cpp:1502
void Sys_Shutdown(void)
Definition: win_main.cpp:1128
bool GetBool(void) const
Definition: CVarSystem.h:142
#define show(x)
Definition: getpart.c:36
const char * Sys_GetThreadName(int *index)
Definition: win_main.cpp:139
int eventTail
Definition: win_main.cpp:721
void ClearModified(void)
Definition: CVarSystem.h:139
tuple f
Definition: idal.py:89
void Sys_Quit(void)
Definition: win_main.cpp:375
GLuint in
Definition: glext.h:5388
void Sys_QueEvent(int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr)
Definition: win_main.cpp:731
int Num(void) const
Definition: List.h:265
unsigned char byte
Definition: Lib.h:75
void Sys_GenerateEvents(void)
Definition: win_main.cpp:794
ID_TIME_T Sys_FileTimeStamp(FILE *fp)
Definition: win_main.cpp:479
int Sys_FPU_PrintStateFlags(char *ptr, int ctrl, int stat, int tags, int inof, int inse, int opof, int opse)
Definition: win_cpu.cpp:648
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
void Sys_EnterCriticalSection(int index)
Definition: win_main.cpp:161
bool IsModified(void) const
Definition: CVarSystem.h:137
Definition: Str.h:116
sysEvent_t eventQue[MAX_QUED_EVENTS]
Definition: win_main.cpp:719
static idCVar win_timerUpdate
Definition: win_local.h:149
void GLimp_Shutdown(void)
Definition: dedicated.cpp:83
GLuint address
Definition: glext.h:5165
void Sys_SetPhysicalWorkMemory(int minBytes, int maxBytes)
Definition: posix_main.cpp:508
typedef LPVOID(WINAPI *PFNWGLCREATEIMAGEBUFFERI3DPROC)(HDC hDC
const char * Sys_DefaultSavePath(void)
Definition: win_main.cpp:522
const int MAX_THREADS
Definition: sys_public.h:494
int vsprintf(idStr &string, const char *fmt, va_list argptr)
Definition: Str.cpp:1549
virtual void StartProcess(const char *exeName, bool quit)
Definition: posix_main.cpp:132
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
#define FALSE
Definition: mprintf.c:70
int threadHandle
Definition: sys_public.h:490
void DeclBrowserRun(void)
const char * Sys_GetProcessorString(void)
Definition: win_main.cpp:1146
void Sys_Mkdir(const char *path)
Definition: win_main.cpp:470
const char * GetExceptionCodeInfo(UINT code)
Definition: win_main.cpp:1203
void Sys_GetCurrentMemoryStatus(sysMemoryStats_t &stats)
Definition: posix_main.cpp:355
virtual void Quit(void)=0
#define TRUE
Definition: mprintf.c:69
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
EventHandlerUPP handler
HINSTANCE hInstance
Definition: win_local.h:102
int Sys_GetVideoRam(void)
Definition: dedicated.cpp:65
void DisableTaskKeys(BOOL bDisable, BOOL bBeep, BOOL bTaskMgr)
void Sys_FPU_SetPrecision(int precision)
Definition: posix_main.cpp:482
int Sys_DLL_Load(const char *dllName)
Definition: win_main.cpp:658
virtual void DPrintf(const char *fmt,...) id_attribute((format(printf
virtual void Error(const char *fmt,...) id_attribute((format(printf
#define MAXPRINTMSG
Definition: win_main.cpp:411
static idCVar sys_cpustring
Definition: win_local.h:139
int ReadToken(idToken *token)
Definition: Lexer.cpp:820
void OutputDebugString(const char *text)
Definition: macosx_sys.mm:243
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
virtual void Init(int argc, const char **argv, const char *cmdline)=0
void Sys_GetExeLaunchMemoryStatus(sysMemoryStats_t &stats)
Definition: win_main.cpp:84
idCVar com_version("si_version", version.string, CVAR_SYSTEM|CVAR_ROM|CVAR_SERVERINFO,"engine version")
void ParticleEditorRun(void)
Definition: edit_stub.cpp:52
virtual void AddCommand(const char *cmdName, cmdFunction_t function, int flags, const char *description, argCompletion_t argCompletion=NULL)=0
int IcmpPath(const char *text) const
Definition: Str.h:687
int Sys_ListFiles(const char *directory, const char *extension, idStrList &list)
Definition: win_main.cpp:542
EXCEPTION_DISPOSITION __cdecl _except_handler(struct _EXCEPTION_RECORD *ExceptionRecord, void *EstablisherFrame, struct _CONTEXT *ContextRecord, void *DispatcherContext)
Definition: win_main.cpp:1286
static idCVar win_notaskkeys
Definition: win_local.h:142
void ScriptEditorRun(void)
Definition: edit_stub.cpp:56
GLdouble GLdouble t
Definition: glext.h:2943
void Clear(void)
Definition: List.h:184
void CreateResourceIDs_f(const idCmdArgs &args)