Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

win_main.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // win_main.c
00023 
00024 #include "../client/client.h"
00025 #include "../qcommon/qcommon.h"
00026 #include "win_local.h"
00027 #include "resource.h"
00028 #include <errno.h>
00029 #include <float.h>
00030 #include <fcntl.h>
00031 #include <stdio.h>
00032 #include <direct.h>
00033 #include <io.h>
00034 #include <conio.h>
00035 
00036 #define CD_BASEDIR  "quake3"
00037 #define CD_EXE      "quake3.exe"
00038 #define CD_BASEDIR_LINUX    "bin\\x86\\glibc-2.1"
00039 #define CD_EXE_LINUX "quake3"
00040 #define MEM_THRESHOLD 96*1024*1024
00041 
00042 static char     sys_cmdline[MAX_STRING_CHARS];
00043 
00044 // define this to use alternate spanking method
00045 // I found out that the regular way doesn't work on my box for some reason
00046 // see the associated spank.sh script
00047 #define ALT_SPANK
00048 #ifdef ALT_SPANK
00049 #include <stdio.h>
00050 #include <sys\stat.h>
00051 
00052 int fh = 0;
00053 
00054 void Spk_Open(char *name)
00055 {
00056   fh = open( name, O_TRUNC | O_CREAT | O_WRONLY, S_IREAD | S_IWRITE );
00057 };
00058 
00059 void Spk_Close()
00060 {
00061   if (!fh)
00062     return;
00063 
00064   close( fh );
00065   fh = 0;
00066 }
00067 
00068 void Spk_Printf (const char *text, ...)
00069 {
00070   va_list argptr;
00071   char buf[32768];
00072 
00073   if (!fh)
00074     return;
00075 
00076   va_start (argptr,text);
00077   vsprintf (buf, text, argptr);
00078   write(fh, buf, strlen(buf));
00079   _commit(fh);
00080   va_end (argptr);
00081 
00082 };
00083 #endif
00084 
00085 /*
00086 ==================
00087 Sys_LowPhysicalMemory()
00088 ==================
00089 */
00090 
00091 qboolean Sys_LowPhysicalMemory() {
00092     MEMORYSTATUS stat;
00093   GlobalMemoryStatus (&stat);
00094     return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;
00095 }
00096 
00097 /*
00098 ==================
00099 Sys_BeginProfiling
00100 ==================
00101 */
00102 void Sys_BeginProfiling( void ) {
00103     // this is just used on the mac build
00104 }
00105 
00106 /*
00107 =============
00108 Sys_Error
00109 
00110 Show the early console as an error dialog
00111 =============
00112 */
00113 void QDECL Sys_Error( const char *error, ... ) {
00114     va_list     argptr;
00115     char        text[4096];
00116     MSG        msg;
00117 
00118     va_start (argptr, error);
00119     vsprintf (text, error, argptr);
00120     va_end (argptr);
00121 
00122     Conbuf_AppendText( text );
00123     Conbuf_AppendText( "\n" );
00124 
00125     Sys_SetErrorText( text );
00126     Sys_ShowConsole( 1, qtrue );
00127 
00128     timeEndPeriod( 1 );
00129 
00130     IN_Shutdown();
00131 
00132     // wait for the user to quit
00133     while ( 1 ) {
00134         if (!GetMessage (&msg, NULL, 0, 0))
00135             Com_Quit_f ();
00136         TranslateMessage (&msg);
00137         DispatchMessage (&msg);
00138     }
00139 
00140     Sys_DestroyConsole();
00141 
00142     exit (1);
00143 }
00144 
00145 /*
00146 ==============
00147 Sys_Quit
00148 ==============
00149 */
00150 void Sys_Quit( void ) {
00151     timeEndPeriod( 1 );
00152     IN_Shutdown();
00153     Sys_DestroyConsole();
00154 
00155     exit (0);
00156 }
00157 
00158 /*
00159 ==============
00160 Sys_Print
00161 ==============
00162 */
00163 void Sys_Print( const char *msg ) {
00164     Conbuf_AppendText( msg );
00165 }
00166 
00167 
00168 /*
00169 ==============
00170 Sys_Mkdir
00171 ==============
00172 */
00173 void Sys_Mkdir( const char *path ) {
00174     _mkdir (path);
00175 }
00176 
00177 /*
00178 ==============
00179 Sys_Cwd
00180 ==============
00181 */
00182 char *Sys_Cwd( void ) {
00183     static char cwd[MAX_OSPATH];
00184 
00185     _getcwd( cwd, sizeof( cwd ) - 1 );
00186     cwd[MAX_OSPATH-1] = 0;
00187 
00188     return cwd;
00189 }
00190 
00191 /*
00192 ==============
00193 Sys_DefaultCDPath
00194 ==============
00195 */
00196 char *Sys_DefaultCDPath( void ) {
00197     return "";
00198 }
00199 
00200 /*
00201 ==============
00202 Sys_DefaultBasePath
00203 ==============
00204 */
00205 char *Sys_DefaultBasePath( void ) {
00206     return Sys_Cwd();
00207 }
00208 
00209 /*
00210 ==============================================================
00211 
00212 DIRECTORY SCANNING
00213 
00214 ==============================================================
00215 */
00216 
00217 #define MAX_FOUND_FILES 0x1000
00218 
00219 void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) {
00220     char        search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
00221     char        filename[MAX_OSPATH];
00222     int         findhandle;
00223     struct _finddata_t findinfo;
00224 
00225     if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
00226         return;
00227     }
00228 
00229     if (strlen(subdirs)) {
00230         Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs );
00231     }
00232     else {
00233         Com_sprintf( search, sizeof(search), "%s\\*", basedir );
00234     }
00235 
00236     findhandle = _findfirst (search, &findinfo);
00237     if (findhandle == -1) {
00238         return;
00239     }
00240 
00241     do {
00242         if (findinfo.attrib & _A_SUBDIR) {
00243             if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
00244                 if (strlen(subdirs)) {
00245                     Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
00246                 }
00247                 else {
00248                     Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
00249                 }
00250                 Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
00251             }
00252         }
00253         if ( *numfiles >= MAX_FOUND_FILES - 1 ) {
00254             break;
00255         }
00256         Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name );
00257         if (!Com_FilterPath( filter, filename, qfalse ))
00258             continue;
00259         list[ *numfiles ] = CopyString( filename );
00260         (*numfiles)++;
00261     } while ( _findnext (findhandle, &findinfo) != -1 );
00262 
00263     _findclose (findhandle);
00264 }
00265 
00266 static qboolean strgtr(const char *s0, const char *s1) {
00267     int l0, l1, i;
00268 
00269     l0 = strlen(s0);
00270     l1 = strlen(s1);
00271 
00272     if (l1<l0) {
00273         l0 = l1;
00274     }
00275 
00276     for(i=0;i<l0;i++) {
00277         if (s1[i] > s0[i]) {
00278             return qtrue;
00279         }
00280         if (s1[i] < s0[i]) {
00281             return qfalse;
00282         }
00283     }
00284     return qfalse;
00285 }
00286 
00287 char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) {
00288     char        search[MAX_OSPATH];
00289     int         nfiles;
00290     char        **listCopy;
00291     char        *list[MAX_FOUND_FILES];
00292     struct _finddata_t findinfo;
00293     int         findhandle;
00294     int         flag;
00295     int         i;
00296 
00297     if (filter) {
00298 
00299         nfiles = 0;
00300         Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
00301 
00302         list[ nfiles ] = 0;
00303         *numfiles = nfiles;
00304 
00305         if (!nfiles)
00306             return NULL;
00307 
00308         listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
00309         for ( i = 0 ; i < nfiles ; i++ ) {
00310             listCopy[i] = list[i];
00311         }
00312         listCopy[i] = NULL;
00313 
00314         return listCopy;
00315     }
00316 
00317     if ( !extension) {
00318         extension = "";
00319     }
00320 
00321     // passing a slash as extension will find directories
00322     if ( extension[0] == '/' && extension[1] == 0 ) {
00323         extension = "";
00324         flag = 0;
00325     } else {
00326         flag = _A_SUBDIR;
00327     }
00328 
00329     Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
00330 
00331     // search
00332     nfiles = 0;
00333 
00334     findhandle = _findfirst (search, &findinfo);
00335     if (findhandle == -1) {
00336         *numfiles = 0;
00337         return NULL;
00338     }
00339 
00340     do {
00341         if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
00342             if ( nfiles == MAX_FOUND_FILES - 1 ) {
00343                 break;
00344             }
00345             list[ nfiles ] = CopyString( findinfo.name );
00346             nfiles++;
00347         }
00348     } while ( _findnext (findhandle, &findinfo) != -1 );
00349 
00350     list[ nfiles ] = 0;
00351 
00352     _findclose (findhandle);
00353 
00354     // return a copy of the list
00355     *numfiles = nfiles;
00356 
00357     if ( !nfiles ) {
00358         return NULL;
00359     }
00360 
00361     listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
00362     for ( i = 0 ; i < nfiles ; i++ ) {
00363         listCopy[i] = list[i];
00364     }
00365     listCopy[i] = NULL;
00366 
00367     do {
00368         flag = 0;
00369         for(i=1; i<nfiles; i++) {
00370             if (strgtr(listCopy[i-1], listCopy[i])) {
00371                 char *temp = listCopy[i];
00372                 listCopy[i] = listCopy[i-1];
00373                 listCopy[i-1] = temp;
00374                 flag = 1;
00375             }
00376         }
00377     } while(flag);
00378 
00379     return listCopy;
00380 }
00381 
00382 void    Sys_FreeFileList( char **list ) {
00383     int     i;
00384 
00385     if ( !list ) {
00386         return;
00387     }
00388 
00389     for ( i = 0 ; list[i] ; i++ ) {
00390         Z_Free( list[i] );
00391     }
00392 
00393     Z_Free( list );
00394 }
00395 
00396 //========================================================
00397 
00398 
00399 /*
00400 ================
00401 Sys_ScanForCD
00402 
00403 Search all the drives to see if there is a valid CD to grab
00404 the cddir from
00405 ================
00406 */
00407 qboolean Sys_ScanForCD( void ) {
00408     static char cddir[MAX_OSPATH];
00409     char        drive[4];
00410     FILE        *f;
00411     char        test[MAX_OSPATH];
00412 #if 0
00413     // don't override a cdpath on the command line
00414     if ( strstr( sys_cmdline, "cdpath" ) ) {
00415         return;
00416     }
00417 #endif
00418 
00419     drive[0] = 'c';
00420     drive[1] = ':';
00421     drive[2] = '\\';
00422     drive[3] = 0;
00423 
00424     // scan the drives
00425     for ( drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++ ) {
00426         if ( GetDriveType (drive) != DRIVE_CDROM ) {
00427             continue;
00428         }
00429 
00430         sprintf (cddir, "%s%s", drive, CD_BASEDIR);
00431         sprintf (test, "%s\\%s", cddir, CD_EXE);
00432         f = fopen( test, "r" );
00433         if ( f ) {
00434             fclose (f);
00435             return qtrue;
00436     } else {
00437       sprintf(cddir, "%s%s", drive, CD_BASEDIR_LINUX);
00438       sprintf(test, "%s\\%s", cddir, CD_EXE_LINUX);
00439         f = fopen( test, "r" );
00440         if ( f ) {
00441             fclose (f);
00442               return qtrue;
00443       }
00444     }
00445     }
00446 
00447     return qfalse;
00448 }
00449 
00450 /*
00451 ================
00452 Sys_CheckCD
00453 
00454 Return true if the proper CD is in the drive
00455 ================
00456 */
00457 qboolean    Sys_CheckCD( void ) {
00458   // FIXME: mission pack
00459   return qtrue;
00460     //return Sys_ScanForCD();
00461 }
00462 
00463 
00464 /*
00465 ================
00466 Sys_GetClipboardData
00467 
00468 ================
00469 */
00470 char *Sys_GetClipboardData( void ) {
00471     char *data = NULL;
00472     char *cliptext;
00473 
00474     if ( OpenClipboard( NULL ) != 0 ) {
00475         HANDLE hClipboardData;
00476 
00477         if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) {
00478             if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) {
00479                 data = Z_Malloc( GlobalSize( hClipboardData ) + 1 );
00480                 Q_strncpyz( data, cliptext, GlobalSize( hClipboardData ) );
00481                 GlobalUnlock( hClipboardData );
00482                 
00483                 strtok( data, "\n\r\b" );
00484             }
00485         }
00486         CloseClipboard();
00487     }
00488     return data;
00489 }
00490 
00491 
00492 /*
00493 ========================================================================
00494 
00495 LOAD/UNLOAD DLL
00496 
00497 ========================================================================
00498 */
00499 
00500 /*
00501 =================
00502 Sys_UnloadDll
00503 
00504 =================
00505 */
00506 void Sys_UnloadDll( void *dllHandle ) {
00507     if ( !dllHandle ) {
00508         return;
00509     }
00510     if ( !FreeLibrary( dllHandle ) ) {
00511         Com_Error (ERR_FATAL, "Sys_UnloadDll FreeLibrary failed");
00512     }
00513 }
00514 
00515 /*
00516 =================
00517 Sys_LoadDll
00518 
00519 Used to load a development dll instead of a virtual machine
00520 
00521 TTimo: added some verbosity in debug
00522 =================
00523 */
00524 extern char     *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
00525 
00526 // fqpath param added 7/20/02 by T.Ray - Sys_LoadDll is only called in vm.c at this time
00527 // fqpath will be empty if dll not loaded, otherwise will hold fully qualified path of dll module loaded
00528 // fqpath buffersize must be at least MAX_QPATH+1 bytes long
00529 void * QDECL Sys_LoadDll( const char *name, char *fqpath , int (QDECL **entryPoint)(int, ...),
00530                   int (QDECL *systemcalls)(int, ...) ) {
00531     static int  lastWarning = 0;
00532     HINSTANCE   libHandle;
00533     void    (QDECL *dllEntry)( int (QDECL *syscallptr)(int, ...) );
00534     char    *basepath;
00535     char    *cdpath;
00536     char    *gamedir;
00537     char    *fn;
00538 #ifdef NDEBUG
00539     int     timestamp;
00540   int   ret;
00541 #endif
00542     char    filename[MAX_QPATH];
00543 
00544     *fqpath = 0 ;       // added 7/20/02 by T.Ray
00545 
00546     Com_sprintf( filename, sizeof( filename ), "%sx86.dll", name );
00547 
00548 #ifdef NDEBUG
00549     timestamp = Sys_Milliseconds();
00550     if( ((timestamp - lastWarning) > (5 * 60000)) && !Cvar_VariableIntegerValue( "dedicated" )
00551         && !Cvar_VariableIntegerValue( "com_blindlyLoadDLLs" ) ) {
00552         if (FS_FileExists(filename)) {
00553             lastWarning = timestamp;
00554             ret = MessageBoxEx( NULL, "You are about to load a .DLL executable that\n"
00555                   "has not been verified for use with Quake III Arena.\n"
00556                   "This type of file can compromise the security of\n"
00557                   "your computer.\n\n"
00558                   "Select 'OK' if you choose to load it anyway.",
00559                   "Security Warning", MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_TOPMOST | MB_SETFOREGROUND,
00560                   MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) );
00561             if( ret != IDOK ) {
00562                 return NULL;
00563             }
00564         }
00565     }
00566 #endif
00567 
00568 #ifndef NDEBUG
00569     libHandle = LoadLibrary( filename );
00570   if (libHandle)
00571     Com_Printf("LoadLibrary '%s' ok\n", filename);
00572   else
00573     Com_Printf("LoadLibrary '%s' failed\n", filename);
00574     if ( !libHandle ) {
00575 #endif
00576     basepath = Cvar_VariableString( "fs_basepath" );
00577     cdpath = Cvar_VariableString( "fs_cdpath" );
00578     gamedir = Cvar_VariableString( "fs_game" );
00579 
00580     fn = FS_BuildOSPath( basepath, gamedir, filename );
00581     libHandle = LoadLibrary( fn );
00582 #ifndef NDEBUG
00583   if (libHandle)
00584     Com_Printf("LoadLibrary '%s' ok\n", fn);
00585   else
00586     Com_Printf("LoadLibrary '%s' failed\n", fn);
00587 #endif
00588 
00589     if ( !libHandle ) {
00590         if( cdpath[0] ) {
00591             fn = FS_BuildOSPath( cdpath, gamedir, filename );
00592             libHandle = LoadLibrary( fn );
00593 #ifndef NDEBUG
00594       if (libHandle)
00595         Com_Printf("LoadLibrary '%s' ok\n", fn);
00596       else
00597         Com_Printf("LoadLibrary '%s' failed\n", fn);
00598 #endif
00599         }
00600 
00601         if ( !libHandle ) {
00602             return NULL;
00603         }
00604     }
00605 #ifndef NDEBUG
00606     }
00607 #endif
00608 
00609     dllEntry = ( void (QDECL *)( int (QDECL *)( int, ... ) ) )GetProcAddress( libHandle, "dllEntry" ); 
00610     *entryPoint = (int (QDECL *)(int,...))GetProcAddress( libHandle, "vmMain" );
00611     if ( !*entryPoint || !dllEntry ) {
00612         FreeLibrary( libHandle );
00613         return NULL;
00614     }
00615     dllEntry( systemcalls );
00616 
00617     if ( libHandle ) Q_strncpyz ( fqpath , filename , MAX_QPATH ) ;     // added 7/20/02 by T.Ray
00618     return libHandle;
00619 }
00620 
00621 
00622 /*
00623 ========================================================================
00624 
00625 BACKGROUND FILE STREAMING
00626 
00627 ========================================================================
00628 */
00629 
00630 #if 1
00631 
00632 void Sys_InitStreamThread( void ) {
00633 }
00634 
00635 void Sys_ShutdownStreamThread( void ) {
00636 }
00637 
00638 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
00639 }
00640 
00641 void Sys_EndStreamedFile( fileHandle_t f ) {
00642 }
00643 
00644 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
00645    return FS_Read( buffer, size * count, f );
00646 }
00647 
00648 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
00649    FS_Seek( f, offset, origin );
00650 }
00651 
00652 
00653 #else
00654 
00655 typedef struct {
00656     fileHandle_t    file;
00657     byte    *buffer;
00658     qboolean    eof;
00659     qboolean    active;
00660     int     bufferSize;
00661     int     streamPosition; // next byte to be returned by Sys_StreamRead
00662     int     threadPosition; // next byte to be read from file
00663 } streamsIO_t;
00664 
00665 typedef struct {
00666     HANDLE              threadHandle;
00667     int                 threadId;
00668     CRITICAL_SECTION    crit;
00669     streamsIO_t         sIO[MAX_FILE_HANDLES];
00670 } streamState_t;
00671 
00672 streamState_t   stream;
00673 
00674 /*
00675 ===============
00676 Sys_StreamThread
00677 
00678 A thread will be sitting in this loop forever
00679 ================
00680 */
00681 void Sys_StreamThread( void ) {
00682     int     buffer;
00683     int     count;
00684     int     readCount;
00685     int     bufferPoint;
00686     int     r, i;
00687 
00688     while (1) {
00689         Sleep( 10 );
00690 //      EnterCriticalSection (&stream.crit);
00691 
00692         for (i=1;i<MAX_FILE_HANDLES;i++) {
00693             // if there is any space left in the buffer, fill it up
00694             if ( stream.sIO[i].active  && !stream.sIO[i].eof ) {
00695                 count = stream.sIO[i].bufferSize - (stream.sIO[i].threadPosition - stream.sIO[i].streamPosition);
00696                 if ( !count ) {
00697                     continue;
00698                 }
00699 
00700                 bufferPoint = stream.sIO[i].threadPosition % stream.sIO[i].bufferSize;
00701                 buffer = stream.sIO[i].bufferSize - bufferPoint;
00702                 readCount = buffer < count ? buffer : count;
00703 
00704                 r = FS_Read( stream.sIO[i].buffer + bufferPoint, readCount, stream.sIO[i].file );
00705                 stream.sIO[i].threadPosition += r;
00706 
00707                 if ( r != readCount ) {
00708                     stream.sIO[i].eof = qtrue;
00709                 }
00710             }
00711         }
00712 //      LeaveCriticalSection (&stream.crit);
00713     }
00714 }
00715 
00716 /*
00717 ===============
00718 Sys_InitStreamThread
00719 
00720 ================
00721 */
00722 void Sys_InitStreamThread( void ) {
00723     int i;
00724 
00725     InitializeCriticalSection ( &stream.crit );
00726 
00727     // don't leave the critical section until there is a
00728     // valid file to stream, which will cause the StreamThread
00729     // to sleep without any overhead
00730 //  EnterCriticalSection( &stream.crit );
00731 
00732     stream.threadHandle = CreateThread(
00733        NULL,    // LPSECURITY_ATTRIBUTES lpsa,
00734        0,       // DWORD cbStack,
00735        (LPTHREAD_START_ROUTINE)Sys_StreamThread,    // LPTHREAD_START_ROUTINE lpStartAddr,
00736        0,           // LPVOID lpvThreadParm,
00737        0,           //   DWORD fdwCreate,
00738        &stream.threadId);
00739     for(i=0;i<MAX_FILE_HANDLES;i++) {
00740         stream.sIO[i].active = qfalse;
00741     }
00742 }
00743 
00744 /*
00745 ===============
00746 Sys_ShutdownStreamThread
00747 
00748 ================
00749 */
00750 void Sys_ShutdownStreamThread( void ) {
00751 }
00752 
00753 
00754 /*
00755 ===============
00756 Sys_BeginStreamedFile
00757 
00758 ================
00759 */
00760 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
00761     if ( stream.sIO[f].file ) {
00762         Sys_EndStreamedFile( stream.sIO[f].file );
00763     }
00764 
00765     stream.sIO[f].file = f;
00766     stream.sIO[f].buffer = Z_Malloc( readAhead );
00767     stream.sIO[f].bufferSize = readAhead;
00768     stream.sIO[f].streamPosition = 0;
00769     stream.sIO[f].threadPosition = 0;
00770     stream.sIO[f].eof = qfalse;
00771     stream.sIO[f].active = qtrue;
00772 
00773     // let the thread start running
00774 //  LeaveCriticalSection( &stream.crit );
00775 }
00776 
00777 /*
00778 ===============
00779 Sys_EndStreamedFile
00780 
00781 ================
00782 */
00783 void Sys_EndStreamedFile( fileHandle_t f ) {
00784     if ( f != stream.sIO[f].file ) {
00785         Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file");
00786     }
00787     // don't leave critical section until another stream is started
00788     EnterCriticalSection( &stream.crit );
00789 
00790     stream.sIO[f].file = 0;
00791     stream.sIO[f].active = qfalse;
00792 
00793     Z_Free( stream.sIO[f].buffer );
00794 
00795     LeaveCriticalSection( &stream.crit );
00796 }
00797 
00798 
00799 /*
00800 ===============
00801 Sys_StreamedRead
00802 
00803 ================
00804 */
00805 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
00806     int     available;
00807     int     remaining;
00808     int     sleepCount;
00809     int     copy;
00810     int     bufferCount;
00811     int     bufferPoint;
00812     byte    *dest;
00813 
00814     if (stream.sIO[f].active == qfalse) {
00815         Com_Error( ERR_FATAL, "Streamed read with non-streaming file" );
00816     }
00817 
00818     dest = (byte *)buffer;
00819     remaining = size * count;
00820 
00821     if ( remaining <= 0 ) {
00822         Com_Error( ERR_FATAL, "Streamed read with non-positive size" );
00823     }
00824 
00825     sleepCount = 0;
00826     while ( remaining > 0 ) {
00827         available = stream.sIO[f].threadPosition - stream.sIO[f].streamPosition;
00828         if ( !available ) {
00829             if ( stream.sIO[f].eof ) {
00830                 break;
00831             }
00832             if ( sleepCount == 1 ) {
00833                 Com_DPrintf( "Sys_StreamedRead: waiting\n" );
00834             }
00835             if ( ++sleepCount > 100 ) {
00836                 Com_Error( ERR_FATAL, "Sys_StreamedRead: thread has died");
00837             }
00838             Sleep( 10 );
00839             continue;
00840         }
00841 
00842         EnterCriticalSection( &stream.crit );
00843 
00844         bufferPoint = stream.sIO[f].streamPosition % stream.sIO[f].bufferSize;
00845         bufferCount = stream.sIO[f].bufferSize - bufferPoint;
00846 
00847         copy = available < bufferCount ? available : bufferCount;
00848         if ( copy > remaining ) {
00849             copy = remaining;
00850         }
00851         memcpy( dest, stream.sIO[f].buffer + bufferPoint, copy );
00852         stream.sIO[f].streamPosition += copy;
00853         dest += copy;
00854         remaining -= copy;
00855 
00856         LeaveCriticalSection( &stream.crit );
00857     }
00858 
00859     return (count * size - remaining) / size;
00860 }
00861 
00862 /*
00863 ===============
00864 Sys_StreamSeek
00865 
00866 ================
00867 */
00868 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
00869 
00870     // halt the thread
00871     EnterCriticalSection( &stream.crit );
00872 
00873     // clear to that point
00874     FS_Seek( f, offset, origin );
00875     stream.sIO[f].streamPosition = 0;
00876     stream.sIO[f].threadPosition = 0;
00877     stream.sIO[f].eof = qfalse;
00878 
00879     // let the thread start running at the new position
00880     LeaveCriticalSection( &stream.crit );
00881 }
00882 
00883 #endif
00884 
00885 /*
00886 ========================================================================
00887 
00888 EVENT LOOP
00889 
00890 ========================================================================
00891 */
00892 
00893 #define MAX_QUED_EVENTS     256
00894 #define MASK_QUED_EVENTS    ( MAX_QUED_EVENTS - 1 )
00895 
00896 sysEvent_t  eventQue[MAX_QUED_EVENTS];
00897 int         eventHead, eventTail;
00898 byte        sys_packetReceived[MAX_MSGLEN];
00899 
00900 /*
00901 ================
00902 Sys_QueEvent
00903 
00904 A time of 0 will get the current time
00905 Ptr should either be null, or point to a block of data that can
00906 be freed by the game later.
00907 ================
00908 */
00909 void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
00910     sysEvent_t  *ev;
00911 
00912     ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
00913     if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
00914         Com_Printf("Sys_QueEvent: overflow\n");
00915         // we are discarding an event, but don't leak memory
00916         if ( ev->evPtr ) {
00917             Z_Free( ev->evPtr );
00918         }
00919         eventTail++;
00920     }
00921 
00922     eventHead++;
00923 
00924     if ( time == 0 ) {
00925         time = Sys_Milliseconds();
00926     }
00927 
00928     ev->evTime = time;
00929     ev->evType = type;
00930     ev->evValue = value;
00931     ev->evValue2 = value2;
00932     ev->evPtrLength = ptrLength;
00933     ev->evPtr = ptr;
00934 }
00935 
00936 /*
00937 ================
00938 Sys_GetEvent
00939 
00940 ================
00941 */
00942 sysEvent_t Sys_GetEvent( void ) {
00943     MSG         msg;
00944     sysEvent_t  ev;
00945     char        *s;
00946     msg_t       netmsg;
00947     netadr_t    adr;
00948 
00949     // return if we have data
00950     if ( eventHead > eventTail ) {
00951         eventTail++;
00952         return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
00953     }
00954 
00955     // pump the message loop
00956     while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
00957         if ( !GetMessage (&msg, NULL, 0, 0) ) {
00958             Com_Quit_f();
00959         }
00960 
00961         // save the msg time, because wndprocs don't have access to the timestamp
00962         g_wv.sysMsgTime = msg.time;
00963 
00964         TranslateMessage (&msg);
00965         DispatchMessage (&msg);
00966     }
00967 
00968     // check for console commands
00969     s = Sys_ConsoleInput();
00970     if ( s ) {
00971         char    *b;
00972         int     len;
00973 
00974         len = strlen( s ) + 1;
00975         b = Z_Malloc( len );
00976         Q_strncpyz( b, s, len-1 );
00977         Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
00978     }
00979 
00980     // check for network packets
00981     MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
00982     if ( Sys_GetPacket ( &adr, &netmsg ) ) {
00983         netadr_t        *buf;
00984         int             len;
00985 
00986         // copy out to a seperate buffer for qeueing
00987         // the readcount stepahead is for SOCKS support
00988         len = sizeof( netadr_t ) + netmsg.cursize - netmsg.readcount;
00989         buf = Z_Malloc( len );
00990         *buf = adr;
00991         memcpy( buf+1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount );
00992         Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
00993     }
00994 
00995     // return if we have data
00996     if ( eventHead > eventTail ) {
00997         eventTail++;
00998         return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
00999     }
01000 
01001     // create an empty event to return
01002 
01003     memset( &ev, 0, sizeof( ev ) );
01004     ev.evTime = timeGetTime();
01005 
01006     return ev;
01007 }
01008 
01009 //================================================================
01010 
01011 /*
01012 =================
01013 Sys_In_Restart_f
01014 
01015 Restart the input subsystem
01016 =================
01017 */
01018 void Sys_In_Restart_f( void ) {
01019     IN_Shutdown();
01020     IN_Init();
01021 }
01022 
01023 
01024 /*
01025 =================
01026 Sys_Net_Restart_f
01027 
01028 Restart the network subsystem
01029 =================
01030 */
01031 void Sys_Net_Restart_f( void ) {
01032     NET_Restart();
01033 }
01034 
01035 
01036 /*
01037 ================
01038 Sys_Init
01039 
01040 Called after the common systems (cvars, files, etc)
01041 are initialized
01042 ================
01043 */
01044 #define OSR2_BUILD_NUMBER 1111
01045 #define WIN98_BUILD_NUMBER 1998
01046 
01047 void Sys_Init( void ) {
01048     int cpuid;
01049 
01050     // make sure the timer is high precision, otherwise
01051     // NT gets 18ms resolution
01052     timeBeginPeriod( 1 );
01053 
01054     Cmd_AddCommand ("in_restart", Sys_In_Restart_f);
01055     Cmd_AddCommand ("net_restart", Sys_Net_Restart_f);
01056 
01057     g_wv.osversion.dwOSVersionInfoSize = sizeof( g_wv.osversion );
01058 
01059     if (!GetVersionEx (&g_wv.osversion))
01060         Sys_Error ("Couldn't get OS info");
01061 
01062     if (g_wv.osversion.dwMajorVersion < 4)
01063         Sys_Error ("Quake3 requires Windows version 4 or greater");
01064     if (g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32s)
01065         Sys_Error ("Quake3 doesn't run on Win32s");
01066 
01067     if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT )
01068     {
01069         Cvar_Set( "arch", "winnt" );
01070     }
01071     else if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
01072     {
01073         if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= WIN98_BUILD_NUMBER )
01074         {
01075             Cvar_Set( "arch", "win98" );
01076         }
01077         else if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
01078         {
01079             Cvar_Set( "arch", "win95 osr2.x" );
01080         }
01081         else
01082         {
01083             Cvar_Set( "arch", "win95" );
01084         }
01085     }
01086     else
01087     {
01088         Cvar_Set( "arch", "unknown Windows variant" );
01089     }
01090 
01091     // save out a couple things in rom cvars for the renderer to access
01092     Cvar_Get( "win_hinstance", va("%i", (int)g_wv.hInstance), CVAR_ROM );
01093     Cvar_Get( "win_wndproc", va("%i", (int)MainWndProc), CVAR_ROM );
01094 
01095     //
01096     // figure out our CPU
01097     //
01098     Cvar_Get( "sys_cpustring", "detect", 0 );
01099     if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring"), "detect" ) )
01100     {
01101         Com_Printf( "...detecting CPU, found " );
01102 
01103         cpuid = Sys_GetProcessorId();
01104 
01105         switch ( cpuid )
01106         {
01107         case CPUID_GENERIC:
01108             Cvar_Set( "sys_cpustring", "generic" );
01109             break;
01110         case CPUID_INTEL_UNSUPPORTED:
01111             Cvar_Set( "sys_cpustring", "x86 (pre-Pentium)" );
01112             break;
01113         case CPUID_INTEL_PENTIUM:
01114             Cvar_Set( "sys_cpustring", "x86 (P5/PPro, non-MMX)" );
01115             break;
01116         case CPUID_INTEL_MMX:
01117             Cvar_Set( "sys_cpustring", "x86 (P5/Pentium2, MMX)" );
01118             break;
01119         case CPUID_INTEL_KATMAI:
01120             Cvar_Set( "sys_cpustring", "Intel Pentium III" );
01121             break;
01122         case CPUID_AMD_3DNOW:
01123             Cvar_Set( "sys_cpustring", "AMD w/ 3DNow!" );
01124             break;
01125         case CPUID_AXP:
01126             Cvar_Set( "sys_cpustring", "Alpha AXP" );
01127             break;
01128         default:
01129             Com_Error( ERR_FATAL, "Unknown cpu type %d\n", cpuid );
01130             break;
01131         }
01132     }
01133     else
01134     {
01135         Com_Printf( "...forcing CPU type to " );
01136         if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "generic" ) )
01137         {
01138             cpuid = CPUID_GENERIC;
01139         }
01140         else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "x87" ) )
01141         {
01142             cpuid = CPUID_INTEL_PENTIUM;
01143         }
01144         else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "mmx" ) )
01145         {
01146             cpuid = CPUID_INTEL_MMX;
01147         }
01148         else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "3dnow" ) )
01149         {
01150             cpuid = CPUID_AMD_3DNOW;
01151         }
01152         else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "PentiumIII" ) )
01153         {
01154             cpuid = CPUID_INTEL_KATMAI;
01155         }
01156         else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "axp" ) )
01157         {
01158             cpuid = CPUID_AXP;
01159         }
01160         else
01161         {
01162             Com_Printf( "WARNING: unknown sys_cpustring '%s'\n", Cvar_VariableString( "sys_cpustring" ) );
01163             cpuid = CPUID_GENERIC;
01164         }
01165     }
01166     Cvar_SetValue( "sys_cpuid", cpuid );
01167     Com_Printf( "%s\n", Cvar_VariableString( "sys_cpustring" ) );
01168 
01169     Cvar_Set( "username", Sys_GetCurrentUser() );
01170 
01171     IN_Init();      // FIXME: not in dedicated?
01172 }
01173 
01174 
01175 //=======================================================================
01176 
01177 int totalMsec, countMsec;
01178 
01179 /*
01180 ==================
01181 WinMain
01182 
01183 ==================
01184 */
01185 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
01186     char        cwd[MAX_OSPATH];
01187     int         startTime, endTime;
01188 
01189     // should never get a previous instance in Win32
01190     if ( hPrevInstance ) {
01191         return 0;
01192     }
01193 
01194     g_wv.hInstance = hInstance;
01195     Q_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) );
01196 
01197     // done before Com/Sys_Init since we need this for error output
01198     Sys_CreateConsole();
01199 
01200     // no abort/retry/fail errors
01201     SetErrorMode( SEM_FAILCRITICALERRORS );
01202 
01203     // get the initial time base
01204     Sys_Milliseconds();
01205 #if 0
01206     // if we find the CD, add a +set cddir xxx command line
01207     Sys_ScanForCD();
01208 #endif
01209 
01210     Sys_InitStreamThread();
01211 
01212     Com_Init( sys_cmdline );
01213     NET_Init();
01214 
01215     _getcwd (cwd, sizeof(cwd));
01216     Com_Printf("Working directory: %s\n", cwd);
01217 
01218     // hide the early console since we've reached the point where we
01219     // have a working graphics subsystems
01220     if ( !com_dedicated->integer && !com_viewlog->integer ) {
01221         Sys_ShowConsole( 0, qfalse );
01222     }
01223 
01224     // main game loop
01225     while( 1 ) {
01226         // if not running as a game client, sleep a bit
01227         if ( g_wv.isMinimized || ( com_dedicated && com_dedicated->integer ) ) {
01228             Sleep( 5 );
01229         }
01230 
01231         // set low precision every frame, because some system calls
01232         // reset it arbitrarily
01233 //      _controlfp( _PC_24, _MCW_PC );
01234 //    _controlfp( -1, _MCW_EM  ); // no exceptions, even if some crappy
01235                                 // syscall turns them back on!
01236 
01237         startTime = Sys_Milliseconds();
01238 
01239         // make sure mouse and joystick are only called once a frame
01240         IN_Frame();
01241 
01242         // run the game
01243         Com_Frame();
01244 
01245         endTime = Sys_Milliseconds();
01246         totalMsec += endTime - startTime;
01247         countMsec++;
01248     }
01249 
01250     // never gets here
01251 }
01252 
01253 

Generated on Thu Aug 25 12:38:05 2005 for Quake III Arena by  doxygen 1.3.9.1