diff options
author | Tim Angus <tim@ngus.net> | 2009-10-03 15:17:16 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2013-01-03 00:16:38 +0000 |
commit | 6d2ffb4c637a49983bc6ce22b68ccec0ed09e0f4 (patch) | |
tree | ff15343e4a2ae5a2512c1c21e05a3821a46f10da /src | |
parent | e9e52d0b7ec9bae071534df7581126d69d3e9bf8 (diff) |
* Merge ioq3-r1637
Diffstat (limited to 'src')
48 files changed, 2560 insertions, 1110 deletions
diff --git a/src/asm/matha.s b/src/asm/matha.s index 3bc22204..e4770d37 100644 --- a/src/asm/matha.s +++ b/src/asm/matha.s @@ -28,12 +28,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #if id386 - .data - - .align 4 -Ljmptab: .long Lcase0, Lcase1, Lcase2, Lcase3 - .long Lcase4, Lcase5, Lcase6, Lcase7 - .text // TODO: rounding needed? @@ -57,368 +51,4 @@ LOutOfRange: movl $0xFFFFFFFF,%eax ret -#if 0 - -#define in 4 -#define out 8 - - .align 2 -.globl C(TransformVector) -C(TransformVector): - movl in(%esp),%eax - movl out(%esp),%edx - - flds (%eax) // in[0] - fmuls C(vright) // in[0]*vright[0] - flds (%eax) // in[0] | in[0]*vright[0] - fmuls C(vup) // in[0]*vup[0] | in[0]*vright[0] - flds (%eax) // in[0] | in[0]*vup[0] | in[0]*vright[0] - fmuls C(vpn) // in[0]*vpn[0] | in[0]*vup[0] | in[0]*vright[0] - - flds 4(%eax) // in[1] | ... - fmuls C(vright)+4 // in[1]*vright[1] | ... - flds 4(%eax) // in[1] | in[1]*vright[1] | ... - fmuls C(vup)+4 // in[1]*vup[1] | in[1]*vright[1] | ... - flds 4(%eax) // in[1] | in[1]*vup[1] | in[1]*vright[1] | ... - fmuls C(vpn)+4 // in[1]*vpn[1] | in[1]*vup[1] | in[1]*vright[1] | ... - fxch %st(2) // in[1]*vright[1] | in[1]*vup[1] | in[1]*vpn[1] | ... - - faddp %st(0),%st(5) // in[1]*vup[1] | in[1]*vpn[1] | ... - faddp %st(0),%st(3) // in[1]*vpn[1] | ... - faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum - - flds 8(%eax) // in[2] | ... - fmuls C(vright)+8 // in[2]*vright[2] | ... - flds 8(%eax) // in[2] | in[2]*vright[2] | ... - fmuls C(vup)+8 // in[2]*vup[2] | in[2]*vright[2] | ... - flds 8(%eax) // in[2] | in[2]*vup[2] | in[2]*vright[2] | ... - fmuls C(vpn)+8 // in[2]*vpn[2] | in[2]*vup[2] | in[2]*vright[2] | ... - fxch %st(2) // in[2]*vright[2] | in[2]*vup[2] | in[2]*vpn[2] | ... - - faddp %st(0),%st(5) // in[2]*vup[2] | in[2]*vpn[2] | ... - faddp %st(0),%st(3) // in[2]*vpn[2] | ... - faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum - - fstps 8(%edx) // out[2] - fstps 4(%edx) // out[1] - fstps (%edx) // out[0] - - ret - -#endif - -#define EMINS 4+4 -#define EMAXS 4+8 -#define P 4+12 - - .align 2 -.globl C(BoxOnPlaneSide) -C(BoxOnPlaneSide): - pushl %ebx - - movl P(%esp),%edx - movl EMINS(%esp),%ecx - xorl %eax,%eax - movl EMAXS(%esp),%ebx - movb pl_signbits(%edx),%al - cmpb $8,%al - jge Lerror - flds pl_normal(%edx) // p->normal[0] - fld %st(0) // p->normal[0] | p->normal[0] - // bk000422 - warning: missing prefix `*' in absolute indirect address, maybe misassembled! - // bk001129 - fix from Andrew Henderson, was: Ljmptab(,%eax,4) - jmp *Ljmptab(,%eax,4) - - -//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; -//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; -Lcase0: - fmuls (%ebx) // p->normal[0]*emaxs[0] | p->normal[0] - flds pl_normal+4(%edx) // p->normal[1] | p->normal[0]*emaxs[0] | - // p->normal[0] - fxch %st(2) // p->normal[0] | p->normal[0]*emaxs[0] | - // p->normal[1] - fmuls (%ecx) // p->normal[0]*emins[0] | - // p->normal[0]*emaxs[0] | p->normal[1] - fxch %st(2) // p->normal[1] | p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fld %st(0) // p->normal[1] | p->normal[1] | - // p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fmuls 4(%ebx) // p->normal[1]*emaxs[1] | p->normal[1] | - // p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - flds pl_normal+8(%edx) // p->normal[2] | p->normal[1]*emaxs[1] | - // p->normal[1] | p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fxch %st(2) // p->normal[1] | p->normal[1]*emaxs[1] | - // p->normal[2] | p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fmuls 4(%ecx) // p->normal[1]*emins[1] | - // p->normal[1]*emaxs[1] | - // p->normal[2] | p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fxch %st(2) // p->normal[2] | p->normal[1]*emaxs[1] | - // p->normal[1]*emins[1] | - // p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fld %st(0) // p->normal[2] | p->normal[2] | - // p->normal[1]*emaxs[1] | - // p->normal[1]*emins[1] | - // p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fmuls 8(%ebx) // p->normal[2]*emaxs[2] | - // p->normal[2] | - // p->normal[1]*emaxs[1] | - // p->normal[1]*emins[1] | - // p->normal[0]*emaxs[0] | - // p->normal[0]*emins[0] - fxch %st(5) // p->normal[0]*emins[0] | - // p->normal[2] | - // p->normal[1]*emaxs[1] | - // p->normal[1]*emins[1] | - // p->normal[0]*emaxs[0] | - // p->normal[2]*emaxs[2] - faddp %st(0),%st(3) //p->normal[2] | - // p->normal[1]*emaxs[1] | - // p->normal[1]*emins[1]+p->normal[0]*emins[0]| - // p->normal[0]*emaxs[0] | - // p->normal[2]*emaxs[2] - fmuls 8(%ecx) //p->normal[2]*emins[2] | - // p->normal[1]*emaxs[1] | - // p->normal[1]*emins[1]+p->normal[0]*emins[0]| - // p->normal[0]*emaxs[0] | - // p->normal[2]*emaxs[2] - fxch %st(1) //p->normal[1]*emaxs[1] | - // p->normal[2]*emins[2] | - // p->normal[1]*emins[1]+p->normal[0]*emins[0]| - // p->normal[0]*emaxs[0] | - // p->normal[2]*emaxs[2] - faddp %st(0),%st(3) //p->normal[2]*emins[2] | - // p->normal[1]*emins[1]+p->normal[0]*emins[0]| - // p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]| - // p->normal[2]*emaxs[2] - fxch %st(3) //p->normal[2]*emaxs[2] + - // p->normal[1]*emins[1]+p->normal[0]*emins[0]| - // p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]| - // p->normal[2]*emins[2] - faddp %st(0),%st(2) //p->normal[1]*emins[1]+p->normal[0]*emins[0]| - // dist1 | p->normal[2]*emins[2] - - jmp LSetSides - -//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; -//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; -Lcase1: - fmuls (%ecx) // emins[0] - flds pl_normal+4(%edx) - fxch %st(2) - fmuls (%ebx) // emaxs[0] - fxch %st(2) - fld %st(0) - fmuls 4(%ebx) // emaxs[1] - flds pl_normal+8(%edx) - fxch %st(2) - fmuls 4(%ecx) // emins[1] - fxch %st(2) - fld %st(0) - fmuls 8(%ebx) // emaxs[2] - fxch %st(5) - faddp %st(0),%st(3) - fmuls 8(%ecx) // emins[2] - fxch %st(1) - faddp %st(0),%st(3) - fxch %st(3) - faddp %st(0),%st(2) - - jmp LSetSides - -//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; -//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; -Lcase2: - fmuls (%ebx) // emaxs[0] - flds pl_normal+4(%edx) - fxch %st(2) - fmuls (%ecx) // emins[0] - fxch %st(2) - fld %st(0) - fmuls 4(%ecx) // emins[1] - flds pl_normal+8(%edx) - fxch %st(2) - fmuls 4(%ebx) // emaxs[1] - fxch %st(2) - fld %st(0) - fmuls 8(%ebx) // emaxs[2] - fxch %st(5) - faddp %st(0),%st(3) - fmuls 8(%ecx) // emins[2] - fxch %st(1) - faddp %st(0),%st(3) - fxch %st(3) - faddp %st(0),%st(2) - - jmp LSetSides - -//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; -//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; -Lcase3: - fmuls (%ecx) // emins[0] - flds pl_normal+4(%edx) - fxch %st(2) - fmuls (%ebx) // emaxs[0] - fxch %st(2) - fld %st(0) - fmuls 4(%ecx) // emins[1] - flds pl_normal+8(%edx) - fxch %st(2) - fmuls 4(%ebx) // emaxs[1] - fxch %st(2) - fld %st(0) - fmuls 8(%ebx) // emaxs[2] - fxch %st(5) - faddp %st(0),%st(3) - fmuls 8(%ecx) // emins[2] - fxch %st(1) - faddp %st(0),%st(3) - fxch %st(3) - faddp %st(0),%st(2) - - jmp LSetSides - -//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; -//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; -Lcase4: - fmuls (%ebx) // emaxs[0] - flds pl_normal+4(%edx) - fxch %st(2) - fmuls (%ecx) // emins[0] - fxch %st(2) - fld %st(0) - fmuls 4(%ebx) // emaxs[1] - flds pl_normal+8(%edx) - fxch %st(2) - fmuls 4(%ecx) // emins[1] - fxch %st(2) - fld %st(0) - fmuls 8(%ecx) // emins[2] - fxch %st(5) - faddp %st(0),%st(3) - fmuls 8(%ebx) // emaxs[2] - fxch %st(1) - faddp %st(0),%st(3) - fxch %st(3) - faddp %st(0),%st(2) - - jmp LSetSides - -//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; -//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; -Lcase5: - fmuls (%ecx) // emins[0] - flds pl_normal+4(%edx) - fxch %st(2) - fmuls (%ebx) // emaxs[0] - fxch %st(2) - fld %st(0) - fmuls 4(%ebx) // emaxs[1] - flds pl_normal+8(%edx) - fxch %st(2) - fmuls 4(%ecx) // emins[1] - fxch %st(2) - fld %st(0) - fmuls 8(%ecx) // emins[2] - fxch %st(5) - faddp %st(0),%st(3) - fmuls 8(%ebx) // emaxs[2] - fxch %st(1) - faddp %st(0),%st(3) - fxch %st(3) - faddp %st(0),%st(2) - - jmp LSetSides - -//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; -//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; -Lcase6: - fmuls (%ebx) // emaxs[0] - flds pl_normal+4(%edx) - fxch %st(2) - fmuls (%ecx) // emins[0] - fxch %st(2) - fld %st(0) - fmuls 4(%ecx) // emins[1] - flds pl_normal+8(%edx) - fxch %st(2) - fmuls 4(%ebx) // emaxs[1] - fxch %st(2) - fld %st(0) - fmuls 8(%ecx) // emins[2] - fxch %st(5) - faddp %st(0),%st(3) - fmuls 8(%ebx) // emaxs[2] - fxch %st(1) - faddp %st(0),%st(3) - fxch %st(3) - faddp %st(0),%st(2) - - jmp LSetSides - -//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; -//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; -Lcase7: - fmuls (%ecx) // emins[0] - flds pl_normal+4(%edx) - fxch %st(2) - fmuls (%ebx) // emaxs[0] - fxch %st(2) - fld %st(0) - fmuls 4(%ecx) // emins[1] - flds pl_normal+8(%edx) - fxch %st(2) - fmuls 4(%ebx) // emaxs[1] - fxch %st(2) - fld %st(0) - fmuls 8(%ecx) // emins[2] - fxch %st(5) - faddp %st(0),%st(3) - fmuls 8(%ebx) // emaxs[2] - fxch %st(1) - faddp %st(0),%st(3) - fxch %st(3) - faddp %st(0),%st(2) - -LSetSides: - -// sides = 0; -// if (dist1 >= p->dist) -// sides = 1; -// if (dist2 < p->dist) -// sides |= 2; - - faddp %st(0),%st(2) // dist1 | dist2 - fcomps pl_dist(%edx) - xorl %ecx,%ecx - fnstsw %ax - fcomps pl_dist(%edx) - andb $1,%ah - xorb $1,%ah - addb %ah,%cl - - fnstsw %ax - andb $1,%ah - addb %ah,%ah - addb %ah,%cl - -// return sides; - - popl %ebx - movl %ecx,%eax // return status - - ret - - -Lerror: - movl 1, %eax - ret - #endif // id386 diff --git a/src/asm/qasm.h b/src/asm/qasm.h index b26e9524..e12e2adb 100644 --- a/src/asm/qasm.h +++ b/src/asm/qasm.h @@ -34,13 +34,4 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define C(label) _##label #endif -// plane_t structure -// !!! if this is changed, it must be changed in q_shared.h too !!! -#define pl_normal 0 -#define pl_dist 12 -#define pl_type 16 -#define pl_signbits 17 -#define pl_pad 18 -#define pl_size 20 - #endif diff --git a/src/client/cl_avi.c b/src/client/cl_avi.c index df7bc7b9..fee1340e 100644 --- a/src/client/cl_avi.c +++ b/src/client/cl_avi.c @@ -555,7 +555,7 @@ void CL_WriteAVIAudioFrame( const byte *pcmBuffer, int size ) afd.numAudioFrames++; afd.moviSize += ( chunkSize + paddingSize ); - afd.a.totalBytes =+ bytesInBuffer; + afd.a.totalBytes += bytesInBuffer; // Index bufIndex = 0; diff --git a/src/client/cl_cgame.c b/src/client/cl_cgame.c index 9a16d3bf..d30d4ac0 100644 --- a/src/client/cl_cgame.c +++ b/src/client/cl_cgame.c @@ -336,6 +336,8 @@ rescan: // clear notify lines and outgoing commands before passing // the restart to the cgame Con_ClearNotify(); + // reparse the string, because Con_ClearNotify() may have done another Cmd_TokenizeString() + Cmd_TokenizeString( s ); Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) ); return qtrue; } diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 47cf0196..16fbe56b 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -194,8 +194,10 @@ void CL_UpdateVoipIgnore(const char *idstr, qboolean ignore) ignore ? "ignore" : "unignore", id)); Com_Printf("VoIP: %s ignoring player #%d\n", ignore ? "Now" : "No longer", id); + return; } } + Com_Printf("VoIP: invalid player ID#\n"); } static @@ -234,7 +236,19 @@ void CL_Voip_f( void ) } else if (strcmp(cmd, "unignore") == 0) { CL_UpdateVoipIgnore(Cmd_Argv(2), qfalse); } else if (strcmp(cmd, "gain") == 0) { - CL_UpdateVoipGain(Cmd_Argv(2), atof(Cmd_Argv(3))); + if (Cmd_Argc() > 3) { + CL_UpdateVoipGain(Cmd_Argv(2), atof(Cmd_Argv(3))); + } else if (Q_isanumber(Cmd_Argv(2))) { + int id = atoi(Cmd_Argv(2)); + if (id >= 0 && id < MAX_CLIENTS) { + Com_Printf("VoIP: current gain for player #%d " + "is %f\n", id, clc.voipGain[id]); + } else { + Com_Printf("VoIP: invalid player ID#\n"); + } + } else { + Com_Printf("usage: voip gain <playerID#> [value]\n"); + } } else if (strcmp(cmd, "muteall") == 0) { Com_Printf("VoIP: muting incoming voice\n"); CL_AddReliableCommand("voip muteall"); @@ -243,6 +257,10 @@ void CL_Voip_f( void ) Com_Printf("VoIP: unmuting incoming voice\n"); CL_AddReliableCommand("voip unmuteall"); clc.voipMuteAll = qfalse; + } else { + Com_Printf("usage: voip [un]ignore <playerID#>\n" + " voip [un]muteall\n" + " voip gain <playerID#> [value]\n"); } } @@ -1354,11 +1372,7 @@ void CL_RequestMotd( void ) { NET_AdrToStringwPort( cls.updateServer ) ); info[0] = 0; - // NOTE TTimo xoring against Com_Milliseconds, otherwise we may not have a true randomization - // only srand I could catch before here is tr_noise.c l:26 srand(1001) - // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=382 - // NOTE: the Com_Milliseconds xoring only affects the lower 16-bit word, - // but I decided it was enough randomization + Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds()); @@ -1531,10 +1545,14 @@ void CL_Connect_f( void ) { // if we aren't playing on a lan, we need to authenticate // with the cd key - if ( NET_IsLocalAddress( clc.serverAddress ) ) { + if(NET_IsLocalAddress(clc.serverAddress)) cls.state = CA_CHALLENGING; - } else { + else + { cls.state = CA_CONNECTING; + + // Set a client challenge number that ideally is mirrored back by the server. + clc.challenge = ((rand() << 16) ^ rand()) ^ Com_Milliseconds(); } Key_SetCatcher( 0 ); @@ -2129,7 +2147,11 @@ void CL_CheckForResend( void ) { switch ( cls.state ) { case CA_CONNECTING: // requesting a challenge - NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "getchallenge"); + + // The challenge request shall be followed by a client challenge so no malicious server can hijack this connection. + Com_sprintf(data, sizeof(data), "getchallenge %d", clc.challenge); + + NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "%s", data); break; case CA_CHALLENGING: @@ -2505,8 +2527,7 @@ Responses to broadcasts, etc */ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { char *s; - char c[ BIG_INFO_STRING ]; - char arg1[ BIG_INFO_STRING ]; + char *c; MSG_BeginReadingOOB( msg ); MSG_ReadLong( msg ); // skip the -1 @@ -2515,27 +2536,44 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { Cmd_TokenizeString( s ); - Q_strncpyz( c, Cmd_Argv( 0 ), BIG_INFO_STRING ); - Q_strncpyz( arg1, Cmd_Argv( 1 ), BIG_INFO_STRING ); + c = Cmd_Argv(0); Com_DPrintf ("CL packet %s: %s\n", NET_AdrToStringwPort(from), c); // challenge from the server we are connecting to - if ( !Q_stricmp(c, "challengeResponse") ) { - if ( cls.state != CA_CONNECTING ) { - Com_DPrintf( "Unwanted challenge response received. Ignored.\n" ); - } else { - // start sending challenge repsonse instead of challenge request packets - clc.challenge = atoi(arg1); - cls.state = CA_CHALLENGING; - clc.connectPacketCount = 0; - clc.connectTime = -99999; - - // take this address as the new server address. This allows - // a server proxy to hand off connections to multiple servers - clc.serverAddress = from; - Com_DPrintf ("challengeResponse: %d\n", clc.challenge); + if (!Q_stricmp(c, "challengeResponse")) + { + if (cls.state != CA_CONNECTING) + { + Com_DPrintf("Unwanted challenge response received. Ignored.\n"); + return; + } + + if(!NET_CompareAdr(from, clc.serverAddress)) + { + // This challenge response is not coming from the expected address. + // Check whether we have a matching client challenge to prevent + // connection hi-jacking. + + c = Cmd_Argv(2); + + if(!*c || atoi(c) != clc.challenge) + { + Com_DPrintf("Challenge response received from unexpected source. Ignored.\n"); + return; + } } + + // start sending challenge response instead of challenge request packets + clc.challenge = atoi(Cmd_Argv(1)); + cls.state = CA_CHALLENGING; + clc.connectPacketCount = 0; + clc.connectTime = -99999; + + // take this address as the new server address. This allows + // a server proxy to hand off connections to multiple servers + clc.serverAddress = from; + Com_DPrintf ("challengeResponse: %d\n", clc.challenge); return; } @@ -2546,13 +2584,11 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { return; } if ( cls.state != CA_CHALLENGING ) { - Com_Printf ("connectResponse packet while not connecting. Ignored.\n"); + Com_Printf ("connectResponse packet while not connecting. Ignored.\n"); return; } - if ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) { - Com_Printf( "connectResponse from a different address. Ignored.\n" ); - Com_Printf( "%s should have been %s\n", NET_AdrToStringwPort( from ), - NET_AdrToStringwPort( clc.serverAddress ) ); + if ( !NET_CompareAdr( from, clc.serverAddress ) ) { + Com_Printf( "connectResponse from wrong address. Ignored.\n" ); return; } Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) ); @@ -2582,7 +2618,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // echo request from server if ( !Q_stricmp(c, "echo") ) { - NET_OutOfBandPrint( NS_CLIENT, from, "%s", arg1 ); + NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) ); return; } @@ -3544,7 +3580,7 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { if ( cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr( from, cl_pinglist[i].adr ) ) { // calc ping time - cl_pinglist[i].time = cls.realtime - cl_pinglist[i].start + 1; + cl_pinglist[i].time = Sys_Milliseconds() - cl_pinglist[i].start; Com_DPrintf( "ping time %dms from %s\n", cl_pinglist[i].time, NET_AdrToString( from ) ); // save of info @@ -3936,7 +3972,7 @@ void CL_GetPing( int n, char *buf, int buflen, int *pingtime ) if (!time) { // check for timeout - time = cls.realtime - cl_pinglist[n].start; + time = Sys_Milliseconds() - cl_pinglist[n].start; maxPing = Cvar_VariableIntegerValue( "cl_maxPing" ); if( maxPing < 100 ) { maxPing = 100; @@ -4043,7 +4079,7 @@ ping_t* CL_GetFreePing( void ) { if (!pingptr->time) { - if (cls.realtime - pingptr->start < 500) + if (Sys_Milliseconds() - pingptr->start < 500) { // still waiting for response continue; @@ -4068,7 +4104,7 @@ ping_t* CL_GetFreePing( void ) for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ ) { // scan for oldest - time = cls.realtime - pingptr->start; + time = Sys_Milliseconds() - pingptr->start; if (time > oldest) { oldest = time; @@ -4121,7 +4157,7 @@ void CL_Ping_f( void ) { pingptr = CL_GetFreePing(); memcpy( &pingptr->adr, &to, sizeof (netadr_t) ); - pingptr->start = cls.realtime; + pingptr->start = Sys_Milliseconds(); pingptr->time = 0; CL_SetServerInfoByAddress(pingptr->adr, NULL, 0); @@ -4193,7 +4229,7 @@ qboolean CL_UpdateVisiblePings_f(int source) { } } memcpy(&cl_pinglist[j].adr, &server[i].adr, sizeof(netadr_t)); - cl_pinglist[j].start = cls.realtime; + cl_pinglist[j].start = Sys_Milliseconds(); cl_pinglist[j].time = 0; NET_OutOfBandPrint( NS_CLIENT, cl_pinglist[j].adr, "getinfo xxx" ); slots++; diff --git a/src/client/cl_ui.c b/src/client/cl_ui.c index 34ae04ea..6c00a353 100644 --- a/src/client/cl_ui.c +++ b/src/client/cl_ui.c @@ -295,7 +295,7 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) { Info_SetValueForKey( info, "game", server->game); Info_SetValueForKey( info, "gametype", va("%i",server->gameType)); Info_SetValueForKey( info, "nettype", va("%i",server->netType)); - Info_SetValueForKey( info, "addr", NET_AdrToString(server->adr)); + Info_SetValueForKey( info, "addr", NET_AdrToStringwPort(server->adr)); Q_strncpyz(buf, info, buflen); } else { if (buf) { diff --git a/src/client/snd_dma.c b/src/client/snd_dma.c index a418733a..c8df2daf 100644 --- a/src/client/snd_dma.c +++ b/src/client/snd_dma.c @@ -1369,17 +1369,13 @@ void S_UpdateBackgroundTrack( void ) { byte raw[30000]; // just enough to fit in a mac stack frame int fileBytes; int r; - static float musicVolume = 0.5f; if(!s_backgroundStream) { return; } - // graeme see if this is OK - musicVolume = (musicVolume + (s_musicVolume->value * 2))/4.0f; - // don't bother playing anything if musicvolume is 0 - if ( musicVolume <= 0 ) { + if ( s_musicVolume->value <= 0 ) { return; } @@ -1394,6 +1390,9 @@ void S_UpdateBackgroundTrack( void ) { // decide how much data needs to be read from the file fileSamples = bufferSamples * s_backgroundStream->info.rate / dma.speed; + if (!fileSamples) + return; + // our max buffer size fileBytes = fileSamples * (s_backgroundStream->info.width * s_backgroundStream->info.channels); if ( fileBytes > sizeof(raw) ) { @@ -1413,7 +1412,7 @@ void S_UpdateBackgroundTrack( void ) { { // add to raw buffer S_Base_RawSamples( 0, fileSamples, s_backgroundStream->info.rate, - s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, musicVolume ); + s_backgroundStream->info.width, s_backgroundStream->info.channels, raw, s_musicVolume->value ); } else { diff --git a/src/client/snd_main.c b/src/client/snd_main.c index d3391b23..c386cd75 100644 --- a/src/client/snd_main.c +++ b/src/client/snd_main.c @@ -32,6 +32,7 @@ cvar_t *s_musicVolume; cvar_t *s_doppler; cvar_t *s_backend; cvar_t *s_muteWhenMinimized; +cvar_t *s_muteWhenUnfocused; static soundInterface_t si; @@ -230,7 +231,8 @@ S_Update */ void S_Update( void ) { - if( s_muteWhenMinimized->integer && com_minimized->integer ) { + if( ( s_muteWhenMinimized->integer && com_minimized->integer ) || + ( s_muteWhenUnfocused->integer && com_unfocused->integer ) ) { S_StopAllSounds( ); return; } @@ -466,6 +468,7 @@ void S_Init( void ) s_doppler = Cvar_Get( "s_doppler", "1", CVAR_ARCHIVE ); s_backend = Cvar_Get( "s_backend", "", CVAR_ROM ); s_muteWhenMinimized = Cvar_Get( "s_muteWhenMinimized", "0", CVAR_ARCHIVE ); + s_muteWhenUnfocused = Cvar_Get( "s_muteWhenUnfocused", "0", CVAR_ARCHIVE ); cv = Cvar_Get( "s_initsound", "1", 0 ); if( !cv->integer ) { diff --git a/src/client/snd_openal.c b/src/client/snd_openal.c index 912006d8..1f91ae95 100644 --- a/src/client/snd_openal.c +++ b/src/client/snd_openal.c @@ -1419,6 +1419,8 @@ S_AL_StreamDie static void S_AL_StreamDie( int stream ) { + int numBuffers; + if ((stream < 0) || (stream >= MAX_RAW_STREAMS)) return; @@ -1427,6 +1429,16 @@ void S_AL_StreamDie( int stream ) streamPlaying[stream] = qfalse; qalSourceStop(streamSources[stream]); + + // Un-queue any buffers, and delete them + qalGetSourcei( streamSources[stream], AL_BUFFERS_PROCESSED, &numBuffers ); + while( numBuffers-- ) + { + ALuint buffer; + qalSourceUnqueueBuffers(streamSources[stream], 1, &buffer); + qalDeleteBuffers(1, &buffer); + } + S_AL_FreeStreamChannel(stream); } @@ -1726,7 +1738,6 @@ static cvar_t *s_alCapture; #ifdef _WIN32 #define ALDRIVER_DEFAULT "OpenAL32.dll" -#define ALDEVICE_DEFAULT "Generic Software" #elif defined(MACOS_X) #define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" #else @@ -1976,8 +1987,7 @@ S_AL_Init qboolean S_AL_Init( soundInterface_t *si ) { #ifdef USE_OPENAL - - qboolean enumsupport, founddev = qfalse; + const char* device = NULL; int i; if( !si ) { @@ -2001,7 +2011,9 @@ qboolean S_AL_Init( soundInterface_t *si ) s_alRolloff = Cvar_Get( "s_alRolloff", "2", CVAR_CHEAT); s_alGraceDistance = Cvar_Get("s_alGraceDistance", "512", CVAR_CHEAT); - s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE ); + s_alDriver = Cvar_Get( "s_alDriver", ALDRIVER_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH ); + + s_alDevice = Cvar_Get("s_alDevice", "", CVAR_ARCHIVE | CVAR_LATCH); // Load QAL if( !QAL_Init( s_alDriver->string ) ) @@ -2010,8 +2022,12 @@ qboolean S_AL_Init( soundInterface_t *si ) return qfalse; } + device = s_alDevice->string; + if(device && !*device) + device = NULL; + // Device enumeration support (extension is implemented reasonably only on Windows right now). - if((enumsupport = qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))) + if(qalcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) { char devicenames[1024] = ""; const char *devicelist; @@ -2027,11 +2043,9 @@ qboolean S_AL_Init( soundInterface_t *si ) // Generic Software as that one works more reliably with various sound systems. // If it's not, use OpenAL's default selection as we don't want to ignore // native hardware acceleration. - if(!strcmp(defaultdevice, "Generic Hardware")) - s_alDevice = Cvar_Get("s_alDevice", ALDEVICE_DEFAULT, CVAR_ARCHIVE | CVAR_LATCH); - else + if(!device && !strcmp(defaultdevice, "Generic Hardware")) + device = "Generic Software"; #endif - s_alDevice = Cvar_Get("s_alDevice", defaultdevice, CVAR_ARCHIVE | CVAR_LATCH); // dump a list of available devices to a cvar for the user to see. while((curlen = strlen(devicelist))) @@ -2039,26 +2053,18 @@ qboolean S_AL_Init( soundInterface_t *si ) Q_strcat(devicenames, sizeof(devicenames), devicelist); Q_strcat(devicenames, sizeof(devicenames), "\n"); - // check whether the device we want to load is available at all. - if(!strcmp(s_alDevice->string, devicelist)) - founddev = qtrue; - devicelist += curlen + 1; } s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); - - if(!founddev) - { - Cvar_ForceReset("s_alDevice"); - founddev = 1; - } } - if(founddev) - alDevice = qalcOpenDevice(s_alDevice->string); - else + alDevice = qalcOpenDevice(device); + if( !alDevice && device ) + { + Com_Printf( "Failed to open OpenAL device '%s', trying default.\n", device ); alDevice = qalcOpenDevice(NULL); + } if( !alDevice ) { @@ -2067,9 +2073,6 @@ qboolean S_AL_Init( soundInterface_t *si ) return qfalse; } - if(enumsupport) - Cvar_Set("s_alDevice", qalcGetString(alDevice, ALC_DEVICE_SPECIFIER)); - // Create OpenAL context alContext = qalcCreateContext( alDevice, NULL ); if( !alContext ) diff --git a/src/libspeex/config.h b/src/libspeex/config.h index abd35f09..e6657fc0 100644 --- a/src/libspeex/config.h +++ b/src/libspeex/config.h @@ -6,6 +6,9 @@ // SSE is enabled. #ifndef _USE_SSE # define USE_ALLOCA +# if defined(__sun) /* Solaris needs this for alloca(). */ +# define HAVE_ALLOCA_H +# endif #endif /* Default to floating point */ diff --git a/src/qcommon/cmd.c b/src/qcommon/cmd.c index e04f314c..ecf747d8 100644 --- a/src/qcommon/cmd.c +++ b/src/qcommon/cmd.c @@ -53,6 +53,8 @@ bind g "cmd use rocket ; +attack ; wait ; -attack ; cmd use blaster" void Cmd_Wait_f( void ) { if ( Cmd_Argc() == 2 ) { cmd_wait = atoi( Cmd_Argv( 1 ) ); + if ( cmd_wait < 0 ) + cmd_wait = 1; // ignore the argument } else { cmd_wait = 1; } @@ -177,7 +179,7 @@ void Cbuf_Execute (void) while (cmd_text.cursize) { - if ( cmd_wait ) { + if ( cmd_wait > 0 ) { // skip out while text still remains in buffer, leaving it // for next frame cmd_wait--; @@ -296,11 +298,7 @@ Just prints the rest of the line to the console */ void Cmd_Echo_f (void) { - int i; - - for (i=1 ; i<Cmd_Argc() ; i++) - Com_Printf ("%s ",Cmd_Argv(i)); - Com_Printf ("\n"); + Com_Printf ("%s\n", Cmd_Args()); } diff --git a/src/qcommon/common.c b/src/qcommon/common.c index ef9ee76a..b97626ed 100644 --- a/src/qcommon/common.c +++ b/src/qcommon/common.c @@ -41,8 +41,6 @@ int demo_protocols[] = #define MIN_COMHUNKMEGS 128 #define DEF_COMHUNKMEGS 128 #define DEF_COMZONEMEGS 24 -#define XSTRING(x) STRING(x) -#define STRING(x) #x #define DEF_COMHUNKMEGS_S XSTRING(DEF_COMHUNKMEGS) #define DEF_COMZONEMEGS_S XSTRING(DEF_COMZONEMEGS) @@ -1398,9 +1396,11 @@ void Com_InitSmallZoneMemory( void ) { void Com_InitZoneMemory( void ) { cvar_t *cv; - //FIXME: 05/01/06 com_zoneMegs is useless right now as neither q3config.cfg nor - // Com_StartupVariable have been executed by this point. The net result is that - // s_zoneTotal will always be set to the default value. + // Please note: com_zoneMegs can only be set on the command line, and + // not in q3config.cfg or Com_StartupVariable, as they haven't been + // executed by this point. It's a chicken and egg problem. We need the + // memory manager configured to handle those places where you would + // configure the memory manager. // allocate the random block zone cv = Cvar_Get( "com_zoneMegs", DEF_COMZONEMEGS_S, CVAR_LATCH | CVAR_ARCHIVE ); @@ -2378,6 +2378,21 @@ static void Com_DetectAltivec(void) } } +/* +================= +Com_InitRand +Seed the random number generator, if possible with an OS supplied random seed. +================= +*/ +static void Com_InitRand(void) +{ + unsigned int seed; + + if(Sys_RandomBytes((byte *) &seed, sizeof(seed))) + srand(seed); + else + srand(time(NULL)); +} /* ================= @@ -2386,6 +2401,7 @@ Com_Init */ void Com_Init( char *commandLine ) { char *s; + int qport; Com_Printf( "%s %s %s\n", Q3_VERSION, PLATFORM_STRING, __DATE__ ); @@ -2397,8 +2413,11 @@ void Com_Init( char *commandLine ) { Com_Memset( &eventQueue[ 0 ], 0, MAX_QUEUED_EVENTS * sizeof( sysEvent_t ) ); Com_Memset( &sys_packetReceived[ 0 ], 0, MAX_MSGLEN * sizeof( byte ) ); - // do this before anything else decides to push events - Com_InitPushEvent(); + // initialize the weak pseudo-random number generator for use later. + Com_InitRand(); + + // do this before anything else decides to push events + Com_InitPushEvent(); Com_InitSmallZoneMemory(); Cvar_Init (); @@ -2410,12 +2429,12 @@ void Com_Init( char *commandLine ) { // Swap_Init (); Cbuf_Init (); - Com_InitZoneMemory(); - Cmd_Init (); - // override anything from the config files with command line args Com_StartupVariable( NULL ); + Com_InitZoneMemory(); + Cmd_Init (); + // get the developer cvar set as early as possible Com_StartupVariable( "developer" ); @@ -2501,7 +2520,11 @@ void Com_Init( char *commandLine ) { com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO ); Sys_Init(); - Netchan_Init( Com_Milliseconds() & 0xffff ); // pick a port value that should be nice and random + + // Pick a random port value + Com_RandomBytes( (byte*)&qport, sizeof(int) ); + Netchan_Init( qport & 0xffff ); + VM_Init(); SV_Init(); @@ -3171,7 +3194,6 @@ void Com_RandomBytes( byte *string, int len ) return; Com_Printf( "Com_RandomBytes: using weak randomization\n" ); - srand( time( 0 ) ); for( i = 0; i < len; i++ ) string[i] = (unsigned char)( rand() % 255 ); } diff --git a/src/qcommon/cvar.c b/src/qcommon/cvar.c index c26ba543..0af10587 100644 --- a/src/qcommon/cvar.c +++ b/src/qcommon/cvar.c @@ -306,9 +306,9 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { cvar_t *var; long hash; - if ( !var_name || ! var_value ) { + if ( !var_name || ! var_value ) { Com_Error( ERR_FATAL, "Cvar_Get: NULL parameter" ); - } + } if ( !Cvar_ValidateString( var_name ) ) { Com_Printf("invalid cvar name string: %s\n", var_name ); @@ -616,15 +616,15 @@ void Cvar_SetCheatState( void ) { // set all default vars to the safe value for ( var = cvar_vars ; var ; var = var->next ) { if ( var->flags & CVAR_CHEAT ) { - // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here - // because of a different var->latchedString - if (var->latchedString) - { - Z_Free(var->latchedString); - var->latchedString = NULL; - } + // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here + // because of a different var->latchedString + if (var->latchedString) + { + Z_Free(var->latchedString); + var->latchedString = NULL; + } if (strcmp(var->resetString,var->string)) { - Cvar_Set( var->name, var->resetString ); + Cvar_Set( var->name, var->resetString ); } } } @@ -653,7 +653,7 @@ qboolean Cvar_Command( void ) { } // set the value if forcing isn't required - Cvar_Set2 (v->name, Cmd_Argv(1), qfalse); + Cvar_Set2 (v->name, Cmd_Args(), qfalse); return qtrue; } @@ -691,21 +691,44 @@ void Cvar_Print_f(void) ============ Cvar_Toggle_f -Toggles a cvar for easy single key binding +Toggles a cvar for easy single key binding, optionally through a list of +given values ============ */ void Cvar_Toggle_f( void ) { - int v; + int i, c = Cmd_Argc(); + char *curval; - if ( Cmd_Argc() != 2 ) { - Com_Printf ("usage: toggle <variable>\n"); + if(c < 2) { + Com_Printf("usage: toggle <variable> [value1, value2, ...]\n"); + return; + } + + if(c == 2) { + Cvar_Set2(Cmd_Argv(1), va("%d", + !Cvar_VariableValue(Cmd_Argv(1))), + qfalse); + return; + } + + if(c == 3) { + Com_Printf("toggle: nothing to toggle to\n"); return; } - v = Cvar_VariableValue( Cmd_Argv( 1 ) ); - v = !v; + curval = Cvar_VariableString(Cmd_Argv(1)); - Cvar_Set2 (Cmd_Argv(1), va("%i", v), qfalse); + // don't bother checking the last arg for a match since the desired + // behaviour is the same as no match (set to the first argument) + for(i = 2; i + 1 < c; i++) { + if(strcmp(curval, Cmd_Argv(i)) == 0) { + Cvar_Set2(Cmd_Argv(1), Cmd_Argv(i + 1), qfalse); + return; + } + } + + // fallback + Cvar_Set2(Cmd_Argv(1), Cmd_Argv(2), qfalse); } /* @@ -840,6 +863,11 @@ void Cvar_List_f( void ) { } else { Com_Printf(" "); } + if (var->flags & CVAR_SYSTEMINFO) { + Com_Printf("s"); + } else { + Com_Printf(" "); + } if (var->flags & CVAR_USERINFO) { Com_Printf("U"); } else { @@ -870,6 +898,11 @@ void Cvar_List_f( void ) { } else { Com_Printf(" "); } + if (var->flags & CVAR_USER_CREATED) { + Com_Printf("?"); + } else { + Com_Printf(" "); + } Com_Printf (" %s \"%s\"\n", var->name, var->string); } diff --git a/src/qcommon/files.c b/src/qcommon/files.c index 6b407c20..db7e79d4 100644 --- a/src/qcommon/files.c +++ b/src/qcommon/files.c @@ -479,7 +479,7 @@ FS_CreatePath Creates any directories needed to store the given filename ============ */ -static qboolean FS_CreatePath (char *OSPath) { +qboolean FS_CreatePath (char *OSPath) { char *ofs; // make absolutely sure that it can't back up the path @@ -502,18 +502,19 @@ static qboolean FS_CreatePath (char *OSPath) { /* ================= -FS_FilenameIsExecutable +FS_CheckFilenameIsNotExecutable ERR_FATAL if trying to maniuplate a file with the platform library extension ================= */ -static void FS_FilenameIsExecutable( const char *filename, const char *function ) +static void FS_CheckFilenameIsNotExecutable( const char *filename, + const char *function ) { // Check if the filename ends with the library extension - if( !Q_stricmp( filename + strlen( filename ) - strlen( DLL_EXT ), DLL_EXT ) ) + if( !Q_stricmp( COM_GetExtension( filename ), DLL_EXT ) ) { - Com_Error( ERR_FATAL, "%s: Not allowed to write '%s' due to %s extension\n", - function, filename, DLL_EXT ); + Com_Error( ERR_FATAL, "%s: Not allowed to manipulate '%s' due " + "to %s extension\n", function, filename, DLL_EXT ); } } @@ -532,7 +533,7 @@ static void FS_CopyFile( char *fromOSPath, char *toOSPath ) { Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath ); - FS_FilenameIsExecutable( toOSPath, __func__ ); + FS_CheckFilenameIsNotExecutable( toOSPath, __func__ ); if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) { Com_Printf( "Ignoring journal files\n"); @@ -575,7 +576,7 @@ FS_Remove =========== */ void FS_Remove( const char *osPath ) { - FS_FilenameIsExecutable( osPath, __func__ ); + FS_CheckFilenameIsNotExecutable( osPath, __func__ ); remove( osPath ); } @@ -587,7 +588,7 @@ FS_HomeRemove =========== */ void FS_HomeRemove( const char *homePath ) { - FS_FilenameIsExecutable( homePath, __func__ ); + FS_CheckFilenameIsNotExecutable( homePath, __func__ ); remove( FS_BuildOSPath( fs_homepath->string, fs_gamedir, homePath ) ); @@ -666,7 +667,7 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath ); } - FS_FilenameIsExecutable( ospath, __func__ ); + FS_CheckFilenameIsNotExecutable( ospath, __func__ ); if( FS_CreatePath( ospath ) ) { return 0; @@ -777,7 +778,7 @@ void FS_SV_Rename( const char *from, const char *to ) { Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath ); } - FS_FilenameIsExecutable( to_ospath, __func__ ); + FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); if (rename( from_ospath, to_ospath )) { // Failed, try copying it and deleting the original @@ -811,7 +812,7 @@ void FS_Rename( const char *from, const char *to ) { Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath ); } - FS_FilenameIsExecutable( to_ospath, __func__ ); + FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); if (rename( from_ospath, to_ospath )) { // Failed, try copying it and deleting the original @@ -874,7 +875,7 @@ fileHandle_t FS_FOpenFileWrite( const char *filename ) { Com_Printf( "FS_FOpenFileWrite: %s\n", ospath ); } - FS_FilenameIsExecutable( ospath, __func__ ); + FS_CheckFilenameIsNotExecutable( ospath, __func__ ); if( FS_CreatePath( ospath ) ) { return 0; @@ -922,7 +923,7 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) { Com_Printf( "FS_FOpenFileAppend: %s\n", ospath ); } - FS_FilenameIsExecutable( ospath, __func__ ); + FS_CheckFilenameIsNotExecutable( ospath, __func__ ); if( FS_CreatePath( ospath ) ) { return 0; diff --git a/src/qcommon/net_ip.c b/src/qcommon/net_ip.c index e7a52996..9ad4a821 100644 --- a/src/qcommon/net_ip.c +++ b/src/qcommon/net_ip.c @@ -92,13 +92,6 @@ typedef int SOCKET; static qboolean usingSocks = qfalse; static int networkingEnabled = 0; -#define NET_ENABLEV4 0x01 -#define NET_ENABLEV6 0x02 -// if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found. -#define NET_PRIOV6 0x04 -// disables ipv6 multicast support if set. -#define NET_DISABLEMCAST 0x08 - static cvar_t *net_enabled; static cvar_t *net_socksEnabled; @@ -274,7 +267,9 @@ Sys_StringToSockaddr */ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int sadr_len, sa_family_t family) { - struct addrinfo hints, *res = NULL, *search; + struct addrinfo hints; + struct addrinfo *res = NULL; + struct addrinfo *search = NULL; struct addrinfo *hintsp; int retval; @@ -284,8 +279,6 @@ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int s hintsp = &hints; hintsp->ai_family = family; hintsp->ai_socktype = SOCK_DGRAM; - // FIXME: we should set "->ai_flags" to AI_PASSIVE if we intend - // to use this structure for a bind() - instead of a sendto() retval = getaddrinfo(s, NULL, hintsp, &res); @@ -294,18 +287,20 @@ static qboolean Sys_StringToSockaddr(const char *s, struct sockaddr *sadr, int s if(family == AF_UNSPEC) { // Decide here and now which protocol family to use - if((net_enabled->integer & NET_ENABLEV6) && (net_enabled->integer & NET_PRIOV6)) - search = SearchAddrInfo(res, AF_INET6); + if(net_enabled->integer & NET_PRIOV6) + { + if(net_enabled->integer & NET_ENABLEV6) + search = SearchAddrInfo(res, AF_INET6); + + if(!search && (net_enabled->integer & NET_ENABLEV4)) + search = SearchAddrInfo(res, AF_INET); + } else - search = SearchAddrInfo(res, AF_INET); - - if(!search) { - if((net_enabled->integer & NET_ENABLEV6) && - (net_enabled->integer & NET_PRIOV6) && - (net_enabled->integer & NET_ENABLEV4)) + if(net_enabled->integer & NET_ENABLEV4) search = SearchAddrInfo(res, AF_INET); - else if(net_enabled->integer & NET_ENABLEV6) + + if(!search && (net_enabled->integer & NET_ENABLEV6)) search = SearchAddrInfo(res, AF_INET6); } } @@ -348,7 +343,8 @@ static void Sys_SockaddrToString(char *dest, int destlen, struct sockaddr *input else inputlen = sizeof(struct sockaddr_in); - getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST); + if(getnameinfo(input, inputlen, dest, destlen, NULL, 0, NI_NUMERICHOST) && destlen > 0) + *dest = '\0'; } /* @@ -382,47 +378,96 @@ qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ) { /* =================== -NET_CompareBaseAdr +NET_CompareBaseAdrMask -Compares without the port +Compare without port, and up to the bit number given in netmask. =================== */ -qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) +qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask) { + qboolean differed; + byte cmpmask, *addra, *addrb; + int curbyte; + if (a.type != b.type) return qfalse; if (a.type == NA_LOOPBACK) return qtrue; - if (a.type == NA_IP) + if(a.type == NA_IP) { - if(!memcmp(a.ip, b.ip, sizeof(a.ip))) - return qtrue; + addra = (byte *) &a.ip; + addrb = (byte *) &b.ip; - return qfalse; + if(netmask < 0 || netmask > 32) + netmask = 32; } - - if (a.type == NA_IP6) + else if(a.type == NA_IP6) { - if(!memcmp(a.ip6, b.ip6, sizeof(a.ip6)) && a.scope_id == b.scope_id) - return qtrue; + addra = (byte *) &a.ip6; + addrb = (byte *) &b.ip6; + if(netmask < 0 || netmask > 128) + netmask = 128; + } + else + { + Com_Printf ("NET_CompareBaseAdr: bad address type\n"); return qfalse; } - Com_Printf ("NET_CompareBaseAdr: bad address type\n"); + differed = qfalse; + curbyte = 0; + + while(netmask > 7) + { + if(addra[curbyte] != addrb[curbyte]) + { + differed = qtrue; + break; + } + + curbyte++; + netmask -= 8; + } + + if(differed) + return qfalse; + + if(netmask) + { + cmpmask = (1 << netmask) - 1; + cmpmask <<= 8 - netmask; + + if((addra[curbyte] & cmpmask) == (addrb[curbyte] & cmpmask)) + return qtrue; + } + else + return qtrue; + return qfalse; } + +/* +=================== +NET_CompareBaseAdr + +Compares without the port +=================== +*/ +qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b) +{ + return NET_CompareBaseAdrMask(a, b, -1); +} + const char *NET_AdrToString (netadr_t a) { static char s[NET_ADDRSTRMAXLEN]; if (a.type == NA_LOOPBACK) - { Com_sprintf (s, sizeof(s), "loopback"); - } else if (a.type == NA_IP || a.type == NA_IP6) { struct sockaddr_storage sadr; @@ -440,16 +485,11 @@ const char *NET_AdrToStringwPort (netadr_t a) static char s[NET_ADDRSTRMAXLEN]; if (a.type == NA_LOOPBACK) - { Com_sprintf (s, sizeof(s), "loopback"); - } - else if (a.type == NA_IP || a.type == NA_IP6) - { - if(a.type == NA_IP) - Com_sprintf(s, sizeof(s), "%s:%hu", NET_AdrToString(a), ntohs(a.port)); - else if(a.type == NA_IP6) - Com_sprintf(s, sizeof(s), "[%s]:%hu", NET_AdrToString(a), ntohs(a.port)); - } + else if(a.type == NA_IP) + Com_sprintf(s, sizeof(s), "%s:%hu", NET_AdrToString(a), ntohs(a.port)); + else if(a.type == NA_IP6) + Com_sprintf(s, sizeof(s), "[%s]:%hu", NET_AdrToString(a), ntohs(a.port)); return s; } @@ -886,7 +926,7 @@ int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, i #ifdef IPV6_V6ONLY { - int i; + int i = 1; // ipv4 addresses should not be allowed to connect via this socket. if(setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &i, sizeof(i)) == SOCKET_ERROR) @@ -1278,9 +1318,6 @@ void NET_GetLocalAddress( void ) { char hostname[256]; struct addrinfo hint; struct addrinfo *res = NULL; - struct addrinfo *search; - struct sockaddr_in mask4; - struct sockaddr_in6 mask6; if(gethostname( hostname, 256 ) == SOCKET_ERROR) return; @@ -1292,29 +1329,36 @@ void NET_GetLocalAddress( void ) { hint.ai_family = AF_UNSPEC; hint.ai_socktype = SOCK_DGRAM; - if(getaddrinfo(hostname, NULL, &hint, &res)) - return; - - /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a - * netmask with all bits set. */ - - memset(&mask4, 0, sizeof(mask4)); - memset(&mask6, 0, sizeof(mask6)); - mask4.sin_family = AF_INET; - memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr)); - mask6.sin6_family = AF_INET6; - memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr)); - - // add all IPs from returned list. - for(search = res; search; search = search->ai_next) + if(!getaddrinfo(hostname, NULL, &hint, &res)) { - if(search->ai_family == AF_INET) - NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask4); - else if(search->ai_family == AF_INET6) - NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask6); + struct sockaddr_in mask4; + struct sockaddr_in6 mask6; + struct addrinfo *search; + + /* On operating systems where it's more difficult to find out the configured interfaces, we'll just assume a + * netmask with all bits set. */ + + memset(&mask4, 0, sizeof(mask4)); + memset(&mask6, 0, sizeof(mask6)); + mask4.sin_family = AF_INET; + memset(&mask4.sin_addr.s_addr, 0xFF, sizeof(mask4.sin_addr.s_addr)); + mask6.sin6_family = AF_INET6; + memset(&mask6.sin6_addr, 0xFF, sizeof(mask6.sin6_addr)); + + // add all IPs from returned list. + for(search = res; search; search = search->ai_next) + { + if(search->ai_family == AF_INET) + NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask4); + else if(search->ai_family == AF_INET6) + NET_AddLocalAddress("", search->ai_addr, (struct sockaddr *) &mask6); + } + + Sys_ShowIP(); } - Sys_ShowIP(); + if(res) + freeaddrinfo(res); } #endif @@ -1329,11 +1373,6 @@ void NET_OpenIP( void ) { int port; int port6; - net_ip = Cvar_Get( "net_ip", "0.0.0.0", CVAR_LATCH ); - net_ip6 = Cvar_Get( "net_ip6", "::", CVAR_LATCH ); - net_port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH ); - net_port6 = Cvar_Get( "net_port6", va( "%i", PORT_SERVER ), CVAR_LATCH ); - port = net_port->integer; port6 = net_port6->integer; @@ -1397,14 +1436,8 @@ NET_GetCvars ==================== */ static qboolean NET_GetCvars( void ) { - qboolean modified; - - modified = qfalse; + int modified; - if( net_enabled && net_enabled->modified ) { - modified = qtrue; - } - #ifdef DEDICATED // I want server owners to explicitly turn on ipv6 support. net_enabled = Cvar_Get( "net_enabled", "1", CVAR_LATCH | CVAR_ARCHIVE ); @@ -1413,45 +1446,55 @@ static qboolean NET_GetCvars( void ) { * used if available due to ping */ net_enabled = Cvar_Get( "net_enabled", "3", CVAR_LATCH | CVAR_ARCHIVE ); #endif + modified = net_enabled->modified; + net_enabled->modified = qfalse; + + net_ip = Cvar_Get( "net_ip", "0.0.0.0", CVAR_LATCH ); + modified += net_ip->modified; + net_ip->modified = qfalse; + + net_ip6 = Cvar_Get( "net_ip6", "::", CVAR_LATCH ); + modified += net_ip6->modified; + net_ip6->modified = qfalse; + + net_port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH ); + modified += net_port->modified; + net_port->modified = qfalse; + + net_port6 = Cvar_Get( "net_port6", va( "%i", PORT_SERVER ), CVAR_LATCH ); + modified += net_port6->modified; + net_port6->modified = qfalse; // Some cvars for configuring multicast options which facilitates scanning for servers on local subnets. - if( net_mcast6addr && net_mcast6addr->modified ) { - modified = qtrue; - } net_mcast6addr = Cvar_Get( "net_mcast6addr", NET_MULTICAST_IP6, CVAR_LATCH | CVAR_ARCHIVE ); + modified += net_mcast6addr->modified; + net_mcast6addr->modified = qfalse; - if( net_mcast6iface && net_mcast6iface->modified ) { - modified = qtrue; - } net_mcast6iface = Cvar_Get( "net_mcast6iface", "0", CVAR_LATCH | CVAR_ARCHIVE ); + modified += net_mcast6iface->modified; + net_mcast6iface->modified = qfalse; - if( net_socksEnabled && net_socksEnabled->modified ) { - modified = qtrue; - } net_socksEnabled = Cvar_Get( "net_socksEnabled", "0", CVAR_LATCH | CVAR_ARCHIVE ); + modified += net_socksEnabled->modified; + net_socksEnabled->modified = qfalse; - if( net_socksServer && net_socksServer->modified ) { - modified = qtrue; - } net_socksServer = Cvar_Get( "net_socksServer", "", CVAR_LATCH | CVAR_ARCHIVE ); + modified += net_socksServer->modified; + net_socksServer->modified = qfalse; - if( net_socksPort && net_socksPort->modified ) { - modified = qtrue; - } net_socksPort = Cvar_Get( "net_socksPort", "1080", CVAR_LATCH | CVAR_ARCHIVE ); + modified += net_socksPort->modified; + net_socksPort->modified = qfalse; - if( net_socksUsername && net_socksUsername->modified ) { - modified = qtrue; - } net_socksUsername = Cvar_Get( "net_socksUsername", "", CVAR_LATCH | CVAR_ARCHIVE ); + modified += net_socksUsername->modified; + net_socksUsername->modified = qfalse; - if( net_socksPassword && net_socksPassword->modified ) { - modified = qtrue; - } net_socksPassword = Cvar_Get( "net_socksPassword", "", CVAR_LATCH | CVAR_ARCHIVE ); + modified += net_socksPassword->modified; + net_socksPassword->modified = qfalse; - - return modified; + return modified ? qtrue : qfalse; } @@ -1555,10 +1598,9 @@ void NET_Init( void ) { Com_Printf( "Winsock Initialized\n" ); #endif - // this is really just to get the cvars registered - NET_GetCvars(); - NET_Config( qtrue ); + + Cmd_AddCommand ("net_restart", NET_Restart_f); } @@ -1608,8 +1650,7 @@ void NET_Sleep( int msec ) { { FD_SET(ip_socket, &fdset); - if(ip_socket > highestfd) - highestfd = ip_socket; + highestfd = ip_socket; } if(ip6_socket != INVALID_SOCKET) { @@ -1621,7 +1662,7 @@ void NET_Sleep( int msec ) { timeout.tv_sec = msec/1000; timeout.tv_usec = (msec%1000)*1000; - select(ip_socket+1, &fdset, NULL, NULL, &timeout); + select(highestfd + 1, &fdset, NULL, NULL, &timeout); } @@ -1630,6 +1671,6 @@ void NET_Sleep( int msec ) { NET_Restart_f ==================== */ -void NET_Restart( void ) { +void NET_Restart_f( void ) { NET_Config( networkingEnabled ); } diff --git a/src/qcommon/q_math.c b/src/qcommon/q_math.c index e7924073..ba910a37 100644 --- a/src/qcommon/q_math.c +++ b/src/qcommon/q_math.c @@ -696,50 +696,14 @@ void SetPlaneSignbits (cplane_t *out) { BoxOnPlaneSide Returns 1, 2, or 1 + 2 - -// this is the slow, general version -int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p) -{ - int i; - float dist1, dist2; - int sides; - vec3_t corners[2]; - - for (i=0 ; i<3 ; i++) - { - if (p->normal[i] < 0) - { - corners[0][i] = emins[i]; - corners[1][i] = emaxs[i]; - } - else - { - corners[1][i] = emins[i]; - corners[0][i] = emaxs[i]; - } - } - dist1 = DotProduct (p->normal, corners[0]) - p->dist; - dist2 = DotProduct (p->normal, corners[1]) - p->dist; - sides = 0; - if (dist1 >= 0) - sides = 1; - if (dist2 < 0) - sides |= 2; - - return sides; -} - ================== */ - -#if !id386 - -int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p) +int BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p) { - float dist1, dist2; - int sides; + float dist[2]; + int sides, b, i; -// fast axial cases + // fast axial cases if (p->type < 3) { if (p->dist <= emins[p->type]) @@ -749,291 +713,27 @@ int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p) return 3; } -// general case - switch (p->signbits) + // general case + dist[0] = dist[1] = 0; + if (p->signbits < 8) // >= 8: default case is original code (dist[0]=dist[1]=0) { - case 0: - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; - break; - case 1: - dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; - break; - case 2: - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; - break; - case 3: - dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; - break; - case 4: - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; - break; - case 5: - dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; - break; - case 6: - dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; - break; - case 7: - dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; - dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; - break; - default: - dist1 = dist2 = 0; // shut up compiler - break; + for (i=0 ; i<3 ; i++) + { + b = (p->signbits >> i) & 1; + dist[ b] += p->normal[i]*emaxs[i]; + dist[!b] += p->normal[i]*emins[i]; + } } sides = 0; - if (dist1 >= p->dist) + if (dist[0] >= p->dist) sides = 1; - if (dist2 < p->dist) + if (dist[1] < p->dist) sides |= 2; return sides; } -#elif __GNUC__ -// use matha.s -#else -#pragma warning( disable: 4035 ) - -__declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p) -{ - static int bops_initialized; - static int Ljmptab[8]; - - __asm { - - push ebx - - cmp bops_initialized, 1 - je initialized - mov bops_initialized, 1 - - mov Ljmptab[0*4], offset Lcase0 - mov Ljmptab[1*4], offset Lcase1 - mov Ljmptab[2*4], offset Lcase2 - mov Ljmptab[3*4], offset Lcase3 - mov Ljmptab[4*4], offset Lcase4 - mov Ljmptab[5*4], offset Lcase5 - mov Ljmptab[6*4], offset Lcase6 - mov Ljmptab[7*4], offset Lcase7 - -initialized: - - mov edx,dword ptr[4+12+esp] - mov ecx,dword ptr[4+4+esp] - xor eax,eax - mov ebx,dword ptr[4+8+esp] - mov al,byte ptr[17+edx] - cmp al,8 - jge Lerror - fld dword ptr[0+edx] - fld st(0) - jmp dword ptr[Ljmptab+eax*4] -Lcase0: - fmul dword ptr[ebx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ecx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ebx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ecx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ebx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ecx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) - jmp LSetSides -Lcase1: - fmul dword ptr[ecx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ebx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ebx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ecx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ebx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ecx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) - jmp LSetSides -Lcase2: - fmul dword ptr[ebx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ecx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ecx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ebx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ebx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ecx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) - jmp LSetSides -Lcase3: - fmul dword ptr[ecx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ebx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ecx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ebx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ebx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ecx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) - jmp LSetSides -Lcase4: - fmul dword ptr[ebx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ecx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ebx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ecx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ecx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ebx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) - jmp LSetSides -Lcase5: - fmul dword ptr[ecx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ebx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ebx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ecx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ecx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ebx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) - jmp LSetSides -Lcase6: - fmul dword ptr[ebx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ecx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ecx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ebx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ecx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ebx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) - jmp LSetSides -Lcase7: - fmul dword ptr[ecx] - fld dword ptr[0+4+edx] - fxch st(2) - fmul dword ptr[ebx] - fxch st(2) - fld st(0) - fmul dword ptr[4+ecx] - fld dword ptr[0+8+edx] - fxch st(2) - fmul dword ptr[4+ebx] - fxch st(2) - fld st(0) - fmul dword ptr[8+ecx] - fxch st(5) - faddp st(3),st(0) - fmul dword ptr[8+ebx] - fxch st(1) - faddp st(3),st(0) - fxch st(3) - faddp st(2),st(0) -LSetSides: - faddp st(2),st(0) - fcomp dword ptr[12+edx] - xor ecx,ecx - fnstsw ax - fcomp dword ptr[12+edx] - and ah,1 - xor ah,1 - add cl,ah - fnstsw ax - and ah,1 - add ah,ah - add cl,ah - pop ebx - mov eax,ecx - ret -Lerror: - int 3 - } -} -#pragma warning( default: 4035 ) -#endif /* ================= diff --git a/src/qcommon/q_platform.h b/src/qcommon/q_platform.h index 4ce1fb56..5da62b38 100644 --- a/src/qcommon/q_platform.h +++ b/src/qcommon/q_platform.h @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define id386 0 #define idppc 0 #define idppc_altivec 0 +#define idsparc 0 #else @@ -59,6 +60,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define idppc_altivec 0 #endif +#if defined(__sparc__) && !defined(C_ONLY) +#define idsparc 1 +#else +#define idsparc 0 +#endif + #endif #ifndef __ASM_I386__ // don't include the C bits if included from qasm.h @@ -193,6 +200,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifdef __i386__ #define ARCH_STRING "x86" +#elif defined __amd64__ +#define ARCH_STRING "x86_64" #elif defined __axp__ #define ARCH_STRING "alpha" #endif diff --git a/src/qcommon/q_shared.h b/src/qcommon/q_shared.h index 622d71fe..a346bf5e 100644 --- a/src/qcommon/q_shared.h +++ b/src/qcommon/q_shared.h @@ -74,6 +74,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #endif #endif +#if (defined _MSC_VER) +#define Q_EXPORT __declspec(dllexport) +#elif (defined __SUNPRO_C) +#define Q_EXPORT __global +#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun)) +#define Q_EXPORT __attribute__((visibility("default"))) +#else +#define Q_EXPORT +#endif + /********************************************************************** VM Considerations @@ -167,6 +177,10 @@ typedef int clipHandle_t; #define NULL ((void *)0) #endif +#define STRING(s) #s +// expand constants before stringifying them +#define XSTRING(s) STRING(s) + #define MAX_QINT 0x7fffffff #define MIN_QINT (-MAX_QINT-1) diff --git a/src/qcommon/qcommon.h b/src/qcommon/qcommon.h index e4234f54..bcfd60b9 100644 --- a/src/qcommon/qcommon.h +++ b/src/qcommon/qcommon.h @@ -120,6 +120,14 @@ NET ============================================================== */ +#define NET_ENABLEV4 0x01 +#define NET_ENABLEV6 0x02 +// if this flag is set, always attempt ipv6 connections instead of ipv4 if a v6 address is found. +#define NET_PRIOV6 0x04 +// disables ipv6 multicast support if set. +#define NET_DISABLEMCAST 0x08 + + #define PACKET_BACKUP 32 // number of old messages that must be kept on client and // server for delta comrpession and ping estimation #define PACKET_MASK (PACKET_BACKUP-1) @@ -131,7 +139,7 @@ NET #define MAX_RELIABLE_COMMANDS 128 // max string commands buffered for restransmit typedef enum { - NA_BAD, // an address lookup failed + NA_BAD = 0, // an address lookup failed NA_LOOPBACK, NA_BROADCAST, NA_IP, @@ -158,7 +166,7 @@ typedef struct { void NET_Init( void ); void NET_Shutdown( void ); -void NET_Restart( void ); +void NET_Restart_f( void ); void NET_Config( qboolean enableNetworking ); void NET_FlushPacketQueue(void); void NET_SendPacket (netsrc_t sock, int length, const void *data, netadr_t to); @@ -166,6 +174,7 @@ void QDECL NET_OutOfBandPrint( netsrc_t net_socket, netadr_t adr, const char *f void QDECL NET_OutOfBandData( netsrc_t sock, netadr_t adr, byte *format, int len ); qboolean NET_CompareAdr (netadr_t a, netadr_t b); +qboolean NET_CompareBaseAdrMask(netadr_t a, netadr_t b, int netmask); qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b); qboolean NET_IsLocalAddress (netadr_t adr); const char *NET_AdrToString (netadr_t a); @@ -584,6 +593,7 @@ void FS_FreeFileList( char **list ); qboolean FS_FileExists( const char *file ); +qboolean FS_CreatePath (char *OSPath); char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); int FS_LoadStack( void ); diff --git a/src/qcommon/vm.c b/src/qcommon/vm.c index c1a829a6..713256a7 100644 --- a/src/qcommon/vm.c +++ b/src/qcommon/vm.c @@ -357,6 +357,9 @@ intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) { #endif } + +#define STACK_SIZE 0x20000 + /* ================= VM_LoadQVM @@ -424,7 +427,8 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) { // round up to next power of 2 so all data operations can // be mask protected - dataLength = header.h->dataLength + header.h->litLength + header.h->bssLength; + dataLength = header.h->dataLength + header.h->litLength + + header.h->bssLength + STACK_SIZE; for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) { } dataLength = 1 << i; @@ -516,9 +520,6 @@ If image ends in .qvm it will be interpreted, otherwise it will attempt to load as a system dll ================ */ - -#define STACK_SIZE 0x20000 - vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), vmInterpret_t interpret ) { vm_t *vm; @@ -766,7 +767,7 @@ intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) { args[4], args[5], args[6], args[7], args[8], args[9]); } else { -#if id386 // i386 calling convention doesn't need conversion +#if id386 || idsparc // i386/sparc calling convention doesn't need conversion #ifndef NO_VM_COMPILED if ( vm->compiled ) r = VM_CallCompiled( vm, (int*)&callnum ); diff --git a/src/qcommon/vm_sparc.c b/src/qcommon/vm_sparc.c new file mode 100644 index 00000000..39f2202a --- /dev/null +++ b/src/qcommon/vm_sparc.c @@ -0,0 +1,1648 @@ +/* +=========================================================================== +Copyright (C) 2009 David S. Miller <davem@davemloft.net> + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +/* This code is based almost entirely upon the vm_powerpc.c code by + * Przemyslaw Iskra. All I did was make it work on Sparc :-) -DaveM + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <time.h> +#include <stddef.h> + +#include "vm_local.h" +#include "vm_sparc.h" + +/* exit() won't be called but use it because it is marked with noreturn */ +#define DIE( reason ) \ + do { \ + Com_Error(ERR_DROP, "vm_sparc compiler error: " reason "\n"); \ + exit(1); \ + } while(0) + +/* Select Length - first value on 32 bits, second on 64 */ +#ifdef __arch64__ +#define SL(a, b) (b) +#else +#define SL(a, b) (a) +#endif + +#define rTMP G1 +#define rVMDATA G2 +#define rPSTACK G3 +#define rDATABASE G4 +#define rDATAMASK G5 + +struct sparc_opcode { + const char *name; + unsigned int opcode; + unsigned int mask; + unsigned char args[4]; +#define ARG_NONE 0 +#define ARG_RS1 1 +#define ARG_RS2 2 +#define ARG_RD 3 +#define ARG_SIMM13 4 +#define ARG_DISP30 5 +#define ARG_IMM22 6 +#define ARG_DISP22 7 +#define ARG_SWTRAP 8 +}; + +#define ARG_RS1_RS2_RD { ARG_RS1, ARG_RS2, ARG_RD } +#define ARG_RS1_SIMM13_RD { ARG_RS1, ARG_SIMM13, ARG_RD } +#define ARG_RS1_RS2 { ARG_RS1, ARG_RS2 } +#define ARG_RS2_RD { ARG_RS2, ARG_RD } + +#define OP_MASK 0xc0000000 +#define OP2_MASK 0x01c00000 +#define OP3_MASK 0x01f80000 +#define OPF_MASK 0x00003fe0 + +#define IMM 0x00002000 + +#define FMT1(op) ((op) << 30), OP_MASK +#define FMT2(op,op2) ((op) << 30)|((op2)<<22), (OP_MASK | OP2_MASK) +#define FMT3(op,op3) ((op) << 30)|((op3)<<19), (OP_MASK | OP3_MASK | IMM) +#define FMT3I(op,op3) ((op) << 30)|((op3)<<19)|IMM, (OP_MASK | OP3_MASK | IMM) +#define FMT3F(op,op3,opf) ((op) << 30)|((op3)<<19)|((opf)<<5), \ + (OP_MASK | OP3_MASK | OPF_MASK) + +#define BICC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x2)) +#define BFCC(A,COND) FMT2(0,((A<<7)|(COND<<3)|0x6)) +#define TICC(COND) FMT3I(0,((COND<<6)|0x3a)) + +enum sparc_iname { + CALL, NOP, SETHI, + + BA, BN, BNE, BE, BG, BLE, BGE, BL, BGU, BLEU, BCC, BCS, + BPOS, BNEG, BVC, BVS, + + ADDI, ADD, + ANDI, AND, + ORI, OR, + XORI, XOR, + SUBI, SUB, + ANDNI, ANDN, + ORNI, ORN, + XNORI, XNOR, + + UMULI, UMUL, + SMULI, SMUL, + UDIVI, UDIV, + SDIVI, SDIV, + + SUBCCI, SUBCC, + + SLLI, SLL, + SRLI, SRL, + SRAI, SRA, + + WRI, WR, + + SAVEI, SAVE, + RESTOREI, RESTORE, + + TA, + + JMPLI, JMPL, + + LDXI, LDX, + LDUWI, LDUW, + LDUHI, LDUH, + LDUBI, LDUB, + + STXI, STX, + STWI, STW, + STHI, STH, + STBI, STB, + + LDFI, LDF, + STFI, STF, + + FADD, FSUB, FCMP, FSTOI, FITOS, FNEG, FDIV, FMUL, + FBE, FBNE, FBL, FBGE, FBG, FBLE, +}; + +#define LDLI SL(LDUWI, LDXI) +#define LDL SL(LDUW, LDX) +#define STLI SL(STWI, STXI) +#define STL SL(STW, STX) + +#define SPARC_NOP 0x01000000 + +static const struct sparc_opcode sparc_opcodes[] = { + { "call", FMT1(1), { ARG_DISP30 }, }, + { "nop", SPARC_NOP, 0xffffffff, { ARG_NONE }, }, /* sethi %hi(0), %g0 */ + { "sethi", FMT2(0,4), { ARG_IMM22, ARG_RD }, }, + { "ba", BICC(0,8), { ARG_DISP22 }, }, + { "bn", BICC(0,0), { ARG_DISP22 }, }, + { "bne", BICC(0,9), { ARG_DISP22 }, }, + { "be", BICC(0,1), { ARG_DISP22 }, }, + { "bg", BICC(0,10), { ARG_DISP22 }, }, + { "ble", BICC(0,2), { ARG_DISP22 }, }, + { "bge", BICC(0,11), { ARG_DISP22 }, }, + { "bl", BICC(0,3), { ARG_DISP22 }, }, + { "bgu", BICC(0,12), { ARG_DISP22 }, }, + { "bleu", BICC(0,4), { ARG_DISP22 }, }, + { "bcc", BICC(0,13), { ARG_DISP22 }, }, + { "bcs", BICC(0,5), { ARG_DISP22 }, }, + { "bpos", BICC(0,14), { ARG_DISP22 }, }, + { "bneg", BICC(0,6), { ARG_DISP22 }, }, + { "bvc", BICC(0,15), { ARG_DISP22 }, }, + { "bvs", BICC(0,7), { ARG_DISP22 }, }, + + { "add", FMT3I(2, 0x00), ARG_RS1_SIMM13_RD, }, + { "add", FMT3 (2, 0x00), ARG_RS1_RS2_RD, }, + { "and", FMT3I(2, 0x01), ARG_RS1_SIMM13_RD, }, + { "and", FMT3 (2, 0x01), ARG_RS1_RS2_RD, }, + { "or", FMT3I(2, 0x02), ARG_RS1_SIMM13_RD, }, + { "or", FMT3 (2, 0x02), ARG_RS1_RS2_RD, }, + { "xor", FMT3I(2, 0x03), ARG_RS1_SIMM13_RD, }, + { "xor", FMT3 (2, 0x03), ARG_RS1_RS2_RD, }, + { "sub", FMT3I(2, 0x04), ARG_RS1_SIMM13_RD, }, + { "sub", FMT3 (2, 0x04), ARG_RS1_RS2_RD, }, + { "andn", FMT3I(2, 0x05), ARG_RS1_SIMM13_RD, }, + { "andn", FMT3 (2, 0x05), ARG_RS1_RS2_RD, }, + { "orn", FMT3I(2, 0x06), ARG_RS1_SIMM13_RD, }, + { "orn", FMT3 (2, 0x06), ARG_RS1_RS2_RD, }, + { "xnor", FMT3I(2, 0x07), ARG_RS1_SIMM13_RD, }, + { "xnor", FMT3 (2, 0x07), ARG_RS1_RS2_RD, }, + + { "umul", FMT3I(2, 0x0a), ARG_RS1_SIMM13_RD, }, + { "umul", FMT3 (2, 0x0a), ARG_RS1_RS2_RD, }, + { "smul", FMT3I(2, 0x0b), ARG_RS1_SIMM13_RD, }, + { "smul", FMT3 (2, 0x0b), ARG_RS1_RS2_RD, }, + { "udiv", FMT3I(2, 0x0e), ARG_RS1_SIMM13_RD, }, + { "udiv", FMT3 (2, 0x0e), ARG_RS1_RS2_RD, }, + { "sdiv", FMT3I(2, 0x0f), ARG_RS1_SIMM13_RD, }, + { "sdiv", FMT3 (2, 0x0f), ARG_RS1_RS2_RD, }, + + { "subcc", FMT3I(2, 0x14), ARG_RS1_SIMM13_RD, }, + { "subcc", FMT3 (2, 0x14), ARG_RS1_RS2_RD, }, + + { "sll", FMT3I(2, 0x25), ARG_RS1_SIMM13_RD, }, + { "sll", FMT3 (2, 0x25), ARG_RS1_RS2_RD, }, + { "srl", FMT3I(2, 0x26), ARG_RS1_SIMM13_RD, }, + { "srl", FMT3 (2, 0x26), ARG_RS1_RS2_RD, }, + { "sra", FMT3I(2, 0x27), ARG_RS1_SIMM13_RD, }, + { "sra", FMT3 (2, 0x27), ARG_RS1_RS2_RD, }, + + { "wr", FMT3I(2, 0x30), ARG_RS1_SIMM13_RD, }, + { "wr", FMT3 (2, 0x30), ARG_RS1_SIMM13_RD, }, + + { "save", FMT3I(2,0x3c), ARG_RS1_SIMM13_RD, }, + { "save", FMT3 (2,0x3c), ARG_RS1_RS2_RD, }, + { "restore", FMT3I(2,0x3d), ARG_RS1_SIMM13_RD, }, + { "restore", FMT3 (2,0x3d), ARG_RS1_RS2_RD, }, + { "ta", TICC(8), { ARG_SWTRAP, ARG_NONE }, }, + { "jmpl", FMT3I(2,0x38), ARG_RS1_SIMM13_RD, }, + { "jmpl", FMT3 (2,0x38), ARG_RS1_RS2_RD, }, + + { "ldx", FMT3I(3,0x0b), ARG_RS1_SIMM13_RD, }, + { "ldx", FMT3 (3,0x0b), ARG_RS1_RS2_RD, }, + { "lduw", FMT3I(3,0x00), ARG_RS1_SIMM13_RD, }, + { "lduw", FMT3 (3,0x00), ARG_RS1_RS2_RD, }, + { "lduh", FMT3I(3,0x02), ARG_RS1_SIMM13_RD, }, + { "lduh", FMT3 (3,0x02), ARG_RS1_RS2_RD, }, + { "ldub", FMT3I(3,0x01), ARG_RS1_SIMM13_RD, }, + { "ldub", FMT3 (3,0x01), ARG_RS1_RS2_RD, }, + + { "stx", FMT3I(3,0x0e), ARG_RS1_SIMM13_RD, }, + { "stx", FMT3 (3,0x0e), ARG_RS1_RS2_RD, }, + { "stw", FMT3I(3,0x04), ARG_RS1_SIMM13_RD, }, + { "stw", FMT3 (3,0x04), ARG_RS1_RS2_RD, }, + { "sth", FMT3I(3,0x06), ARG_RS1_SIMM13_RD, }, + { "sth", FMT3 (3,0x06), ARG_RS1_RS2_RD, }, + { "stb", FMT3I(3,0x05), ARG_RS1_SIMM13_RD, }, + { "stb", FMT3 (3,0x05), ARG_RS1_RS2_RD, }, + + { "ldf", FMT3I(3,0x20), ARG_RS1_SIMM13_RD, }, + { "ldf", FMT3 (3,0x20), ARG_RS1_RS2_RD, }, + { "stf", FMT3I(3,0x24), ARG_RS1_SIMM13_RD, }, + { "stf", FMT3 (3,0x24), ARG_RS1_RS2_RD, }, + + { "fadd", FMT3F(2,0x34,0x041), ARG_RS1_RS2_RD, }, + { "fsub", FMT3F(2,0x34,0x045), ARG_RS1_RS2_RD, }, + { "fcmp", FMT3F(2,0x35,0x051), ARG_RS1_RS2, }, + { "fstoi", FMT3F(2,0x34,0x0d1), ARG_RS2_RD, }, + { "fitos", FMT3F(2,0x34,0x0c4), ARG_RS2_RD, }, + + { "fneg", FMT3F(2,0x34,0x005), ARG_RS2_RD, }, + { "fdiv", FMT3F(2,0x34,0x04d), ARG_RS1_RS2_RD, }, + { "fmul", FMT3F(2,0x34,0x049), ARG_RS1_RS2_RD, }, + + { "fbe", BFCC(0,9), { ARG_DISP22 }, }, + { "fbne", BFCC(0,1), { ARG_DISP22 }, }, + { "fbl", BFCC(0,4), { ARG_DISP22 }, }, + { "fbge", BFCC(0,11), { ARG_DISP22 }, }, + { "fbg", BFCC(0,6), { ARG_DISP22 }, }, + { "fble", BFCC(0,13), { ARG_DISP22 }, }, +}; +#define SPARC_NUM_OPCODES (sizeof(sparc_opcodes) / sizeof(sparc_opcodes[0])) + +#define RS1(X) (((X) & 0x1f) << 14) +#define RS2(X) (((X) & 0x1f) << 0) +#define RD(X) (((X) & 0x1f) << 25) +#define SIMM13(X) (((X) & 0x1fff) << 0) +#define IMM22(X) (((X) & 0x3fffff) << 0) +#define DISP30(X) ((((X) >> 2) & 0x3fffffff) << 0) +#define DISP22(X) ((((X) >> 2) & 0x3fffff) << 0) +#define SWTRAP(X) (((X) & 0x7f) << 0) + +#define SIMM13_P(X) ((unsigned int) (X) + 0x1000 < 0x2000) + +static void vimm(unsigned int val, int bits, int shift, int sgned, int arg_index) +{ + unsigned int orig_val = val; + int orig_bits = bits; + + if (sgned) { + int x = (int) val; + if (x < 0) + x = -x; + val = (unsigned int) x; + bits--; + } + if (val & ~((1U << bits) - 1U)) { + Com_Printf("VM ERROR: immediate value 0x%08x out of %d bit range\n", + orig_val, orig_bits); + DIE("sparc VM bug"); + } +} + +static unsigned int sparc_assemble(enum sparc_iname iname, const int argc, const int *argv) +{ + const struct sparc_opcode *op = &sparc_opcodes[iname]; + unsigned int insn = op->opcode; + int i, flt, rd_flt; + + flt = (op->name[0] == 'f'); + rd_flt = flt || (op->name[2] == 'f'); + + for (i = 0; op->args[i] != ARG_NONE; i++) { + int val = argv[i]; + + switch (op->args[i]) { + case ARG_RS1: insn |= RS1(val); break; + case ARG_RS2: insn |= RS2(val); break; + case ARG_RD: insn |= RD(val); break; + case ARG_SIMM13: insn |= SIMM13(val); vimm(val,13,0,1,i); break; + case ARG_DISP30: insn |= DISP30(val); vimm(val,30,0,1,i); break; + case ARG_IMM22: insn |= IMM22(val); vimm(val,22,0,0,i); break; + case ARG_DISP22: insn |= DISP22(val); vimm(val,22,0,1,i); break; + case ARG_SWTRAP: insn |= SWTRAP(val); vimm(val,7,0,0,i); break; + } + } + + return insn; +} + +#define IN(inst, args...) \ +({ const int argv[] = { args }; \ + const int argc = sizeof(argv) / sizeof(argv[0]); \ + sparc_assemble(inst, argc, argv); \ +}) + +#if 0 +static void pgreg(int reg_num, int arg_index, int flt) +{ + if (!flt) { + const char *fmt[] = { "%g", "%o", "%l", "%i" }; + + Com_Printf("%s%s%d", + (arg_index ? ", " : ""), + fmt[reg_num >> 3], reg_num & 7); + } else + Com_Printf("%s%%f%d", (arg_index ? ", " : ""), reg_num); +} + +static void pimm(unsigned int val, int bits, int shift, int sgned, int arg_index) + +{ + val >>= shift; + val &= ((1 << bits) - 1); + if (sgned) { + int sval = val << (32 - bits); + sval >>= (32 - bits); + Com_Printf("%s%d", + (arg_index ? ", " : ""), sval); + } else + Com_Printf("%s0x%08x", + (arg_index ? ", " : ""), val); +} + +static void sparc_disassemble(unsigned int insn) +{ + int op_idx; + + for (op_idx = 0; op_idx < SPARC_NUM_OPCODES; op_idx++) { + const struct sparc_opcode *op = &sparc_opcodes[op_idx]; + int i, flt, rd_flt; + + if ((insn & op->mask) != op->opcode) + continue; + + flt = (op->name[0] == 'f'); + rd_flt = flt || (op->name[2] == 'f'); + + Com_Printf("ASM: %7s\t", op->name); + for (i = 0; op->args[i] != ARG_NONE; i++) { + switch (op->args[i]) { + case ARG_RS1: pgreg((insn >> 14) & 0x1f, i, flt); break; + case ARG_RS2: pgreg((insn >> 0) & 0x1f, i, flt); break; + case ARG_RD: pgreg((insn >> 25) & 0x1f, i, rd_flt); break; + case ARG_SIMM13: pimm(insn, 13, 0, 1, i); break; + case ARG_DISP30: pimm(insn, 30, 0, 0, i); break; + case ARG_IMM22: pimm(insn, 22, 0, 0, i); break; + case ARG_DISP22: pimm(insn, 22, 0, 0, i); break; + case ARG_SWTRAP: pimm(insn, 7, 0, 0, i); break; + } + } + Com_Printf("\n"); + return; + } +} +#endif + +/* + * opcode information table: + * - length of immediate value + * - returned register type + * - required register(s) type + */ +#define opImm0 0x0000 /* no immediate */ +#define opImm1 0x0001 /* 1 byte immadiate value after opcode */ +#define opImm4 0x0002 /* 4 bytes immediate value after opcode */ + +#define opRet0 0x0000 /* returns nothing */ +#define opRetI 0x0004 /* returns integer */ +#define opRetF 0x0008 /* returns float */ +#define opRetIF (opRetI | opRetF) /* returns integer or float */ + +#define opArg0 0x0000 /* requires nothing */ +#define opArgI 0x0010 /* requires integer(s) */ +#define opArgF 0x0020 /* requires float(s) */ +#define opArgIF (opArgI | opArgF) /* requires integer or float */ + +#define opArg2I 0x0040 /* requires second argument, integer */ +#define opArg2F 0x0080 /* requires second argument, float */ +#define opArg2IF (opArg2I | opArg2F) /* requires second argument, integer or float */ + +static const unsigned char vm_opInfo[256] = +{ + [OP_UNDEF] = opImm0, + [OP_IGNORE] = opImm0, + [OP_BREAK] = opImm0, + [OP_ENTER] = opImm4, + /* OP_LEAVE has to accept floats, they will be converted to ints */ + [OP_LEAVE] = opImm4 | opRet0 | opArgIF, + /* only STORE4 and POP use values from OP_CALL, + * no need to convert floats back */ + [OP_CALL] = opImm0 | opRetI | opArgI, + [OP_PUSH] = opImm0 | opRetIF, + [OP_POP] = opImm0 | opRet0 | opArgIF, + [OP_CONST] = opImm4 | opRetIF, + [OP_LOCAL] = opImm4 | opRetI, + [OP_JUMP] = opImm0 | opRet0 | opArgI, + + [OP_EQ] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_NE] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_LTI] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_LEI] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_GTI] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_GEI] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_LTU] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_LEU] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_GTU] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_GEU] = opImm4 | opRet0 | opArgI | opArg2I, + [OP_EQF] = opImm4 | opRet0 | opArgF | opArg2F, + [OP_NEF] = opImm4 | opRet0 | opArgF | opArg2F, + [OP_LTF] = opImm4 | opRet0 | opArgF | opArg2F, + [OP_LEF] = opImm4 | opRet0 | opArgF | opArg2F, + [OP_GTF] = opImm4 | opRet0 | opArgF | opArg2F, + [OP_GEF] = opImm4 | opRet0 | opArgF | opArg2F, + + [OP_LOAD1] = opImm0 | opRetI | opArgI, + [OP_LOAD2] = opImm0 | opRetI | opArgI, + [OP_LOAD4] = opImm0 | opRetIF| opArgI, + [OP_STORE1] = opImm0 | opRet0 | opArgI | opArg2I, + [OP_STORE2] = opImm0 | opRet0 | opArgI | opArg2I, + [OP_STORE4] = opImm0 | opRet0 | opArgIF| opArg2I, + [OP_ARG] = opImm1 | opRet0 | opArgIF, + [OP_BLOCK_COPY] = opImm4 | opRet0 | opArgI | opArg2I, + + [OP_SEX8] = opImm0 | opRetI | opArgI, + [OP_SEX16] = opImm0 | opRetI | opArgI, + [OP_NEGI] = opImm0 | opRetI | opArgI, + [OP_ADD] = opImm0 | opRetI | opArgI | opArg2I, + [OP_SUB] = opImm0 | opRetI | opArgI | opArg2I, + [OP_DIVI] = opImm0 | opRetI | opArgI | opArg2I, + [OP_DIVU] = opImm0 | opRetI | opArgI | opArg2I, + [OP_MODI] = opImm0 | opRetI | opArgI | opArg2I, + [OP_MODU] = opImm0 | opRetI | opArgI | opArg2I, + [OP_MULI] = opImm0 | opRetI | opArgI | opArg2I, + [OP_MULU] = opImm0 | opRetI | opArgI | opArg2I, + [OP_BAND] = opImm0 | opRetI | opArgI | opArg2I, + [OP_BOR] = opImm0 | opRetI | opArgI | opArg2I, + [OP_BXOR] = opImm0 | opRetI | opArgI | opArg2I, + [OP_BCOM] = opImm0 | opRetI | opArgI, + [OP_LSH] = opImm0 | opRetI | opArgI | opArg2I, + [OP_RSHI] = opImm0 | opRetI | opArgI | opArg2I, + [OP_RSHU] = opImm0 | opRetI | opArgI | opArg2I, + [OP_NEGF] = opImm0 | opRetF | opArgF, + [OP_ADDF] = opImm0 | opRetF | opArgF | opArg2F, + [OP_SUBF] = opImm0 | opRetF | opArgF | opArg2F, + [OP_DIVF] = opImm0 | opRetF | opArgF | opArg2F, + [OP_MULF] = opImm0 | opRetF | opArgF | opArg2F, + [OP_CVIF] = opImm0 | opRetF | opArgI, + [OP_CVFI] = opImm0 | opRetI | opArgF, +}; + +static const char *opnames[256] = { + "OP_UNDEF", "OP_IGNORE", "OP_BREAK", "OP_ENTER", "OP_LEAVE", "OP_CALL", + "OP_PUSH", "OP_POP", "OP_CONST", "OP_LOCAL", "OP_JUMP", + "OP_EQ", "OP_NE", "OP_LTI", "OP_LEI", "OP_GTI", "OP_GEI", + "OP_LTU", "OP_LEU", "OP_GTU", "OP_GEU", "OP_EQF", "OP_NEF", + "OP_LTF", "OP_LEF", "OP_GTF", "OP_GEF", + "OP_LOAD1", "OP_LOAD2", "OP_LOAD4", "OP_STORE1", "OP_STORE2", + "OP_STORE4", "OP_ARG", "OP_BLOCK_COPY", + "OP_SEX8", "OP_SEX16", + "OP_NEGI", "OP_ADD", "OP_SUB", "OP_DIVI", "OP_DIVU", + "OP_MODI", "OP_MODU", "OP_MULI", "OP_MULU", "OP_BAND", + "OP_BOR", "OP_BXOR", "OP_BCOM", "OP_LSH", "OP_RSHI", "OP_RSHU", + "OP_NEGF", "OP_ADDF", "OP_SUBF", "OP_DIVF", "OP_MULF", + "OP_CVIF", "OP_CVFI", +}; + +static void VM_Destroy_Compiled(vm_t *vm) +{ + if (vm->codeBase) { + if (munmap(vm->codeBase, vm->codeLength)) + Com_Printf(S_COLOR_RED "Memory unmap failed, possible memory leak\n"); + } + vm->codeBase = NULL; +} + +typedef struct VM_Data { + unsigned int dataLength; + unsigned int codeLength; + unsigned int *CallThunk; + int (*AsmCall)(int, int); + void (*BlockCopy)(unsigned int, unsigned int, unsigned int); + unsigned int *iPointers; + unsigned int data[0]; +} vm_data_t; + +#ifdef offsetof +# define VM_Data_Offset(field) offsetof(vm_data_t, field) +#else +# define OFFSET(structName, field) \ + ((void *)&(((structName *)NULL)->field) - NULL) +# define VM_Data_Offset(field) OFFSET(vm_data_t, field) +#endif + +struct src_insn { + unsigned char op; + unsigned int i_count; + + union { + unsigned int i; + signed int si; + signed short ss[2]; + unsigned short us[2]; + unsigned char b; + } arg; + + unsigned char dst_reg_flags; + unsigned char src1_reg_flags; + unsigned char src2_reg_flags; +#define REG_FLAGS_FLOAT 0x1 + + struct src_insn *next; +}; + +struct dst_insn; +struct jump_insn { + enum sparc_iname jump_iname; + int jump_dest_insn; + struct dst_insn *parent; + struct jump_insn *next; +}; + +struct dst_insn { + struct dst_insn *next; + + unsigned int count; + unsigned int i_count; + + struct jump_insn *jump; + unsigned int length; + unsigned int code[0]; +}; + +#define HUNK_SIZE 29 +struct data_hunk { + struct data_hunk *next; + int count; + unsigned int data[HUNK_SIZE]; +}; + +struct func_info { + struct src_insn *first; + struct src_insn *last; + int has_call; + int need_float_tmp; + + struct src_insn *cached_const; + + int stack_space; + int gpr_pos; +#define rFIRST(fp) ((fp)->gpr_pos - 1) +#define rSECOND(fp) ((fp)->gpr_pos - 2) +#define POP_GPR(fp) ((fp)->gpr_pos--) +#define PUSH_GPR(fp) ((fp)->gpr_pos++) + + int fpr_pos; +#define fFIRST(fp) ((fp)->fpr_pos - 1) +#define fSECOND(fp) ((fp)->fpr_pos - 2) +#define POP_FPR(fp) ((fp)->fpr_pos--) +#define PUSH_FPR(fp) ((fp)->fpr_pos++) + +#define INSN_BUF_SIZE 50 + unsigned int insn_buf[INSN_BUF_SIZE]; + int insn_index; + + int saved_icount; + int force_emit; + + struct jump_insn *jump_first; + struct jump_insn *jump_last; + + struct dst_insn *dst_first; + struct dst_insn *dst_last; + int dst_count; + + struct dst_insn **dst_by_i_count; + + struct data_hunk *data_first; + int data_num; +}; + +#define THUNK_ICOUNT -1 + +static unsigned int sparc_push_data(struct func_info * const fp, unsigned int val) +{ + struct data_hunk *last, *dp = fp->data_first; + int off = 0; + + last = NULL; + while (dp) { + int i; + + for (i = 0; i < dp->count; i++) { + if (dp->data[i] == val) { + off += i; + return VM_Data_Offset(data[off]); + } + } + off += dp->count; + last = dp; + dp = dp->next; + } + + dp = last; + if (!dp || dp->count >= HUNK_SIZE) { + struct data_hunk *new = Z_Malloc(sizeof(*new)); + if (!dp) + fp->data_first = new; + else + dp->next = new; + dp = new; + dp->count = 0; + dp->next = NULL; + } + dp->data[dp->count++] = val; + fp->data_num = off + 1; + return VM_Data_Offset(data[off]); +} + +static void dst_insn_insert_tail(struct func_info * const fp, + struct dst_insn *dp) +{ + if (!fp->dst_first) { + fp->dst_first = fp->dst_last = dp; + } else { + fp->dst_last->next = dp; + fp->dst_last = dp; + } +} + +static void jump_insn_insert_tail(struct func_info * const fp, + struct jump_insn *jp) +{ + if (!fp->jump_first) { + fp->jump_first = fp->jump_last = jp; + } else { + fp->jump_last->next = jp; + fp->jump_last = jp; + } +} + +static struct dst_insn *dst_new(struct func_info * const fp, unsigned int length, + struct jump_insn *jp, int insns_size) +{ + struct dst_insn *dp = Z_Malloc(sizeof(struct dst_insn) + insns_size); + + dp->length = length; + dp->jump = jp; + dp->count = fp->dst_count++; + dp->i_count = fp->saved_icount; + dp->next = NULL; + if (fp->saved_icount != THUNK_ICOUNT) + fp->dst_by_i_count[fp->saved_icount] = dp; + + return dp; +} + +static void dst_insn_append(struct func_info * const fp) +{ + int insns_size = (sizeof(unsigned int) * fp->insn_index); + struct dst_insn *dp; + + dp = dst_new(fp, fp->insn_index, NULL, insns_size); + if (insns_size) + memcpy(&dp->code[0], fp->insn_buf, insns_size); + dst_insn_insert_tail(fp, dp); + + fp->insn_index = 0; +} + +static void jump_insn_append(struct func_info * const fp, enum sparc_iname iname, int dest) +{ + struct jump_insn *jp = Z_Malloc(sizeof(*jp)); + struct dst_insn *dp; + + dp = dst_new(fp, 2, jp, 0); + + jp->jump_iname = iname; + jp->jump_dest_insn = dest; + jp->parent = dp; + jp->next = NULL; + + jump_insn_insert_tail(fp, jp); + dst_insn_insert_tail(fp, dp); +} + +static void start_emit(struct func_info * const fp, int i_count) +{ + fp->saved_icount = i_count; + fp->insn_index = 0; + fp->force_emit = 0; +} + +static void __do_emit_one(struct func_info * const fp, unsigned int insn) +{ + fp->insn_buf[fp->insn_index++] = insn; +} + +#define in(inst, args...) __do_emit_one(fp, IN(inst, args)) + +static void end_emit(struct func_info * const fp) +{ + if (fp->insn_index || fp->force_emit) + dst_insn_append(fp); +} + +static void emit_jump(struct func_info * const fp, enum sparc_iname iname, int dest) +{ + end_emit(fp); + jump_insn_append(fp, iname, dest); +} + +static void analyze_function(struct func_info * const fp) +{ + struct src_insn *value_provider[20] = { NULL }; + struct src_insn *sp = fp->first; + int opstack_depth = 0; + + while ((sp = sp->next) != NULL) { + unsigned char opi, op = sp->op; + + opi = vm_opInfo[op]; + if (opi & opArgIF) { + struct src_insn *vp = value_provider[--opstack_depth]; + unsigned char vpopi = vm_opInfo[vp->op]; + + if ((opi & opArgI) && (vpopi & opRetI)) { + /* src1 and dst are integers */ + } else if ((opi & opArgF) && (vpopi & opRetF)) { + /* src1 and dst are floats */ + vp->dst_reg_flags |= REG_FLAGS_FLOAT; + sp->src1_reg_flags = REG_FLAGS_FLOAT; + } else { + /* illegal combination */ + DIE("unrecognized instruction combination"); + } + } + if (opi & opArg2IF) { + struct src_insn *vp = value_provider[--opstack_depth]; + unsigned char vpopi = vm_opInfo[vp->op]; + + if ((opi & opArg2I) && (vpopi & opRetI)) { + /* src2 and dst are integers */ + } else if ( (opi & opArg2F) && (vpopi & opRetF) ) { + /* src2 and dst are floats */ + vp->dst_reg_flags |= REG_FLAGS_FLOAT; + sp->src2_reg_flags = REG_FLAGS_FLOAT; + } else { + /* illegal combination */ + DIE("unrecognized instruction combination"); + } + } + if (opi & opRetIF) { + value_provider[opstack_depth] = sp; + opstack_depth++; + } + } +} + +static int asmcall(int call, int pstack) +{ + vm_t *savedVM = currentVM; + int i, ret; + + currentVM->programStack = pstack - 4; + if (sizeof(intptr_t) == sizeof(int)) { + intptr_t *argPosition = (intptr_t *)((byte *)currentVM->dataBase + pstack + 4); + argPosition[0] = -1 - call; + ret = currentVM->systemCall(argPosition); + } else { + intptr_t args[11]; + + args[0] = -1 - call; + int *argPosition = (int *)((byte *)currentVM->dataBase + pstack + 4); + for( i = 1; i < 11; i++ ) + args[i] = argPosition[i]; + + ret = currentVM->systemCall(args); + } + + currentVM = savedVM; + + return ret; +} + +static void blockcopy(unsigned int dest, unsigned int src, unsigned int count) +{ + unsigned int dataMask = currentVM->dataMask; + + if ((dest & dataMask) != dest || + (src & dataMask) != src || + ((dest+count) & dataMask) != dest + count || + ((src+count) & dataMask) != src + count) { + DIE("OP_BLOCK_COPY out of range!"); + } + + memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count); +} + +static void do_emit_const(struct func_info * const fp, struct src_insn *sp) +{ + start_emit(fp, sp->i_count); + if (sp->dst_reg_flags & REG_FLAGS_FLOAT) { + in(LDFI, rVMDATA, sparc_push_data(fp, sp->arg.i), fFIRST(fp)); + } else { + if ((sp->arg.i & ~0x3ff) == 0) { + in(ORI, G0, sp->arg.i & 0x3ff, rFIRST(fp)); + } else if ((sp->arg.i & 0x3ff) == 0) { + in(SETHI, sp->arg.i >> 10, rFIRST(fp)); + } else { + in(SETHI, sp->arg.i >> 10, rFIRST(fp)); + in(ORI, rFIRST(fp), sp->arg.i & 0x3ff, rFIRST(fp)); + } + } + end_emit(fp); +} + +#define MAYBE_EMIT_CONST(fp) \ +do { if ((fp)->cached_const) { \ + int saved_i_count = (fp)->saved_icount; \ + do_emit_const(fp, (fp)->cached_const); \ + (fp)->saved_icount = saved_i_count; \ + } \ +} while (0) + +#define EMIT_FALSE_CONST(fp) \ +do { int saved_i_count = (fp)->saved_icount; \ + (fp)->saved_icount = (fp)->cached_const->i_count; \ + dst_insn_append(fp); \ + (fp)->saved_icount = saved_i_count; \ +} while (0) + +static void compile_one_insn(struct func_info * const fp, struct src_insn *sp) +{ + start_emit(fp, sp->i_count); + + switch (sp->op) { + default: + Com_Printf("VM: Unhandled opcode 0x%02x[%s]\n", + sp->op, + opnames[sp->op] ? opnames[sp->op] : "UNKNOWN"); + DIE("Unsupported opcode"); + break; + + case OP_ENTER: { + int stack = SL(64, 128); + + if (fp->need_float_tmp) + stack += 16; + + in(SAVEI, O6, -stack, O6); + if (!SIMM13_P(sp->arg.si)) { + in(SETHI, sp->arg.i >> 10, rTMP); + in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP); + in(SUB, rPSTACK, rTMP, rPSTACK); + } else + in(SUBI, rPSTACK, sp->arg.si, rPSTACK); + break; + } + case OP_LEAVE: + if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) { + EMIT_FALSE_CONST(fp); + if (fp->cached_const->src1_reg_flags & REG_FLAGS_FLOAT) + DIE("constant float in OP_LEAVE"); + + if (!SIMM13_P(sp->arg.si)) { + in(SETHI, sp->arg.i >> 10, rTMP); + in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP); + in(ADD, rPSTACK, rTMP, rPSTACK); + } else + in(ADDI, rPSTACK, sp->arg.si, rPSTACK); + in(JMPLI, I7, 8, G0); + in(RESTOREI, G0, fp->cached_const->arg.si, O0); + POP_GPR(fp); + } else { + MAYBE_EMIT_CONST(fp); + if (!SIMM13_P(sp->arg.si)) { + in(SETHI, sp->arg.i >> 10, rTMP); + in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP); + in(ADD, rPSTACK, rTMP, rPSTACK); + } else + in(ADDI, rPSTACK, sp->arg.si, rPSTACK); + if (sp->src1_reg_flags & REG_FLAGS_FLOAT) { + in(STFI, O6, SL(64, 128), fFIRST(fp)); + in(LDUWI, O6, SL(64, 128), O0); + in(JMPLI, I7, 8, G0); + in(RESTORE, O0, G0, O0); + POP_FPR(fp); + } else { + in(JMPLI, I7, 8, G0); + in(RESTORE, rFIRST(fp), G0, O0); + POP_GPR(fp); + } + } + assert(fp->gpr_pos == L0); + assert(fp->fpr_pos == F0); + break; + case OP_JUMP: + if (fp->cached_const) { + EMIT_FALSE_CONST(fp); + emit_jump(fp, BA, fp->cached_const->arg.i); + } else { + MAYBE_EMIT_CONST(fp); + in(LDLI, rVMDATA, VM_Data_Offset(iPointers), rTMP); + in(SLLI, rFIRST(fp), 2, rFIRST(fp)); + in(LDL, rTMP, rFIRST(fp), rTMP); + in(JMPL, rTMP, G0, G0); + in(NOP); + } + POP_GPR(fp); + break; + case OP_CALL: + if (fp->cached_const) { + EMIT_FALSE_CONST(fp); + if (fp->cached_const->arg.si >= 0) { + emit_jump(fp, CALL, fp->cached_const->arg.i); + } else { + in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP); + in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3); + in(ORI, G0, fp->cached_const->arg.si, O0); + in(JMPL, rTMP, G0, O7); + in(OR, G0, rPSTACK, O1); + } + in(OR, G0, O0, rFIRST(fp)); + } else { + MAYBE_EMIT_CONST(fp); + in(SUBCCI, rFIRST(fp), 0, G0); + in(BL, +4*7); + in(NOP); + + /* normal call */ + in(LDLI, rVMDATA, VM_Data_Offset(iPointers), O5); + in(SLLI, rFIRST(fp), 2, rFIRST(fp)); + in(LDL, O5, rFIRST(fp), rTMP); + in(BA, +4*4); + in(NOP); + + /* syscall */ + in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP); + in(LDLI, rVMDATA, VM_Data_Offset(AsmCall), O3); + + in(OR, G0, rFIRST(fp), O0); + in(JMPL, rTMP, G0, O7); + in(OR, G0, rPSTACK, O1); + + /* return value */ + in(OR, G0, O0, rFIRST(fp)); + } + break; + case OP_BLOCK_COPY: + MAYBE_EMIT_CONST(fp); + in(LDLI, rVMDATA, VM_Data_Offset(CallThunk), rTMP); + in(LDLI, rVMDATA, VM_Data_Offset(BlockCopy), O3); + in(OR, G0, rSECOND(fp), O0); + in(OR, G0, rFIRST(fp), O1); + if ((sp->arg.i & ~0x3ff) == 0) { + in(ORI, G0, sp->arg.i & 0x3ff, O2); + } else if ((sp->arg.i & 0x3ff) == 0) { + in(SETHI, sp->arg.i >> 10, O2); + } else { + in(SETHI, sp->arg.i >> 10, O2); + in(ORI, O2, sp->arg.i & 0x3ff, O2); + } + in(JMPL, rTMP, G0, O7); + in(NOP); + POP_GPR(fp); + POP_GPR(fp); + break; + + case OP_PUSH: + MAYBE_EMIT_CONST(fp); + if (sp->dst_reg_flags & REG_FLAGS_FLOAT) + PUSH_FPR(fp); + else + PUSH_GPR(fp); + fp->force_emit = 1; + break; + case OP_POP: + MAYBE_EMIT_CONST(fp); + if (sp->src1_reg_flags & REG_FLAGS_FLOAT) + POP_FPR(fp); + else + POP_GPR(fp); + fp->force_emit = 1; + break; + case OP_ARG: + MAYBE_EMIT_CONST(fp); + in(ADDI, rPSTACK, sp->arg.b, rTMP); + if (sp->src1_reg_flags & REG_FLAGS_FLOAT) { + in(STF, rDATABASE, rTMP, fFIRST(fp)); + POP_FPR(fp); + } else { + in(STW, rDATABASE, rTMP, rFIRST(fp)); + POP_GPR(fp); + } + break; + case OP_IGNORE: + MAYBE_EMIT_CONST(fp); + in(NOP); + break; + case OP_BREAK: + MAYBE_EMIT_CONST(fp); + in(TA, 0x5); + break; + case OP_LOCAL: + MAYBE_EMIT_CONST(fp); + PUSH_GPR(fp); + if (!SIMM13_P(sp->arg.i)) { + in(SETHI, sp->arg.i >> 10, rTMP); + in(ORI, rTMP, sp->arg.i & 0x3ff, rTMP); + in(ADD, rPSTACK, rTMP, rFIRST(fp)); + } else + in(ADDI, rPSTACK, sp->arg.i, rFIRST(fp)); + break; + case OP_CONST: + MAYBE_EMIT_CONST(fp); + break; + case OP_LOAD4: + MAYBE_EMIT_CONST(fp); + in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp)); + if (sp->dst_reg_flags & REG_FLAGS_FLOAT) { + PUSH_FPR(fp); + in(LDF, rFIRST(fp), rDATABASE, fFIRST(fp)); + POP_GPR(fp); + } else { + in(LDUW, rFIRST(fp), rDATABASE, rFIRST(fp)); + } + break; + case OP_LOAD2: + MAYBE_EMIT_CONST(fp); + in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp)); + in(LDUH, rFIRST(fp), rDATABASE, rFIRST(fp)); + break; + case OP_LOAD1: + MAYBE_EMIT_CONST(fp); + in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp)); + in(LDUB, rFIRST(fp), rDATABASE, rFIRST(fp)); + break; + case OP_STORE4: + MAYBE_EMIT_CONST(fp); + if (sp->src1_reg_flags & REG_FLAGS_FLOAT) { + in(AND, rFIRST(fp), rDATAMASK, rFIRST(fp)); + in(STF, rFIRST(fp), rDATABASE, fFIRST(fp)); + POP_FPR(fp); + } else { + in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp)); + in(STW, rSECOND(fp), rDATABASE, rFIRST(fp)); + POP_GPR(fp); + } + POP_GPR(fp); + break; + case OP_STORE2: + MAYBE_EMIT_CONST(fp); + in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp)); + in(STH, rSECOND(fp), rDATABASE, rFIRST(fp)); + POP_GPR(fp); + POP_GPR(fp); + break; + case OP_STORE1: + MAYBE_EMIT_CONST(fp); + in(AND, rSECOND(fp), rDATAMASK, rSECOND(fp)); + in(STB, rSECOND(fp), rDATABASE, rFIRST(fp)); + POP_GPR(fp); + POP_GPR(fp); + break; + case OP_EQ: + case OP_NE: + case OP_LTI: + case OP_GEI: + case OP_GTI: + case OP_LEI: + case OP_LTU: + case OP_GEU: + case OP_GTU: + case OP_LEU: { + enum sparc_iname iname = BA; + + if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) { + EMIT_FALSE_CONST(fp); + in(SUBCCI, rSECOND(fp), fp->cached_const->arg.si, G0); + } else { + MAYBE_EMIT_CONST(fp); + in(SUBCC, rSECOND(fp), rFIRST(fp), G0); + } + switch(sp->op) { + case OP_EQ: iname = BE; break; + case OP_NE: iname = BNE; break; + case OP_LTI: iname = BL; break; + case OP_GEI: iname = BGE; break; + case OP_GTI: iname = BG; break; + case OP_LEI: iname = BLE; break; + case OP_LTU: iname = BCS; break; + case OP_GEU: iname = BCC; break; + case OP_GTU: iname = BGU; break; + case OP_LEU: iname = BLEU; break; + } + emit_jump(fp, iname, sp->arg.i); + POP_GPR(fp); + POP_GPR(fp); + break; + } + + case OP_SEX8: + MAYBE_EMIT_CONST(fp); + in(SLLI, rFIRST(fp), 24, rFIRST(fp)); + in(SRAI, rFIRST(fp), 24, rFIRST(fp)); + break; + case OP_SEX16: + MAYBE_EMIT_CONST(fp); + in(SLLI, rFIRST(fp), 16, rFIRST(fp)); + in(SRAI, rFIRST(fp), 16, rFIRST(fp)); + break; + case OP_NEGI: + MAYBE_EMIT_CONST(fp); + in(SUB, G0, rFIRST(fp), rFIRST(fp)); + break; + case OP_ADD: + if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) { + EMIT_FALSE_CONST(fp); + in(ADDI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp)); + } else { + MAYBE_EMIT_CONST(fp); + in(ADD, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + } + POP_GPR(fp); + break; + case OP_SUB: + if (fp->cached_const && SIMM13_P(fp->cached_const->arg.si)) { + EMIT_FALSE_CONST(fp); + in(SUBI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp)); + } else { + MAYBE_EMIT_CONST(fp); + in(SUB, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + } + POP_GPR(fp); + break; + case OP_DIVI: + MAYBE_EMIT_CONST(fp); + in(SRAI, rSECOND(fp), 31, rTMP); + in(WRI, rTMP, 0, Y_REG); + in(SDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + POP_GPR(fp); + break; + case OP_DIVU: + MAYBE_EMIT_CONST(fp); + in(WRI, G0, 0, Y_REG); + in(UDIV, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + POP_GPR(fp); + break; + case OP_MODI: + MAYBE_EMIT_CONST(fp); + in(SRAI, rSECOND(fp), 31, rTMP); + in(WRI, rTMP, 0, Y_REG); + in(SDIV, rSECOND(fp), rFIRST(fp), rTMP); + in(SMUL, rTMP, rFIRST(fp), rTMP); + in(SUB, rSECOND(fp), rTMP, rSECOND(fp)); + POP_GPR(fp); + break; + case OP_MODU: + MAYBE_EMIT_CONST(fp); + in(WRI, G0, 0, Y_REG); + in(UDIV, rSECOND(fp), rFIRST(fp), rTMP); + in(SMUL, rTMP, rFIRST(fp), rTMP); + in(SUB, rSECOND(fp), rTMP, rSECOND(fp)); + POP_GPR(fp); + break; + case OP_MULI: + MAYBE_EMIT_CONST(fp); + in(SMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + POP_GPR(fp); + break; + case OP_MULU: + MAYBE_EMIT_CONST(fp); + in(UMUL, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + POP_GPR(fp); + break; + case OP_BAND: + MAYBE_EMIT_CONST(fp); + in(AND, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + POP_GPR(fp); + break; + case OP_BOR: + MAYBE_EMIT_CONST(fp); + in(OR, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + POP_GPR(fp); + break; + case OP_BXOR: + MAYBE_EMIT_CONST(fp); + in(XOR, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + POP_GPR(fp); + break; + case OP_BCOM: + MAYBE_EMIT_CONST(fp); + in(XNOR, rFIRST(fp), G0, rFIRST(fp)); + break; + case OP_LSH: + if (fp->cached_const) { + EMIT_FALSE_CONST(fp); + in(SLLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp)); + } else { + MAYBE_EMIT_CONST(fp); + in(SLL, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + } + POP_GPR(fp); + break; + case OP_RSHI: + if (fp->cached_const) { + EMIT_FALSE_CONST(fp); + in(SRAI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp)); + } else { + MAYBE_EMIT_CONST(fp); + in(SRA, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + } + POP_GPR(fp); + break; + case OP_RSHU: + if (fp->cached_const) { + EMIT_FALSE_CONST(fp); + in(SRLI, rSECOND(fp), fp->cached_const->arg.si, rSECOND(fp)); + } else { + MAYBE_EMIT_CONST(fp); + in(SRL, rSECOND(fp), rFIRST(fp), rSECOND(fp)); + } + POP_GPR(fp); + break; + + case OP_NEGF: + MAYBE_EMIT_CONST(fp); + in(FNEG, fFIRST(fp), fFIRST(fp)); + break; + case OP_ADDF: + MAYBE_EMIT_CONST(fp); + in(FADD, fSECOND(fp), fFIRST(fp), fSECOND(fp)); + POP_FPR(fp); + break; + case OP_SUBF: + MAYBE_EMIT_CONST(fp); + in(FSUB, fSECOND(fp), fFIRST(fp), fSECOND(fp)); + POP_FPR(fp); + break; + case OP_DIVF: + MAYBE_EMIT_CONST(fp); + in(FDIV, fSECOND(fp), fFIRST(fp), fSECOND(fp)); + POP_FPR(fp); + break; + case OP_MULF: + MAYBE_EMIT_CONST(fp); + in(FMUL, fSECOND(fp), fFIRST(fp), fSECOND(fp)); + POP_FPR(fp); + break; + + case OP_EQF: + case OP_NEF: + case OP_LTF: + case OP_GEF: + case OP_GTF: + case OP_LEF: { + enum sparc_iname iname = FBE; + + MAYBE_EMIT_CONST(fp); + in(FCMP, fSECOND(fp), fFIRST(fp)); + switch(sp->op) { + case OP_EQF: iname = FBE; break; + case OP_NEF: iname = FBNE; break; + case OP_LTF: iname = FBL; break; + case OP_GEF: iname = FBGE; break; + case OP_GTF: iname = FBG; break; + case OP_LEF: iname = FBLE; break; + } + emit_jump(fp, iname, sp->arg.i); + POP_FPR(fp); + POP_FPR(fp); + break; + } + case OP_CVIF: + MAYBE_EMIT_CONST(fp); + PUSH_FPR(fp); + in(STWI, O6, SL(64, 128), rFIRST(fp)); + in(LDFI, O6, SL(64, 128), fFIRST(fp)); + in(FITOS, fFIRST(fp), fFIRST(fp)); + POP_GPR(fp); + break; + case OP_CVFI: + MAYBE_EMIT_CONST(fp); + PUSH_GPR(fp); + in(FSTOI, fFIRST(fp), fFIRST(fp)); + in(STFI, O6, SL(64, 128), fFIRST(fp)); + in(LDUWI, O6, SL(64, 128), rFIRST(fp)); + POP_FPR(fp); + break; + } + if (sp->op != OP_CONST) { + fp->cached_const = NULL; + end_emit(fp); + } else { + fp->cached_const = sp; + if (sp->dst_reg_flags & REG_FLAGS_FLOAT) { + PUSH_FPR(fp); + } else { + PUSH_GPR(fp); + } + } + end_emit(fp); +} + +static void free_source_insns(struct func_info * const fp) +{ + struct src_insn *sp = fp->first->next; + + while (sp) { + struct src_insn *next = sp->next; + Z_Free(sp); + sp = next; + } +} + +static void compile_function(struct func_info * const fp) +{ + struct src_insn *sp; + + analyze_function(fp); + + fp->gpr_pos = L0; + fp->fpr_pos = F0; + fp->insn_index = 0; + + fp->stack_space = SL(64, 128); + fp->cached_const = NULL; + + sp = fp->first; + while ((sp = sp->next) != NULL) + compile_one_insn(fp, sp); + + free_source_insns(fp); +} + +/* We have two thunks for sparc. The first is for the entry into + * the VM, where setup the fixed global registers. The second is + * for calling out to C code from the VM, where we need to preserve + * those fixed globals across the call. + */ +static void emit_vm_thunk(struct func_info * const fp) +{ + /* int vm_thunk(void *vmdata, int programstack, void *database, int datamask) */ + start_emit(fp, THUNK_ICOUNT); + + in(OR, G0, O0, rVMDATA); + in(OR, G0, O1, rPSTACK); + in(OR, G0, O2, rDATABASE); + in(BA, +4*17); + in(OR, G0, O3, rDATAMASK); + + /* int call_thunk(int arg0, int arg1, int arg2, int (*func)(int int int)) */ +#define CALL_THUNK_INSN_OFFSET 5 + in(SAVEI, O6, -SL(64, 128), O6); + + in(OR, G0, rVMDATA, L0); + in(OR, G0, rPSTACK, L1); + in(OR, G0, rDATABASE, L2); + in(OR, G0, rDATAMASK, L3); + + in(OR, G0, I0, O0); + in(OR, G0, I1, O1); + in(JMPL, I3, G0, O7); + in(OR, G0, I2, O2); + + in(OR, G0, L0, rVMDATA); + in(OR, G0, L1, rPSTACK); + in(OR, G0, L2, rDATABASE); + in(OR, G0, L3, rDATAMASK); + + in(JMPLI, I7, 8, G0); + in(RESTORE, O0, G0, O0); + + end_emit(fp); +} + +static void sparc_compute_code(vm_t *vm, struct func_info * const fp) +{ + struct dst_insn *dp = fp->dst_first; + unsigned int *code_now, *code_begin; + unsigned char *data_and_code; + unsigned int code_length; + int code_insns = 0, off; + struct data_hunk *dhp; + struct jump_insn *jp; + vm_data_t *data; + + while (dp) { + code_insns += dp->length; + dp = dp->next; + } + + code_length = (sizeof(vm_data_t) + + (fp->data_num * sizeof(unsigned int)) + + (code_insns * sizeof(unsigned int))); + + data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (!data_and_code) + DIE("Not enough memory"); + + code_now = code_begin = (unsigned int *) + (data_and_code + VM_Data_Offset(data[fp->data_num])); + + dp = fp->dst_first; + while (dp) { + int i_count = dp->i_count; + + if (i_count != THUNK_ICOUNT) { + if (!fp->dst_by_i_count[i_count]) + fp->dst_by_i_count[i_count] = (void *) code_now; + } + if (!dp->jump) { + memcpy(code_now, &dp->code[0], dp->length * sizeof(unsigned int)); + code_now += dp->length; + } else { + int i; + + dp->jump->parent = (void *) code_now; + + for (i = 0; i < dp->length; i++) + code_now[i] = SPARC_NOP; + code_now += dp->length; + } + + dp = dp->next; + } + + jp = fp->jump_first; + while (jp) { + unsigned int *from = (void *) jp->parent; + unsigned int *to = (void *) fp->dst_by_i_count[jp->jump_dest_insn]; + signed int disp = (to - from); + + *from = IN(jp->jump_iname, disp << 2); + + jp = jp->next; + } + + vm->codeBase = data_and_code; + vm->codeLength = code_length; + + data = (vm_data_t *) data_and_code; + data->CallThunk = code_begin + CALL_THUNK_INSN_OFFSET; + data->AsmCall = asmcall; + data->BlockCopy = blockcopy; + data->iPointers = (unsigned int *) vm->instructionPointers; + data->dataLength = VM_Data_Offset(data[fp->data_num]); + data->codeLength = (code_now - code_begin) * sizeof(unsigned int); + +#if 0 + { + unsigned int *insn = code_begin; + int i; + + Com_Printf("INSN DUMP\n"); + for (i = 0; i < data->codeLength / 4; i+= 8) { + Com_Printf("\t.word\t0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + insn[i + 0], insn[i + 1], + insn[i + 2], insn[i + 3], + insn[i + 4], insn[i + 5], + insn[i + 6], insn[i + 7]); + } + } +#endif + + dhp = fp->data_first; + off = 0; + while (dhp) { + struct data_hunk *next = dhp->next; + int i; + + for (i = 0; i < dhp->count; i++) + data->data[off + i] = dhp->data[i]; + + off += dhp->count; + + Z_Free(dhp); + + dhp = next; + } + fp->data_first = NULL; + fp->data_num = 0; + + dp = fp->dst_first; + while (dp) { + struct dst_insn *next = dp->next; + if (dp->jump) + Z_Free(dp->jump); + Z_Free(dp); + dp = next; + } + fp->dst_first = fp->dst_last = NULL; +} + +void VM_Compile(vm_t *vm, vmHeader_t *header) +{ + struct func_info fi; + unsigned char *code; + int i_count, pc, i; + + memset(&fi, 0, sizeof(fi)); + + fi.first = Z_Malloc(sizeof(struct src_insn)); + fi.first->next = NULL; + +#ifdef __arch64__ + Z_Free(vm->instructionPointers); + vm->instructionPointers = Z_Malloc(header->instructionCount * + sizeof(void *)); +#endif + + fi.dst_by_i_count = (struct dst_insn **) vm->instructionPointers; + memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *)); + + vm->compiled = qfalse; + + emit_vm_thunk(&fi); + + code = (unsigned char *) header + header->codeOffset; + pc = 0; + + for (i_count = 0; i_count < header->instructionCount; i_count++) { + unsigned char opi, op = code[pc++]; + struct src_insn *sp; + + if (op == OP_CALL || op == OP_BLOCK_COPY) + fi.has_call = 1; + opi = vm_opInfo[op]; + if (op == OP_CVIF || op == OP_CVFI || + (op == OP_LEAVE && (opi & opArgF))) + fi.need_float_tmp = 1; + + if (op == OP_ENTER) { + if (fi.first->next) + compile_function(&fi); + fi.first->next = NULL; + fi.last = fi.first; + fi.has_call = fi.need_float_tmp = 0; + } + + sp = Z_Malloc(sizeof(*sp)); + sp->op = op; + sp->i_count = i_count; + sp->arg.i = 0; + sp->next = NULL; + + if (vm_opInfo[op] & opImm4) { + union { + unsigned char b[4]; + unsigned int i; + } c = { { code[ pc + 3 ], code[ pc + 2 ], + code[ pc + 1 ], code[ pc + 0 ] }, }; + + sp->arg.i = c.i; + pc += 4; + } else if (vm_opInfo[op] & opImm1) { + sp->arg.b = code[pc++]; + } + + fi.last->next = sp; + fi.last = sp; + } + compile_function(&fi); + + Z_Free(fi.first); + + memset(fi.dst_by_i_count, 0, header->instructionCount * sizeof(void *)); + sparc_compute_code(vm, &fi); + + for (i = 0; i < header->instructionCount; i++) { + if (!fi.dst_by_i_count[i]) { + Com_Printf(S_COLOR_RED "Pointer %d not initialized !\n", i); + DIE("sparc JIT bug"); + } + } + + if (mprotect(vm->codeBase, vm->codeLength, PROT_READ|PROT_EXEC)) { + VM_Destroy_Compiled(vm); + DIE("mprotect failed"); + } + + vm->destroy = VM_Destroy_Compiled; + vm->compiled = qtrue; +} + +int VM_CallCompiled(vm_t *vm, int *args) +{ + vm_data_t *vm_dataAndCode = (void *) vm->codeBase; + int programStack = vm->programStack; + int stackOnEntry = programStack; + byte *image = vm->dataBase; + int *argPointer; + int retVal; + + currentVM = vm; + + vm->currentlyInterpreting = qtrue; + + programStack -= 48; + argPointer = (int *)&image[ programStack + 8 ]; + memcpy( argPointer, args, 4 * 9 ); + argPointer[-1] = 0; + argPointer[-2] = -1; + + /* call generated code */ + { + int (*entry)(void *, int, void *, int); + entry = (void *)(vm->codeBase + vm_dataAndCode->dataLength); + retVal = entry(vm->codeBase, programStack, vm->dataBase, vm->dataMask); + } + + vm->programStack = stackOnEntry; + vm->currentlyInterpreting = qfalse; + + return retVal; +} diff --git a/src/qcommon/vm_sparc.h b/src/qcommon/vm_sparc.h new file mode 100644 index 00000000..dbed6278 --- /dev/null +++ b/src/qcommon/vm_sparc.h @@ -0,0 +1,78 @@ +#ifndef VM_SPARC_H +#define VM_SPARC_H + +/* integer regs */ +#define G0 0 +#define G1 1 +#define G2 2 +#define G3 3 +#define G4 4 +#define G5 5 +#define G6 6 +#define G7 7 +#define O0 8 +#define O1 9 +#define O2 10 +#define O3 11 +#define O4 12 +#define O5 13 +#define O6 14 +#define O7 15 +#define L0 16 +#define L1 17 +#define L2 18 +#define L3 19 +#define L4 20 +#define L5 21 +#define L6 22 +#define L7 23 +#define I0 24 +#define I1 25 +#define I2 26 +#define I3 27 +#define I4 28 +#define I5 29 +#define I6 30 +#define I7 31 + +/* float regs */ +#define F0 0 +#define F1 1 +#define F2 2 +#define F3 3 +#define F4 4 +#define F5 5 +#define F6 6 +#define F7 7 +#define F8 8 +#define F9 9 +#define F10 10 +#define F11 11 +#define F12 12 +#define F13 13 +#define F14 14 +#define F15 15 +#define F16 16 +#define F17 17 +#define F18 18 +#define F19 19 +#define F20 20 +#define F21 21 +#define F22 22 +#define F23 23 +#define F24 24 +#define F25 25 +#define F26 26 +#define F27 27 +#define F28 28 +#define F29 29 +#define F30 30 +#define F31 31 + +/* state registers */ +#define Y_REG 0 +#define CCR_REG 2 +#define ASI_REG 3 +#define FPRS_REG 6 + +#endif diff --git a/src/qcommon/vm_x86.c b/src/qcommon/vm_x86.c index 64af7d11..0f558ef7 100644 --- a/src/qcommon/vm_x86.c +++ b/src/qcommon/vm_x86.c @@ -177,9 +177,14 @@ _asm { #else //!_MSC_VER #if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols -# define CMANG(sym) "_"#sym +#define CMANGVAR(sym) "_"#sym +#define CMANGFUNC(sym) "_"#sym +#elif defined(__ICC) && (__ICC >= 1000) +#define CMANGVAR(sym) #sym".0" +#define CMANGFUNC(sym) #sym #else -# define CMANG(sym) #sym +#define CMANGVAR(sym) #sym +#define CMANGFUNC(sym) #sym #endif static void __attribute__((cdecl, used)) CallAsmCall(int const syscallNum, @@ -200,32 +205,37 @@ __asm__( ".text\n\t" ".p2align 4,,15\n\t" #if defined __ELF__ - ".type " CMANG(AsmCall) ", @function\n" + ".type " CMANGFUNC(AsmCall) ", @function\n" #endif - CMANG(AsmCall) ":\n\t" + CMANGFUNC(AsmCall) ":\n\t" "movl (%edi), %eax\n\t" "subl $4, %edi\n\t" "testl %eax, %eax\n\t" "jl 0f\n\t" "shll $2, %eax\n\t" - "addl " CMANG(instructionPointers) ", %eax\n\t" + "addl " CMANGVAR(instructionPointers) ", %eax\n\t" "call *(%eax)\n\t" "movl (%edi), %eax\n\t" - "andl " CMANG(callMask) ", %eax\n\t" + "andl " CMANGVAR(callMask) ", %eax\n\t" "ret\n" "0:\n\t" // system call "notl %eax\n\t" + "pushl %ebp\n\t" + "movl %esp, %ebp\n\t" + "andl $-16, %esp\n\t" // align the stack so engine can use sse "pushl %ecx\n\t" "pushl %edi\n\t" // opStack "pushl %esi\n\t" // programStack "pushl %eax\n\t" // syscallNum - "call " CMANG(CallAsmCall) "\n\t" + "call " CMANGFUNC(CallAsmCall) "\n\t" "addl $12, %esp\n\t" "popl %ecx\n\t" + "movl %ebp, %esp\n\t" + "popl %ebp\n\t" "addl $4, %edi\n\t" "ret\n\t" #if defined __ELF__ - ".size " CMANG(AsmCall)", .-" CMANG(AsmCall) + ".size " CMANGFUNC(AsmCall)", .-" CMANGFUNC(AsmCall) #endif ); diff --git a/src/qcommon/vm_x86_64.c b/src/qcommon/vm_x86_64.c index 09a9c6d1..b424baf8 100644 --- a/src/qcommon/vm_x86_64.c +++ b/src/qcommon/vm_x86_64.c @@ -247,7 +247,7 @@ void emit(const char* fmt, ...) #else #define JMPIARG \ emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ - emit("jmpq *%rax"); + emit("jmpq *%%rax"); #endif // integer compare and jump diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c index f90b8026..ce2b8642 100644 --- a/src/renderer/tr_init.c +++ b/src/renderer/tr_init.c @@ -99,6 +99,7 @@ cvar_t *r_depthbits; cvar_t *r_colorbits; cvar_t *r_primitives; cvar_t *r_texturebits; +cvar_t *r_ext_multisample; cvar_t *r_drawBuffer; cvar_t *r_lightmap; @@ -388,7 +389,7 @@ void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { } // gamma correct - if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + if ( glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 ); } @@ -410,7 +411,7 @@ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); // gamma correct - if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + if ( glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); } @@ -530,7 +531,7 @@ void R_LevelShot( void ) { float xScale, yScale; int xx, yy; - sprintf( checkname, "levelshots/%s.tga", tr.world->baseName ); + Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); @@ -565,7 +566,7 @@ void R_LevelShot( void ) { } // gamma correct - if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { + if ( glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); } @@ -714,7 +715,7 @@ const void *RB_TakeVideoFrameCmd( const void *data ) GL_UNSIGNED_BYTE, cmd->captureBuffer ); // gamma correct - if( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) + if( glConfig.deviceSupportsGamma ) R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 ); if( cmd->motionJpeg ) @@ -913,6 +914,8 @@ void R_Register( void ) r_colorbits = ri.Cvar_Get( "r_colorbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_stencilbits = ri.Cvar_Get( "r_stencilbits", "8", CVAR_ARCHIVE | CVAR_LATCH ); r_depthbits = ri.Cvar_Get( "r_depthbits", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_multisample = ri.Cvar_Get( "r_ext_multisample", "0", CVAR_ARCHIVE | CVAR_LATCH ); + ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue ); r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); diff --git a/src/renderer/tr_local.h b/src/renderer/tr_local.h index ef434718..9f8e44f9 100644 --- a/src/renderer/tr_local.h +++ b/src/renderer/tr_local.h @@ -1002,6 +1002,7 @@ extern cvar_t *r_stencilbits; // number of desired stencil bits extern cvar_t *r_depthbits; // number of desired depth bits extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen extern cvar_t *r_texturebits; // number of desired texture bits +extern cvar_t *r_ext_multisample; // 0 = use framebuffer depth // 16 = use 16-bit textures // 32 = use 32-bit textures diff --git a/src/renderer/tr_main.c b/src/renderer/tr_main.c index 3d908316..105dfdf2 100644 --- a/src/renderer/tr_main.c +++ b/src/renderer/tr_main.c @@ -457,7 +457,7 @@ void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, floa float oppleg, adjleg, length; int i; - if(stereoSep == 0 && xmin != -xmax) + if(stereoSep == 0 && xmin == -xmax) { // symmetric case can be simplified VectorCopy(dest->or.origin, ofsorigin); @@ -524,9 +524,9 @@ void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) if(stereoSep != 0) { if(dest->stereoFrame == STEREO_LEFT) - stereoSep = zProj / r_stereoSeparation->value; + stereoSep = zProj / stereoSep; else if(dest->stereoFrame == STEREO_RIGHT) - stereoSep = zProj / -r_stereoSeparation->value; + stereoSep = zProj / -stereoSep; else stereoSep = 0; } diff --git a/src/renderer/tr_noise.c b/src/renderer/tr_noise.c index c8eeeed3..3a38d9d8 100644 --- a/src/renderer/tr_noise.c +++ b/src/renderer/tr_noise.c @@ -45,8 +45,6 @@ void R_NoiseInit( void ) { int i; - srand( 1001 ); - for ( i = 0; i < NOISE_SIZE; i++ ) { s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) ); diff --git a/src/renderer/tr_scene.c b/src/renderer/tr_scene.c index 22b3842b..e11c0a3d 100644 --- a/src/renderer/tr_scene.c +++ b/src/renderer/tr_scene.c @@ -212,6 +212,14 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) { if ( r_numentities >= MAX_ENTITIES ) { return; } + if ( Q_isnan(ent->origin[0]) || Q_isnan(ent->origin[1]) || Q_isnan(ent->origin[2]) ) { + static qboolean first_time = qtrue; + if (first_time) { + first_time = qfalse; + Com_Printf(S_COLOR_YELLOW "WARNING: You might have built ioquake3 with a buggy compiler!\n"); + } + return; + } if ( ent->reType < 0 || ent->reType >= RT_MAX_REF_ENTITY_TYPE ) { ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); } diff --git a/src/renderer/tr_surface.c b/src/renderer/tr_surface.c index 2a291c84..fca9841c 100644 --- a/src/renderer/tr_surface.c +++ b/src/renderer/tr_surface.c @@ -190,7 +190,7 @@ static void RB_SurfaceSprite( void ) { RB_SurfacePolychain ============= */ -void RB_SurfacePolychain( srfPoly_t *p ) { +static void RB_SurfacePolychain( srfPoly_t *p ) { int i; int numv; @@ -224,7 +224,7 @@ void RB_SurfacePolychain( srfPoly_t *p ) { RB_SurfaceTriangles ============= */ -void RB_SurfaceTriangles( srfTriangles_t *srf ) { +static void RB_SurfaceTriangles( srfTriangles_t *srf ) { int i; drawVert_t *dv; float *xyz, *normal, *texCoords; @@ -285,7 +285,7 @@ void RB_SurfaceTriangles( srfTriangles_t *srf ) { RB_SurfaceBeam ============== */ -void RB_SurfaceBeam( void ) +static void RB_SurfaceBeam( void ) { #define NUM_BEAM_SEGS 6 refEntity_t *e; @@ -455,7 +455,7 @@ static void DoRailDiscs( int numSegs, const vec3_t start, const vec3_t dir, cons /* ** RB_SurfaceRailRinges */ -void RB_SurfaceRailRings( void ) { +static void RB_SurfaceRailRings( void ) { refEntity_t *e; int numSegs; int len; @@ -485,7 +485,7 @@ void RB_SurfaceRailRings( void ) { /* ** RB_SurfaceRailCore */ -void RB_SurfaceRailCore( void ) { +static void RB_SurfaceRailCore( void ) { refEntity_t *e; int len; vec3_t right; @@ -515,7 +515,7 @@ void RB_SurfaceRailCore( void ) { /* ** RB_SurfaceLightningBolt */ -void RB_SurfaceLightningBolt( void ) { +static void RB_SurfaceLightningBolt( void ) { refEntity_t *e; int len; vec3_t right; @@ -857,7 +857,7 @@ static void LerpMeshVertexes(md3Surface_t *surf, float backlerp) RB_SurfaceMesh ============= */ -void RB_SurfaceMesh(md3Surface_t *surface) { +static void RB_SurfaceMesh(md3Surface_t *surface) { int j; float backlerp; int *triangles; @@ -904,7 +904,7 @@ void RB_SurfaceMesh(md3Surface_t *surface) { RB_SurfaceFace ============== */ -void RB_SurfaceFace( srfSurfaceFace_t *surf ) { +static void RB_SurfaceFace( srfSurfaceFace_t *surf ) { int i; unsigned *indices, *tessIndexes; float *v; @@ -994,7 +994,7 @@ RB_SurfaceGrid Just copy the grid of points and triangulate ============= */ -void RB_SurfaceGrid( srfGridMesh_t *cv ) { +static void RB_SurfaceGrid( srfGridMesh_t *cv ) { int i, j; float *xyz; float *texCoords; @@ -1161,7 +1161,7 @@ RB_SurfaceAxis Draws x/y/z lines from the origin for orientation debugging =================== */ -void RB_SurfaceAxis( void ) { +static void RB_SurfaceAxis( void ) { GL_Bind( tr.whiteImage ); qglLineWidth( 3 ); qglBegin( GL_LINES ); @@ -1187,7 +1187,7 @@ RB_SurfaceEntity Entities that have a single procedurally generated surface ==================== */ -void RB_SurfaceEntity( surfaceType_t *surfType ) { +static void RB_SurfaceEntity( surfaceType_t *surfType ) { switch( backEnd.currentEntity->e.reType ) { case RT_SPRITE: RB_SurfaceSprite(); @@ -1211,23 +1211,23 @@ void RB_SurfaceEntity( surfaceType_t *surfType ) { return; } -void RB_SurfaceBad( surfaceType_t *surfType ) { +static void RB_SurfaceBad( surfaceType_t *surfType ) { ri.Printf( PRINT_ALL, "Bad surface tesselated.\n" ); } -void RB_SurfaceFlare(srfFlare_t *surf) +static void RB_SurfaceFlare(srfFlare_t *surf) { if (r_flares->integer) RB_AddFlare(surf, tess.fogNum, surf->origin, surf->color, surf->normal); } -void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { +static void RB_SurfaceDisplayList( srfDisplayList_t *surf ) { // all apropriate state must be set in RB_BeginSurface // this isn't implemented yet... qglCallList( surf->listNum ); } -void RB_SurfaceSkip( void *surf ) { +static void RB_SurfaceSkip( void *surf ) { } diff --git a/src/sdl/sdl_glimp.c b/src/sdl/sdl_glimp.c index 6125a321..1bbccb84 100644 --- a/src/sdl/sdl_glimp.c +++ b/src/sdl/sdl_glimp.c @@ -79,6 +79,7 @@ static SDL_Surface *screen = NULL; static const SDL_VideoInfo *videoInfo = NULL; cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained +cvar_t *r_allowResize; // make window resizable cvar_t *r_sdlDriver; void (APIENTRYP qglActiveTextureARB) (GLenum texture); @@ -214,12 +215,16 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen ) int sdlcolorbits; int colorbits, depthbits, stencilbits; int tcolorbits, tdepthbits, tstencilbits; + int samples; int i = 0; SDL_Surface *vidscreen = NULL; Uint32 flags = SDL_OPENGL; ri.Printf( PRINT_ALL, "Initializing OpenGL display\n"); + if ( r_allowResize->integer ) + flags |= SDL_RESIZABLE; + #if !SDL_VERSION_ATLEAST(1, 2, 10) // 1.2.10 is needed to get the desktop resolution glConfig.displayAspect = 4.0f / 3.0f; @@ -240,12 +245,20 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen ) sVideoInfo.vfmt = &sPixelFormat; videoInfo = &sVideoInfo; - // Guess the display aspect ratio through the desktop resolution - // by assuming (relatively safely) that it is set at or close to - // the display's native aspect ratio - glConfig.displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h; + if( videoInfo->current_h > 0 ) + { + // Guess the display aspect ratio through the desktop resolution + // by assuming (relatively safely) that it is set at or close to + // the display's native aspect ratio + glConfig.displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h; - ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", glConfig.displayAspect ); + ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", glConfig.displayAspect ); + } + else + { + ri.Printf( PRINT_ALL, + "Cannot estimate display aspect, assuming 1.333\n" ); + } } #endif @@ -279,16 +292,16 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen ) else glConfig.isFullscreen = qfalse; - if (!r_colorbits->value) + colorbits = r_colorbits->value; + if ((!colorbits) || (colorbits >= 32)) colorbits = 24; - else - colorbits = r_colorbits->value; if (!r_depthbits->value) depthbits = 24; else depthbits = r_depthbits->value; stencilbits = r_stencilbits->value; + samples = r_ext_multisample->value; for (i = 0; i < 16; i++) { @@ -350,12 +363,23 @@ static int GLimp_SetMode( qboolean failSafe, qboolean fullscreen ) if (tcolorbits == 24) sdlcolorbits = 8; +#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */ + if (sdlcolorbits == 4) + sdlcolorbits = 0; /* Use minimum size for 16-bit color */ + + /* Need alpha or else SGIs choose 36+ bit RGB mode */ + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1); +#endif + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, sdlcolorbits ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, sdlcolorbits ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, sdlcolorbits ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples ); + if(r_stereoEnabled->integer) { glConfig.stereoEnabled = qtrue; @@ -677,23 +701,30 @@ of OpenGL */ void GLimp_Init( void ) { - qboolean success = qtrue; - r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); + r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE ); Sys_GLimpInit( ); - // create the window and set up the context - if( !GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) ) - { - if( !GLimp_StartDriverAndSetMode( qtrue, r_fullscreen->integer ) ) - success = qfalse; - } + // Create the window and set up the context + if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) ) + goto success; + + // Try again, this time in a platform specific "safe mode" + Sys_GLimpSafeInit( ); + + if( GLimp_StartDriverAndSetMode( qfalse, r_fullscreen->integer ) ) + goto success; + + // Finally, try the default screen resolution + if( GLimp_StartDriverAndSetMode( qtrue, r_fullscreen->integer ) ) + goto success; - if( !success ) - ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" ); + // Nothing worked, give up + ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" ); +success: // This values force the UI to disable driver selection glConfig.driverType = GLDRV_ICD; glConfig.hardwareType = GLHW_GENERIC; diff --git a/src/sdl/sdl_input.c b/src/sdl/sdl_input.c index 3263932a..2949c8fd 100644 --- a/src/sdl/sdl_input.c +++ b/src/sdl/sdl_input.c @@ -70,6 +70,8 @@ static cvar_t *in_joystickDebug = NULL; static cvar_t *in_joystickThreshold = NULL; static cvar_t *in_joystickNo = NULL; +static int vidRestartTime = 0; + #define CTRL(a) ((a)-'a'+1) /* @@ -949,6 +951,20 @@ static void IN_ProcessEvents( void ) Sys_Quit( ); break; + case SDL_VIDEORESIZE: + { + char width[32], height[32]; + Com_sprintf( width, sizeof(width), "%d", e.resize.w ); + Com_sprintf( height, sizeof(height), "%d", e.resize.h ); + ri.Cvar_Set( "r_width", width ); + ri.Cvar_Set( "r_height", height ); + /* wait until user stops dragging for 1 second, so + we aren't constantly recreating the GL context while + he tries to drag...*/ + vidRestartTime = Sys_Milliseconds() + 1000; + } + break; + default: break; } @@ -1001,6 +1017,13 @@ void IN_Frame( void ) SDL_GetMouseState( &x, &y ); IN_SetUIMousePosition( x, y ); } + + // In case we had to delay actual restart of video system + if( ( vidRestartTime != 0 ) && ( vidRestartTime < Sys_Milliseconds( ) ) ) + { + vidRestartTime = 0; + Cbuf_AddText( "vid_restart" ); + } } /* diff --git a/src/server/server.h b/src/server/server.h index eb3766e8..fe78026c 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -205,6 +205,7 @@ typedef struct client_s { typedef struct { netadr_t adr; int challenge; + int clientChallenge; // challenge number coming from the client int time; // time the last packet was sent to the autherize server int pingTime; // time the challenge response was sent to client int firstTime; // time the adr was first used, for authorize timeout checks @@ -313,7 +314,7 @@ void SV_SpawnServer( char *server, qboolean killBots ); // // sv_client.c // -void SV_GetChallenge( netadr_t from ); +void SV_GetChallenge(netadr_t from); void SV_DirectConnect( netadr_t from ); diff --git a/src/server/sv_client.c b/src/server/sv_client.c index 4b7b3bb6..4449f1c8 100644 --- a/src/server/sv_client.c +++ b/src/server/sv_client.c @@ -42,12 +42,21 @@ to be sent to the authorize server. When an authorizeip is returned, a challenge response will be sent to that ip. + +ioquake3: we added a possibility for clients to add a challenge +to their packets, to make it more difficult for malicious servers +to hi-jack client connections. +Also, the auth stuff is completely disabled for com_standalone games +as well as IPv6 connections, since there is no way to use the +v4-only auth server for these new types of connections. ================= */ -void SV_GetChallenge( netadr_t from ) { +void SV_GetChallenge(netadr_t from) +{ int i; int oldest; int oldestTime; + const char *clientChallenge = Cmd_Argv(1); challenge_t *challenge; oldest = 0; @@ -65,21 +74,24 @@ void SV_GetChallenge( netadr_t from ) { } } - if (i == MAX_CHALLENGES) { + if (i == MAX_CHALLENGES) + { // this is the first time this client has asked for a challenge challenge = &svs.challenges[oldest]; - challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; + challenge->clientChallenge = 0; challenge->adr = from; challenge->firstTime = svs.time; challenge->time = svs.time; challenge->connected = qfalse; - i = oldest; } // send the challengeResponse challenge->pingTime = svs.time; NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge ); + + challenge->pingTime = svs.time; + NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i %s", challenge->challenge, clientChallenge); } /* @@ -339,7 +351,7 @@ void SV_DropClient( client_t *drop, const char *reason ) { for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { - challenge->connected = qfalse; + Com_Memset(challenge, 0, sizeof(*challenge)); break; } } @@ -350,7 +362,6 @@ void SV_DropClient( client_t *drop, const char *reason ) { // tell everyone why they got dropped SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason ); - if (drop->download) { FS_FCloseFile( drop->download ); drop->download = 0; @@ -394,7 +405,7 @@ It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ -void SV_SendClientGameState( client_t *client ) { +static void SV_SendClientGameState( client_t *client ) { int start; entityState_t *base, nullstate; msg_t msg; @@ -531,7 +542,7 @@ SV_StopDownload_f Abort a download if in progress ================== */ -void SV_StopDownload_f( client_t *cl ) { +static void SV_StopDownload_f( client_t *cl ) { if (*cl->downloadName) Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", (int) (cl - svs.clients), cl->downloadName ); @@ -545,7 +556,7 @@ SV_DoneDownload_f Downloads are finished ================== */ -void SV_DoneDownload_f( client_t *cl ) { +static void SV_DoneDownload_f( client_t *cl ) { Com_DPrintf( "clientDownload: %s Done\n", cl->name); // resend the game state to update any clients that entered during the download SV_SendClientGameState(cl); @@ -559,7 +570,7 @@ The argument will be the last acknowledged block from the client, it should be the same as cl->downloadClientBlock ================== */ -void SV_NextDownload_f( client_t *cl ) +static void SV_NextDownload_f( client_t *cl ) { int block = atoi( Cmd_Argv(1) ); @@ -588,7 +599,7 @@ void SV_NextDownload_f( client_t *cl ) SV_BeginDownload_f ================== */ -void SV_BeginDownload_f( client_t *cl ) { +static void SV_BeginDownload_f( client_t *cl ) { // Kill any existing download SV_CloseDownload( cl ); diff --git a/src/server/sv_game.c b/src/server/sv_game.c index d375c095..1efa6d5f 100644 --- a/src/server/sv_game.c +++ b/src/server/sv_game.c @@ -182,17 +182,14 @@ qboolean SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2) { int leafnum; int cluster; - int area1, area2; byte *mask; leafnum = CM_PointLeafnum (p1); cluster = CM_LeafCluster (leafnum); - area1 = CM_LeafArea (leafnum); mask = CM_ClusterPVS (cluster); leafnum = CM_PointLeafnum (p2); cluster = CM_LeafCluster (leafnum); - area2 = CM_LeafArea (leafnum); if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) return qfalse; diff --git a/src/server/sv_init.c b/src/server/sv_init.c index 43eb2c09..34ced5c5 100644 --- a/src/server/sv_init.c +++ b/src/server/sv_init.c @@ -105,7 +105,7 @@ SV_SetConfigstring =============== */ void SV_SetConfigstring (int index, const char *val) { - int len, i; + int i; client_t *client; if ( index < 0 || index >= MAX_CONFIGSTRINGS ) { @@ -141,8 +141,6 @@ void SV_SetConfigstring (int index, const char *val) { continue; } - - len = strlen( val ); SV_SendConfigstring(client, index); } } @@ -217,7 +215,7 @@ to the clients -- only the fields that differ from the baseline will be transmitted ================ */ -void SV_CreateBaseline( void ) { +static void SV_CreateBaseline( void ) { sharedEntity_t *svent; int entnum; @@ -242,7 +240,7 @@ SV_BoundMaxClients =============== */ -void SV_BoundMaxClients( int minimum ) { +static void SV_BoundMaxClients( int minimum ) { // get the current maxclients value Cvar_Get( "sv_maxclients", "8", 0 ); @@ -266,7 +264,7 @@ NOT cause this to be called, unless the game is exited to the menu system first. =============== */ -void SV_Startup( void ) { +static void SV_Startup( void ) { if ( svs.initialized ) { Com_Error( ERR_FATAL, "SV_Startup: svs.initialized" ); } @@ -364,7 +362,7 @@ void SV_ChangeMaxClients( void ) { SV_ClearServer ================ */ -void SV_ClearServer(void) { +static void SV_ClearServer(void) { int i; for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) { @@ -382,7 +380,7 @@ SV_TouchCGame touch the cgame.vm so that a pure client can load it if it's in a seperate pk3 ================ */ -void SV_TouchCGame(void) { +static void SV_TouchCGame(void) { fileHandle_t f; char filename[MAX_QPATH]; @@ -470,7 +468,6 @@ void SV_SpawnServer( char *server, qboolean killBots ) { Cvar_Set("cl_paused", "0"); // get a new checksum feed and restart the file system - srand(Com_Milliseconds()); sv.checksumFeed = ( ((int) rand() << 16) ^ rand() ) ^ Com_Milliseconds(); FS_Restart( sv.checksumFeed ); diff --git a/src/server/sv_main.c b/src/server/sv_main.c index 305cf299..41bfec4a 100644 --- a/src/server/sv_main.c +++ b/src/server/sv_main.c @@ -74,7 +74,7 @@ SV_ExpandNewlines Converts newlines to "\n" so a line prints nicer =============== */ -char *SV_ExpandNewlines( char *in ) { +static char *SV_ExpandNewlines( char *in ) { static char string[1024]; int l; @@ -97,10 +97,11 @@ char *SV_ExpandNewlines( char *in ) { ====================== SV_ReplacePendingServerCommands - This is ugly +FIXME: This is ugly ====================== */ -int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) { +#if 0 // unused +static int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) { int i, index, csnum1, csnum2; for ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) { @@ -117,6 +118,7 @@ int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) { } return qfalse; } +#endif /* ====================== @@ -223,52 +225,89 @@ but not on every player enter or exit. #define HEARTBEAT_MSEC 300*1000 #define HEARTBEAT_GAME "Tremulous" void SV_MasterHeartbeat( void ) { - static netadr_t adr[MAX_MASTER_SERVERS]; + static netadr_t adr[MAX_MASTER_SERVERS][2]; // [2] for v4 and v6 address for the same address string. int i; int res; + int netenabled; + + netenabled = Cvar_VariableIntegerValue("net_enabled"); // "dedicated 1" is for lan play, "dedicated 2" is for inet public play - if ( !com_dedicated || com_dedicated->integer != 2 ) { + if (!com_dedicated || com_dedicated->integer != 2 || !(netenabled & (NET_ENABLEV4 | NET_ENABLEV6))) return; // only dedicated servers send heartbeats - } // if not time yet, don't send anything - if ( svs.time < svs.nextHeartbeatTime ) { + if ( svs.time < svs.nextHeartbeatTime ) return; - } - svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC; + svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC; // send to group masters - for ( i = 0 ; i < MAX_MASTER_SERVERS ; i++ ) { - if ( !sv_master[i]->string[0] ) { + for (i = 0; i < MAX_MASTER_SERVERS; i++) + { + if(!sv_master[i]->string[0]) continue; - } // see if we haven't already resolved the name // resolving usually causes hitches on win95, so only // do it when needed - if ( sv_master[i]->modified ) { + if(sv_master[i]->modified || (adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD)) + { sv_master[i]->modified = qfalse; - - Com_Printf( "Resolving %s\n", sv_master[i]->string ); - res = NET_StringToAdr( sv_master[i]->string, &adr[i], NA_UNSPEC ); - if ( !res ) { - Com_Printf( "Couldn't resolve address: %s\n", sv_master[i]->string ); - continue; + + if(netenabled & NET_ENABLEV4) + { + Com_Printf("Resolving %s (IPv4)\n", sv_master[i]->string); + res = NET_StringToAdr(sv_master[i]->string, &adr[i][0], NA_IP); + + if(res == 2) + { + // if no port was specified, use the default master port + adr[i][0].port = BigShort(PORT_MASTER); + } + + if(res) + Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][0])); + else + Com_Printf( "%s has no IPv4 address.\n", sv_master[i]->string); } - if ( res == 2 ) { - // if no port was specified, use the default master port - adr[i].port = BigShort( PORT_MASTER ); + + if(netenabled & NET_ENABLEV6) + { + Com_Printf("Resolving %s (IPv6)\n", sv_master[i]->string); + res = NET_StringToAdr(sv_master[i]->string, &adr[i][1], NA_IP6); + + if(res == 2) + { + // if no port was specified, use the default master port + adr[i][1].port = BigShort(PORT_MASTER); + } + + if(res) + Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][1])); + else + Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string); + } + + if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD) + { + Com_Printf("Couldn't resolve address: %s\n", sv_master[i]->string); + Cvar_Set(sv_master[i]->name, ""); + sv_master[i]->modified = qfalse; + continue; } - Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i])); } Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string ); + // this command should be changed if the server info / status format // ever incompatably changes - NET_OutOfBandPrint( NS_SERVER, adr[i], "heartbeat %s\n", HEARTBEAT_GAME ); + + if(adr[i][0].type != NA_BAD) + NET_OutOfBandPrint( NS_SERVER, adr[i][0], "heartbeat %s\n", HEARTBEAT_GAME ); + if(adr[i][1].type != NA_BAD) + NET_OutOfBandPrint( NS_SERVER, adr[i][1], "heartbeat %s\n", HEARTBEAT_GAME ); } } @@ -342,7 +381,7 @@ and all connected players. Used for getting detailed information after the simple info query. ================ */ -void SVC_Status( netadr_t from ) { +static void SVC_Status( netadr_t from ) { char player[1024]; char status[MAX_MSGLEN]; int i; @@ -449,7 +488,7 @@ SVC_FlushRedirect ================ */ -void SV_FlushRedirect( char *outputbuf ) { +static void SV_FlushRedirect( char *outputbuf ) { NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf ); } @@ -462,7 +501,7 @@ Shift down the remaining args Redirect all printfs =============== */ -void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { +static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { qboolean valid; unsigned int time; char remaining[1024]; @@ -483,10 +522,10 @@ void SVC_RemoteCommand( netadr_t from, msg_t *msg ) { if ( !strlen( sv_rconPassword->string ) || strcmp (Cmd_Argv(1), sv_rconPassword->string) ) { valid = qfalse; - Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); + Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) ); } else { valid = qtrue; - Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (from), Cmd_Argv(2) ); + Com_Printf ("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) ); } // start redirecting all print outputs to the packet @@ -532,7 +571,7 @@ Clients that are in the game can still send connectionless packets. ================= */ -void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { +static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { char *s; char *c; @@ -554,7 +593,7 @@ void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) { } else if (!Q_stricmp(c, "getinfo")) { SVC_Info( from ); } else if (!Q_stricmp(c, "getchallenge")) { - SV_GetChallenge( from ); + SV_GetChallenge(from); } else if (!Q_stricmp(c, "connect")) { SV_DirectConnect( from ); } else if (!Q_stricmp(c, "rcon")) { @@ -641,7 +680,7 @@ SV_CalcPings Updates the cl->ping variables =================== */ -void SV_CalcPings( void ) { +static void SV_CalcPings( void ) { int i, j; client_t *cl; int total, count; @@ -697,7 +736,7 @@ for a few seconds to make sure any final reliable message gets resent if necessary ================== */ -void SV_CheckTimeouts( void ) { +static void SV_CheckTimeouts( void ) { int i; client_t *cl; int droppoint; @@ -738,7 +777,7 @@ void SV_CheckTimeouts( void ) { SV_CheckPaused ================== */ -qboolean SV_CheckPaused( void ) { +static qboolean SV_CheckPaused( void ) { int count; client_t *cl; int i; diff --git a/src/server/sv_net_chan.c b/src/server/sv_net_chan.c index 0de49d4f..dd2bb204 100644 --- a/src/server/sv_net_chan.c +++ b/src/server/sv_net_chan.c @@ -35,28 +35,29 @@ SV_Netchan_Encode ============== */ static void SV_Netchan_Encode( client_t *client, msg_t *msg ) { - long reliableAcknowledge, i, index; + long i, index; byte key, *string; - int srdc, sbit, soob; - + int srdc, sbit; + qboolean soob; + if ( msg->cursize < SV_ENCODE_START ) { return; } - srdc = msg->readcount; - sbit = msg->bit; - soob = msg->oob; - - msg->bit = 0; - msg->readcount = 0; - msg->oob = 0; - - reliableAcknowledge = MSG_ReadLong(msg); + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->bit = 0; + msg->readcount = 0; + msg->oob = qfalse; + + /* reliableAcknowledge = */ MSG_ReadLong(msg); + + msg->oob = soob; + msg->bit = sbit; + msg->readcount = srdc; - msg->oob = soob; - msg->bit = sbit; - msg->readcount = srdc; - string = (byte *)client->lastClientCommandString; index = 0; // xor the client challenge with the netchan sequence number @@ -90,23 +91,24 @@ SV_Netchan_Decode */ static void SV_Netchan_Decode( client_t *client, msg_t *msg ) { int serverId, messageAcknowledge, reliableAcknowledge; - int i, index, srdc, sbit, soob; + int i, index, srdc, sbit; + qboolean soob; byte key, *string; - srdc = msg->readcount; - sbit = msg->bit; - soob = msg->oob; - - msg->oob = 0; - - serverId = MSG_ReadLong(msg); + srdc = msg->readcount; + sbit = msg->bit; + soob = msg->oob; + + msg->oob = qfalse; + + serverId = MSG_ReadLong(msg); messageAcknowledge = MSG_ReadLong(msg); reliableAcknowledge = MSG_ReadLong(msg); - msg->oob = soob; - msg->bit = sbit; - msg->readcount = srdc; - + msg->oob = soob; + msg->bit = sbit; + msg->readcount = srdc; + string = (byte *)client->reliableCommands[ reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ]; index = 0; // @@ -137,7 +139,7 @@ void SV_Netchan_TransmitNextFragment( client_t *client ) { if (!client->netchan.unsentFragments) { // make sure the netchan queue has been properly initialized (you never know) - if (!client->netchan_end_queue) { + if ((!client->netchan_end_queue) && (client->state >= CS_CONNECTED)) { Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n"); } // the last fragment was transmitted, check wether we have queued messages diff --git a/src/server/sv_snapshot.c b/src/server/sv_snapshot.c index 037b772d..d813aad4 100644 --- a/src/server/sv_snapshot.c +++ b/src/server/sv_snapshot.c @@ -299,7 +299,6 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra int l; int clientarea, clientcluster; int leafnum; - int c_fullsend; byte *clientpvs; byte *bitvector; @@ -319,8 +318,6 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra clientpvs = CM_ClusterPVS (clientcluster); - c_fullsend = 0; - for ( e = 0 ; e < sv.num_entities ; e++ ) { ent = SV_GentityNum(e); diff --git a/src/server/sv_world.c b/src/server/sv_world.c index d40cc217..508ff0cc 100644 --- a/src/server/sv_world.c +++ b/src/server/sv_world.c @@ -104,7 +104,7 @@ SV_CreateworldSector Builds a uniformly subdivided tree for the given world size =============== */ -worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) { +static worldSector_t *SV_CreateworldSector( int depth, vec3_t mins, vec3_t maxs ) { worldSector_t *anode; vec3_t size; vec3_t mins1, maxs1, mins2, maxs2; @@ -380,7 +380,7 @@ SV_AreaEntities_r ==================== */ -void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) { +static void SV_AreaEntities_r( worldSector_t *node, areaParms_t *ap ) { svEntity_t *check, *next; sharedEntity_t *gcheck; int count; @@ -508,7 +508,7 @@ SV_ClipMoveToEntities ==================== */ -void SV_ClipMoveToEntities( moveclip_t *clip ) { +static void SV_ClipMoveToEntities( moveclip_t *clip ) { int i, num; int touchlist[MAX_GENTITIES]; sharedEntity_t *touch; diff --git a/src/sys/con_tty.c b/src/sys/con_tty.c index cdd686a1..6f3376e1 100644 --- a/src/sys/con_tty.c +++ b/src/sys/con_tty.c @@ -41,6 +41,7 @@ called before and after a stdout or stderr output ============================================================= */ +static qboolean stdin_active; // general flag to tell about tty console mode static qboolean ttycon_on = qfalse; static int ttycon_hide = 0; @@ -255,6 +256,7 @@ Initialize the console input (tty mode if possible) void CON_Init( void ) { struct termios tc; + const char* term = getenv("TERM"); // If the process is backgrounded (running non interactively) // then SIGTTIN or SIGTOU is emitted, if not caught, turns into a SIGSTP @@ -264,10 +266,12 @@ void CON_Init( void ) // Make stdin reads non-blocking fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | O_NONBLOCK ); - if (isatty(STDIN_FILENO)!=1) + if (isatty(STDIN_FILENO) != 1 + || (term && (!strcmp(term, "raw") || !strcmp(term, "dumb")))) { - Com_Printf( "stdin is not a tty, tty console mode disabled\n"); + Com_Printf("tty console mode disabled\n"); ttycon_on = qfalse; + stdin_active = qtrue; return; } @@ -409,18 +413,11 @@ char *CON_Input( void ) return NULL; } - else + else if (stdin_active) { int len; fd_set fdset; struct timeval timeout; - static qboolean stdin_active; - - if (!com_dedicated || !com_dedicated->value) - return NULL; - - if (!stdin_active) - return NULL; FD_ZERO(&fdset); FD_SET(0, &fdset); // stdin @@ -444,6 +441,7 @@ char *CON_Input( void ) return text; } + return NULL; } /* diff --git a/src/sys/sys_cocoa.m b/src/sys/sys_cocoa.m new file mode 100644 index 00000000..cfc754dd --- /dev/null +++ b/src/sys/sys_cocoa.m @@ -0,0 +1,40 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code is distributed in the hope that it will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifndef MACOS_X +#error This file is for Mac OS X only. You probably should not compile it. +#endif + +// Please note that this file is just some Mac-specific bits. Most of the +// Mac OS X code is shared with other Unix platforms in sys_unix.c ... + +#import <Cocoa/Cocoa.h> + +void Cocoa_MsgBox( const char *text ) +{ + NSRunInformationalAlertPanel(@"ioquake3", + [NSString stringWithUTF8String:text], + @"OK", nil, nil); +} + +// end of sys_cocoa.m ... + diff --git a/src/sys/sys_local.h b/src/sys/sys_local.h index 6d001046..4ecc9227 100644 --- a/src/sys/sys_local.h +++ b/src/sys/sys_local.h @@ -48,6 +48,7 @@ unsigned int CON_LogRead( char *out, unsigned int outSize ); char *Sys_StripAppBundle( char *pwd ); #endif +void Sys_GLimpSafeInit( void ); void Sys_GLimpInit( void ); void Sys_PlatformInit( void ); void Sys_SigHandler( int signal ); diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c index 0d682261..0a4183c7 100644 --- a/src/sys/sys_main.c +++ b/src/sys/sys_main.c @@ -517,8 +517,6 @@ int main( int argc, char **argv ) // Run time const SDL_version *ver = SDL_Linked_Version( ); -#define STRING(s) #s -#define XSTRING(s) STRING(s) #define MINSDL_VERSION \ XSTRING(MINSDL_MAJOR) "." \ XSTRING(MINSDL_MINOR) "." \ @@ -534,6 +532,9 @@ int main( int argc, char **argv ) Sys_PlatformInit( ); + // Set the initial time base + Sys_Milliseconds( ); + Sys_ParseArgs( argc, argv ); Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) ); Sys_SetDefaultInstallPath( DEFAULT_BASEDIR ); @@ -541,7 +542,15 @@ int main( int argc, char **argv ) // Concatenate the command line for passing to Com_Init for( i = 1; i < argc; i++ ) { + const qboolean containsSpaces = strchr(argv[i], ' ') != NULL; + if (containsSpaces) + Q_strcat( commandLine, sizeof( commandLine ), "\"" ); + Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] ); + + if (containsSpaces) + Q_strcat( commandLine, sizeof( commandLine ), "\"" ); + Q_strcat( commandLine, sizeof( commandLine ), " " ); } diff --git a/src/sys/sys_unix.c b/src/sys/sys_unix.c index b55bbe6d..3360469d 100644 --- a/src/sys/sys_unix.c +++ b/src/sys/sys_unix.c @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include <sys/time.h> #include <pwd.h> #include <libgen.h> +#include <fcntl.h> // Used to determine where to store user-specific files static char homePath[ MAX_OSPATH ] = { 0 }; @@ -54,11 +55,15 @@ char *Sys_DefaultHomePath(void) { Q_strncpyz( homePath, p, sizeof( homePath ) ); #ifdef MACOS_X - Q_strcat( homePath, sizeof( homePath ), "/Library/Application Support/Tremulous" ); + Q_strcat( homePath, sizeof( homePath ), "/Library" ); + mkdir( homePath, 0750 ); + Q_strcat( homePath, sizeof( homePath ), "/Application Support" ); + mkdir( homePath, 0750 ); + Q_strcat( homePath, sizeof( homePath ), "/Tremulous" ); #else Q_strcat( homePath, sizeof( homePath ), "/.tremulous" ); #endif - if( mkdir( homePath, 0777 ) ) + if( mkdir( homePath, 0750 ) ) { if( errno != EEXIST ) { @@ -497,23 +502,58 @@ void Sys_ErrorDialog( const char *error ) { char buffer[ 1024 ]; unsigned int size; - fileHandle_t f; + int f = -1; + const char *homepath = Cvar_VariableString( "fs_homepath" ); + const char *gamedir = Cvar_VariableString( "fs_gamedir" ); const char *fileName = "crashlog.txt"; + char *ospath = FS_BuildOSPath( homepath, gamedir, fileName ); Sys_Print( va( "%s\n", error ) ); - // Write console log to file - f = FS_FOpenFileWrite( fileName ); - if( !f ) +#if defined(MACOS_X) && !DEDICATED + /* This function has to be in a separate file, compiled as Objective-C. */ + extern void Cocoa_MsgBox( const char *text ); + if (!com_dedicated || !com_dedicated->integer) + Cocoa_MsgBox(error); +#endif + + /* make sure the write path for the crashlog exists... */ + if( FS_CreatePath( ospath ) ) { + Com_Printf( "ERROR: couldn't create path '%s' for crash log.\n", ospath ); + return; + } + + /* we might be crashing because we maxed out the Quake MAX_FILE_HANDLES, + which will come through here, so we don't want to recurse forever by + calling FS_FOpenFileWrite()...use the Unix system APIs instead. */ + f = open(ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640); + if( f == -1 ) { Com_Printf( "ERROR: couldn't open %s\n", fileName ); return; } - while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) - FS_Write( buffer, size, f ); + /* We're crashing, so we don't care much if write() or close() fails. */ + while( ( size = CON_LogRead( buffer, sizeof( buffer ) ) ) > 0 ) { + if (write( f, buffer, size ) != size) { + Com_Printf( "ERROR: couldn't fully write to %s\n", fileName ); + break; + } + } - FS_FCloseFile( f ); + close(f); +} + +/* +============== +Sys_GLimpSafeInit + +Unix specific "safe" GL implementation initialisation +============== +*/ +void Sys_GLimpSafeInit( void ) +{ + // NOP } /* diff --git a/src/sys/sys_win32.c b/src/sys/sys_win32.c index aac4384d..18efe406 100644 --- a/src/sys/sys_win32.c +++ b/src/sys/sys_win32.c @@ -583,6 +583,25 @@ static qboolean SDL_VIDEODRIVER_externallySet = qfalse; /* ============== +Sys_GLimpSafeInit + +Windows specific "safe" GL implementation initialisation +============== +*/ +void Sys_GLimpSafeInit( void ) +{ +#ifndef DEDICATED + if( !SDL_VIDEODRIVER_externallySet ) + { + // Here, we want to let SDL decide what do to unless + // explicitly requested otherwise + _putenv( "SDL_VIDEODRIVER=" ); + } +#endif +} + +/* +============== Sys_GLimpInit Windows specific GL implementation initialisation diff --git a/src/tools/asm/cmdlib.c b/src/tools/asm/cmdlib.c index ac088675..aca34313 100644 --- a/src/tools/asm/cmdlib.c +++ b/src/tools/asm/cmdlib.c @@ -186,7 +186,7 @@ void _printf( const char *format, ... ) { vsprintf (text, format, argptr); va_end (argptr); - printf(text); + printf("%s", text); #ifdef WIN32 if (!lookedForServer) { @@ -397,10 +397,12 @@ void Q_getwd (char *out) int i = 0; #ifdef WIN32 - _getcwd (out, 256); + if (_getcwd (out, 256) == NULL) + strcpy(out, "."); /* shrug */ strcat (out, "\\"); #else - getcwd (out, 256); + if (getcwd (out, 256) == NULL) + strcpy(out, "."); /* shrug */ strcat (out, "/"); #endif diff --git a/src/tools/asm/q3asm.c b/src/tools/asm/q3asm.c index 3c334815..481a1acb 100644 --- a/src/tools/asm/q3asm.c +++ b/src/tools/asm/q3asm.c @@ -490,10 +490,10 @@ static void CodeError( char *fmt, ... ) { errorCount++; - report( "%s:%i ", currentFileName, currentFileLine ); + fprintf( stderr, "%s:%i ", currentFileName, currentFileLine ); va_start( argptr,fmt ); - vprintf( fmt,argptr ); + vfprintf( stderr, fmt, argptr ); va_end( argptr ); } @@ -1521,12 +1521,13 @@ static void ShowHelp( char *argv0 ) { Error("Usage: %s [OPTION]... [FILES]...\n\ Assemble LCC bytecode assembly to Q3VM bytecode.\n\ \n\ - -o OUTPUT Write assembled output to file OUTPUT.qvm\n\ - -f LISTFILE Read options and list of files to assemble from LISTFILE.q3asm\n\ - -b BUCKETS Set symbol hash table to BUCKETS buckets\n\ - -v Verbose compilation report\n\ - -vq3 Produce a qvm file compatible with Q3 1.32b\n\ - -h --help -? Show this help\n\ + -o OUTPUT Write assembled output to file OUTPUT.qvm\n\ + -f LISTFILE Read options and list of files to assemble from LISTFILE.q3asm\n\ + -b BUCKETS Set symbol hash table to BUCKETS buckets\n\ + -m Generate a mapfile for each OUTPUT.qvm\n\ + -v Verbose compilation report\n\ + -vq3 Produce a qvm file compatible with Q3 1.32b\n\ + -h --help -? Show this help\n\ ", argv0); } |