Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

win_main.c (26994B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // win_main.c
     23 
     24 #include "../client/client.h"
     25 #include "../qcommon/qcommon.h"
     26 #include "win_local.h"
     27 #include "resource.h"
     28 #include <errno.h>
     29 #include <float.h>
     30 #include <fcntl.h>
     31 #include <stdio.h>
     32 #include <direct.h>
     33 #include <io.h>
     34 #include <conio.h>
     35 
     36 #define	CD_BASEDIR	"quake3"
     37 #define	CD_EXE		"quake3.exe"
     38 #define	CD_BASEDIR_LINUX	"bin\\x86\\glibc-2.1"
     39 #define	CD_EXE_LINUX "quake3"
     40 #define MEM_THRESHOLD 96*1024*1024
     41 
     42 static char		sys_cmdline[MAX_STRING_CHARS];
     43 
     44 // define this to use alternate spanking method
     45 // I found out that the regular way doesn't work on my box for some reason
     46 // see the associated spank.sh script
     47 #define ALT_SPANK
     48 #ifdef ALT_SPANK
     49 #include <stdio.h>
     50 #include <sys\stat.h>
     51 
     52 int fh = 0;
     53 
     54 void Spk_Open(char *name)
     55 {
     56   fh = open( name, O_TRUNC | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE );
     57 };
     58 
     59 void Spk_Close()
     60 {
     61   if (!fh)
     62     return;
     63 
     64   close( fh );
     65   fh = 0;
     66 }
     67 
     68 void Spk_Printf (const char *text, ...)
     69 {
     70   va_list argptr;
     71   char buf[32768];
     72 
     73   if (!fh)
     74     return;
     75 
     76   va_start (argptr,text);
     77   vsprintf (buf, text, argptr);
     78   write(fh, buf, strlen(buf));
     79   _commit(fh);
     80   va_end (argptr);
     81 
     82 };
     83 #endif
     84 
     85 /*
     86 ==================
     87 Sys_LowPhysicalMemory()
     88 ==================
     89 */
     90 
     91 qboolean Sys_LowPhysicalMemory() {
     92 	MEMORYSTATUS stat;
     93   GlobalMemoryStatus (&stat);
     94 	return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;
     95 }
     96 
     97 /*
     98 ==================
     99 Sys_BeginProfiling
    100 ==================
    101 */
    102 void Sys_BeginProfiling( void ) {
    103 	// this is just used on the mac build
    104 }
    105 
    106 /*
    107 =============
    108 Sys_Error
    109 
    110 Show the early console as an error dialog
    111 =============
    112 */
    113 void QDECL Sys_Error( const char *error, ... ) {
    114 	va_list		argptr;
    115 	char		text[4096];
    116     MSG        msg;
    117 
    118 	va_start (argptr, error);
    119 	vsprintf (text, error, argptr);
    120 	va_end (argptr);
    121 
    122 	Conbuf_AppendText( text );
    123 	Conbuf_AppendText( "\n" );
    124 
    125 	Sys_SetErrorText( text );
    126 	Sys_ShowConsole( 1, qtrue );
    127 
    128 	timeEndPeriod( 1 );
    129 
    130 	IN_Shutdown();
    131 
    132 	// wait for the user to quit
    133 	while ( 1 ) {
    134 		if (!GetMessage (&msg, NULL, 0, 0))
    135 			Com_Quit_f ();
    136 		TranslateMessage (&msg);
    137       	DispatchMessage (&msg);
    138 	}
    139 
    140 	Sys_DestroyConsole();
    141 
    142 	exit (1);
    143 }
    144 
    145 /*
    146 ==============
    147 Sys_Quit
    148 ==============
    149 */
    150 void Sys_Quit( void ) {
    151 	timeEndPeriod( 1 );
    152 	IN_Shutdown();
    153 	Sys_DestroyConsole();
    154 
    155 	exit (0);
    156 }
    157 
    158 /*
    159 ==============
    160 Sys_Print
    161 ==============
    162 */
    163 void Sys_Print( const char *msg ) {
    164 	Conbuf_AppendText( msg );
    165 }
    166 
    167 
    168 /*
    169 ==============
    170 Sys_Mkdir
    171 ==============
    172 */
    173 void Sys_Mkdir( const char *path ) {
    174 	_mkdir (path);
    175 }
    176 
    177 /*
    178 ==============
    179 Sys_Cwd
    180 ==============
    181 */
    182 char *Sys_Cwd( void ) {
    183 	static char cwd[MAX_OSPATH];
    184 
    185 	_getcwd( cwd, sizeof( cwd ) - 1 );
    186 	cwd[MAX_OSPATH-1] = 0;
    187 
    188 	return cwd;
    189 }
    190 
    191 /*
    192 ==============
    193 Sys_DefaultCDPath
    194 ==============
    195 */
    196 char *Sys_DefaultCDPath( void ) {
    197 	return "";
    198 }
    199 
    200 /*
    201 ==============
    202 Sys_DefaultBasePath
    203 ==============
    204 */
    205 char *Sys_DefaultBasePath( void ) {
    206 	return Sys_Cwd();
    207 }
    208 
    209 /*
    210 ==============================================================
    211 
    212 DIRECTORY SCANNING
    213 
    214 ==============================================================
    215 */
    216 
    217 #define	MAX_FOUND_FILES	0x1000
    218 
    219 void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) {
    220 	char		search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
    221 	char		filename[MAX_OSPATH];
    222 	int			findhandle;
    223 	struct _finddata_t findinfo;
    224 
    225 	if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
    226 		return;
    227 	}
    228 
    229 	if (strlen(subdirs)) {
    230 		Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs );
    231 	}
    232 	else {
    233 		Com_sprintf( search, sizeof(search), "%s\\*", basedir );
    234 	}
    235 
    236 	findhandle = _findfirst (search, &findinfo);
    237 	if (findhandle == -1) {
    238 		return;
    239 	}
    240 
    241 	do {
    242 		if (findinfo.attrib & _A_SUBDIR) {
    243 			if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
    244 				if (strlen(subdirs)) {
    245 					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
    246 				}
    247 				else {
    248 					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
    249 				}
    250 				Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
    251 			}
    252 		}
    253 		if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
    254 			break;
    255 		}
    256 		Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name );
    257 		if (!Com_FilterPath( filter, filename, qfalse ))
    258 			continue;
    259 		list[ *numfiles ] = CopyString( filename );
    260 		(*numfiles)++;
    261 	} while ( _findnext (findhandle, &findinfo) != -1 );
    262 
    263 	_findclose (findhandle);
    264 }
    265 
    266 static qboolean strgtr(const char *s0, const char *s1) {
    267 	int l0, l1, i;
    268 
    269 	l0 = strlen(s0);
    270 	l1 = strlen(s1);
    271 
    272 	if (l1<l0) {
    273 		l0 = l1;
    274 	}
    275 
    276 	for(i=0;i<l0;i++) {
    277 		if (s1[i] > s0[i]) {
    278 			return qtrue;
    279 		}
    280 		if (s1[i] < s0[i]) {
    281 			return qfalse;
    282 		}
    283 	}
    284 	return qfalse;
    285 }
    286 
    287 char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) {
    288 	char		search[MAX_OSPATH];
    289 	int			nfiles;
    290 	char		**listCopy;
    291 	char		*list[MAX_FOUND_FILES];
    292 	struct _finddata_t findinfo;
    293 	int			findhandle;
    294 	int			flag;
    295 	int			i;
    296 
    297 	if (filter) {
    298 
    299 		nfiles = 0;
    300 		Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
    301 
    302 		list[ nfiles ] = 0;
    303 		*numfiles = nfiles;
    304 
    305 		if (!nfiles)
    306 			return NULL;
    307 
    308 		listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
    309 		for ( i = 0 ; i < nfiles ; i++ ) {
    310 			listCopy[i] = list[i];
    311 		}
    312 		listCopy[i] = NULL;
    313 
    314 		return listCopy;
    315 	}
    316 
    317 	if ( !extension) {
    318 		extension = "";
    319 	}
    320 
    321 	// passing a slash as extension will find directories
    322 	if ( extension[0] == '/' && extension[1] == 0 ) {
    323 		extension = "";
    324 		flag = 0;
    325 	} else {
    326 		flag = _A_SUBDIR;
    327 	}
    328 
    329 	Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
    330 
    331 	// search
    332 	nfiles = 0;
    333 
    334 	findhandle = _findfirst (search, &findinfo);
    335 	if (findhandle == -1) {
    336 		*numfiles = 0;
    337 		return NULL;
    338 	}
    339 
    340 	do {
    341 		if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
    342 			if ( nfiles == MAX_FOUND_FILES - 1 ) {
    343 				break;
    344 			}
    345 			list[ nfiles ] = CopyString( findinfo.name );
    346 			nfiles++;
    347 		}
    348 	} while ( _findnext (findhandle, &findinfo) != -1 );
    349 
    350 	list[ nfiles ] = 0;
    351 
    352 	_findclose (findhandle);
    353 
    354 	// return a copy of the list
    355 	*numfiles = nfiles;
    356 
    357 	if ( !nfiles ) {
    358 		return NULL;
    359 	}
    360 
    361 	listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
    362 	for ( i = 0 ; i < nfiles ; i++ ) {
    363 		listCopy[i] = list[i];
    364 	}
    365 	listCopy[i] = NULL;
    366 
    367 	do {
    368 		flag = 0;
    369 		for(i=1; i<nfiles; i++) {
    370 			if (strgtr(listCopy[i-1], listCopy[i])) {
    371 				char *temp = listCopy[i];
    372 				listCopy[i] = listCopy[i-1];
    373 				listCopy[i-1] = temp;
    374 				flag = 1;
    375 			}
    376 		}
    377 	} while(flag);
    378 
    379 	return listCopy;
    380 }
    381 
    382 void	Sys_FreeFileList( char **list ) {
    383 	int		i;
    384 
    385 	if ( !list ) {
    386 		return;
    387 	}
    388 
    389 	for ( i = 0 ; list[i] ; i++ ) {
    390 		Z_Free( list[i] );
    391 	}
    392 
    393 	Z_Free( list );
    394 }
    395 
    396 //========================================================
    397 
    398 
    399 /*
    400 ================
    401 Sys_ScanForCD
    402 
    403 Search all the drives to see if there is a valid CD to grab
    404 the cddir from
    405 ================
    406 */
    407 qboolean Sys_ScanForCD( void ) {
    408 	static char	cddir[MAX_OSPATH];
    409 	char		drive[4];
    410 	FILE		*f;
    411 	char		test[MAX_OSPATH];
    412 #if 0
    413 	// don't override a cdpath on the command line
    414 	if ( strstr( sys_cmdline, "cdpath" ) ) {
    415 		return;
    416 	}
    417 #endif
    418 
    419 	drive[0] = 'c';
    420 	drive[1] = ':';
    421 	drive[2] = '\\';
    422 	drive[3] = 0;
    423 
    424 	// scan the drives
    425 	for ( drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++ ) {
    426 		if ( GetDriveType (drive) != DRIVE_CDROM ) {
    427 			continue;
    428 		}
    429 
    430 		sprintf (cddir, "%s%s", drive, CD_BASEDIR);
    431 		sprintf (test, "%s\\%s", cddir, CD_EXE);
    432 		f = fopen( test, "r" );
    433 		if ( f ) {
    434 			fclose (f);
    435 			return qtrue;
    436     } else {
    437       sprintf(cddir, "%s%s", drive, CD_BASEDIR_LINUX);
    438       sprintf(test, "%s\\%s", cddir, CD_EXE_LINUX);
    439   		f = fopen( test, "r" );
    440 	  	if ( f ) {
    441 		  	fclose (f);
    442 			  return qtrue;
    443       }
    444     }
    445 	}
    446 
    447 	return qfalse;
    448 }
    449 
    450 /*
    451 ================
    452 Sys_CheckCD
    453 
    454 Return true if the proper CD is in the drive
    455 ================
    456 */
    457 qboolean	Sys_CheckCD( void ) {
    458   // FIXME: mission pack
    459   return qtrue;
    460 	//return Sys_ScanForCD();
    461 }
    462 
    463 
    464 /*
    465 ================
    466 Sys_GetClipboardData
    467 
    468 ================
    469 */
    470 char *Sys_GetClipboardData( void ) {
    471 	char *data = NULL;
    472 	char *cliptext;
    473 
    474 	if ( OpenClipboard( NULL ) != 0 ) {
    475 		HANDLE hClipboardData;
    476 
    477 		if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {
    478 			if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) {
    479 				data = Z_Malloc( GlobalSize( hClipboardData ) + 1 );
    480 				Q_strncpyz( data, cliptext, GlobalSize( hClipboardData ) );
    481 				GlobalUnlock( hClipboardData );
    482 				
    483 				strtok( data, "\n\r\b" );
    484 			}
    485 		}
    486 		CloseClipboard();
    487 	}
    488 	return data;
    489 }
    490 
    491 
    492 /*
    493 ========================================================================
    494 
    495 LOAD/UNLOAD DLL
    496 
    497 ========================================================================
    498 */
    499 
    500 /*
    501 =================
    502 Sys_UnloadDll
    503 
    504 =================
    505 */
    506 void Sys_UnloadDll( void *dllHandle ) {
    507 	if ( !dllHandle ) {
    508 		return;
    509 	}
    510 	if ( !FreeLibrary( dllHandle ) ) {
    511 		Com_Error (ERR_FATAL, "Sys_UnloadDll FreeLibrary failed");
    512 	}
    513 }
    514 
    515 /*
    516 =================
    517 Sys_LoadDll
    518 
    519 Used to load a development dll instead of a virtual machine
    520 
    521 TTimo: added some verbosity in debug
    522 =================
    523 */
    524 extern char		*FS_BuildOSPath( const char *base, const char *game, const char *qpath );
    525 
    526 // fqpath param added 7/20/02 by T.Ray - Sys_LoadDll is only called in vm.c at this time
    527 // fqpath will be empty if dll not loaded, otherwise will hold fully qualified path of dll module loaded
    528 // fqpath buffersize must be at least MAX_QPATH+1 bytes long
    529 void * QDECL Sys_LoadDll( const char *name, char *fqpath , int (QDECL **entryPoint)(int, ...),
    530 				  int (QDECL *systemcalls)(int, ...) ) {
    531 	static int	lastWarning = 0;
    532 	HINSTANCE	libHandle;
    533 	void	(QDECL *dllEntry)( int (QDECL *syscallptr)(int, ...) );
    534 	char	*basepath;
    535 	char	*cdpath;
    536 	char	*gamedir;
    537 	char	*fn;
    538 #ifdef NDEBUG
    539 	int		timestamp;
    540   int   ret;
    541 #endif
    542 	char	filename[MAX_QPATH];
    543 
    544 	*fqpath = 0 ;		// added 7/20/02 by T.Ray
    545 
    546 	Com_sprintf( filename, sizeof( filename ), "%sx86.dll", name );
    547 
    548 #ifdef NDEBUG
    549 	timestamp = Sys_Milliseconds();
    550 	if( ((timestamp - lastWarning) > (5 * 60000)) && !Cvar_VariableIntegerValue( "dedicated" )
    551 		&& !Cvar_VariableIntegerValue( "com_blindlyLoadDLLs" ) ) {
    552 		if (FS_FileExists(filename)) {
    553 			lastWarning = timestamp;
    554 			ret = MessageBoxEx( NULL, "You are about to load a .DLL executable that\n"
    555 				  "has not been verified for use with Quake III Arena.\n"
    556 				  "This type of file can compromise the security of\n"
    557 				  "your computer.\n\n"
    558 				  "Select 'OK' if you choose to load it anyway.",
    559 				  "Security Warning", MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_TOPMOST | MB_SETFOREGROUND,
    560 				  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) );
    561 			if( ret != IDOK ) {
    562 				return NULL;
    563 			}
    564 		}
    565 	}
    566 #endif
    567 
    568 #ifndef NDEBUG
    569 	libHandle = LoadLibrary( filename );
    570   if (libHandle)
    571     Com_Printf("LoadLibrary '%s' ok\n", filename);
    572   else
    573     Com_Printf("LoadLibrary '%s' failed\n", filename);
    574 	if ( !libHandle ) {
    575 #endif
    576 	basepath = Cvar_VariableString( "fs_basepath" );
    577 	cdpath = Cvar_VariableString( "fs_cdpath" );
    578 	gamedir = Cvar_VariableString( "fs_game" );
    579 
    580 	fn = FS_BuildOSPath( basepath, gamedir, filename );
    581 	libHandle = LoadLibrary( fn );
    582 #ifndef NDEBUG
    583   if (libHandle)
    584     Com_Printf("LoadLibrary '%s' ok\n", fn);
    585   else
    586     Com_Printf("LoadLibrary '%s' failed\n", fn);
    587 #endif
    588 
    589 	if ( !libHandle ) {
    590 		if( cdpath[0] ) {
    591 			fn = FS_BuildOSPath( cdpath, gamedir, filename );
    592 			libHandle = LoadLibrary( fn );
    593 #ifndef NDEBUG
    594       if (libHandle)
    595         Com_Printf("LoadLibrary '%s' ok\n", fn);
    596       else
    597         Com_Printf("LoadLibrary '%s' failed\n", fn);
    598 #endif
    599 		}
    600 
    601 		if ( !libHandle ) {
    602 			return NULL;
    603 		}
    604 	}
    605 #ifndef NDEBUG
    606 	}
    607 #endif
    608 
    609 	dllEntry = ( void (QDECL *)( int (QDECL *)( int, ... ) ) )GetProcAddress( libHandle, "dllEntry" ); 
    610 	*entryPoint = (int (QDECL *)(int,...))GetProcAddress( libHandle, "vmMain" );
    611 	if ( !*entryPoint || !dllEntry ) {
    612 		FreeLibrary( libHandle );
    613 		return NULL;
    614 	}
    615 	dllEntry( systemcalls );
    616 
    617 	if ( libHandle ) Q_strncpyz ( fqpath , filename , MAX_QPATH ) ;		// added 7/20/02 by T.Ray
    618 	return libHandle;
    619 }
    620 
    621 
    622 /*
    623 ========================================================================
    624 
    625 BACKGROUND FILE STREAMING
    626 
    627 ========================================================================
    628 */
    629 
    630 #if 1
    631 
    632 void Sys_InitStreamThread( void ) {
    633 }
    634 
    635 void Sys_ShutdownStreamThread( void ) {
    636 }
    637 
    638 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
    639 }
    640 
    641 void Sys_EndStreamedFile( fileHandle_t f ) {
    642 }
    643 
    644 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
    645    return FS_Read( buffer, size * count, f );
    646 }
    647 
    648 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
    649    FS_Seek( f, offset, origin );
    650 }
    651 
    652 
    653 #else
    654 
    655 typedef struct {
    656 	fileHandle_t	file;
    657 	byte	*buffer;
    658 	qboolean	eof;
    659 	qboolean	active;
    660 	int		bufferSize;
    661 	int		streamPosition;	// next byte to be returned by Sys_StreamRead
    662 	int		threadPosition;	// next byte to be read from file
    663 } streamsIO_t;
    664 
    665 typedef struct {
    666 	HANDLE				threadHandle;
    667 	int					threadId;
    668 	CRITICAL_SECTION	crit;
    669 	streamsIO_t			sIO[MAX_FILE_HANDLES];
    670 } streamState_t;
    671 
    672 streamState_t	stream;
    673 
    674 /*
    675 ===============
    676 Sys_StreamThread
    677 
    678 A thread will be sitting in this loop forever
    679 ================
    680 */
    681 void Sys_StreamThread( void ) {
    682 	int		buffer;
    683 	int		count;
    684 	int		readCount;
    685 	int		bufferPoint;
    686 	int		r, i;
    687 
    688 	while (1) {
    689 		Sleep( 10 );
    690 //		EnterCriticalSection (&stream.crit);
    691 
    692 		for (i=1;i<MAX_FILE_HANDLES;i++) {
    693 			// if there is any space left in the buffer, fill it up
    694 			if ( stream.sIO[i].active  && !stream.sIO[i].eof ) {
    695 				count = stream.sIO[i].bufferSize - (stream.sIO[i].threadPosition - stream.sIO[i].streamPosition);
    696 				if ( !count ) {
    697 					continue;
    698 				}
    699 
    700 				bufferPoint = stream.sIO[i].threadPosition % stream.sIO[i].bufferSize;
    701 				buffer = stream.sIO[i].bufferSize - bufferPoint;
    702 				readCount = buffer < count ? buffer : count;
    703 
    704 				r = FS_Read( stream.sIO[i].buffer + bufferPoint, readCount, stream.sIO[i].file );
    705 				stream.sIO[i].threadPosition += r;
    706 
    707 				if ( r != readCount ) {
    708 					stream.sIO[i].eof = qtrue;
    709 				}
    710 			}
    711 		}
    712 //		LeaveCriticalSection (&stream.crit);
    713 	}
    714 }
    715 
    716 /*
    717 ===============
    718 Sys_InitStreamThread
    719 
    720 ================
    721 */
    722 void Sys_InitStreamThread( void ) {
    723 	int i;
    724 
    725 	InitializeCriticalSection ( &stream.crit );
    726 
    727 	// don't leave the critical section until there is a
    728 	// valid file to stream, which will cause the StreamThread
    729 	// to sleep without any overhead
    730 //	EnterCriticalSection( &stream.crit );
    731 
    732 	stream.threadHandle = CreateThread(
    733 	   NULL,	// LPSECURITY_ATTRIBUTES lpsa,
    734 	   0,		// DWORD cbStack,
    735 	   (LPTHREAD_START_ROUTINE)Sys_StreamThread,	// LPTHREAD_START_ROUTINE lpStartAddr,
    736 	   0,			// LPVOID lpvThreadParm,
    737 	   0,			//   DWORD fdwCreate,
    738 	   &stream.threadId);
    739 	for(i=0;i<MAX_FILE_HANDLES;i++) {
    740 		stream.sIO[i].active = qfalse;
    741 	}
    742 }
    743 
    744 /*
    745 ===============
    746 Sys_ShutdownStreamThread
    747 
    748 ================
    749 */
    750 void Sys_ShutdownStreamThread( void ) {
    751 }
    752 
    753 
    754 /*
    755 ===============
    756 Sys_BeginStreamedFile
    757 
    758 ================
    759 */
    760 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
    761 	if ( stream.sIO[f].file ) {
    762 		Sys_EndStreamedFile( stream.sIO[f].file );
    763 	}
    764 
    765 	stream.sIO[f].file = f;
    766 	stream.sIO[f].buffer = Z_Malloc( readAhead );
    767 	stream.sIO[f].bufferSize = readAhead;
    768 	stream.sIO[f].streamPosition = 0;
    769 	stream.sIO[f].threadPosition = 0;
    770 	stream.sIO[f].eof = qfalse;
    771 	stream.sIO[f].active = qtrue;
    772 
    773 	// let the thread start running
    774 //	LeaveCriticalSection( &stream.crit );
    775 }
    776 
    777 /*
    778 ===============
    779 Sys_EndStreamedFile
    780 
    781 ================
    782 */
    783 void Sys_EndStreamedFile( fileHandle_t f ) {
    784 	if ( f != stream.sIO[f].file ) {
    785 		Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file");
    786 	}
    787 	// don't leave critical section until another stream is started
    788 	EnterCriticalSection( &stream.crit );
    789 
    790 	stream.sIO[f].file = 0;
    791 	stream.sIO[f].active = qfalse;
    792 
    793 	Z_Free( stream.sIO[f].buffer );
    794 
    795 	LeaveCriticalSection( &stream.crit );
    796 }
    797 
    798 
    799 /*
    800 ===============
    801 Sys_StreamedRead
    802 
    803 ================
    804 */
    805 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
    806 	int		available;
    807 	int		remaining;
    808 	int		sleepCount;
    809 	int		copy;
    810 	int		bufferCount;
    811 	int		bufferPoint;
    812 	byte	*dest;
    813 
    814 	if (stream.sIO[f].active == qfalse) {
    815 		Com_Error( ERR_FATAL, "Streamed read with non-streaming file" );
    816 	}
    817 
    818 	dest = (byte *)buffer;
    819 	remaining = size * count;
    820 
    821 	if ( remaining <= 0 ) {
    822 		Com_Error( ERR_FATAL, "Streamed read with non-positive size" );
    823 	}
    824 
    825 	sleepCount = 0;
    826 	while ( remaining > 0 ) {
    827 		available = stream.sIO[f].threadPosition - stream.sIO[f].streamPosition;
    828 		if ( !available ) {
    829 			if ( stream.sIO[f].eof ) {
    830 				break;
    831 			}
    832 			if ( sleepCount == 1 ) {
    833 				Com_DPrintf( "Sys_StreamedRead: waiting\n" );
    834 			}
    835 			if ( ++sleepCount > 100 ) {
    836 				Com_Error( ERR_FATAL, "Sys_StreamedRead: thread has died");
    837 			}
    838 			Sleep( 10 );
    839 			continue;
    840 		}
    841 
    842 		EnterCriticalSection( &stream.crit );
    843 
    844 		bufferPoint = stream.sIO[f].streamPosition % stream.sIO[f].bufferSize;
    845 		bufferCount = stream.sIO[f].bufferSize - bufferPoint;
    846 
    847 		copy = available < bufferCount ? available : bufferCount;
    848 		if ( copy > remaining ) {
    849 			copy = remaining;
    850 		}
    851 		memcpy( dest, stream.sIO[f].buffer + bufferPoint, copy );
    852 		stream.sIO[f].streamPosition += copy;
    853 		dest += copy;
    854 		remaining -= copy;
    855 
    856 		LeaveCriticalSection( &stream.crit );
    857 	}
    858 
    859 	return (count * size - remaining) / size;
    860 }
    861 
    862 /*
    863 ===============
    864 Sys_StreamSeek
    865 
    866 ================
    867 */
    868 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
    869 
    870 	// halt the thread
    871 	EnterCriticalSection( &stream.crit );
    872 
    873 	// clear to that point
    874 	FS_Seek( f, offset, origin );
    875 	stream.sIO[f].streamPosition = 0;
    876 	stream.sIO[f].threadPosition = 0;
    877 	stream.sIO[f].eof = qfalse;
    878 
    879 	// let the thread start running at the new position
    880 	LeaveCriticalSection( &stream.crit );
    881 }
    882 
    883 #endif
    884 
    885 /*
    886 ========================================================================
    887 
    888 EVENT LOOP
    889 
    890 ========================================================================
    891 */
    892 
    893 #define	MAX_QUED_EVENTS		256
    894 #define	MASK_QUED_EVENTS	( MAX_QUED_EVENTS - 1 )
    895 
    896 sysEvent_t	eventQue[MAX_QUED_EVENTS];
    897 int			eventHead, eventTail;
    898 byte		sys_packetReceived[MAX_MSGLEN];
    899 
    900 /*
    901 ================
    902 Sys_QueEvent
    903 
    904 A time of 0 will get the current time
    905 Ptr should either be null, or point to a block of data that can
    906 be freed by the game later.
    907 ================
    908 */
    909 void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
    910 	sysEvent_t	*ev;
    911 
    912 	ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
    913 	if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
    914 		Com_Printf("Sys_QueEvent: overflow\n");
    915 		// we are discarding an event, but don't leak memory
    916 		if ( ev->evPtr ) {
    917 			Z_Free( ev->evPtr );
    918 		}
    919 		eventTail++;
    920 	}
    921 
    922 	eventHead++;
    923 
    924 	if ( time == 0 ) {
    925 		time = Sys_Milliseconds();
    926 	}
    927 
    928 	ev->evTime = time;
    929 	ev->evType = type;
    930 	ev->evValue = value;
    931 	ev->evValue2 = value2;
    932 	ev->evPtrLength = ptrLength;
    933 	ev->evPtr = ptr;
    934 }
    935 
    936 /*
    937 ================
    938 Sys_GetEvent
    939 
    940 ================
    941 */
    942 sysEvent_t Sys_GetEvent( void ) {
    943     MSG			msg;
    944 	sysEvent_t	ev;
    945 	char		*s;
    946 	msg_t		netmsg;
    947 	netadr_t	adr;
    948 
    949 	// return if we have data
    950 	if ( eventHead > eventTail ) {
    951 		eventTail++;
    952 		return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
    953 	}
    954 
    955 	// pump the message loop
    956 	while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
    957 		if ( !GetMessage (&msg, NULL, 0, 0) ) {
    958 			Com_Quit_f();
    959 		}
    960 
    961 		// save the msg time, because wndprocs don't have access to the timestamp
    962 		g_wv.sysMsgTime = msg.time;
    963 
    964 		TranslateMessage (&msg);
    965       	DispatchMessage (&msg);
    966 	}
    967 
    968 	// check for console commands
    969 	s = Sys_ConsoleInput();
    970 	if ( s ) {
    971 		char	*b;
    972 		int		len;
    973 
    974 		len = strlen( s ) + 1;
    975 		b = Z_Malloc( len );
    976 		Q_strncpyz( b, s, len-1 );
    977 		Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
    978 	}
    979 
    980 	// check for network packets
    981 	MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
    982 	if ( Sys_GetPacket ( &adr, &netmsg ) ) {
    983 		netadr_t		*buf;
    984 		int				len;
    985 
    986 		// copy out to a seperate buffer for qeueing
    987 		// the readcount stepahead is for SOCKS support
    988 		len = sizeof( netadr_t ) + netmsg.cursize - netmsg.readcount;
    989 		buf = Z_Malloc( len );
    990 		*buf = adr;
    991 		memcpy( buf+1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount );
    992 		Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
    993 	}
    994 
    995 	// return if we have data
    996 	if ( eventHead > eventTail ) {
    997 		eventTail++;
    998 		return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
    999 	}
   1000 
   1001 	// create an empty event to return
   1002 
   1003 	memset( &ev, 0, sizeof( ev ) );
   1004 	ev.evTime = timeGetTime();
   1005 
   1006 	return ev;
   1007 }
   1008 
   1009 //================================================================
   1010 
   1011 /*
   1012 =================
   1013 Sys_In_Restart_f
   1014 
   1015 Restart the input subsystem
   1016 =================
   1017 */
   1018 void Sys_In_Restart_f( void ) {
   1019 	IN_Shutdown();
   1020 	IN_Init();
   1021 }
   1022 
   1023 
   1024 /*
   1025 =================
   1026 Sys_Net_Restart_f
   1027 
   1028 Restart the network subsystem
   1029 =================
   1030 */
   1031 void Sys_Net_Restart_f( void ) {
   1032 	NET_Restart();
   1033 }
   1034 
   1035 
   1036 /*
   1037 ================
   1038 Sys_Init
   1039 
   1040 Called after the common systems (cvars, files, etc)
   1041 are initialized
   1042 ================
   1043 */
   1044 #define OSR2_BUILD_NUMBER 1111
   1045 #define WIN98_BUILD_NUMBER 1998
   1046 
   1047 void Sys_Init( void ) {
   1048 	int cpuid;
   1049 
   1050 	// make sure the timer is high precision, otherwise
   1051 	// NT gets 18ms resolution
   1052 	timeBeginPeriod( 1 );
   1053 
   1054 	Cmd_AddCommand ("in_restart", Sys_In_Restart_f);
   1055 	Cmd_AddCommand ("net_restart", Sys_Net_Restart_f);
   1056 
   1057 	g_wv.osversion.dwOSVersionInfoSize = sizeof( g_wv.osversion );
   1058 
   1059 	if (!GetVersionEx (&g_wv.osversion))
   1060 		Sys_Error ("Couldn't get OS info");
   1061 
   1062 	if (g_wv.osversion.dwMajorVersion < 4)
   1063 		Sys_Error ("Quake3 requires Windows version 4 or greater");
   1064 	if (g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32s)
   1065 		Sys_Error ("Quake3 doesn't run on Win32s");
   1066 
   1067 	if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT )
   1068 	{
   1069 		Cvar_Set( "arch", "winnt" );
   1070 	}
   1071 	else if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
   1072 	{
   1073 		if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= WIN98_BUILD_NUMBER )
   1074 		{
   1075 			Cvar_Set( "arch", "win98" );
   1076 		}
   1077 		else if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
   1078 		{
   1079 			Cvar_Set( "arch", "win95 osr2.x" );
   1080 		}
   1081 		else
   1082 		{
   1083 			Cvar_Set( "arch", "win95" );
   1084 		}
   1085 	}
   1086 	else
   1087 	{
   1088 		Cvar_Set( "arch", "unknown Windows variant" );
   1089 	}
   1090 
   1091 	// save out a couple things in rom cvars for the renderer to access
   1092 	Cvar_Get( "win_hinstance", va("%i", (int)g_wv.hInstance), CVAR_ROM );
   1093 	Cvar_Get( "win_wndproc", va("%i", (int)MainWndProc), CVAR_ROM );
   1094 
   1095 	//
   1096 	// figure out our CPU
   1097 	//
   1098 	Cvar_Get( "sys_cpustring", "detect", 0 );
   1099 	if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring"), "detect" ) )
   1100 	{
   1101 		Com_Printf( "...detecting CPU, found " );
   1102 
   1103 		cpuid = Sys_GetProcessorId();
   1104 
   1105 		switch ( cpuid )
   1106 		{
   1107 		case CPUID_GENERIC:
   1108 			Cvar_Set( "sys_cpustring", "generic" );
   1109 			break;
   1110 		case CPUID_INTEL_UNSUPPORTED:
   1111 			Cvar_Set( "sys_cpustring", "x86 (pre-Pentium)" );
   1112 			break;
   1113 		case CPUID_INTEL_PENTIUM:
   1114 			Cvar_Set( "sys_cpustring", "x86 (P5/PPro, non-MMX)" );
   1115 			break;
   1116 		case CPUID_INTEL_MMX:
   1117 			Cvar_Set( "sys_cpustring", "x86 (P5/Pentium2, MMX)" );
   1118 			break;
   1119 		case CPUID_INTEL_KATMAI:
   1120 			Cvar_Set( "sys_cpustring", "Intel Pentium III" );
   1121 			break;
   1122 		case CPUID_AMD_3DNOW:
   1123 			Cvar_Set( "sys_cpustring", "AMD w/ 3DNow!" );
   1124 			break;
   1125 		case CPUID_AXP:
   1126 			Cvar_Set( "sys_cpustring", "Alpha AXP" );
   1127 			break;
   1128 		default:
   1129 			Com_Error( ERR_FATAL, "Unknown cpu type %d\n", cpuid );
   1130 			break;
   1131 		}
   1132 	}
   1133 	else
   1134 	{
   1135 		Com_Printf( "...forcing CPU type to " );
   1136 		if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "generic" ) )
   1137 		{
   1138 			cpuid = CPUID_GENERIC;
   1139 		}
   1140 		else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "x87" ) )
   1141 		{
   1142 			cpuid = CPUID_INTEL_PENTIUM;
   1143 		}
   1144 		else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "mmx" ) )
   1145 		{
   1146 			cpuid = CPUID_INTEL_MMX;
   1147 		}
   1148 		else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "3dnow" ) )
   1149 		{
   1150 			cpuid = CPUID_AMD_3DNOW;
   1151 		}
   1152 		else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "PentiumIII" ) )
   1153 		{
   1154 			cpuid = CPUID_INTEL_KATMAI;
   1155 		}
   1156 		else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "axp" ) )
   1157 		{
   1158 			cpuid = CPUID_AXP;
   1159 		}
   1160 		else
   1161 		{
   1162 			Com_Printf( "WARNING: unknown sys_cpustring '%s'\n", Cvar_VariableString( "sys_cpustring" ) );
   1163 			cpuid = CPUID_GENERIC;
   1164 		}
   1165 	}
   1166 	Cvar_SetValue( "sys_cpuid", cpuid );
   1167 	Com_Printf( "%s\n", Cvar_VariableString( "sys_cpustring" ) );
   1168 
   1169 	Cvar_Set( "username", Sys_GetCurrentUser() );
   1170 
   1171 	IN_Init();		// FIXME: not in dedicated?
   1172 }
   1173 
   1174 
   1175 //=======================================================================
   1176 
   1177 int	totalMsec, countMsec;
   1178 
   1179 /*
   1180 ==================
   1181 WinMain
   1182 
   1183 ==================
   1184 */
   1185 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
   1186 	char		cwd[MAX_OSPATH];
   1187 	int			startTime, endTime;
   1188 
   1189     // should never get a previous instance in Win32
   1190     if ( hPrevInstance ) {
   1191         return 0;
   1192 	}
   1193 
   1194 	g_wv.hInstance = hInstance;
   1195 	Q_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) );
   1196 
   1197 	// done before Com/Sys_Init since we need this for error output
   1198 	Sys_CreateConsole();
   1199 
   1200 	// no abort/retry/fail errors
   1201 	SetErrorMode( SEM_FAILCRITICALERRORS );
   1202 
   1203 	// get the initial time base
   1204 	Sys_Milliseconds();
   1205 #if 0
   1206 	// if we find the CD, add a +set cddir xxx command line
   1207 	Sys_ScanForCD();
   1208 #endif
   1209 
   1210 	Sys_InitStreamThread();
   1211 
   1212 	Com_Init( sys_cmdline );
   1213 	NET_Init();
   1214 
   1215 	_getcwd (cwd, sizeof(cwd));
   1216 	Com_Printf("Working directory: %s\n", cwd);
   1217 
   1218 	// hide the early console since we've reached the point where we
   1219 	// have a working graphics subsystems
   1220 	if ( !com_dedicated->integer && !com_viewlog->integer ) {
   1221 		Sys_ShowConsole( 0, qfalse );
   1222 	}
   1223 
   1224     // main game loop
   1225 	while( 1 ) {
   1226 		// if not running as a game client, sleep a bit
   1227 		if ( g_wv.isMinimized || ( com_dedicated && com_dedicated->integer ) ) {
   1228 			Sleep( 5 );
   1229 		}
   1230 
   1231 		// set low precision every frame, because some system calls
   1232 		// reset it arbitrarily
   1233 //		_controlfp( _PC_24, _MCW_PC );
   1234 //    _controlfp( -1, _MCW_EM  ); // no exceptions, even if some crappy
   1235                                 // syscall turns them back on!
   1236 
   1237 		startTime = Sys_Milliseconds();
   1238 
   1239 		// make sure mouse and joystick are only called once a frame
   1240 		IN_Frame();
   1241 
   1242 		// run the game
   1243 		Com_Frame();
   1244 
   1245 		endTime = Sys_Milliseconds();
   1246 		totalMsec += endTime - startTime;
   1247 		countMsec++;
   1248 	}
   1249 
   1250 	// never gets here
   1251 }
   1252 
   1253