📄 win_main.c
字号:
#if 1
void Sys_InitStreamThread( void ) {
}
void Sys_ShutdownStreamThread( void ) {
}
void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
}
void Sys_EndStreamedFile( fileHandle_t f ) {
}
int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
return FS_Read( buffer, size * count, f );
}
void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
FS_Seek( f, offset, origin );
}
#else
typedef struct {
fileHandle_t file;
byte *buffer;
qboolean eof;
qboolean active;
int bufferSize;
int streamPosition; // next byte to be returned by Sys_StreamRead
int threadPosition; // next byte to be read from file
} streamsIO_t;
typedef struct {
HANDLE threadHandle;
int threadId;
CRITICAL_SECTION crit;
streamsIO_t sIO[MAX_FILE_HANDLES];
} streamState_t;
streamState_t stream;
/*
===============
Sys_StreamThread
A thread will be sitting in this loop forever
================
*/
void Sys_StreamThread( void ) {
int buffer;
int count;
int readCount;
int bufferPoint;
int r, i;
while (1) {
Sleep( 10 );
// EnterCriticalSection (&stream.crit);
for (i=1;i<MAX_FILE_HANDLES;i++) {
// if there is any space left in the buffer, fill it up
if ( stream.sIO[i].active && !stream.sIO[i].eof ) {
count = stream.sIO[i].bufferSize - (stream.sIO[i].threadPosition - stream.sIO[i].streamPosition);
if ( !count ) {
continue;
}
bufferPoint = stream.sIO[i].threadPosition % stream.sIO[i].bufferSize;
buffer = stream.sIO[i].bufferSize - bufferPoint;
readCount = buffer < count ? buffer : count;
r = FS_Read( stream.sIO[i].buffer + bufferPoint, readCount, stream.sIO[i].file );
stream.sIO[i].threadPosition += r;
if ( r != readCount ) {
stream.sIO[i].eof = qtrue;
}
}
}
// LeaveCriticalSection (&stream.crit);
}
}
/*
===============
Sys_InitStreamThread
================
*/
void Sys_InitStreamThread( void ) {
int i;
InitializeCriticalSection ( &stream.crit );
// don't leave the critical section until there is a
// valid file to stream, which will cause the StreamThread
// to sleep without any overhead
// EnterCriticalSection( &stream.crit );
stream.threadHandle = CreateThread(
NULL, // LPSECURITY_ATTRIBUTES lpsa,
0, // DWORD cbStack,
(LPTHREAD_START_ROUTINE)Sys_StreamThread, // LPTHREAD_START_ROUTINE lpStartAddr,
0, // LPVOID lpvThreadParm,
0, // DWORD fdwCreate,
&stream.threadId);
for(i=0;i<MAX_FILE_HANDLES;i++) {
stream.sIO[i].active = qfalse;
}
}
/*
===============
Sys_ShutdownStreamThread
================
*/
void Sys_ShutdownStreamThread( void ) {
}
/*
===============
Sys_BeginStreamedFile
================
*/
void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
if ( stream.sIO[f].file ) {
Sys_EndStreamedFile( stream.sIO[f].file );
}
stream.sIO[f].file = f;
stream.sIO[f].buffer = Z_Malloc( readAhead );
stream.sIO[f].bufferSize = readAhead;
stream.sIO[f].streamPosition = 0;
stream.sIO[f].threadPosition = 0;
stream.sIO[f].eof = qfalse;
stream.sIO[f].active = qtrue;
// let the thread start running
// LeaveCriticalSection( &stream.crit );
}
/*
===============
Sys_EndStreamedFile
================
*/
void Sys_EndStreamedFile( fileHandle_t f ) {
if ( f != stream.sIO[f].file ) {
Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file");
}
// don't leave critical section until another stream is started
EnterCriticalSection( &stream.crit );
stream.sIO[f].file = 0;
stream.sIO[f].active = qfalse;
Z_Free( stream.sIO[f].buffer );
LeaveCriticalSection( &stream.crit );
}
/*
===============
Sys_StreamedRead
================
*/
int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
int available;
int remaining;
int sleepCount;
int copy;
int bufferCount;
int bufferPoint;
byte *dest;
if (stream.sIO[f].active == qfalse) {
Com_Error( ERR_FATAL, "Streamed read with non-streaming file" );
}
dest = (byte *)buffer;
remaining = size * count;
if ( remaining <= 0 ) {
Com_Error( ERR_FATAL, "Streamed read with non-positive size" );
}
sleepCount = 0;
while ( remaining > 0 ) {
available = stream.sIO[f].threadPosition - stream.sIO[f].streamPosition;
if ( !available ) {
if ( stream.sIO[f].eof ) {
break;
}
if ( sleepCount == 1 ) {
Com_DPrintf( "Sys_StreamedRead: waiting\n" );
}
if ( ++sleepCount > 100 ) {
Com_Error( ERR_FATAL, "Sys_StreamedRead: thread has died");
}
Sleep( 10 );
continue;
}
EnterCriticalSection( &stream.crit );
bufferPoint = stream.sIO[f].streamPosition % stream.sIO[f].bufferSize;
bufferCount = stream.sIO[f].bufferSize - bufferPoint;
copy = available < bufferCount ? available : bufferCount;
if ( copy > remaining ) {
copy = remaining;
}
memcpy( dest, stream.sIO[f].buffer + bufferPoint, copy );
stream.sIO[f].streamPosition += copy;
dest += copy;
remaining -= copy;
LeaveCriticalSection( &stream.crit );
}
return (count * size - remaining) / size;
}
/*
===============
Sys_StreamSeek
================
*/
void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
// halt the thread
EnterCriticalSection( &stream.crit );
// clear to that point
FS_Seek( f, offset, origin );
stream.sIO[f].streamPosition = 0;
stream.sIO[f].threadPosition = 0;
stream.sIO[f].eof = qfalse;
// let the thread start running at the new position
LeaveCriticalSection( &stream.crit );
}
#endif
/*
========================================================================
EVENT LOOP
========================================================================
*/
#define MAX_QUED_EVENTS 256
#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 )
sysEvent_t eventQue[MAX_QUED_EVENTS];
int eventHead, eventTail;
byte sys_packetReceived[MAX_MSGLEN];
/*
================
Sys_QueEvent
A time of 0 will get the current time
Ptr should either be null, or point to a block of data that can
be freed by the game later.
================
*/
void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
sysEvent_t *ev;
ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
if ( eventHead - eventTail >= MAX_QUED_EVENTS ) {
Com_Printf("Sys_QueEvent: overflow\n");
// we are discarding an event, but don't leak memory
if ( ev->evPtr ) {
Z_Free( ev->evPtr );
}
eventTail++;
}
eventHead++;
if ( time == 0 ) {
time = Sys_Milliseconds();
}
ev->evTime = time;
ev->evType = type;
ev->evValue = value;
ev->evValue2 = value2;
ev->evPtrLength = ptrLength;
ev->evPtr = ptr;
}
/*
================
Sys_GetEvent
================
*/
sysEvent_t Sys_GetEvent( void ) {
MSG msg;
sysEvent_t ev;
char *s;
msg_t netmsg;
netadr_t adr;
// return if we have data
if ( eventHead > eventTail ) {
eventTail++;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// pump the message loop
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
if ( !GetMessage (&msg, NULL, 0, 0) ) {
Com_Quit_f();
}
// save the msg time, because wndprocs don't have access to the timestamp
g_wv.sysMsgTime = msg.time;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
// check for console commands
s = Sys_ConsoleInput();
if ( s ) {
char *b;
int len;
len = strlen( s ) + 1;
b = Z_Malloc( len );
Q_strncpyz( b, s, len-1 );
Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
}
// check for network packets
MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
if ( Sys_GetPacket ( &adr, &netmsg ) ) {
netadr_t *buf;
int len;
// copy out to a seperate buffer for qeueing
// the readcount stepahead is for SOCKS support
len = sizeof( netadr_t ) + netmsg.cursize - netmsg.readcount;
buf = Z_Malloc( len );
*buf = adr;
memcpy( buf+1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount );
Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
}
// return if we have data
if ( eventHead > eventTail ) {
eventTail++;
return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
}
// create an empty event to return
memset( &ev, 0, sizeof( ev ) );
ev.evTime = timeGetTime();
return ev;
}
//================================================================
/*
=================
Sys_In_Restart_f
Restart the input subsystem
=================
*/
void Sys_In_Restart_f( void ) {
IN_Shutdown();
IN_Init();
}
/*
=================
Sys_Net_Restart_f
Restart the network subsystem
=================
*/
void Sys_Net_Restart_f( void ) {
NET_Restart();
}
/*
================
Sys_Init
Called after the common systems (cvars, files, etc)
are initialized
================
*/
#define OSR2_BUILD_NUMBER 1111
#define WIN98_BUILD_NUMBER 1998
void Sys_Init( void ) {
int cpuid;
// make sure the timer is high precision, otherwise
// NT gets 18ms resolution
timeBeginPeriod( 1 );
Cmd_AddCommand ("in_restart", Sys_In_Restart_f);
Cmd_AddCommand ("net_restart", Sys_Net_Restart_f);
g_wv.osversion.dwOSVersionInfoSize = sizeof( g_wv.osversion );
if (!GetVersionEx (&g_wv.osversion))
Sys_Error ("Couldn't get OS info");
if (g_wv.osversion.dwMajorVersion < 4)
Sys_Error ("Quake3 requires Windows version 4 or greater");
if (g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32s)
Sys_Error ("Quake3 doesn't run on Win32s");
if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT )
{
Cvar_Set( "arch", "winnt" );
}
else if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
{
if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= WIN98_BUILD_NUMBER )
{
Cvar_Set( "arch", "win98" );
}
else if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
{
Cvar_Set( "arch", "win95 osr2.x" );
}
else
{
Cvar_Set( "arch", "win95" );
}
}
else
{
Cvar_Set( "arch", "unknown Windows variant" );
}
// save out a couple things in rom cvars for the renderer to access
Cvar_Get( "win_hinstance", va("%i", (int)g_wv.hInstance), CVAR_ROM );
Cvar_Get( "win_wndproc", va("%i", (int)MainWndProc), CVAR_ROM );
//
// figure out our CPU
//
Cvar_Get( "sys_cpustring", "detect", 0 );
if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring"), "detect" ) )
{
Com_Printf( "...detecting CPU, found " );
cpuid = Sys_GetProcessorId();
switch ( cpuid )
{
case CPUID_GENERIC:
Cvar_Set( "sys_cpustring", "generic" );
break;
case CPUID_INTEL_UNSUPPORTED:
Cvar_Set( "sys_cpustring", "x86 (pre-Pentium)" );
break;
case CPUID_INTEL_PENTIUM:
Cvar_Set( "sys_cpustring", "x86 (P5/PPro, non-MMX)" );
break;
case CPUID_INTEL_MMX:
Cvar_Set( "sys_cpustring", "x86 (P5/Pentium2, MMX)" );
break;
case CPUID_INTEL_KATMAI:
Cvar_Set( "sys_cpustring", "Intel Pentium III" );
break;
case CPUID_AMD_3DNOW:
Cvar_Set( "sys_cpustring", "AMD w/ 3DNow!" );
break;
case CPUID_AXP:
Cvar_Set( "sys_cpustring", "Alpha AXP" );
break;
default:
Com_Error( ERR_FATAL, "Unknown cpu type %d\n", cpuid );
break;
}
}
else
{
Com_Printf( "...forcing CPU type to " );
if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "generic" ) )
{
cpuid = CPUID_GENERIC;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "x87" ) )
{
cpuid = CPUID_INTEL_PENTIUM;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "mmx" ) )
{
cpuid = CPUID_INTEL_MMX;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "3dnow" ) )
{
cpuid = CPUID_AMD_3DNOW;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "PentiumIII" ) )
{
cpuid = CPUID_INTEL_KATMAI;
}
else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "axp" ) )
{
cpuid = CPUID_AXP;
}
else
{
Com_Printf( "WARNING: unknown sys_cpustring '%s'\n", Cvar_VariableString( "sys_cpustring" ) );
cpuid = CPUID_GENERIC;
}
}
Cvar_SetValue( "sys_cpuid", cpuid );
Com_Printf( "%s\n", Cvar_VariableString( "sys_cpustring" ) );
Cvar_Set( "username", Sys_GetCurrentUser() );
IN_Init(); // FIXME: not in dedicated?
}
//=======================================================================
int totalMsec, countMsec;
/*
==================
WinMain
==================
*/
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
char cwd[MAX_OSPATH];
int startTime, endTime;
// should never get a previous instance in Win32
if ( hPrevInstance ) // hPrevInstance 不是无效吗???
{
return 0;
}
g_wv.hInstance = hInstance;
Q_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) ); // 全局函数
// done before Com/Sys_Init since we need this for error output
Sys_CreateConsole(); // 全局函数,创建控件台
// no abort/retry/fail errors
SetErrorMode( SEM_FAILCRITICALERRORS ); // api function
// get the initial time base
Sys_Milliseconds(); // 全局函数
#if 0
// if we find the CD, add a +set cddir xxx command line
Sys_ScanForCD(); // 全局函数
#endif
Sys_InitStreamThread(); // 全局函数
Com_Init( sys_cmdline ); // 全局函数
NET_Init();
_getcwd (cwd, sizeof(cwd)); // api function
Com_Printf("Working directory: %s\n", cwd); // 全局函数
// hide the early console since we've reached the point where we
// have a working graphics subsystems
if ( !com_dedicated->integer && !com_viewlog->integer )
{
Sys_ShowConsole( 0, qfalse );
}
// main game loop
while( 1 ) {
// if not running as a game client, sleep a bit
if ( g_wv.isMinimized || ( com_dedicated && com_dedicated->integer ) ) {
Sleep( 5 );
}
// set low precision every frame, because some system calls
// reset it arbitrarily
// _controlfp( _PC_24, _MCW_PC );
// _controlfp( -1, _MCW_EM ); // no exceptions, even if some crappy
// syscall turns them back on!
startTime = Sys_Milliseconds();
// make sure mouse and joystick are only called once a frame
IN_Frame();
// run the game
Com_Frame();
endTime = Sys_Milliseconds();
totalMsec += endTime - startTime;
countMsec++;
}
// never gets here
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -