diff --git a/3rdparty/library_suffix b/3rdparty/library_suffix index 5b670f63..6e14ae31 160000 --- a/3rdparty/library_suffix +++ b/3rdparty/library_suffix @@ -1 +1 @@ -Subproject commit 5b670f638b4eaee9d455678d803ca017be7d3c77 +Subproject commit 6e14ae31e86ba4cbab22f14dd439b17f76d3c5ba diff --git a/3rdparty/mainui b/3rdparty/mainui index d5946734..af2b5abd 160000 --- a/3rdparty/mainui +++ b/3rdparty/mainui @@ -1 +1 @@ -Subproject commit d594673462ae72851e82be0c606fb2ba909dab5d +Subproject commit af2b5abdde3f9b590944934af16ab652914c2cce diff --git a/common/com_model.h b/common/com_model.h index a6e09ca4..f907447d 100644 --- a/common/com_model.h +++ b/common/com_model.h @@ -612,9 +612,9 @@ static inline mnode_t *node_child( const mnode_t *n, int side, const model_t *mo } } - return n->children_[side]; + return n->children_[side ? 1 : 0]; #else - return n->children_[side]; + return n->children_[side ? 1 : 0]; #endif } diff --git a/engine/client/avi/avi_ffmpeg.c b/engine/client/avi/avi_ffmpeg.c index d77f7e39..a569e370 100644 --- a/engine/client/avi/avi_ffmpeg.c +++ b/engine/client/avi/avi_ffmpeg.c @@ -255,9 +255,9 @@ static void AVI_StreamAudio( movie_state_t *Avi ) rawchan_t *ch = NULL; // keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled - qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !s_listener.streaming : false; + qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !snd.streaming : false; - if( !dma.initialized || disable_stream || cl.paused || !Avi->cached_audio ) + if( !snd.initialized || disable_stream || cl.paused || !Avi->cached_audio ) return; ch = S_FindRawChannel( Avi->entnum, true ); @@ -268,14 +268,14 @@ static void AVI_StreamAudio( movie_state_t *Avi ) ch->master_vol = Avi->volume; ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE); - if( ch->s_rawend < soundtime ) - ch->s_rawend = soundtime; + if( ch->s_rawend < snd.soundtime ) + ch->s_rawend = snd.soundtime; - while( ch->s_rawend < soundtime + ch->max_samples ) + while( ch->s_rawend < snd.soundtime + ch->max_samples ) { size_t copy; - buffer_samples = ch->max_samples - (ch->s_rawend - soundtime); + buffer_samples = ch->max_samples - (ch->s_rawend - snd.soundtime); file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED); if( file_samples <= 1 ) return; // no more samples need diff --git a/engine/client/cl_font.c b/engine/client/cl_font.c index 59d03274..131b7ee7 100644 --- a/engine/client/cl_font.c +++ b/engine/client/cl_font.c @@ -70,11 +70,7 @@ void CL_SetFontRendermode( cl_font_t *font ) void CL_SetFontColor( cl_font_t *font, const rgba_t color ) { - // don't apply color to fixed fonts it's already colored - if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8 - ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] ); - else - ref.dllFuncs.Color4ub( 255, 255, 255, color[3] ); + ref.dllFuncs.Color4ub( color[0], color[1], color[2], color[3] ); } qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags ) diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index 68a4d9cd..dcd27323 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -1381,7 +1381,7 @@ qboolean CL_GetEntitySpatialization( channel_t *ch ) if( ch->entnum == 0 ) { - ch->staticsound = true; + SetBits( ch->flags, FL_CHAN_STATIC_SOUND ); return true; // static sound } diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index c86faad0..1116b6cf 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -37,11 +37,20 @@ GNU General Public License for more details. #include "platform/platform.h" #define MAX_LINELENGTH 80 -#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels) -#define TEXT_MSGNAME "TextMessage%i" +#define TEXT_MSGNAME "TextMessage" static char cl_textbuffer[MAX_TEXTCHANNELS][2048]; -static client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS]; +client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS] = +{ +{ .pName = "TextMessage0", .pMessage = cl_textbuffer[0] }, +{ .pName = "TextMessage1", .pMessage = cl_textbuffer[1] }, +{ .pName = "TextMessage2", .pMessage = cl_textbuffer[2] }, +{ .pName = "TextMessage3", .pMessage = cl_textbuffer[3] }, +{ .pName = "TextMessage4", .pMessage = cl_textbuffer[4] }, +{ .pName = "TextMessage5", .pMessage = cl_textbuffer[5] }, +{ .pName = "TextMessage6", .pMessage = cl_textbuffer[6] }, +{ .pName = "TextMessage7", .pMessage = cl_textbuffer[7] }, +}; static const dllfunc_t cdll_exports[] = { @@ -180,7 +189,13 @@ static void CL_InitCDAudio( const char *filename ) while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL ) { if( !Q_stricmp( token, "blank" )) + { clgame.cdtracks[c][0] = '\0'; + } + else if( token[0] == '/' ) // allow custom path + { + Q_strncpy( clgame.cdtracks[c], &token[1], sizeof( clgame.cdtracks[c] )); + } else { Q_snprintf( clgame.cdtracks[c], sizeof( clgame.cdtracks[c] ), @@ -561,31 +576,18 @@ and hold them into permament memory pool */ static void CL_InitTitles( const char *filename ) { - fs_offset_t fileSize; - byte *pMemFile; - int i; - - // initialize text messages (game_text) - for( i = 0; i < MAX_TEXTCHANNELS; i++ ) - { - char name[MAX_VA_STRING]; - - Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i ); - - cl_textmessage[i].pName = copystringpool( clgame.mempool, name ); - cl_textmessage[i].pMessage = cl_textbuffer[i]; - } - // clear out any old data that's sitting around. - if( clgame.titles ) Mem_Free( clgame.titles ); + Mem_Free( clgame.titles ); clgame.titles = NULL; clgame.numTitles = 0; - pMemFile = FS_LoadFile( filename, &fileSize, false ); - if( !pMemFile ) return; + fs_offset_t fileSize = 0; + char *pMemFile = (char *)FS_LoadFile( filename, &fileSize, false ); + if( !pMemFile ) + return; - clgame.titles = CL_TextMessageParse( clgame.mempool, (char *)pMemFile, fileSize, &clgame.numTitles ); + clgame.titles = CL_TextMessageParse( clgame.mempool, pMemFile, fileSize, &clgame.numTitles ); Mem_Free( pMemFile ); } @@ -654,54 +656,6 @@ void CL_ParseTextMessage( sizebuf_t *msg ) CL_HudMessage( text->pName ); } -/* -================ -CL_ParseFinaleCutscene - -show display finale or cutscene message -================ -*/ -void CL_ParseFinaleCutscene( sizebuf_t *msg, int level ) -{ - static int msgindex = 0; - client_textmessage_t *text; - int channel; - - cl.intermission = level; - - channel = msgindex; - msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1); - - // grab message channel - text = &cl_textmessage[channel]; - - // NOTE: svc_finale and svc_cutscene has a - // predefined settings like Quake-style - text->x = -1.0f; - text->y = 0.15f; - text->effect = 2; // scan out effect - text->r1 = 245; - text->g1 = 245; - text->b1 = 245; - text->a1 = 0; // unused - text->r2 = 0; - text->g2 = 0; - text->b2 = 0; - text->a2 = 0; - text->fadein = 0.15f; - text->fadeout = 0.0f; - text->holdtime = 99999.0f; - text->fxtime = 0.0f; - - // to prevent grab too long messages - Q_strncpy( (char *)text->pMessage, MSG_ReadString( msg ), 2048 ); - - if( *text->pMessage == '\0' ) - return; // no real text - - CL_HudMessage( text->pName ); -} - /* ==================== CL_GetMaxlients @@ -1975,13 +1929,12 @@ client_textmessage_t *CL_TextMessageGet( const char *pName ) int i; // first check internal messages - for( i = 0; i < MAX_TEXTCHANNELS; i++ ) + if( Q_strlen( pName ) == sizeof( TEXT_MSGNAME ) // including the digit + && !Q_strncmp( pName, TEXT_MSGNAME, sizeof( TEXT_MSGNAME ) - 1 )) { - char name[MAX_VA_STRING]; + i = pName[sizeof( TEXT_MSGNAME ) - 1] - '0'; - Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i ); - - if( !Q_strcmp( pName, name )) + if( i >= 0 && i < MAX_TEXTCHANNELS ) return cl_textmessage + i; } @@ -4096,14 +4049,14 @@ qboolean CL_LoadProgs( const char *name ) CL_InitCDAudio( "media/cdaudio.txt" ); CL_InitTitles( "titles.txt" ); - CL_InitParticles (); - CL_InitViewBeams (); - CL_InitTempEnts (); + CL_InitParticles( ); + CL_InitViewBeams( ); + CL_InitTempEnts( ); - if( !R_InitRenderAPI()) // Xash3D extension + if( !R_InitRenderAPI( )) // Xash3D extension Con_Reportf( S_WARN "%s: couldn't get render API\n", __func__ ); - if( !Mobile_Init() ) // Xash3D FWGS extension: mobile interface + if( !Mobile_Init( )) // Xash3D FWGS extension: mobile interface Con_Reportf( S_WARN "%s: couldn't get mobility API\n", __func__ ); CL_InitEdicts( cl.maxclients ); // initailize local player and world diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 3580bf4a..f185f1e3 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1174,7 +1174,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge ) else { const char *qport = Cvar_VariableString( "net_qport" ); - int extensions = NET_EXT_SPLITSIZE; + int extensions = Host_IsLocalGame() ? 0 : NET_EXT_SPLITSIZE; string key; ID_GetMD5ForAddress( key, adr, sizeof( key )); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 5078fff3..c5567a73 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -42,7 +42,7 @@ CL_ParseViewEntity ================== */ -void CL_ParseViewEntity( sizebuf_t *msg ) +static void CL_ParseViewEntity( sizebuf_t *msg ) { cl.viewentity = MSG_ReadWord( msg ); @@ -161,7 +161,7 @@ CL_ParseSignon ================== */ -void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto ) +static void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto ) { int i = MSG_ReadByte( msg ); @@ -209,7 +209,7 @@ CL_ParseParticles ================== */ -void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto ) +static void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto ) { vec3_t org, dir; int i, count, color; @@ -362,7 +362,7 @@ CL_ParseSoundFade ================== */ -void CL_ParseSoundFade( sizebuf_t *msg ) +static void CL_ParseSoundFade( sizebuf_t *msg ) { int fade_percent = MSG_ReadByte( msg ); int hold_time = MSG_ReadByte( msg ); @@ -616,7 +616,7 @@ CL_ParseCustomization ================== */ -void CL_ParseCustomization( sizebuf_t *msg ) +static void CL_ParseCustomization( sizebuf_t *msg ) { customization_t *pExistingCustomization; customization_t *pList; @@ -704,7 +704,7 @@ CL_ParseResourceRequest ================== */ -void CL_ParseResourceRequest( sizebuf_t *msg ) +static void CL_ParseResourceRequest( sizebuf_t *msg ) { byte buffer[MAX_INIT_MSG]; int i, arg, nStartIndex; @@ -776,7 +776,7 @@ CL_ParseFileTransferFailed ================== */ -void CL_ParseFileTransferFailed( sizebuf_t *msg ) +static void CL_ParseFileTransferFailed( sizebuf_t *msg ) { const char *name = MSG_ReadString( msg ); @@ -796,7 +796,7 @@ void CL_ParseFileTransferFailed( sizebuf_t *msg ) CL_ParseServerData ================== */ -void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto ) +static void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto ) { char gamefolder[MAX_QPATH]; string mapfile; @@ -1234,7 +1234,7 @@ void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto ) CL_ParseLightStyle ================ */ -void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto ) +static void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto ) { int style; const char *s; @@ -1255,7 +1255,7 @@ CL_ParseSetAngle set the view angle to this absolute value ================ */ -void CL_ParseSetAngle( sizebuf_t *msg ) +static void CL_ParseSetAngle( sizebuf_t *msg ) { MSG_ReadVec3Angles( msg, cl.viewangles ); } @@ -1267,7 +1267,7 @@ CL_ParseAddAngle add the view angle yaw ================ */ -void CL_ParseAddAngle( sizebuf_t *msg ) +static void CL_ParseAddAngle( sizebuf_t *msg ) { pred_viewangle_t *a; float delta_yaw; @@ -1296,7 +1296,7 @@ CL_ParseCrosshairAngle offset crosshair angles ================ */ -void CL_ParseCrosshairAngle( sizebuf_t *msg ) +static void CL_ParseCrosshairAngle( sizebuf_t *msg ) { cl.crosshairangle[0] = MSG_ReadChar( msg ) * 0.2f; cl.crosshairangle[1] = MSG_ReadChar( msg ) * 0.2f; @@ -1310,7 +1310,7 @@ CL_ParseRestore reading decals, etc. ================ */ -void CL_ParseRestore( sizebuf_t *msg ) +static void CL_ParseRestore( sizebuf_t *msg ) { string filename; int i, mapCount; @@ -1337,7 +1337,7 @@ CL_RegisterUserMessage register new user message or update existing ================ */ -void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto ) +static void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto ) { char *pszName; char szName[17]; @@ -1375,7 +1375,7 @@ CL_UpdateUserinfo collect userinfo from all players ================ */ -void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto ) +static void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto ) { int slot, id; qboolean active; @@ -1898,7 +1898,7 @@ CL_ParseVoiceInit ================== */ -void CL_ParseVoiceInit( sizebuf_t *msg ) +static void CL_ParseVoiceInit( sizebuf_t *msg ) { char *pszCodec = MSG_ReadString( msg ); int quality = MSG_ReadByte( msg ); @@ -1912,7 +1912,7 @@ CL_ParseVoiceData ================== */ -void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto ) +static void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto ) { int size, idx, frames = 0; byte received[VOICE_MAX_DATA_SIZE]; @@ -1962,7 +1962,7 @@ CL_ParseResLocation ================== */ -void CL_ParseResLocation( sizebuf_t *msg ) +static void CL_ParseResLocation( sizebuf_t *msg ) { char *data = MSG_ReadString( msg ); char token[256]; @@ -1991,7 +1991,7 @@ sended from game.dll normal client ignores any of HLTV messages ============== */ -void CL_ParseHLTV( sizebuf_t *msg ) +static void CL_ParseHLTV( sizebuf_t *msg ) { switch( MSG_ReadByte( msg )) { @@ -2025,7 +2025,7 @@ spectator message (director) sended from game.dll ============== */ -void CL_ParseDirector( sizebuf_t *msg ) +static void CL_ParseDirector( sizebuf_t *msg ) { int iSize = MSG_ReadByte( msg ); byte pbuf[256]; @@ -2119,7 +2119,7 @@ Find the client cvar value and sent it back to the server ============== */ -void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext, const connprotocol_t proto ) +static void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext, const connprotocol_t proto ) { const char *cvarName, *response = NULL; convar_t *cvar; @@ -2181,7 +2181,7 @@ CL_ParseExec Exec map/class specific configs ============== */ -void CL_ParseExec( sizebuf_t *msg ) +static void CL_ParseExec( sizebuf_t *msg ) { qboolean is_class; int class_idx; @@ -2357,25 +2357,150 @@ ACTION MESSAGES */ /* -============ -CL_ParseCommonDLLMessage +================ +CL_ParseFinaleCutscene -parse a message which structure is enforced by DLL compatibility -it should always be the same regardless of protocol used +show display finale or cutscene message +================ +*/ +static void CL_ParseFinaleCutscene( sizebuf_t *msg, int level ) +{ + static int msgindex = 0; + client_textmessage_t *text; + int channel; + + cl.intermission = level; + + channel = msgindex; + msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1); + + // grab message channel + text = &cl_textmessage[channel]; + + // NOTE: svc_finale and svc_cutscene has a + // predefined settings like Quake-style + text->x = -1.0f; + text->y = 0.15f; + text->effect = 2; // scan out effect + text->r1 = 245; + text->g1 = 245; + text->b1 = 245; + text->a1 = 0; // unused + text->r2 = 0; + text->g2 = 0; + text->b2 = 0; + text->a2 = 0; + text->fadein = 0.15f; + text->fadeout = 0.0f; + text->holdtime = 99999.0f; + text->fxtime = 0.0f; + + // to prevent grab too long messages + Q_strncpy( (char *)text->pMessage, MSG_ReadString( msg ), 2048 ); + + if( *text->pMessage == '\0' ) + return; // no real text + + CL_HudMessage( text->pName ); +} + +/* +============ +CL_ParseCommonMessage + +parse a message which is the same across all supported protocols ============ */ -qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ) +qboolean CL_ParseCommonMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ) { - int param1, param2; + switch( svc_num ) + { + case svc_nop: + break; + case svc_setview: + CL_ParseViewEntity( msg ); + break; + case svc_lightstyle: + CL_ParseLightStyle( msg, proto ); + break; + case svc_intermission: + cl.intermission = 1; + break; + case svc_finale: + CL_ParseFinaleCutscene( msg, 2 ); + break; + case svc_cutscene: + CL_ParseFinaleCutscene( msg, 3 ); + break; + default: + return false; + } + + return true; +} + +/* +============ +CL_ParseCommonHLMessage + +parse a message which structure is enforced by DLL compatibility +it should always be the same regardless of HL-based protocol used +============ +*/ +qboolean CL_ParseCommonHLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ) +{ + const char *s; + int param1, param2; switch( svc_num ) { + case svc_bad: + Host_Error( "svc_bad\n" ); + break; + case svc_time: + CL_ParseServerTime( msg, proto ); + break; + case svc_print: + Con_Printf( "%s", MSG_ReadString( msg )); + break; + case svc_stufftext: + s = MSG_ReadString( msg ); + if( cl_trace_stufftext.value ) + { + size_t len = Q_strlen( s ); + Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' ); + } + +#ifdef HACKS_RELATED_HLMODS + // disable Cry Of Fear antisave protection + if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) + break; // too early +#endif + + Cbuf_AddFilteredText( s ); + break; + case svc_setangle: + CL_ParseSetAngle( msg ); + break; + case svc_serverdata: + Cbuf_Execute(); // make sure any stuffed commands are done + CL_ParseServerData( msg, proto ); + break; + case svc_updateuserinfo: + CL_UpdateUserinfo( msg, proto ); + break; + case svc_particle: + CL_ParseParticles( msg, proto ); + break; case svc_temp_entity: CL_ParseTempEntity( msg, proto ); // need protocol because message header differs cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - startoffset; break; - case svc_intermission: - cl.intermission = 1; + case svc_signonnum: + CL_ParseSignon( msg, proto ); + break; + case svc_centerprint: + CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); break; case svc_cdtrack: param1 = MSG_ReadByte( msg ); @@ -2384,6 +2509,9 @@ qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0, false ); break; + case svc_restore: + CL_ParseRestore( msg ); + break; case svc_weaponanim: param1 = MSG_ReadByte( msg ); // iAnim param2 = MSG_ReadByte( msg ); // body @@ -2393,9 +2521,56 @@ qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc param1 = MSG_ReadShort( msg ); Cvar_SetValue( "room_type", param1 ); break; + case svc_addangle: + CL_ParseAddAngle( msg ); + break; + case svc_usermessage: + CL_RegisterUserMessage( msg, proto ); + break; + case svc_choke: + cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true; + cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0; + break; + case svc_resourcerequest: + CL_ParseResourceRequest( msg ); + break; + case svc_customization: + CL_ParseCustomization( msg ); + break; + case svc_crosshairangle: + CL_ParseCrosshairAngle( msg ); + break; + case svc_soundfade: + CL_ParseSoundFade( msg ); + break; + case svc_filetxferfailed: + CL_ParseFileTransferFailed( msg ); + break; + case svc_hltv: + CL_ParseHLTV( msg ); + break; case svc_director: CL_ParseDirector( msg ); break; + case svc_voiceinit: + CL_ParseVoiceInit( msg ); + break; + case svc_voicedata: + CL_ParseVoiceData( msg, proto ); + cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - startoffset; + break; + case svc_resourcelocation: + CL_ParseResLocation( msg ); + break; + case svc_querycvarvalue: + CL_ParseCvarValue( msg, false, proto ); + break; + case svc_querycvarvalue2: + CL_ParseCvarValue( msg, true, proto ); + break; + case svc_exec: + CL_ParseExec( msg ); + break; default: return false; } @@ -2415,7 +2590,6 @@ void CL_ParseServerMessage( sizebuf_t *msg ) size_t bufStart, playerbytes; int cmd; int old_background; - const char *s; // parse the message while( 1 ) @@ -2438,18 +2612,15 @@ void CL_ParseServerMessage( sizebuf_t *msg ) // record command for debugging spew on parse problem CL_Parse_RecordCommand( cmd, bufStart ); - if( CL_ParseCommonDLLMessage( msg, PROTO_CURRENT, cmd, bufStart )) + if( CL_ParseCommonMessage( msg, PROTO_CURRENT, cmd, bufStart )) + continue; + + if( CL_ParseCommonHLMessage( msg, PROTO_CURRENT, cmd, bufStart )) continue; // other commands switch( cmd ) { - case svc_bad: - Host_Error( "svc_bad\n" ); - break; - case svc_nop: - // this does nothing - break; case svc_disconnect: CL_Drop (); Host_AbortCurrentFrame (); @@ -2497,48 +2668,10 @@ void CL_ParseServerMessage( sizebuf_t *msg ) cls.connect_retry = 0; } break; - case svc_setview: - CL_ParseViewEntity( msg ); - break; case svc_sound: CL_ParseSoundPacket( msg, false ); cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; break; - case svc_time: - CL_ParseServerTime( msg, PROTO_CURRENT ); - break; - case svc_print: - Con_Printf( "%s", MSG_ReadString( msg )); - break; - case svc_stufftext: - s = MSG_ReadString( msg ); - if( cl_trace_stufftext.value ) - { - size_t len = Q_strlen( s ); - Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' ); - } - -#ifdef HACKS_RELATED_HLMODS - // disable Cry Of Fear antisave protection - if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) - break; // too early -#endif - - Cbuf_AddFilteredText( s ); - break; - case svc_setangle: - CL_ParseSetAngle( msg ); - break; - case svc_serverdata: - Cbuf_Execute(); // make sure any stuffed commands are done - CL_ParseServerData( msg, PROTO_CURRENT ); - break; - case svc_lightstyle: - CL_ParseLightStyle( msg, PROTO_CURRENT ); - break; - case svc_updateuserinfo: - CL_UpdateUserinfo( msg, PROTO_CURRENT ); - break; case svc_deltatable: Delta_ParseTableField( msg ); break; @@ -2552,9 +2685,6 @@ void CL_ParseServerMessage( sizebuf_t *msg ) case svc_pings: CL_UpdateUserPings( msg ); break; - case svc_particle: - CL_ParseParticles( msg, PROTO_CURRENT ); - break; case svc_restoresound: CL_ParseSoundPacket( msg, true ); cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; @@ -2572,30 +2702,9 @@ void CL_ParseServerMessage( sizebuf_t *msg ) case svc_setpause: cl.paused = ( MSG_ReadOneBit( msg ) != 0 ); break; - case svc_signonnum: - CL_ParseSignon( msg, PROTO_CURRENT ); - break; - case svc_centerprint: - CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); - break; - case svc_finale: - CL_ParseFinaleCutscene( msg, 2 ); - break; - case svc_restore: - CL_ParseRestore( msg ); - break; - case svc_cutscene: - CL_ParseFinaleCutscene( msg, 3 ); - break; case svc_bspdecal: CL_ParseStaticDecal( msg ); break; - case svc_addangle: - CL_ParseAddAngle( msg ); - break; - case svc_usermessage: - CL_RegisterUserMessage( msg, PROTO_CURRENT ); - break; case svc_packetentities: playerbytes = CL_ParsePacketEntities( msg, false, PROTO_CURRENT ); cl.frames[cl.parsecountmod].graphdata.players += playerbytes; @@ -2606,53 +2715,12 @@ void CL_ParseServerMessage( sizebuf_t *msg ) cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; break; - case svc_choke: - cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true; - cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0; - break; case svc_resourcelist: CL_ParseResourceList( msg, PROTO_CURRENT ); break; case svc_deltamovevars: CL_ParseMovevars( msg ); break; - case svc_resourcerequest: - CL_ParseResourceRequest( msg ); - break; - case svc_customization: - CL_ParseCustomization( msg ); - break; - case svc_crosshairangle: - CL_ParseCrosshairAngle( msg ); - break; - case svc_soundfade: - CL_ParseSoundFade( msg ); - break; - case svc_filetxferfailed: - CL_ParseFileTransferFailed( msg ); - break; - case svc_hltv: - CL_ParseHLTV( msg ); - break; - case svc_voiceinit: - CL_ParseVoiceInit( msg ); - break; - case svc_voicedata: - CL_ParseVoiceData( msg, PROTO_CURRENT ); - cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_resourcelocation: - CL_ParseResLocation( msg ); - break; - case svc_querycvarvalue: - CL_ParseCvarValue( msg, false, PROTO_CURRENT ); - break; - case svc_querycvarvalue2: - CL_ParseCvarValue( msg, true, PROTO_CURRENT ); - break; - case svc_exec: - CL_ParseExec( msg ); - break; default: CL_ParseUserMessage( msg, cmd, PROTO_CURRENT ); cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart; diff --git a/engine/client/cl_parse_gs.c b/engine/client/cl_parse_gs.c index 7c6b92c0..5d99aaa5 100644 --- a/engine/client/cl_parse_gs.c +++ b/engine/client/cl_parse_gs.c @@ -569,22 +569,15 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) // record command for debugging spew on parse problem CL_Parse_RecordCommand( cmd, bufStart ); - if( CL_ParseCommonDLLMessage( msg, PROTO_GOLDSRC, cmd, bufStart )) + if( CL_ParseCommonMessage( msg, PROTO_GOLDSRC, cmd, bufStart )) + continue; + + if( CL_ParseCommonHLMessage( msg, PROTO_GOLDSRC, cmd, bufStart )) continue; // other commands switch( cmd ) { - case svc_bad: - Host_Error( "svc_bad\n" ); - break; - case svc_nop: - case svc_spawnstatic: - case svc_goldsrc_damage: - case svc_goldsrc_killedmonster: - case svc_goldsrc_foundsecret: - // this does nothing - break; case svc_disconnect: s = MSG_ReadString( msg ); if( !COM_StringEmpty( s )) @@ -603,47 +596,10 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) if( param1 != PROTOCOL_GOLDSRC_VERSION ) Host_Error( "Server use invalid protocol (%i should be %i)\n", param1, PROTOCOL_GOLDSRC_VERSION ); break; - case svc_setview: - CL_ParseViewEntity( msg ); - break; case svc_sound: CL_ParseSoundPacketGS( msg ); cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; break; - case svc_time: - CL_ParseServerTime( msg, PROTO_GOLDSRC ); - break; - case svc_print: - Con_Printf( "%s", MSG_ReadString( msg )); - break; - case svc_stufftext: - s = MSG_ReadString( msg ); - if( cl_trace_stufftext.value ) - { - size_t len = Q_strlen( s ); - Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' ); - } - -#ifdef HACKS_RELATED_HLMODS - // disable Cry Of Fear antisave protection - if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS ) - break; // too early -#endif - Cbuf_AddFilteredText( s ); - break; - case svc_setangle: - CL_ParseSetAngle( msg ); - break; - case svc_serverdata: - Cbuf_Execute(); // make sure any stuffed commands are done - CL_ParseServerData( msg, PROTO_GOLDSRC ); - break; - case svc_lightstyle: - CL_ParseLightStyle( msg, PROTO_GOLDSRC ); - break; - case svc_updateuserinfo: - CL_UpdateUserinfo( msg, PROTO_GOLDSRC ); - break; case svc_deltatable: Delta_ParseTableField_GS( msg ); break; @@ -663,8 +619,9 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) CL_UpdateUserPings( msg ); MSG_EndBitWriting( msg ); break; - case svc_particle: - CL_ParseParticles( msg, PROTO_GOLDSRC ); + case svc_goldsrc_damage: + case svc_spawnstatic: + // this does nothing break; case svc_event_reliable: MSG_StartBitWriting( msg ); @@ -680,35 +637,18 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) case svc_setpause: cl.paused = ( MSG_ReadByte( msg ) != 0 ); break; - case svc_signonnum: - CL_ParseSignon( msg, PROTO_GOLDSRC ); - break; - case svc_centerprint: - CL_CenterPrint( MSG_ReadString( msg ), 0.25f ); + case svc_goldsrc_killedmonster: + case svc_goldsrc_foundsecret: + // this does nothing break; case svc_goldsrc_spawnstaticsound: CL_ParseSpawnStaticSound( msg ); break; - case svc_finale: - CL_ParseFinaleCutscene( msg, 2 ); - break; - case svc_restore: - CL_ParseRestore( msg ); - break; - case svc_cutscene: - CL_ParseFinaleCutscene( msg, 3 ); - break; case svc_goldsrc_decalname: param1 = MSG_ReadByte( msg ); s = MSG_ReadString( msg ); Q_strncpy( host.draw_decals[param1], s, sizeof( host.draw_decals[param1] )); break; - case svc_addangle: - CL_ParseAddAngle( msg ); - break; - case svc_usermessage: - CL_RegisterUserMessage( msg, PROTO_GOLDSRC ); - break; case svc_packetentities: playerbytes = CL_ParsePacketEntitiesGS( msg, false ); cl.frames[cl.parsecountmod].graphdata.players += playerbytes; @@ -719,10 +659,6 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) cl.frames[cl.parsecountmod].graphdata.players += playerbytes; cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes; break; - case svc_choke: - cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true; - cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0; - break; case svc_resourcelist: MSG_StartBitWriting( msg ); CL_ParseResourceList( msg, PROTO_GOLDSRC ); @@ -731,34 +667,6 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) case svc_deltamovevars: CL_ParseNewMovevars( msg ); break; - case svc_resourcerequest: - CL_ParseResourceRequest( msg ); - break; - case svc_customization: - CL_ParseCustomization( msg ); - break; - case svc_crosshairangle: - CL_ParseCrosshairAngle( msg ); - break; - case svc_soundfade: - CL_ParseSoundFade( msg ); - break; - case svc_filetxferfailed: - CL_ParseFileTransferFailed( msg ); - break; - case svc_hltv: - CL_ParseHLTV( msg ); - break; - case svc_voiceinit: - CL_ParseVoiceInit( msg ); - break; - case svc_voicedata: - CL_ParseVoiceData( msg, PROTO_GOLDSRC ); - cl.frames[cl.parsecountmod].graphdata.voicebytes += MSG_GetNumBytesRead( msg ) - bufStart; - break; - case svc_resourcelocation: - CL_ParseResLocation( msg ); - break; case svc_goldsrc_sendextrainfo: CL_ParseExtraInfo( msg ); break; @@ -768,15 +676,6 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg ) Con_Reportf( S_ERROR "%s: svc_goldsrc_timescale: implement me!\n", __func__ ); MSG_ReadFloat( msg ); break; - case svc_querycvarvalue: - CL_ParseCvarValue( msg, false, PROTO_GOLDSRC ); - break; - case svc_querycvarvalue2: - CL_ParseCvarValue( msg, true, PROTO_GOLDSRC ); - break; - case svc_exec: - CL_ParseExec( msg ); - break; default: CL_ParseUserMessage( msg, cmd, PROTO_GOLDSRC ); cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart; diff --git a/engine/client/cl_qparse.c b/engine/client/cl_qparse.c index 21d339d8..90a9d3af 100644 --- a/engine/client/cl_qparse.c +++ b/engine/client/cl_qparse.c @@ -930,12 +930,12 @@ void CL_ParseQuakeMessage( sizebuf_t *msg ) // record command for debugging spew on parse problem CL_Parse_RecordCommand( cmd, bufStart ); + if( CL_ParseCommonMessage( msg, PROTO_QUAKE, cmd, bufStart )) + continue; + // other commands switch( cmd ) { - case svc_nop: - // this does nothing - break; case svc_disconnect: CL_DemoCompleted (); break; @@ -947,9 +947,6 @@ void CL_ParseQuakeMessage( sizebuf_t *msg ) if( param1 != PROTOCOL_VERSION_QUAKE ) Host_Error( "Server is protocol %i instead of %i\n", param1, PROTOCOL_VERSION_QUAKE ); break; - case svc_setview: - CL_ParseViewEntity( msg ); - break; case svc_sound: CL_ParseQuakeSound( msg ); cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart; @@ -974,9 +971,6 @@ void CL_ParseQuakeMessage( sizebuf_t *msg ) Cbuf_Execute(); // make sure any stuffed commands are done CL_ParseQuakeServerInfo( msg ); break; - case svc_lightstyle: - CL_ParseLightStyle( msg, PROTO_QUAKE ); - break; case svc_updatename: param1 = MSG_ReadByte( msg ); Q_strncpy( cl.players[param1].name, MSG_ReadString( msg ), sizeof( cl.players[0].name )); @@ -1029,8 +1023,7 @@ void CL_ParseQuakeMessage( sizebuf_t *msg ) CL_ParseQuakeSignon( msg ); break; case svc_centerprint: - str = MSG_ReadString( msg ); - CL_DispatchUserMessage( "HudText", Q_strlen( str ) + 1, (void *)str ); + CL_HudMessage( MSG_ReadString( msg )); break; case svc_killedmonster: CL_DispatchQuakeMessage( "KillMonster" ); // just an event @@ -1041,12 +1034,6 @@ void CL_ParseQuakeMessage( sizebuf_t *msg ) case svc_spawnstaticsound: CL_ParseQuakeStaticSound( msg ); break; - case svc_intermission: - cl.intermission = 1; - break; - case svc_finale: - CL_ParseFinaleCutscene( msg, 2 ); - break; case svc_cdtrack: param1 = MSG_ReadByte( msg ); param1 = bound( 0, param1, MAX_CDTRACKS - 1 ); // tracknum @@ -1059,15 +1046,12 @@ void CL_ParseQuakeMessage( sizebuf_t *msg ) case svc_sellscreen: Cmd_ExecuteString( "help" ); // open quake menu break; - case svc_cutscene: - CL_ParseFinaleCutscene( msg, 3 ); + case svc_showlmp: + CL_ParseNehahraShowLMP( msg ); break; case svc_hidelmp: CL_ParseNehahraHideLMP( msg ); break; - case svc_showlmp: - CL_ParseNehahraShowLMP( msg ); - break; case svc_skybox: Q_strncpy( clgame.movevars.skyName, MSG_ReadString( msg ), sizeof( clgame.movevars.skyName )); break; diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index ba90d6be..a5302304 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -744,7 +744,7 @@ void SCR_LoadCreditsFont( void ) success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, &hud_fontrender, TF_FONT ); if( !success ) - success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &hud_fontrender, TF_FONT ); + success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &hud_fontrender, TF_FONT|TF_NEAREST ); // copy font size for client.dll if( success ) diff --git a/engine/client/client.h b/engine/client/client.h index ff8b861e..d8003903 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -37,11 +37,6 @@ GNU General Public License for more details. #include "voice.h" #include "q_client.h" -// client sprite types -#define SPR_CLIENT 0 // client sprite for temp-entities or user-textures -#define SPR_HUDSPRITE 1 // hud sprite -#define SPR_MAPSPRITE 2 // contain overview.bmp that diced into frames 128x128 - //============================================================================= typedef struct netbandwithgraph_s { @@ -112,6 +107,8 @@ extern int CL_UPDATE_BACKUP; #define MAX_EX_INTERP 0.1f +#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channels) + #define CL_MIN_RESEND_TIME 1.5f // mininum time gap (in seconds) before a subsequent connection request is sent. #define CL_MAX_RESEND_TIME 20.0f // max time. The cvar cl_resend is bounded by these. @@ -311,6 +308,14 @@ typedef enum CL_CHANGELEVEL, // draw 'loading' during changelevel } scrstate_t; +// client sprite types +enum +{ + SPR_CLIENT = 0, // client sprite for temp-entities or user-textures + SPR_HUDSPRITE, // hud sprite + SPR_MAPSPRITE, // contain overview.bmp that diced into frames 128x128 +}; + typedef struct { char name[32]; @@ -733,10 +738,7 @@ extern convar_t cl_fixmodelinterpolationartifacts; //============================================================================= -void CL_SetLightstyle( int style, const char* s, float f ); -void CL_DecayLights( void ); -dlight_t *CL_GetDynamicLight( int number ); -dlight_t *CL_GetEntityLight( int number ); +extern client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS]; //================================================= @@ -855,6 +857,7 @@ void CL_FreeEdicts( void ); void CL_ClearWorld( void ); void CL_DrawCenterPrint( void ); void CL_ClearSpriteTextures( void ); +void CL_HudMessage( const char *pMessage ); void CL_CenterPrint( const char *text, float y ); client_textmessage_t *CL_TextMessageGet( const char *pName ); void NetAPI_CancelAllRequests( void ); @@ -925,45 +928,23 @@ static inline cl_entity_t *CL_GetLocalPlayer( void ) // // cl_parse.c // -void CL_ParseSetAngle( sizebuf_t *msg ); -void CL_ParseServerData( sizebuf_t *msg, connprotocol_t proto ); -void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto ); -void CL_UpdateUserinfo( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseResource( sizebuf_t *msg ); void CL_ParseClientData( sizebuf_t *msg, connprotocol_t proto ); void CL_UpdateUserPings( sizebuf_t *msg ); -void CL_ParseParticles( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseBaseline( sizebuf_t *msg, connprotocol_t proto ); -void CL_ParseSignon( sizebuf_t *msg, connprotocol_t proto ); -void CL_ParseRestore( sizebuf_t *msg ); void CL_ParseStaticDecal( sizebuf_t *msg ); -void CL_ParseAddAngle( sizebuf_t *msg ); -void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseResourceList( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseMovevars( sizebuf_t *msg ); -void CL_ParseResourceRequest( sizebuf_t *msg ); -void CL_ParseCustomization( sizebuf_t *msg ); -void CL_ParseCrosshairAngle( sizebuf_t *msg ); -void CL_ParseSoundFade( sizebuf_t *msg ); -void CL_ParseFileTransferFailed( sizebuf_t *msg ); -void CL_ParseHLTV( sizebuf_t *msg ); -void CL_ParseDirector( sizebuf_t *msg ); -void CL_ParseVoiceInit( sizebuf_t *msg ); -void CL_ParseVoiceData( sizebuf_t *msg, connprotocol_t proto ); -void CL_ParseResLocation( sizebuf_t *msg ); -void CL_ParseCvarValue( sizebuf_t *msg, const qboolean ext, const connprotocol_t proto ); void CL_ParseServerMessage( sizebuf_t *msg ); -qboolean CL_ParseCommonDLLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ); +qboolean CL_ParseCommonMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ); +qboolean CL_ParseCommonHLMessage( sizebuf_t *msg, connprotocol_t proto, int svc_num, int startoffset ); void CL_ParseTempEntity( sizebuf_t *msg, connprotocol_t proto ); qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf ); qboolean CL_RequestMissingResources( void ); void CL_RegisterResources( sizebuf_t *msg, connprotocol_t proto ); -void CL_ParseViewEntity( sizebuf_t *msg ); void CL_ParseServerTime( sizebuf_t *msg, connprotocol_t proto ); void CL_ParseUserMessage( sizebuf_t *msg, int svc_num, connprotocol_t proto ); -void CL_ParseFinaleCutscene( sizebuf_t *msg, int level ); void CL_ParseTextMessage( sizebuf_t *msg ); -void CL_ParseExec( sizebuf_t *msg ); void CL_BatchResourceRequest( qboolean initialize ); int CL_EstimateNeededResources( void ); @@ -1085,6 +1066,10 @@ void R_AddEfrags( cl_entity_t *ent ); // cl_tent.c // struct particle_s; +void CL_SetLightstyle( int style, const char* s, float f ); +void CL_DecayLights( void ); +dlight_t *CL_GetDynamicLight( int number ); +dlight_t *CL_GetEntityLight( int number ); void CL_WeaponAnim( int iAnim, int body ); void CL_ClearEffects( void ); void CL_ClearEfrags( void ); diff --git a/engine/client/s_load.c b/engine/client/s_load.c index f227cc25..1d56b963 100644 --- a/engine/client/s_load.c +++ b/engine/client/s_load.c @@ -152,7 +152,7 @@ sfx_t *S_FindName( const char *pname, qboolean *pfInCache ) uint i, hash; string name; - if( COM_StringEmptyOrNULL( pname ) || !dma.initialized ) + if( COM_StringEmptyOrNULL( pname ) || !snd.initialized ) return NULL; if( Q_strlen( pname ) >= sizeof( sfx->name )) @@ -253,7 +253,7 @@ void S_BeginRegistration( void ) { int i; - snd_ambient = false; + snd.have_ambient_sfx = false; // check for automatic ambient sounds for( i = 0; i < NUM_AMBIENTS; i++ ) @@ -261,8 +261,9 @@ void S_BeginRegistration( void ) if( !GI->ambientsound[i][0] ) continue; // empty slot - ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] ); - if( ambient_sfx[i] ) snd_ambient = true; // allow auto-ambients + snd.ambient_sfx[i] = S_RegisterSound( GI->ambientsound[i] ); + if( snd.ambient_sfx[i] ) + snd.have_ambient_sfx = true; // allow auto-ambients } s_registering = true; @@ -279,7 +280,7 @@ void S_EndRegistration( void ) sfx_t *sfx; int i; - if( !s_registering || !dma.initialized ) + if( !s_registering || !snd.initialized ) return; // free any sounds not from this registration sequence @@ -312,7 +313,7 @@ sound_t S_RegisterSound( const char *name ) { sfx_t *sfx; - if( COM_StringEmptyOrNULL( name ) || !dma.initialized ) + if( COM_StringEmptyOrNULL( name ) || !snd.initialized ) return -1; if( S_TestSoundChar( name, '!' )) @@ -336,7 +337,7 @@ sound_t S_RegisterSound( const char *name ) sfx_t *S_GetSfxByHandle( sound_t handle ) { - if( !dma.initialized ) + if( !snd.initialized ) return NULL; // create new sfx @@ -375,7 +376,7 @@ void S_FreeSounds( void ) sfx_t *sfx; int i; - if( !dma.initialized ) + if( !snd.initialized ) return; // stop all sounds diff --git a/engine/client/s_main.c b/engine/client/s_main.c index 3a1cc799..33d2ef96 100644 --- a/engine/client/s_main.c +++ b/engine/client/s_main.c @@ -31,19 +31,18 @@ struct int in_seconds; } soundfade; -dma_t dma; poolhandle_t sndpool; -sound_t ambient_sfx[NUM_AMBIENTS]; -qboolean snd_ambient = false; qboolean snd_fade_sequence = false; -listener_t s_listener; -channel_t channels[MAX_CHANNELS]; -rawchan_t *raw_channels[MAX_RAW_CHANNELS]; -int total_channels; - -int soundtime; // sample PAIRS -int paintedtime; // sample PAIRS +// this confuses the shit out of qt creator parser +// and good luck if you rely on shitty old msvc +snd_globals_t snd = +{ + .channels = (channel_t[MAX_CHANNELS]){}, + .max_channels = MAX_CHANNELS, + .raw_channels = (rawchan_t*[MAX_RAW_CHANNELS]){}, + .max_raw_channels = MAX_RAW_CHANNELS, +}; static snd_interface_state_t s_sndState; @@ -54,7 +53,6 @@ static CVAR_DEFINE_AUTO( s_show, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "show play CVAR_DEFINE_AUTO( s_lerping, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "apply interpolation to sound output" ); static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" ); static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" ); -static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" ); CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" ); CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" ); CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" ); @@ -160,7 +158,7 @@ S_IsClient */ static qboolean S_IsClient( int entnum ) { - return entnum == s_listener.entnum; + return entnum == snd.entnum; } /* @@ -189,13 +187,16 @@ void S_FreeChannel( channel_t *ch ) { S_NotifyChannelUpdate( ch - channels, NULL, -1 ); + // free the currently loaded word's audio cache before nuking the channel + if( ch->words ) + VOX_FreeWord( ch ); + ch->sfx = NULL; ch->name[0] = '\0'; - ch->use_loop = false; - ch->is_sentence = false; + ch->flags = 0; ch->forced_end = ch->sample = 0.0; ch->data = NULL; - ch->finished = false; + Mem_Free2( &ch->words ); SND_CloseMouth( ch ); } @@ -269,7 +270,7 @@ static qboolean SND_FStreamIsPlaying( sfx_t *sfx ) { for( int i = NUM_AMBIENTS; i < MAX_DYNAMIC_CHANNELS; i++ ) { - if( channels[i].sfx == sfx ) + if( snd.channels[i].sfx == sfx ) return true; } return false; @@ -286,14 +287,14 @@ static int SND_GetChannelTimeLeft( const channel_t *ch ) { int remaining; - if( ch->finished || !ch->sfx || !ch->sfx->cache ) + if( FBitSet( ch->flags, FL_CHAN_FINISHED ) || !ch->sfx || !ch->sfx->cache ) return 0; - if( ch->is_sentence ) // sentences are special, count all remaining words + if( ch->words ) // sentences are special, count all remaining words { int i; - if( ch->sentence_finished ) + if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED ) ) return 0; // current word @@ -301,7 +302,7 @@ static int SND_GetChannelTimeLeft( const channel_t *ch ) // here we count all remaining words, stopping if no sfx or sound file is available // see VOX_LoadWord - for( i = ch->word_index + 1; i < ARRAYSIZE( ch->words ); i++ ) + for( i = ch->word_index + 1; i < CVOXWORDMAX; i++ ) { wavdata_t *sc; int end; @@ -323,7 +324,7 @@ static int SND_GetChannelTimeLeft( const channel_t *ch ) else { int samples = ch->sfx->cache->samples; - int curpos = S_AdjustLoopedSamplePosition( ch->sfx->cache, ch->sample, ch->use_loop ); + int curpos = S_AdjustLoopedSamplePosition( ch->sfx->cache, ch->sample, FBitSet( ch->flags, FL_CHAN_USE_LOOP )); remaining = bound( 0, samples - curpos, samples ); } @@ -361,7 +362,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean for( ch_idx = NUM_AMBIENTS; ch_idx < MAX_DYNAMIC_CHANNELS; ch_idx++ ) { - channel_t *ch = &channels[ch_idx]; + channel_t *ch = &snd.channels[ch_idx]; // Never override a streaming sound that is currently playing or // voice over IP data that is playing or any sound on CHAN_VOICE( acting ) @@ -392,14 +393,14 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean if( first_to_die == -1 ) return NULL; - if( channels[first_to_die].sfx ) + if( snd.channels[first_to_die].sfx ) { // don't restart looping sounds for the same entity - wavdata_t *sc = channels[first_to_die].sfx->cache; + wavdata_t *sc = snd.channels[first_to_die].sfx->cache; if( sc && FBitSet( sc->flags, SOUND_LOOPED )) { - channel_t *ch = &channels[first_to_die]; + channel_t *ch = &snd.channels[first_to_die]; if( ch->entnum == entnum && ch->entchannel == channel && ch->sfx == sfx ) { @@ -410,10 +411,10 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean } // be sure and release previous channel if sentence. - S_FreeChannel( &( channels[first_to_die] )); + S_FreeChannel( &( snd.channels[first_to_die] )); } - return &channels[first_to_die]; + return &snd.channels[first_to_die]; } /* @@ -432,32 +433,32 @@ channel_t *SND_PickStaticChannel( const vec3_t pos, sfx_t *sfx ) int i; // check for replacement sound, or find the best one to replace - for( i = MAX_DYNAMIC_CHANNELS; i < total_channels; i++ ) + for( i = MAX_DYNAMIC_CHANNELS; i < snd.total_channels; i++ ) { - if( channels[i].sfx == NULL ) + if( snd.channels[i].sfx == NULL ) break; - if( VectorCompare( pos, channels[i].origin ) && channels[i].sfx == sfx ) + if( VectorCompare( pos, snd.channels[i].origin ) && snd.channels[i].sfx == sfx ) break; } - if( i < total_channels ) + if( i < snd.total_channels ) { // reuse an empty static sound channel - ch = &channels[i]; + ch = &snd.channels[i]; } else { // no empty slots, alloc a new static sound channel - if( total_channels == MAX_CHANNELS ) + if( snd.total_channels == snd.max_channels ) { Con_DPrintf( S_ERROR "%s: no free channels\n", __func__ ); return NULL; } // get a channel for the static sound - ch = &channels[total_channels]; - total_channels++; + ch = &snd.channels[snd.total_channels]; + snd.total_channels++; } return ch; } @@ -473,7 +474,7 @@ static qboolean S_MaybeAlterChannel( channel_t *ch, int entnum, int entchannel, // if no sfx passed, check if it's a sentence if( !sfx ) { - if( !ch->is_sentence ) + if( !ch->words ) return false; } else @@ -514,34 +515,21 @@ returns FALSE if sound was not found (sound is not playing) */ static int S_AlterChannel( int entnum, int channel, const sfx_t *sfx, int vol, int pitch, int flags ) { - channel_t *ch; - int i; + // This is a sentence name. + // For sentences: assume that the entity is only playing one sentence + // at a time, so we can just shut off + // any channel that has ch->is_sentence >= 0 and matches the entnum. + qboolean is_sentence = S_TestSoundChar( sfx->name, '!' ); - if( S_TestSoundChar( sfx->name, '!' )) + for( int i = NUM_AMBIENTS; i < snd.total_channels; i++ ) { - // This is a sentence name. - // For sentences: assume that the entity is only playing one sentence - // at a time, so we can just shut off - // any channel that has ch->is_sentence >= 0 and matches the entnum. + channel_t *ch = &snd.channels[i]; - for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) - { - if( S_MaybeAlterChannel( ch, entnum, channel, flags, NULL, pitch, vol )) - return true; - } - - // channel not found - return false; - - } - - // regular sound or streaming sound - for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) - { - if( S_MaybeAlterChannel( ch, entnum, channel, flags, sfx, pitch, vol )) + if( S_MaybeAlterChannel( ch, entnum, channel, flags, is_sentence ? NULL : sfx, pitch, vol )) return true; } + // channel not found return false; } @@ -589,7 +577,7 @@ static void SND_Spatialize( channel_t *ch ) return; } - if( !ch->staticsound ) + if( !FBitSet( ch->flags, FL_CHAN_STATIC_SOUND )) { if( !CL_GetEntitySpatialization( ch )) { @@ -602,11 +590,11 @@ static void SND_Spatialize( channel_t *ch ) // source_vec is vector from listener to sound source // player sounds come from 1' in front of player vec3_t source_vec; - VectorSubtract( ch->origin, s_listener.origin, source_vec ); + VectorSubtract( ch->origin, snd.origin, source_vec ); // normalize source_vec and get distance from listener to source float dist = VectorNormalizeLength( source_vec ); - float dot = DotProduct( s_listener.right, source_vec ); + float dot = DotProduct( snd.right, source_vec ); if( !FBitSet( host.bugcomp, BUGCOMP_SPATIALIZE_SOUND_WITH_ATTN_NONE )) { @@ -645,7 +633,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv int vol, ch_idx; qboolean bIgnore = false; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; @@ -668,8 +656,10 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv SetBits( flags, SND_STOP_LOOPING ); // pick a channel to play on - if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx ); - else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); + if( chan == CHAN_STATIC ) + target_chan = SND_PickStaticChannel( pos, sfx ); + else + target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); if( !target_chan ) { @@ -682,15 +672,21 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv memset( target_chan, 0, sizeof( *target_chan )); VectorCopy( pos, target_chan->origin ); - target_chan->staticsound = ( ent == 0 ) ? true : false; - target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true; - target_chan->localsound = (flags & SND_LOCALSOUND) ? true : false; + + if( ent == 0 ) + SetBits( target_chan->flags, FL_CHAN_STATIC_SOUND ); + + if( !FBitSet( flags, SND_STOP_LOOPING )) + SetBits( target_chan->flags, FL_CHAN_USE_LOOP ); + + if( FBitSet( flags, SND_LOCALSOUND )) + SetBits( target_chan->flags, FL_CHAN_LOCAL_SOUND ); + target_chan->dist_mult = (attn / SND_CLIP_DISTANCE); target_chan->master_vol = vol; target_chan->entnum = ent; target_chan->entchannel = chan; target_chan->basePitch = pitch; - target_chan->is_sentence = false; target_chan->sfx = sfx; pSource = NULL; @@ -760,7 +756,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float qboolean bIgnore = false; int vol; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; @@ -768,8 +764,10 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float if( pitch <= 1 ) pitch = PITCH_NORM; // Invasion issues // pick a channel to play on - if( chan == CHAN_STATIC ) target_chan = SND_PickStaticChannel( pos, sfx ); - else target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); + if( chan == CHAN_STATIC ) + target_chan = SND_PickStaticChannel( pos, sfx ); + else + target_chan = SND_PickDynamicChannel( ent, chan, sfx, &bIgnore ); if( !target_chan ) { @@ -782,15 +780,21 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float memset( target_chan, 0, sizeof( *target_chan )); VectorCopy( pos, target_chan->origin ); - target_chan->staticsound = ( ent == 0 ) ? true : false; - target_chan->use_loop = (flags & SND_STOP_LOOPING) ? false : true; - target_chan->localsound = (flags & SND_LOCALSOUND) ? true : false; + + if( ent == 0 ) + SetBits( target_chan->flags, FL_CHAN_STATIC_SOUND ); + + if( !FBitSet( flags, SND_STOP_LOOPING )) + SetBits( target_chan->flags, FL_CHAN_USE_LOOP ); + + if( FBitSet( flags, SND_LOCALSOUND )) + SetBits( target_chan->flags, FL_CHAN_LOCAL_SOUND ); + target_chan->dist_mult = (attn / SND_CLIP_DISTANCE); target_chan->master_vol = vol; target_chan->entnum = ent; target_chan->entchannel = chan; target_chan->basePitch = pitch; - target_chan->is_sentence = false; target_chan->sfx = sfx; pSource = NULL; @@ -812,7 +816,7 @@ void S_RestoreSound( const vec3_t pos, int ent, int chan, sound_t handle, float target_chan->word_index = wordIndex; // restore current word VOX_LoadWord( target_chan ); - if( !target_chan->sentence_finished ) + if( !FBitSet( target_chan->flags, FL_CHAN_SENTENCE_FINISHED )) { target_chan->sfx = target_chan->words[target_chan->word_index].sfx; sfx = target_chan->sfx; @@ -874,7 +878,7 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa sfx_t *sfx = NULL; int vol, fvox = 0; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_GetSfxByHandle( handle ); if( !sfx ) return; @@ -916,7 +920,6 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa // load regular or stream sound pSource = S_LoadSound( sfx ); ch->sfx = sfx; - ch->is_sentence = false; ch->name[0] = '\0'; } @@ -929,9 +932,15 @@ void S_AmbientSound( const vec3_t pos, int ent, sound_t handle, float fvol, floa pitch *= (sys_timescale.value + 1) / 2; // never update positions if source entity is 0 - ch->staticsound = ( ent == 0 ) ? true : false; - ch->use_loop = (flags & SND_STOP_LOOPING) ? false : true; - ch->localsound = (flags & SND_LOCALSOUND) ? true : false; + if( ent == 0 ) SetBits( ch->flags, FL_CHAN_STATIC_SOUND ); + else ClearBits( ch->flags, FL_CHAN_STATIC_SOUND ); + + if( !FBitSet( flags, SND_STOP_LOOPING )) SetBits( ch->flags, FL_CHAN_USE_LOOP ); + else ClearBits( ch->flags, FL_CHAN_USE_LOOP ); + + if( FBitSet( flags, SND_LOCALSOUND )) SetBits( ch->flags, FL_CHAN_LOCAL_SOUND ); + else ClearBits( ch->flags, FL_CHAN_LOCAL_SOUND ); + ch->master_vol = vol; ch->dist_mult = (attn / SND_CLIP_DISTANCE); ch->entchannel = CHAN_STATIC; @@ -954,9 +963,9 @@ void S_StartLocalSound( const char *name, float volume, qboolean reliable ) if( reliable ) channel = CHAN_STATIC; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfxHandle = S_RegisterSound( name ); - S_StartSound( NULL, s_listener.entnum, channel, sfxHandle, volume, ATTN_NONE, PITCH_NORM, flags ); + S_StartSound( NULL, snd.entnum, channel, sfxHandle, volume, ATTN_NONE, PITCH_NORM, flags ); } /* @@ -969,32 +978,35 @@ grab all static sounds playing at current channel int S_GetCurrentStaticSounds( soundlist_t *pout, int size ) { int sounds_left = size; - int i; - if( !dma.initialized ) + if( !snd.initialized ) return 0; - for( i = MAX_DYNAMIC_CHANNELS; i < total_channels && sounds_left; i++ ) + for( int i = MAX_DYNAMIC_CHANNELS; i < snd.total_channels && sounds_left; i++ ) { - if( channels[i].entchannel == CHAN_STATIC && channels[i].sfx && channels[i].sfx->name[0] ) - { - if( channels[i].is_sentence && channels[i].name[0] ) - Q_strncpy( pout->name, channels[i].name, sizeof( pout->name )); - else Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name )); - pout->entnum = channels[i].entnum; - VectorCopy( channels[i].origin, pout->origin ); - pout->volume = (float)channels[i].master_vol / 255.0f; - pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE; - pout->looping = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED )); - pout->pitch = channels[i].basePitch; - pout->channel = channels[i].entchannel; - pout->wordIndex = channels[i].word_index; - pout->samplePos = channels[i].sample; - pout->forcedEnd = channels[i].forced_end; + const channel_t *ch = &snd.channels[i]; - sounds_left--; - pout++; - } + if( ch->entchannel != CHAN_STATIC || !ch->sfx || !ch->sfx->name[0] ) + continue; + + if( ch->words && ch->name[0] ) + Q_strncpy( pout->name, ch->name, sizeof( pout->name )); + else + Q_strncpy( pout->name, ch->sfx->name, sizeof( pout->name )); + + pout->entnum = ch->entnum; + VectorCopy( ch->origin, pout->origin ); + pout->volume = (float)ch->master_vol / 255.0f; + pout->attenuation = ch->dist_mult * SND_CLIP_DISTANCE; + pout->looping = ( FBitSet( ch->flags, FL_CHAN_USE_LOOP ) && FBitSet( ch->sfx->cache->flags, SOUND_LOOPED )); + pout->pitch = ch->basePitch; + pout->channel = ch->entchannel; + pout->wordIndex = ch->word_index; + pout->samplePos = ch->sample; + pout->forcedEnd = ch->forced_end; + + sounds_left--; + pout++; } return ( size - sounds_left ); @@ -1012,31 +1024,35 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size ) int sounds_left = size; int i, looped; - if( !dma.initialized ) + if( !snd.initialized ) return 0; - for( i = 0; i < MAX_CHANNELS && sounds_left; i++ ) + for( i = 0; i < snd.max_channels && sounds_left; i++ ) { - if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" )) + const channel_t *ch = &snd.channels[i]; + + if( !ch->sfx || !ch->sfx->name[0] || !Q_stricmp( ch->sfx->name, "*default" )) continue; // don't serialize default sounds - looped = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED )); + looped = ( FBitSet( ch->flags, FL_CHAN_USE_LOOP ) && FBitSet( ch->sfx->cache->flags, SOUND_LOOPED )); - if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible()) + if( ch->entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible()) continue; // never serialize static looped sounds. It will be restoring in game code - if( channels[i].is_sentence && channels[i].name[0] ) - Q_strncpy( pout->name, channels[i].name, sizeof( pout->name )); - else Q_strncpy( pout->name, channels[i].sfx->name, sizeof( pout->name )); - pout->entnum = (channels[i].entnum < 0) ? 0 : channels[i].entnum; - VectorCopy( channels[i].origin, pout->origin ); - pout->volume = (float)channels[i].master_vol / 255.0f; - pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE; - pout->pitch = channels[i].basePitch; - pout->channel = channels[i].entchannel; - pout->wordIndex = channels[i].word_index; - pout->samplePos = channels[i].sample; - pout->forcedEnd = channels[i].forced_end; + if( ch->words && ch->name[0] ) + Q_strncpy( pout->name, ch->name, sizeof( pout->name )); + else + Q_strncpy( pout->name, ch->sfx->name, sizeof( pout->name )); + + pout->entnum = (ch->entnum < 0) ? 0 : ch->entnum; + VectorCopy( ch->origin, pout->origin ); + pout->volume = (float)ch->master_vol / 255.0f; + pout->attenuation = ch->dist_mult * SND_CLIP_DISTANCE; + pout->pitch = ch->basePitch; + pout->channel = ch->entchannel; + pout->wordIndex = ch->word_index; + pout->samplePos = ch->sample; + pout->forcedEnd = ch->forced_end; pout->looping = looped; sounds_left--; @@ -1053,18 +1069,14 @@ S_InitAmbientChannels */ static void S_InitAmbientChannels( void ) { - int ambient_channel; - channel_t *chan; - - for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) + for( int i = 0; i < NUM_AMBIENTS; i++ ) { - chan = &channels[ambient_channel]; + channel_t *ch = &snd.channels[i]; - chan->staticsound = true; - chan->use_loop = true; - chan->entchannel = CHAN_STATIC; - chan->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE); - chan->basePitch = PITCH_NORM; + SetBits( ch->flags, FL_CHAN_USE_LOOP | FL_CHAN_STATIC_SOUND ); + ch->entchannel = CHAN_STATIC; + ch->dist_mult = (ATTN_NONE / SND_CLIP_DISTANCE); + ch->basePitch = PITCH_NORM; } } @@ -1077,27 +1089,27 @@ static void S_UpdateAmbientSounds( void ) { int ambient_channel; - if( !snd_ambient ) + if( !snd.have_ambient_sfx ) return; // calc ambient sound levels if( !cl.worldmodel ) return; - mleaf_t *leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes, cl.worldmodel ); + mleaf_t *leaf = Mod_PointInLeaf( snd.origin, cl.worldmodel->nodes, cl.worldmodel ); if( !leaf || !s_ambient_level.value ) { - for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) - channels[ambient_channel].sfx = NULL; + for( int i = 0; i < NUM_AMBIENTS; i++ ) + snd.channels[i].sfx = NULL; return; } - for( ambient_channel = 0; ambient_channel < NUM_AMBIENTS; ambient_channel++ ) + for( int i = 0; i < NUM_AMBIENTS; i++ ) { - channel_t *chan = &channels[ambient_channel]; - chan->sfx = S_GetSfxByHandle( ambient_sfx[ambient_channel] ); + channel_t *chan = &snd.channels[i]; + chan->sfx = S_GetSfxByHandle( snd.ambient_sfx[i] ); // ambient is unused if( !chan->sfx ) @@ -1156,9 +1168,9 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create ) int best = -1; int free = -1; - for( int i = 0; i < MAX_RAW_CHANNELS; i++ ) + for( int i = 0; i < snd.max_raw_channels; i++ ) { - ch = raw_channels[i]; + ch = snd.raw_channels[i]; if( free < 0 && !ch ) { @@ -1172,7 +1184,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create ) if( ch->entnum == entnum ) return ch; - time = ch->s_rawend - paintedtime; + time = ch->s_rawend - snd.paintedtime; if( time < best_time ) { best = i; @@ -1190,14 +1202,14 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create ) if( best < 0 ) return NULL; // no free slots - if( !raw_channels[best] ) + if( !snd.raw_channels[best] ) { size_t raw_samples = MAX_RAW_SAMPLES; - raw_channels[best] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * raw_samples ); - raw_channels[best]->max_samples = raw_samples; + snd.raw_channels[best] = Mem_Calloc( sndpool, sizeof( *ch ) + sizeof( portable_samplepair_t ) * raw_samples ); + snd.raw_channels[best]->max_samples = raw_samples; } - ch = raw_channels[best]; + ch = snd.raw_channels[best]; ch->entnum = entnum; ch->s_rawend = 0; @@ -1216,8 +1228,8 @@ uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint ma uint fracstep, samplefrac; uint src, dst; - if( rawend < paintedtime ) - rawend = paintedtime; + if( rawend < snd.paintedtime ) + rawend = snd.paintedtime; fracstep = ((double) rate / (double)SOUND_DMA_SPEED) * (double)(1 << S_RAW_SAMPLES_PRECISION_BITS); samplefrac = 0; @@ -1304,14 +1316,14 @@ static void S_FreeIdleRawChannels( void ) { int i; - for( i = 0; i < MAX_RAW_CHANNELS; i++ ) + for( i = 0; i < snd.max_raw_channels; i++ ) { - rawchan_t *ch = raw_channels[i]; + rawchan_t *ch = snd.raw_channels[i]; if( !ch ) continue; - if( ch->s_rawend >= paintedtime ) + if( ch->s_rawend >= snd.paintedtime ) continue; if( ch->entnum > 0 ) @@ -1322,9 +1334,9 @@ static void S_FreeIdleRawChannels( void ) Voice_StopChannel( ch->entnum ); } - if(( paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC ) + if(( snd.paintedtime - ch->s_rawend ) / SOUND_DMA_SPEED >= S_RAW_SOUND_IDLE_SEC ) { - raw_channels[i] = NULL; + snd.raw_channels[i] = NULL; Mem_Free( ch ); } } @@ -1339,9 +1351,9 @@ static void S_ClearRawChannels( void ) { int i; - for( i = 0; i < MAX_RAW_CHANNELS; i++ ) + for( i = 0; i < snd.max_raw_channels; i++ ) { - rawchan_t *ch = raw_channels[i]; + rawchan_t *ch = snd.raw_channels[i]; if( !ch ) continue; ch->s_rawend = 0; @@ -1356,14 +1368,14 @@ S_SpatializeRawChannels */ static void S_SpatializeRawChannels( void ) { - for( int i = 0; i < MAX_RAW_CHANNELS; i++ ) + for( int i = 0; i < snd.max_raw_channels; i++ ) { - rawchan_t *ch = raw_channels[i]; + rawchan_t *ch = snd.raw_channels[i]; if( !ch ) continue; - if( ch->s_rawend < paintedtime ) + if( ch->s_rawend < snd.paintedtime ) { ch->leftvol = ch->rightvol = 0; continue; @@ -1381,11 +1393,11 @@ static void S_SpatializeRawChannels( void ) { vec3_t source_vec; - VectorSubtract( ch->origin, s_listener.origin, source_vec ); + VectorSubtract( ch->origin, snd.origin, source_vec ); // normalize source_vec and get distance from listener to source float dist = VectorNormalizeLength( source_vec ); - float dot = DotProduct( s_listener.right, source_vec ); + float dot = DotProduct( snd.right, source_vec ); // don't pan sounds with no attenuation if( ch->dist_mult <= 0.0f ) dot = 0.0f; @@ -1408,16 +1420,9 @@ S_FreeRawChannels */ static void S_FreeRawChannels( void ) { - int i; - // free raw samples - for( i = 0; i < MAX_RAW_CHANNELS; i++ ) - { - if( raw_channels[i] ) - Mem_Free( raw_channels[i] ); - } - - memset( raw_channels, 0, sizeof( raw_channels )); + for( int i = 0; i < snd.max_raw_channels; i++ ) + Mem_Free2( &snd.raw_channels[i] ); } //============================================================================= @@ -1432,8 +1437,10 @@ static void S_ClearBuffer( void ) S_ClearRawChannels(); SNDDMA_BeginPainting (); - if( dma.buffer ) - memset( dma.buffer, 0, dma.samples * 2 ); + + if( snd.buffer ) + memset( snd.buffer, 0, snd.samples * 2 ); + SNDDMA_Submit (); S_ClearBuffers( PAINTBUFFER_SIZE ); @@ -1450,7 +1457,7 @@ void GAME_EXPORT S_StopSound( int entnum, int channel, const char *soundname ) { sfx_t *sfx; - if( !dma.initialized ) return; + if( !snd.initialized ) return; sfx = S_FindName( soundname, NULL ); S_AlterChannel( entnum, channel, sfx, 0, 0, SND_STOP ); } @@ -1464,19 +1471,21 @@ void S_StopAllSounds( qboolean ambient ) { int i; - if( !dma.initialized ) return; - total_channels = MAX_DYNAMIC_CHANNELS; // no statics + if( !snd.initialized ) return; + snd.total_channels = MAX_DYNAMIC_CHANNELS; // no statics - for( i = 0; i < MAX_CHANNELS; i++ ) + for( i = 0; i < snd.max_channels; i++ ) { - if( !channels[i].sfx ) continue; - S_FreeChannel( &channels[i] ); + if( !snd.channels[i].sfx ) + continue; + + S_FreeChannel( &snd.channels[i] ); } SX_ClearState(); // clear all the channels - memset( channels, 0, sizeof( channels )); + memset( snd.channels, 0, sizeof( snd.channels[0] ) * snd.max_channels ); // restart the ambient sounds if( ambient ) S_InitAmbientChannels (); @@ -1501,22 +1510,22 @@ static int S_GetSoundtime( void ) static int buffers, oldsamplepos; int samplepos, fullsamples; - fullsamples = dma.samples / 2; + fullsamples = snd.samples / 2; // it is possible to miscount buffers // if it has wrapped twice between // calls to S_Update. Oh well. - samplepos = dma.samplepos; + samplepos = snd.samplepos; if( samplepos < oldsamplepos ) { buffers++; // buffer wrapped - if( paintedtime > 0x40000000 ) + if( snd.paintedtime > 0x40000000 ) { // time to chop things off to avoid 32 bit limits buffers = 0; - paintedtime = fullsamples; + snd.paintedtime = fullsamples; S_StopAllSounds( true ); } } @@ -1534,25 +1543,25 @@ static void S_UpdateChannels( void ) SNDDMA_BeginPainting(); - if( !dma.buffer ) return; + if( !snd.buffer ) return; // updates DMA time - soundtime = S_GetSoundtime(); + snd.soundtime = S_GetSoundtime(); // soundtime - total samples that have been played out to hardware at dmaspeed // paintedtime - total samples that have been mixed at speed // endtime - target for samples in mixahead buffer at speed - endtime = soundtime + s_mixahead.value * SOUND_DMA_SPEED; - samps = dma.samples >> 1; + endtime = snd.soundtime + s_mixahead.value * SOUND_DMA_SPEED; + samps = snd.samples >> 1; - if((int)(endtime - soundtime) > samps ) - endtime = soundtime + samps; + if((int)(endtime - snd.soundtime) > samps ) + endtime = snd.soundtime + samps; - if(( endtime - paintedtime ) & 0x3 ) + if(( endtime - snd.paintedtime ) & 0x3 ) { // the difference between endtime and painted time should align on // boundaries of 4 samples. this is important when upsampling from 11khz -> 44khz. - endtime -= ( endtime - paintedtime ) & 0x3; + endtime -= ( endtime - snd.paintedtime ) & 0x3; } s_sndState.total_channels = total_channels; @@ -1573,7 +1582,7 @@ Don't let sound skip if going slow */ void S_ExtraUpdate( void ) { - if( !dma.initialized ) return; + if( !snd.initialized ) return; S_UpdateChannels (); } @@ -1589,9 +1598,9 @@ void S_UpdateFrame( struct ref_viewpass_s *rvp ) if( !FBitSet( rvp->flags, RF_DRAW_WORLD ) || FBitSet( rvp->flags, RF_ONLY_CLIENTDRAW )) return; - VectorCopy( rvp->vieworigin, s_listener.origin ); - AngleVectors( rvp->viewangles, s_listener.forward, s_listener.right, s_listener.up ); - s_listener.entnum = rvp->viewentity; // can be camera entity too + VectorCopy( rvp->vieworigin, snd.origin ); + AngleVectors( rvp->viewangles, snd.forward, snd.right, snd.up ); + snd.entnum = rvp->viewentity; // can be camera entity too } /* @@ -1603,11 +1612,7 @@ Called once each time through the main loop */ void SND_UpdateSound( void ) { - int i, j, total; - channel_t *ch, *combine; - con_nprint_t info; - - if( !dma.initialized ) return; + if( !snd.initialized ) return; if( clgame.soundFuncs.pfnS_UpdateSound ) clgame.soundFuncs.pfnS_UpdateSound(); @@ -1624,55 +1629,15 @@ void SND_UpdateSound( void ) // update general area ambient sound sources S_UpdateAmbientSounds(); - combine = NULL; - // update spatialization for static and dynamic sounds - for( i = NUM_AMBIENTS, ch = channels + NUM_AMBIENTS; i < total_channels; i++, ch++ ) + for( int i = NUM_AMBIENTS; i < snd.total_channels; i++ ) { - if( !ch->sfx ) continue; - SND_Spatialize( ch ); // respatialize channel + channel_t *ch = &snd.channels[i]; - if( !ch->leftvol && !ch->rightvol ) + if( !ch->sfx ) continue; - // try to combine static sounds with a previous channel of the same - // sound effect so we don't mix five torches every frame - // g-cont: perfomance option, probably kill stereo effect in most cases - if( i >= MAX_DYNAMIC_CHANNELS && s_combine_sounds.value ) - { - // see if it can just use the last one - if( combine && combine->sfx == ch->sfx ) - { - combine->leftvol += ch->leftvol; - combine->rightvol += ch->rightvol; - ch->leftvol = ch->rightvol = 0; - continue; - } - - // search for one - combine = channels + MAX_DYNAMIC_CHANNELS; - - for( j = MAX_DYNAMIC_CHANNELS; j < i; j++, combine++ ) - { - if( combine->sfx == ch->sfx ) - break; - } - - if( j == total_channels ) - { - combine = NULL; - } - else - { - if( combine != ch ) - { - combine->leftvol += ch->leftvol; - combine->rightvol += ch->rightvol; - ch->leftvol = ch->rightvol = 0; - } - continue; - } - } + SND_Spatialize( ch ); // respatialize channel } S_SpatializeRawChannels(); @@ -1680,26 +1645,33 @@ void SND_UpdateSound( void ) // debugging output if( s_show.value != 0.0f ) { - info.color[0] = 1.0f; - info.color[1] = 0.6f; - info.color[2] = 0.0f; - info.time_to_live = 0.5f; - - for( i = 0, total = 1, ch = channels; i < MAX_CHANNELS; i++, ch++ ) + con_nprint_t info = { - if( ch->sfx && ( ch->leftvol || ch->rightvol )) - { - info.index = total; - Con_NXPrintf( &info, "chan %i, pos (%.f %.f %.f) ent %i, lv%3i rv%3i %s\n", + .color[0] = 1.0f, + .color[1] = 0.6f, + .color[2] = 0.0f, + .index = 1, + .time_to_live = 0.5f, + }; + + for( int i = 0; i < MAX_CHANNELS; i++ ) + { + channel_t *ch = &snd.channels[i]; + + if( !ch->sfx || ( !ch->leftvol && !ch->rightvol )) + continue; + + Con_NXPrintf( &info, "chan %i, pos (%.f %.f %.f) ent %i, lv%3i rv%3i %s\n", i, ch->origin[0], ch->origin[1], ch->origin[2], ch->entnum, ch->leftvol, ch->rightvol, ch->sfx->name ); - total++; - } + + info.index++; } + int total = info.index - 1; VectorSet( info.color, 1.0f, 1.0f, 1.0f ); info.index = 0; - Con_NXPrintf( &info, "room_type: %i (%s) ----(%i)---- painted: %i\n", idsp_room, Cvar_VariableString( "dsp_coeff_table" ), total - 1, paintedtime ); + Con_NXPrintf( &info, "room_type: %i (%s) ----(%i)---- painted: %i\n", idsp_room, Cvar_VariableString( "dsp_coeff_table" ), total, snd.paintedtime ); } S_StreamBackgroundTrack (); @@ -1929,12 +1901,12 @@ S_SoundInfo_f */ void S_SoundInfo_f( void ) { - Con_Printf( "Audio backend: %s\n", dma.backendName ); + Con_Printf( "Audio backend: %s\n", snd.backend_name ); Con_Printf( "%5d channel(s)\n", 2 ); - Con_Printf( "%5d samples\n", dma.samples ); + Con_Printf( "%5d samples\n", snd.samples ); Con_Printf( "%5d bits/sample\n", 16 ); Con_Printf( "%5d bytes/sec\n", SOUND_DMA_SPEED ); - Con_Printf( "%5d total_channels\n", total_channels ); + Con_Printf( "%5d total_channels\n", snd.total_channels ); S_PrintBackgroundTrackState (); } @@ -2029,7 +2001,6 @@ qboolean S_Init( void ) Cvar_RegisterVariable( &s_lerping ); Cvar_RegisterVariable( &s_ambient_level ); Cvar_RegisterVariable( &s_ambient_fade ); - Cvar_RegisterVariable( &s_combine_sounds ); Cvar_RegisterVariable( &snd_mute_losefocus ); Cvar_RegisterVariable( &s_test ); Cvar_RegisterVariable( &s_samplecount ); @@ -2057,7 +2028,7 @@ qboolean S_Init( void ) Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" ); sndpool = Mem_AllocPool( "Sound Zone" ); - dma.backendName = "None"; + snd.backend_name = "None"; if( !SNDDMA_Init( )) { Con_Printf( "Audio: sound system can't be initialized\n" ); @@ -2065,11 +2036,11 @@ qboolean S_Init( void ) return false; } - soundtime = 0; - paintedtime = 0; + snd.soundtime = 0; + snd.paintedtime = 0; // clear ambient sounds - memset( ambient_sfx, 0, sizeof( ambient_sfx )); + memset( snd.ambient_sfx, 0, sizeof( snd.ambient_sfx )); SX_Init (); S_StopAllSounds ( true ); @@ -2089,7 +2060,7 @@ qboolean S_Init( void ) // ======================================================================= void S_Shutdown( void ) { - if( !dma.initialized ) return; + if( !snd.initialized ) return; Cmd_RemoveCommand( "play" ); Cmd_RemoveCommand( "playvol" ); diff --git a/engine/client/s_mix.c b/engine/client/s_mix.c index c58c77f3..13cbf84d 100644 --- a/engine/client/s_mix.c +++ b/engine/client/s_mix.c @@ -120,7 +120,7 @@ static void S_MixAudio( portable_samplepair_t *pbuf, const int *pvol, const void static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, double timecompress_rate ) { - if( chan->finished ) + if( FBitSet( chan->flags, FL_CHAN_FINISHED )) return 0; // if channel is set to end at specific sample, @@ -132,7 +132,7 @@ static int S_AdjustNumSamples( channel_t *chan, int num_samples, double rate, do if( end_sample >= chan->forced_end ) { - chan->finished = true; + SetBits( chan->flags, FL_CHAN_FINISHED ); return floor(( chan->forced_end - chan->sample ) / ( rate * timecompress_rate )); } } @@ -153,7 +153,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i // timecompress at 100% is skipping the entire sfx, so mark as finished and exit if( timecompress >= 100 ) { - chan->finished = true; + SetBits( chan->flags, FL_CHAN_FINISHED ); return 0; } @@ -173,7 +173,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i // get sample pointer and also amount of samples available const void *audio = NULL; - int available = S_RetrieveAudioSamples( chan->sfx->cache, &audio, chan->sample, request_num_samples, chan->use_loop ); + int available = S_RetrieveAudioSamples( chan->sfx->cache, &audio, chan->sample, request_num_samples, FBitSet( chan->flags, FL_CHAN_USE_LOOP )); // no samples available, exit if( !available ) @@ -196,7 +196,7 @@ static int S_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, i // samples couldn't be retrieved, mark as finished if( num_samples > 0 ) - chan->finished = true; + SetBits( chan->flags, FL_CHAN_FINISHED ); // total amount of samples mixed return offset - initial_offset; @@ -206,10 +206,10 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, { int offset = 0; - if( chan->sentence_finished ) + if( FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED )) return 0; - while( num_samples > 0 && !chan->sentence_finished ) + while( num_samples > 0 && !FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED )) { int outputCount = S_MixChannelToBuffer( pbuf, chan, num_samples, out_rate, pitch, offset, chan->words[chan->word_index].timecompress ); @@ -217,13 +217,13 @@ static int VOX_MixChannelToBuffer( portable_samplepair_t *pbuf, channel_t *chan, num_samples -= outputCount; // if we finished load a next word - if( chan->finished ) + if( FBitSet( chan->flags, FL_CHAN_FINISHED )) { VOX_FreeWord( chan ); chan->word_index++; VOX_LoadWord( chan ); - if( !chan->sentence_finished ) + if( !FBitSet( chan->flags, FL_CHAN_SENTENCE_FINISHED )) chan->sfx = chan->words[chan->word_index].sfx; } } @@ -235,7 +235,7 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate ) { const qboolean local = Host_IsLocalGame(); const qboolean ingame = CL_IsInGame(); - const int num_samples = ( end - paintedtime ) / ( SOUND_DMA_SPEED / rate ); + const int num_samples = ( end - snd.paintedtime ) / ( SOUND_DMA_SPEED / rate ); // FWGS feature: make everybody sound like chipmunks when we're going fast const float pitch_mult = ( sys_timescale.value + 1 ) / 2; @@ -248,25 +248,25 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate ) if( cl.background && cls.key_dest == key_console ) return num_mixed_channels; // no sounds in console with background map - for( int i = 0; i < total_channels; i++ ) + for( int i = 0; i < snd.total_channels; i++ ) { - channel_t *ch = &channels[i]; + channel_t *ch = &snd.channels[i]; if( !ch->sfx ) continue; if( !cl.background ) { - if( cls.key_dest == key_console && ch->localsound ) + if( cls.key_dest == key_console && FBitSet( ch->flags, FL_CHAN_LOCAL_SOUND )) { // play, playvol } - else if(( cls.key_dest == key_menu || cl.paused ) && !ch->localsound && local ) + else if(( cls.key_dest == key_menu || cl.paused ) && !FBitSet( ch->flags, FL_CHAN_LOCAL_SOUND ) && local ) { // play only local sounds, keep pause for other continue; } - else if( cls.key_dest != key_menu && !ingame && !ch->staticsound ) + else if( cls.key_dest != key_menu && !ingame && !FBitSet( ch->flags, FL_CHAN_STATIC_SOUND )) { // play only ambient sounds, keep pause for other continue; @@ -285,7 +285,7 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate ) // if it's also not looping, free it if( ch->leftvol < 8 && ch->rightvol < 8 ) { - if( !FBitSet( sc->flags, SOUND_LOOPED ) || !ch->use_loop ) + if( !FBitSet( sc->flags, SOUND_LOOPED ) || !FBitSet( ch->flags, FL_CHAN_USE_LOOP )) { if( ch->inauduble_free_time == 0.0f ) ch->inauduble_free_time = host.realtime + MAX_CHANNEL_INAUDIBLE_TIME; @@ -308,9 +308,9 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate ) if( ent != NULL ) { if( sc->width == 1 ) - SND_MoveMouth8( &ent->mouth, ch->sample, sc, num_samples, ch->use_loop ); + SND_MoveMouth8( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP )); else - SND_MoveMouth16( &ent->mouth, ch->sample, sc, num_samples, ch->use_loop ); + SND_MoveMouth16( &ent->mouth, ch->sample, sc, num_samples, FBitSet( ch->flags, FL_CHAN_USE_LOOP )); } } @@ -318,18 +318,18 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate ) num_mixed_channels++; - if( ch->is_sentence ) + if( ch->words ) { VOX_MixChannelToBuffer( dst, ch, num_samples, rate, pitch ); - if( ch->sentence_finished ) + if( FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED )) S_FreeChannel( ch ); } else { S_MixChannelToBuffer( dst, ch, num_samples, rate, pitch, 0, 0 ); - if( ch->finished ) + if( FBitSet( ch->flags, FL_CHAN_FINISHED )) S_FreeChannel( ch ); } } @@ -375,7 +375,7 @@ static int S_MixNormalChannelsToRoombuffer( int end, int count ) // until there is no real usecase, let's keep it simple int num_mixed_channels = S_MixNormalChannels( roombuffer, end, SOUND_11k ); - if( dma.format.speed >= SOUND_22k ) + if( snd.format.speed >= SOUND_22k ) { if( num_mixed_channels > 0 ) S_UpsampleBuffer( roombuffer, count / ( SOUND_22k / SOUND_11k )); @@ -383,7 +383,7 @@ static int S_MixNormalChannelsToRoombuffer( int end, int count ) num_mixed_channels += S_MixNormalChannels( roombuffer, end, SOUND_22k ); } - if( dma.format.speed >= SOUND_44k ) + if( snd.format.speed >= SOUND_44k ) { if( num_mixed_channels > 0 ) S_UpsampleBuffer( roombuffer, count / ( SOUND_44k / SOUND_22k )); @@ -402,10 +402,10 @@ static int S_MixRawChannels( int end ) return 0; // paint in the raw channels - for( size_t i = 0; i < ARRAYSIZE( raw_channels ); i++ ) + for( size_t i = 0; i < snd.max_raw_channels; i++ ) { // copy from the streaming sound source - rawchan_t *ch = raw_channels[i]; + rawchan_t *ch = snd.raw_channels[i]; if( !ch ) continue; @@ -434,7 +434,7 @@ static int S_MixRawChannels( int end ) uint stop = (end < ch->s_rawend) ? end : ch->s_rawend; const uint mask = ch->max_samples - 1; - for( size_t i = 0, j = paintedtime; j < stop; i++, j++ ) + for( size_t i = 0, j = snd.paintedtime; j < stop; i++, j++ ) { pbuf[i].left += ( ch->rawsamples[j & mask].left * ch->leftvol ) >> 8; pbuf[i].right += ( ch->rawsamples[j & mask].right * ch->rightvol ) >> 8; @@ -443,8 +443,8 @@ static int S_MixRawChannels( int end ) if( ch->entnum > 0 ) { cl_entity_t *ent = CL_GetEntityByIndex( ch->entnum ); - int pos = paintedtime & ( ch->max_samples - 1 ); - int count = bound( 0, ch->max_samples - pos, stop - paintedtime ); + int pos = snd.paintedtime & ( ch->max_samples - 1 ); + int count = bound( 0, ch->max_samples - pos, stop - snd.paintedtime ); if( ent ) SND_MoveMouthRaw( &ent->mouth, &ch->rawsamples[pos], count ); @@ -486,8 +486,8 @@ static void S_WriteLinearBlastStereo16( short *snd_out, const int *snd_p, size_t static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime ) { const int *snd_p = (const int *)src; - const int sampleMask = ((dma.samples >> 1) - 1); - int lpaintedtime = paintedtime; + const int sampleMask = ((snd.samples >> 1) - 1); + int lpaintedtime = snd.paintedtime; SNDDMA_BeginPainting (); @@ -496,9 +496,9 @@ static void S_TransferPaintBuffer( const portable_samplepair_t *src, int endtime // handle recirculating buffer issues int lpos = lpaintedtime & sampleMask; - short *snd_out = (short *)dma.buffer + (lpos << 1); + short *snd_out = (short *)snd.buffer + (lpos << 1); - int snd_linear_count = (dma.samples>>1) - lpos; + int snd_linear_count = (snd.samples>>1) - lpos; if( lpaintedtime + snd_linear_count > endtime ) snd_linear_count = endtime - lpaintedtime; @@ -526,14 +526,14 @@ void S_PaintChannels( int endtime ) { int gain = S_GetMasterVolume() * 256; - while( paintedtime < endtime ) + while( snd.paintedtime < endtime ) { // if paintbuffer is smaller than DMA buffer int end = endtime; - if( end - paintedtime > PAINTBUFFER_SIZE ) - end = paintedtime + PAINTBUFFER_SIZE; + if( end - snd.paintedtime > PAINTBUFFER_SIZE ) + end = snd.paintedtime + PAINTBUFFER_SIZE; - const int num_samples = end - paintedtime; + const int num_samples = end - snd.paintedtime; S_ClearBuffers( num_samples ); @@ -550,6 +550,6 @@ void S_PaintChannels( int endtime ) // transfer out according to DMA format S_TransferPaintBuffer( paintbuffer, end ); - paintedtime = end; + snd.paintedtime = end; } } diff --git a/engine/client/s_stream.c b/engine/client/s_stream.c index b691bf4c..8e1dd9aa 100644 --- a/engine/client/s_stream.c +++ b/engine/client/s_stream.c @@ -92,7 +92,7 @@ void S_StartBackgroundTrack( const char *introTrack, const char *mainTrack, int { S_StopBackgroundTrack(); - if( !dma.initialized ) return; + if( !snd.initialized ) return; // check for special symbols if( introTrack && *introTrack == '*' ) @@ -132,9 +132,9 @@ S_StopBackgroundTrack */ void S_StopBackgroundTrack( void ) { - s_listener.stream_paused = false; + snd.stream_paused = false; - if( !dma.initialized ) return; + if( !snd.initialized ) return; if( !s_bgTrack.stream ) return; FS_FreeStream( s_bgTrack.stream ); @@ -149,7 +149,7 @@ S_StreamSetPause */ void S_StreamSetPause( int pause ) { - s_listener.stream_paused = pause; + snd.stream_paused = pause; } /* @@ -197,11 +197,11 @@ void S_StreamBackgroundTrack( void ) int r, fileBytes; rawchan_t *ch = NULL; - if( !dma.initialized || !s_bgTrack.stream || s_listener.streaming ) + if( !snd.initialized || !s_bgTrack.stream || snd.streaming ) return; // don't bother playing anything if musicvolume is 0 - if( !s_musicvolume.value || cl.paused || s_listener.stream_paused ) + if( !s_musicvolume.value || cl.paused || snd.stream_paused ) return; if( !cl.background ) @@ -218,14 +218,14 @@ void S_StreamBackgroundTrack( void ) Assert( ch != NULL ); // see how many samples should be copied into the raw buffer - if( ch->s_rawend < soundtime ) - ch->s_rawend = soundtime; + if( ch->s_rawend < snd.soundtime ) + ch->s_rawend = snd.soundtime; - while( ch->s_rawend < soundtime + ch->max_samples ) + while( ch->s_rawend < snd.soundtime + ch->max_samples ) { const stream_t *info = s_bgTrack.stream; - bufferSamples = ch->max_samples - (ch->s_rawend - soundtime); + bufferSamples = ch->max_samples - (ch->s_rawend - snd.soundtime); // decide how much data needs to be read from the file fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED ); @@ -283,9 +283,9 @@ S_StartStreaming */ void S_StartStreaming( void ) { - if( !dma.initialized ) return; + if( !snd.initialized ) return; // begin streaming movie soundtrack - s_listener.streaming = true; + snd.streaming = true; } /* @@ -295,6 +295,6 @@ S_StopStreaming */ void S_StopStreaming( void ) { - if( !dma.initialized ) return; - s_listener.streaming = false; + if( !snd.initialized ) return; + snd.streaming = false; } diff --git a/engine/client/s_vox.c b/engine/client/s_vox.c index 3eb3942a..3216d9a4 100644 --- a/engine/client/s_vox.c +++ b/engine/client/s_vox.c @@ -140,7 +140,7 @@ static void S_TrimStartEndTimes( channel_t *ch, wavdata_t *wav, int start, int e void VOX_LoadWord( channel_t *ch ) { - ch->sentence_finished = true; + SetBits( ch->flags, FL_CHAN_SENTENCE_FINISHED ); if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX ) return; @@ -155,7 +155,7 @@ void VOX_LoadWord( channel_t *ch ) if( !data ) return; - ch->sentence_finished = false; + ClearBits( ch->flags, FL_CHAN_SENTENCE_FINISHED ); ch->data = data; int start = word->start; @@ -171,7 +171,7 @@ void VOX_FreeWord( channel_t *ch ) { // TODO: don't set random fields to zero lol, was memset before ch->sample = ch->forced_end = 0.0; - ch->finished = false; + ClearBits( ch->flags, FL_CHAN_FINISHED ); ch->data = NULL; if( ch->word_index < 0 || ch->word_index >= CVOXWORDMAX ) @@ -179,7 +179,7 @@ void VOX_FreeWord( channel_t *ch ) voxword_t *word = &ch->words[ch->word_index]; - if( !word->sfx || word->in_cache ) + if( !word->sfx || FBitSet( word->flags, FL_VOXWORD_IN_CACHE )) return; FS_FreeSound( word->sfx->cache ); @@ -191,7 +191,7 @@ void VOX_SetChanVol( channel_t *ch ) { voxword_t *word; - if( !ch->is_sentence || ch->sentence_finished ) + if( !ch->words || FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED )) return; word = &ch->words[ch->word_index]; @@ -207,7 +207,7 @@ float VOX_ModifyPitch( channel_t *ch, float pitch ) { voxword_t *word; - if( !ch->is_sentence || ch->sentence_finished ) + if( !ch->words || FBitSet( ch->flags, FL_CHAN_SENTENCE_FINISHED )) return pitch; word = &ch->words[ch->word_index]; @@ -356,10 +356,7 @@ static void VOX_MakeDefaultWordParams( voxword_t *voxword ) *voxword = (voxword_t) { .volume = 100, .pitch = 100, - .start = 0, .end = 100, - .timecompress = 0, - .in_cache = false, }; } @@ -416,19 +413,24 @@ static qboolean VOX_ParseWordParams( char *psz, voxword_t *pvoxword, voxword_t * i = Q_atoi( sznum ); switch( command ) { - case 'e': pvoxword->end = i; break; - case 'p': pvoxword->pitch = i; break; - case 's': pvoxword->start = i; break; - case 't': pvoxword->timecompress = i; break; - case 'v': pvoxword->volume = i; break; + case 'e': + pvoxword->end = bound( 0, i, 100 ); + break; + case 'p': + pvoxword->pitch = bound( 0, i, UINT16_MAX ); + break; + case 's': + pvoxword->start = bound( 0, i, 100 ); + break; + case 't': + pvoxword->timecompress = bound( 0, i, 100 ); + break; + case 'v': + pvoxword->volume = bound( 0, i, UINT16_MAX ); + break; } } - // validate some of the parameters - pvoxword->start = bound( 0, pvoxword->start, 100 ); - pvoxword->end = bound( 0, pvoxword->end, 100 ); - pvoxword->timecompress = bound( 0, pvoxword->timecompress, 100 ); - // no actual word but new defaults if( Q_strlen( pszsave ) == 0 ) { @@ -447,10 +449,18 @@ void VOX_LoadSound( channel_t *ch, const char *pszin ) int i, j; int num_words; voxword_t default_voxword; + voxword_t words_buf[CVOXWORDMAX + 1]; // local scratch: parsed words + null terminator if( !pszin ) return; + // free any existing words from a previous sentence on this channel + if( ch->words ) + { + VOX_FreeWord( ch ); + Mem_Free2( &ch->words ); + } + psz = VOX_LookupString( pszin ); if( !psz ) @@ -478,12 +488,13 @@ void VOX_LoadSound( channel_t *ch, const char *pszin ) num_words = VOX_ParseString( buffer, rgpparseword ); VOX_MakeDefaultWordParams( &default_voxword ); + memset( words_buf, 0, sizeof( words_buf )); for( i = 0, j = 0; i < num_words; i++ ) { char pathbuffer[MAX_SYSPATH]; - if( !VOX_ParseWordParams( rgpparseword[i], &ch->words[j], &default_voxword )) + if( !VOX_ParseWordParams( rgpparseword[i], &words_buf[j], &default_voxword )) continue; if( Q_snprintf( pathbuffer, sizeof( pathbuffer ), "%s%s", szpath, rgpparseword[i] ) < 0 ) @@ -493,17 +504,19 @@ void VOX_LoadSound( channel_t *ch, const char *pszin ) } qboolean in_cache = false; - ch->words[j].sfx = S_FindName( pathbuffer, &in_cache ); - ch->words[j].in_cache = in_cache; + words_buf[j].sfx = S_FindName( pathbuffer, &in_cache ); + if( in_cache ) + SetBits( words_buf[j].flags, FL_VOXWORD_IN_CACHE ); j++; } - ch->words[j].sfx = NULL; + // words_buf[j].sfx is already NULL from the memset — null terminator + ch->words = Mem_Malloc( sndpool, ( j + 1 ) * sizeof( voxword_t )); + memcpy( ch->words, words_buf, ( j + 1 ) * sizeof( voxword_t )); + ch->sfx = ch->words[0].sfx; ch->word_index = 0; - ch->is_sentence = true; - VOX_LoadWord( ch ); } diff --git a/engine/client/sound.h b/engine/client/sound.h index 4d9108de..a596f2f4 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -55,15 +55,17 @@ typedef struct sfx_s struct sfx_s *hashNext; } sfx_t; +#define FL_VOXWORD_IN_CACHE BIT( 0 ) // if set, it was loaded prior and shouldn't be freed + typedef struct voxword_s { - sfx_t *sfx; - uint16_t volume; // volume percent - uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun) - uint16_t timecompress; // percent of skipped data (speeds up playback without pitch shift) - uint16_t start : 7; // percent at which playback starts - uint16_t end : 7; // percent at which playback ends - uint16_t in_cache : 1; // if set to 1, it was loaded prior and shouldn't be freed + sfx_t *sfx; + uint16_t volume; // volume percent + uint16_t pitch; // pitch shift percent (keep large for extra chipmunk fun) + uint8_t timecompress; // percent of skipped data (speeds up playback without pitch shift) + uint8_t start; // percent at which playback starts + uint8_t end; // percent at which playback ends + uint8_t flags; } voxword_t; typedef struct snd_format_s @@ -73,19 +75,9 @@ typedef struct snd_format_s byte channels; } snd_format_t; -typedef struct dma_api_s -{ - snd_format_t format; - int samples; // mono samples in buffer - int samplepos; // in mono samples - qboolean initialized; // sound engine is active - byte *buffer; - const char *backendName; -} dma_t; - typedef struct rawchan_s { - int entnum; + short entnum; short master_vol; short leftvol; // 0-255 left volume short rightvol; // 0-255 right volume @@ -93,31 +85,37 @@ typedef struct rawchan_s vec3_t origin; // only use if fixed_origin is set volatile uint s_rawend; float oldtime; // catch time jumps + + uintptr_t engine_reserved[8]; // only for engine developers + uintptr_t game_reserved[8]; // free space for game developers + size_t max_samples; // buffer length portable_samplepair_t rawsamples[]; // variable sized } rawchan_t; +#define FL_CHAN_USE_LOOP BIT( 0 ) // don't loop default and local sounds +#define FL_CHAN_STATIC_SOUND BIT( 1 ) // use origin instead of fetching entnum's origin +#define FL_CHAN_LOCAL_SOUND BIT( 2 ) // it's a local menu sound (not looped, not paused) +#define FL_CHAN_SENTENCE_FINISHED BIT( 4 ) // if set, finished playing sentence +#define FL_CHAN_FINISHED BIT( 5 ) // if set, finished playing single word + typedef struct channel_s { char name[16]; // keep sentence name - sfx_t *sfx; // sfx number + sfx_t *sfx; // sfx number vec3_t origin; // only use if fixed_origin is set float dist_mult; // distance multiplier (attenuation/clipK) - int entnum; // entity soundsource int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.) + uint flags; + short entnum; // entity soundsource short master_vol; // 0-255 master volume short leftvol; // 0-255 left volume short rightvol; // 0-255 right volume short basePitch; // base pitch percent (100% is normal pitch playback) - byte use_loop : 1; // don't loop default and local sounds - byte staticsound : 1; // use origin instead of fetching entnum's origin - byte localsound : 1; // it's a local menu sound (not looped, not paused) - byte is_sentence : 1; // bit indicating vox sentence - byte sentence_finished : 1; // if set, finished playing sentence - byte finished : 1; // if set, finished playing single word byte word_index; + // HACKHACK: count when this channel became inaudible // to not free it when it could be respatialized soon #define MAX_CHANNEL_INAUDIBLE_TIME 0.1f @@ -126,20 +124,43 @@ typedef struct channel_s double sample; double forced_end; wavdata_t *data; - voxword_t words[CVOXWORDMAX]; + voxword_t *words; // dynamically allocated, (num_words + 1) entries, null sfx terminates + + uintptr_t engine_reserved[8]; // only for engine developers + uintptr_t game_reserved[8]; // free space for game developers } channel_t; -typedef struct -{ - vec3_t origin; // simorg + view_ofs - vec3_t forward; - vec3_t right; - vec3_t up; +typedef int sound_t; - int entnum; - qboolean streaming; // playing AVI-file - qboolean stream_paused; // pause only background track -} listener_t; +typedef struct snd_globals_s +{ + // dma + const char *backend_name; + byte *buffer; + snd_format_t format; + qboolean initialized; // sound engine is active + int samples; // mono samples in buffer + int samplepos; // in mono samples + + int paintedtime; // total samples that have been mixed at speed + int soundtime; // total samples that have been played out to hardware at dma speed + + // listener (client, camera, etc) + vec3_t origin; + vec3_t forward, right, up; + int entnum; + qboolean streaming; // playing AVI-file + qboolean stream_paused; // pause only background track + + // SoundAPI shared pointers + channel_t *const channels; + int max_channels; + int total_channels; + rawchan_t **const raw_channels; + int max_raw_channels; + sound_t ambient_sfx[NUM_AMBIENTS]; + qboolean have_ambient_sfx; +} snd_globals_t; //==================================================================== @@ -149,16 +170,8 @@ typedef struct #define MAX_RAW_SAMPLES 16384 #define SND_CLIP_DISTANCE 1000.0f -extern sound_t ambient_sfx[NUM_AMBIENTS]; -extern qboolean snd_ambient; -extern channel_t channels[MAX_CHANNELS]; -extern rawchan_t *raw_channels[MAX_RAW_CHANNELS]; -extern int total_channels; -extern int paintedtime; -extern int soundtime; -extern listener_t s_listener; -extern int idsp_room; -extern dma_t dma; +extern int idsp_room; +extern snd_globals_t snd; extern convar_t s_musicvolume; extern convar_t s_lerping; diff --git a/engine/client/soundlib/snd_wav.c b/engine/client/soundlib/snd_wav.c index e64e851c..b6e85b64 100644 --- a/engine/client/soundlib/snd_wav.c +++ b/engine/client/soundlib/snd_wav.c @@ -51,12 +51,12 @@ GetLittleLong */ static int GetLittleLong( void ) { - int val = 0; + uint val = 0; - val += (*(iff_dataPtr+0) << 0); - val += (*(iff_dataPtr+1) << 8); - val += (*(iff_dataPtr+2) <<16); - val += (*(iff_dataPtr+3) <<24); + val += ((uint)*(iff_dataPtr+0) << 0); + val += ((uint)*(iff_dataPtr+1) << 8); + val += ((uint)*(iff_dataPtr+2) <<16); + val += ((uint)*(iff_dataPtr+3) <<24); iff_dataPtr += 4; return val; diff --git a/engine/common/common.h b/engine/common/common.h index 146909c1..7e3726f4 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -37,8 +37,6 @@ GNU General Public License for more details. #include "com_model.h" #include "com_strings.h" #include "crtlib.h" -#define FSCALLBACK_OVERRIDE_MALLOC_LIKE -#include "fscallback.h" #include "cvar.h" #include "con_nprint.h" #include "crclib.h" @@ -383,6 +381,10 @@ void Mem_Stats_f( void ); #define Mem_Calloc( pool, size ) _Mem_Alloc( pool, size, true, __FILE__, __LINE__ ) #define Mem_Realloc( pool, ptr, size ) _Mem_Realloc( pool, ptr, size, true, __FILE__, __LINE__ ) #define Mem_Free( mem ) _Mem_Free( mem, __FILE__, __LINE__ ) +#define Mem_Free2( ptr ) { \ + _Mem_Free( *ptr, __FILE__, __LINE__ ); \ + *ptr = NULL; } + #define Mem_AllocPool( name ) _Mem_AllocPool( name, __FILE__, __LINE__ ) #define Mem_FreePool( pool ) _Mem_FreePool( pool, __FILE__, __LINE__ ) #define Mem_EmptyPool( pool ) _Mem_EmptyPool( pool, __FILE__, __LINE__ ) diff --git a/engine/common/con_utils.c b/engine/common/con_utils.c index 5fdef596..11fe6e09 100644 --- a/engine/common/con_utils.c +++ b/engine/common/con_utils.c @@ -1199,6 +1199,9 @@ void Con_CompleteCommand( field_t *field, qboolean print_suggestions ) // setup the completion field con.completionField = field; + if( COM_StringEmpty( con.completionField->buffer )) + return; + // only look at the first token for completion purposes Cmd_TokenizeString( con.completionField->buffer ); diff --git a/engine/common/host.c b/engine/common/host.c index a8712cf6..9253aa74 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -36,6 +36,8 @@ GNU General Public License for more details. #include "enginefeatures.h" #include "render_api.h" // decallist_t #include "tests.h" +#include "library.h" +#include "platform/platform.h" host_parm_t host; // host parms static jmp_buf return_from_main_buf; @@ -861,6 +863,118 @@ static void Host_DetermineExecutableName( char *out, size_t size ) #endif } +static qboolean Host_CollectX86Libraries( ECommonLibraryType lib_type, + const char *win_path, const char *lin_path, const char *osx_path, + char *found, size_t found_size ) +{ + string native_path; + qboolean has_any = false; + + found[0] = 0; + + COM_GetCommonLibraryPath( lib_type, native_path, sizeof( native_path )); + if( Platform_LibraryExists( native_path, true )) + return 0; + +#if !( XASH_WIN32 && XASH_X86 ) + if( !COM_StringEmpty( win_path ) && FS_FileExists( win_path, true )) + { + Q_strncat( found, "Windows (x86)", found_size ); + has_any = true; + } +#endif + +#if !( XASH_LINUX && !XASH_ANDROID && XASH_X86 ) + if( !COM_StringEmpty( lin_path ) && FS_FileExists( lin_path, true )) + { + if( has_any ) + Q_strncat( found, ", ", found_size ); + Q_strncat( found, "GNU/Linux (x86)", found_size ); + has_any = true; + } +#endif + +#if !( XASH_APPLE && XASH_X86 ) + if( !COM_StringEmpty( osx_path ) && FS_FileExists( osx_path, true )) + { + if( has_any ) + Q_strncat( found, ", ", found_size ); + Q_strncat( found, "macOS (x86)", found_size ); + has_any = true; + } +#endif + + return has_any; +} + +static void Host_CheckGameLibraries( void ) +{ +// on Android, game libraries are loaded from APKs and are invisible to FS_FileExists, +// so the check cannot work there; iOS is handled via Platform_LibraryExists -> IOS_LibraryExists +#if !defined( XASH_INTERNAL_GAMELIBS ) && !XASH_ANDROID + struct + { + const char *name; + ECommonLibraryType type; + const char *override; // host.gamedll / host.clientlib / host.menulib + } libs[3] = { + { "client", LIBRARY_CLIENT, host.clientlib }, + { "server", LIBRARY_SERVER, host.gamedll }, + { "menu", LIBRARY_GAMEUI, host.menulib }, + }; + + char details[MAX_VA_STRING]; + details[0] = 0; + + for( int i = 0; i < ARRAYSIZE( libs ); i++ ) + { + string found; + qboolean ret; + + // if the user explicitly set a library path, trust them and skip the check + if( !COM_StringEmpty( libs[i].override )) + continue; + + if( libs[i].type == LIBRARY_SERVER ) + { + // missing server library is only critical when singleplayer is available + // mirrors silent mode in SV_InitGame + if( GI->gamemode != GAME_SINGLEPLAYER_ONLY ) + continue; + + ret = Host_CollectX86Libraries( libs[i].type, + GI->game_dll, GI->game_dll_linux, GI->game_dll_osx, + found, sizeof( found )); + } + else + { + string win, lin, osx; + Q_snprintf( win, sizeof( win ), "%s/%s.dll", GI->dll_path, libs[i].name ); + Q_snprintf( lin, sizeof( lin ), "%s/%s.so", GI->dll_path, libs[i].name ); + Q_snprintf( osx, sizeof( osx ), "%s/%s.dylib", GI->dll_path, libs[i].name ); + ret = Host_CollectX86Libraries( libs[i].type, + win, lin, osx, found, sizeof( found )); + } + + if( ret ) + { + size_t len = Q_strlen( details ); + Q_snprintf( details + len, sizeof( details ) - len, "- %s: %s\n", libs[i].name, found ); + } + } + + if( COM_StringEmpty( details )) + return; + + Sys_Warn( "No native game libraries found for current platform (%s-%s),\n" + "but found libraries for other platforms:\n" + "%s" + "The game may fail to load or work incorrectly.\n" + "Consider using a mod version built for this platform.", + Q_buildos(), Q_buildarch(), details ); +#endif // XASH_INTERNAL_GAMELIBS +} + /* ================= Host_InitCommon @@ -998,6 +1112,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole #endif FS_LoadGameInfo(); + Host_CheckGameLibraries(); Cvar_PostFSInit(); Image_CheckPaletteQ1 (); diff --git a/engine/common/mod_bmodel.c b/engine/common/mod_bmodel.c index d0564535..3bf3bdd5 100644 --- a/engine/common/mod_bmodel.c +++ b/engine/common/mod_bmodel.c @@ -2587,7 +2587,7 @@ static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qbo r_temp.palette = NULL; // load it in - solidskyTexture = GL_LoadTextureInternal( "solid_sky", &r_temp, TF_NOMIPMAP ); + solidskyTexture = GL_LoadTextureInternal( "solid_sky", &r_temp, TF_NOMIPMAP | TF_ALLOW_NEAREST ); for( i = 0; i < r_sky->width >> 1; i++ ) { @@ -2610,7 +2610,7 @@ static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qbo r_temp.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA; // load it in - alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_NOMIPMAP ); + alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", &r_temp, TF_NOMIPMAP | TF_ALLOW_NEAREST ); // clean up FS_FreeImage( r_sky ); @@ -3599,6 +3599,10 @@ Mod_LoadVisibility */ static void Mod_LoadVisibility( model_t *mod, dbspmodel_t *bmod ) { + // external bmodels have no visibility + if( !bmod->visdata || !bmod->visdatasize ) + return; + mod->visdata = Mem_Malloc( mod->mempool, bmod->visdatasize ); memcpy( mod->visdata, bmod->visdata, bmod->visdatasize ); } @@ -3793,7 +3797,7 @@ static fs_offset_t Mod_FindBSPX( const byte *mod_base, size_t bufferlen ) max_offset = ALIGN( max_offset, 4 ); // force 32-bit boundary - if( max_offset > bufferlen ) + if( max_offset + sizeof( dbspx_hdr_t ) > bufferlen ) return -1; bspx_header = (const dbspx_hdr_t *)( mod_base + max_offset ); @@ -3878,8 +3882,11 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, byte *mod_base, size_t buffer Mod_LoadLump( mod_base, &extlumps[i], &worldstats[stat_index], flags, LOADLUMP_BSP30EXT, NULL ); // loading bspx lumps - for( i = 0; i < ARRAYSIZE( bspxlumps ); i++, stat_index++ ) - Mod_LoadLump( mod_base, &bspxlumps[i], &worldstats[stat_index], flags, LOADLUMP_BSPX, mod_base + bspx_header_offset ); + if( bspx_header_offset >= 0 ) + { + for( i = 0; i < ARRAYSIZE( bspxlumps ); i++, stat_index++ ) + Mod_LoadLump( mod_base, &bspxlumps[i], &worldstats[stat_index], flags, LOADLUMP_BSPX, mod_base + bspx_header_offset ); + } if( !bmod->isworld ) // a1ba: why world excluded here? { diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index bfeee3c7..18347c20 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -1658,7 +1658,7 @@ void Netchan_TransmitBits( netchan_t *chan, int length, const byte *data ) MSG_Init( &send, "NetSend", send_buf, sizeof( send_buf )); // prepare the packet header - w1 = chan->outgoing_sequence | (send_reliable << 31); + w1 = chan->outgoing_sequence | (((uint)send_reliable ) << 31); w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence << 31); send_reliable_fragment = false; diff --git a/engine/common/pm_surface.c b/engine/common/pm_surface.c index 5ae4b2d1..06c8f0e7 100644 --- a/engine/common/pm_surface.c +++ b/engine/common/pm_surface.c @@ -112,7 +112,6 @@ msurface_t *PM_RecursiveSurfCheck( model_t *mod, mnode_t *node, vec3_t p1, vec3_ int i, side; msurface_t *surf; vec3_t mid; - mnode_t *children[2]; int numsurfaces, firstsurface; loc0: @@ -122,17 +121,15 @@ loc0: t1 = PlaneDiff( p1, node->plane ); t2 = PlaneDiff( p2, node->plane ); - node_children( children, node, mod ); - if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON ) { - node = children[0]; + node = node_child( node, 0, mod ); goto loc0; } if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON ) { - node = children[1]; + node = node_child( node, 1, mod ); goto loc0; } @@ -142,7 +139,7 @@ loc0: VectorLerp( p1, frac, p2, mid ); - if(( surf = PM_RecursiveSurfCheck( mod, children[side], p1, mid )) != NULL ) + if(( surf = PM_RecursiveSurfCheck( mod, node_child( node, side, mod ), p1, mid )) != NULL ) return surf; // walk through real faces @@ -179,7 +176,7 @@ loc0: return NULL; // through the fence } - return PM_RecursiveSurfCheck( mod, children[side^1], mid, p2 ); + return PM_RecursiveSurfCheck( mod, node_child( node, side^1, mod ), mid, p2 ); } /* @@ -234,7 +231,6 @@ static int PM_TestLine_r( model_t *mod, mnode_t *node, vec_t p1f, vec_t p2f, con float frac, midf; int i, r, side; vec3_t mid; - mnode_t *children[2]; int numsurfaces, firstsurface; loc0: @@ -252,17 +248,15 @@ loc0: front = PlaneDiff( start, node->plane ); back = PlaneDiff( stop, node->plane ); - node_children( children, node, mod ); - if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON ) { - node = children[0]; + node = node_child( node, 0, mod ); goto loc0; } if( front < FRAC_EPSILON && back < FRAC_EPSILON ) { - node = children[1]; + node = node_child( node, 1, mod ); goto loc0; } @@ -273,7 +267,7 @@ loc0: VectorLerp( start, frac, stop, mid ); midf = p1f + ( p2f - p1f ) * frac; - r = PM_TestLine_r( mod, children[side], p1f, midf, start, mid, trace ); + r = PM_TestLine_r( mod, node_child( node, side, mod ), p1f, midf, start, mid, trace ); if( r != CONTENTS_EMPTY ) { @@ -322,7 +316,7 @@ loc0: return contents; } - return PM_TestLine_r( mod, children[!side], midf, p2f, mid, stop, trace ); + return PM_TestLine_r( mod, node_child( node, !side, mod ), midf, p2f, mid, stop, trace ); } int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags ) diff --git a/engine/platform/ios/lib_ios.c b/engine/platform/ios/lib_ios.c index dfe9af01..66ebba17 100644 --- a/engine/platform/ios/lib_ios.c +++ b/engine/platform/ios/lib_ios.c @@ -13,63 +13,83 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include +#include #include #include +#include #include "crtlib.h" #include "library.h" #include "platform/ios/lib_ios.h" #include "common.h" -#define EXT_LENGTH 5 +const char *g_szLibrarySuffix; static void *IOS_LoadLibraryInternal( const char *dllname ) { void *pHandle; - string errorstring = ""; char path[MAX_SYSPATH]; - Q_snprintf( path, MAX_SYSPATH, "%s%s", SDL_GetBasePath(), dllname ); + Q_snprintf( path, sizeof( path ), "%s%s", SDL_GetBasePath(), dllname ); pHandle = dlopen( path, RTLD_LAZY ); if( !pHandle ) - { - COM_PushLibraryError(errorstring); - COM_PushLibraryError(dlerror()); - } + COM_PushLibraryError(dlerror( )); return pHandle; } -const char *g_szLibrarySuffix; + +static qboolean IOS_LibraryExistsInternal( const char *name ) +{ + struct stat buf; + char path[MAX_SYSPATH]; + + Q_snprintf( path, sizeof( path ), "%s%s", SDL_GetBasePath(), name ); + + return stat( path, &buf ) == 0; +} + +static const char *IOS_GetLibraryPostfix( void ) +{ + if( g_szLibrarySuffix ) + return g_szLibrarySuffix; + + return Q_strcmp( host.default_gamedir, FS_Gamedir( )) ? FS_Gamedir( ) : ""; +} + +static void IOS_PrepareGameLibraryPath( const char *dllname, char *out, size_t outsize ) +{ + string strippedname; + + Q_strncpy( strippedname, dllname, sizeof( strippedname )); + COM_StripExtension( strippedname ); + + Q_snprintf( out, outsize, "%s_%s.dylib", strippedname, IOS_GetLibraryPostfix( )); +} + void *IOS_LoadLibrary( const char *dllname ) { - //Immediately load if the library is filesystem_stdio.dylib or we will crash when accessing gamedir - if ( !Q_strcmp( dllname, "filesystem_stdio.dylib" ) ) - { + // filesystem_stdio is a special case, as engine won't work correctly without it + // but it's always located at known path + if( !Q_strcmp( dllname, "filesystem_stdio.dylib" )) return IOS_LoadLibraryInternal( dllname ); - } string name; - string strippedname; - const char *postfix = g_szLibrarySuffix; char *pHandle; - - if( !postfix ) - { - if ( Q_strcmp(FS_Gamedir(), host.default_gamedir ) ) - { - postfix = FS_Gamedir( ); - } - else postfix = ""; - } - Q_strncpy( strippedname, dllname, sizeof( strippedname ) ); - COM_StripExtension(strippedname); - - Q_snprintf( name, MAX_STRING, "%s_%s.dylib", strippedname, postfix ); + IOS_PrepareGameLibraryPath( dllname, name, sizeof( name )); pHandle = IOS_LoadLibraryInternal( name ); - if( pHandle ) - return pHandle; + if( !pHandle ) + pHandle = IOS_LoadLibraryInternal( dllname ); - return IOS_LoadLibraryInternal( dllname ); + return pHandle; +} + +qboolean IOS_LibraryExists( const char *dllname ) +{ + string name; + + IOS_PrepareGameLibraryPath( dllname, name, sizeof( name )); + + return IOS_LibraryExistsInternal( name ) || IOS_LibraryExistsInternal( dllname ); } diff --git a/engine/platform/ios/lib_ios.h b/engine/platform/ios/lib_ios.h index 33f222f4..67bd8bfa 100644 --- a/engine/platform/ios/lib_ios.h +++ b/engine/platform/ios/lib_ios.h @@ -20,6 +20,7 @@ GNU General Public License for more details. #define Platform_POSIX_LoadLibrary( x ) IOS_LoadLibrary(( x )) void *IOS_LoadLibrary( const char *dllname ); +qboolean IOS_LibraryExists( const char *name ); #endif // IOS_LIB_H #endif // TARGET_OS_IPHONE diff --git a/engine/platform/linux/s_alsa.c b/engine/platform/linux/s_alsa.c index 2c6524ef..dac0d4fc 100644 --- a/engine/platform/linux/s_alsa.c +++ b/engine/platform/linux/s_alsa.c @@ -105,8 +105,8 @@ qboolean SNDDMA_Init( void ) return false; } - dma.format.speed = SOUND_DMA_SPEED; - r = dma.format.speed; + snd.format.speed = SOUND_DMA_SPEED; + r = snd.format.speed; if( ( err = snd_pcm_hw_params_set_rate_near( s_alsa.pcm_handle, s_alsa.hw_params, &r, &dir ) ) < 0 ) { @@ -121,14 +121,14 @@ qboolean SNDDMA_Init( void ) if( dir != 0 ) { Con_Printf( "ALSA: rate %d not supported, using %d\n", SOUND_DMA_SPEED, r ); - dma.format.speed = r; + snd.format.speed = r; dir = 0; } } - dma.format.channels = 2; + snd.format.channels = 2; - if( ( err = snd_pcm_hw_params_set_channels(s_alsa.pcm_handle, s_alsa.hw_params, dma.format.channels ) ) < 0 ) + if( ( err = snd_pcm_hw_params_set_channels(s_alsa.pcm_handle, s_alsa.hw_params, snd.format.channels ) ) < 0 ) { Con_Printf( "ALSA: cannot set channels %d(%s)\n", 2, snd_strerror( err ) ); snd_pcm_hw_params_free( s_alsa.hw_params ); @@ -162,7 +162,7 @@ qboolean SNDDMA_Init( void ) } else { - // if period is NPOT it cannot be used as dma.samples in Xash3D + // if period is NPOT it cannot be used as snd.samples in Xash3D // and need more space to send buffer partially samples = 1; while( samples < p * 4 ) @@ -184,15 +184,15 @@ qboolean SNDDMA_Init( void ) return false; } - dma.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer - dma.samplepos = 0; - dma.samples = samples; - dma.format.width = 2; - dma.initialized = 1; - dma.backendName = "ALSA"; + snd.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer + snd.samplepos = 0; + snd.samples = samples; + snd.format.width = 2; + snd.initialized = 1; + snd.backend_name = "ALSA"; snd_pcm_prepare( s_alsa.pcm_handle ); - snd_pcm_writei( s_alsa.pcm_handle, dma.buffer, 2 * s_alsa.period_size ); + snd_pcm_writei( s_alsa.pcm_handle, snd.buffer, 2 * s_alsa.period_size ); snd_pcm_start( s_alsa.pcm_handle ); return true; @@ -208,14 +208,14 @@ Closes the ALSA pcm device and frees the dma buffer. void SNDDMA_Shutdown(void) { Con_Printf( "Shutting down audio.\n" ); - dma.initialized = false; + snd.initialized = false; - if( dma.buffer ) + if( snd.buffer ) { snd_pcm_drop( s_alsa.pcm_handle ); snd_pcm_close( s_alsa.pcm_handle ); - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -240,38 +240,38 @@ void SNDDMA_Submit( void ) while( avail >= s_alsa.period_size ) { - int size = dma.samples << 1; - int pos = dma.samplepos << 1; + int size = snd.samples << 1; + int pos = snd.samplepos << 1; unsigned long len = s_alsa.period_size * 4; int wrapped = pos + len - size; int w; if( wrapped < 0 ) { - w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer + pos, len / 4 ); + w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer + pos, len / 4 ); if( w < 0 ) { snd_pcm_prepare(s_alsa.pcm_handle); return; } - dma.samplepos += len >> 1; + snd.samplepos += len >> 1; } else { int remaining = size - pos; - w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer + pos, remaining / 4 ); + w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer + pos, remaining / 4 ); if( w < 0 ) { snd_pcm_prepare(s_alsa.pcm_handle); return; } - w = snd_pcm_writei( s_alsa.pcm_handle, dma.buffer, wrapped / 4 ); + w = snd_pcm_writei( s_alsa.pcm_handle, snd.buffer, wrapped / 4 ); if( w < 0 ) { snd_pcm_prepare(s_alsa.pcm_handle); return; } - dma.samplepos = wrapped >> 1; + snd.samplepos = wrapped >> 1; } avail = snd_pcm_avail_update( s_alsa.pcm_handle ); @@ -282,11 +282,11 @@ void SNDDMA_Submit( void ) int s, w, frames; void *start; - if( !dma.buffer ) + if( !snd.buffer ) return; - s = dma.samplepos * 2; - start = (void *)&dma.buffer[s]; + s = snd.samplepos * 2; + start = (void *)&snd.buffer[s]; frames = s_alsa.period_size / 2; // write to card if( ( w = snd_pcm_writei( s_alsa.pcm_handle, start, frames ) ) < 0) @@ -296,10 +296,10 @@ void SNDDMA_Submit( void ) return; } - dma.samplepos += w * 2; // mark progress + snd.samplepos += w * 2; // mark progress - if(dma.samplepos >= dma.samples) - dma.samplepos = 0; // wrap buffer + if(snd.samplepos >= snd.samples) + snd.samplepos = 0; // wrap buffer } } @@ -324,7 +324,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; s_alsa.paused = !active; diff --git a/engine/platform/platform.h b/engine/platform/platform.h index 942cc217..0d214936 100644 --- a/engine/platform/platform.h +++ b/engine/platform/platform.h @@ -18,6 +18,8 @@ GNU General Public License for more details. #define PLATFORM_H #include +#define FSCALLBACK_OVERRIDE_MALLOC_LIKE +#include "fscallback.h" #include "common.h" #include "system.h" #include "defaults.h" @@ -43,6 +45,7 @@ qboolean Platform_DebuggerPresent( void ); int IOS_GetArgs( char ***argv ); const char *IOS_GetDocsDir( void ); void IOS_LaunchDialog( void ); +#include "platform/ios/lib_ios.h" #endif // TARGET_OS_IOS #if XASH_WIN32 || XASH_LINUX @@ -207,6 +210,18 @@ static inline void Sys_RestoreCrashHandler( void ) } #endif +static inline qboolean Platform_LibraryExists( const char *name, qboolean gamedironly ) +{ +#if XASH_IOS + return IOS_LibraryExists( name ); +#elif XASH_ANDROID + // sorry, unimplemented + return false; +#else + return g_fsapi.FileExists( name, gamedironly ); +#endif +} + /* ============================================================================== diff --git a/engine/platform/sdl1/s_sdl1.c b/engine/platform/sdl1/s_sdl1.c index 86180d9a..03de7e5b 100644 --- a/engine/platform/sdl1/s_sdl1.c +++ b/engine/platform/sdl1/s_sdl1.c @@ -46,38 +46,38 @@ static char sdl_backend_name[32]; static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len ) { - const int size = dma.samples << 1; + const int size = snd.samples << 1; int pos; int wrapped; - if( !dma.buffer ) + if( !snd.buffer ) { memset( stream, 0, len ); return; } - pos = dma.samplepos << 1; + pos = snd.samplepos << 1; if( pos >= size ) - pos = dma.samplepos = 0; + pos = snd.samplepos = 0; wrapped = pos + len - size; if( wrapped < 0 ) { - memcpy( stream, dma.buffer + pos, len ); - dma.samplepos += len >> 1; + memcpy( stream, snd.buffer + pos, len ); + snd.samplepos += len >> 1; } else { int remaining = size - pos; - memcpy( stream, dma.buffer + pos, remaining ); - memcpy( stream + remaining, dma.buffer, wrapped ); - dma.samplepos = wrapped >> 1; + memcpy( stream, snd.buffer + pos, remaining ); + memcpy( stream + remaining, snd.buffer, wrapped ); + snd.samplepos = wrapped >> 1; } - if( dma.samplepos >= size ) - dma.samplepos = 0; + if( snd.samplepos >= size ) + snd.samplepos = 0; } /* @@ -131,20 +131,20 @@ qboolean SNDDMA_Init( void ) goto fail; } - dma.format.speed = obtained.freq; - dma.format.channels = obtained.channels; - dma.format.width = 2; + snd.format.speed = obtained.freq; + snd.format.channels = obtained.channels; + snd.format.width = 2; samplecount = s_samplecount.value; if( !samplecount ) samplecount = 0x8000; - dma.samples = samplecount * obtained.channels; - dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); - dma.samplepos = 0; + snd.samples = samplecount * obtained.channels; + snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 ); + snd.samplepos = 0; Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL" ); - dma.initialized = true; - dma.backendName = sdl_backend_name; + snd.initialized = true; + snd.backend_name = sdl_backend_name; SNDDMA_Activate( true ); @@ -191,7 +191,7 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf( "Shutting down audio.\n" ); - dma.initialized = false; + snd.initialized = false; if( sdl_dev ) { @@ -203,10 +203,10 @@ void SNDDMA_Shutdown( void ) if( SDL_WasInit( SDL_INIT_AUDIO )) SDL_QuitSubSystem( SDL_INIT_AUDIO ); - if( dma.buffer ) + if( snd.buffer ) { - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -220,7 +220,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; SDL_PauseAudioDevice( sdl_dev, !active ); diff --git a/engine/platform/sdl2/s_sdl2.c b/engine/platform/sdl2/s_sdl2.c index 96b19f43..53183bc6 100644 --- a/engine/platform/sdl2/s_sdl2.c +++ b/engine/platform/sdl2/s_sdl2.c @@ -39,32 +39,32 @@ static char sdl_backend_name[32]; static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len ) { - const int size = dma.samples << 1; + const int size = snd.samples << 1; int pos; int wrapped; - pos = dma.samplepos << 1; + pos = snd.samplepos << 1; if( pos >= size ) - pos = dma.samplepos = 0; + pos = snd.samplepos = 0; wrapped = pos + len - size; if( wrapped < 0 ) { - memcpy( stream, dma.buffer + pos, len ); - dma.samplepos += len >> 1; + memcpy( stream, snd.buffer + pos, len ); + snd.samplepos += len >> 1; } else { int remaining = size - pos; - memcpy( stream, dma.buffer + pos, remaining ); - memcpy( stream + remaining, dma.buffer, wrapped ); - dma.samplepos = wrapped >> 1; + memcpy( stream, snd.buffer + pos, remaining ); + memcpy( stream + remaining, snd.buffer, wrapped ); + snd.samplepos = wrapped >> 1; } - if( dma.samplepos >= size ) - dma.samplepos = 0; + if( snd.samplepos >= size ) + snd.samplepos = 0; } /* @@ -148,22 +148,22 @@ qboolean SNDDMA_Init( void ) goto fail; } - dma.format.speed = obtained.freq; - dma.format.channels = obtained.channels; - dma.format.width = 2; + snd.format.speed = obtained.freq; + snd.format.channels = obtained.channels; + snd.format.width = 2; samplecount = s_samplecount.value; if( !samplecount ) samplecount = 0x8000; - dma.samples = samplecount * obtained.channels; - dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 ); - dma.samplepos = 0; + snd.samples = samplecount * obtained.channels; + snd.buffer = Mem_Calloc( sndpool, snd.samples * 2 ); + snd.samplepos = 0; sdl_format = obtained.format; Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq ); Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL (%s)", SDL_GetCurrentAudioDriver( )); - dma.initialized = true; - dma.backendName = sdl_backend_name; + snd.initialized = true; + snd.backend_name = sdl_backend_name; SNDDMA_Activate( true ); @@ -179,7 +179,7 @@ fail: ============== SNDDMA_BeginPainting -Makes sure dma.buffer is valid +Makes sure snd.buffer is valid =============== */ void SNDDMA_BeginPainting( void ) @@ -210,7 +210,7 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf( "Shutting down audio.\n" ); - dma.initialized = false; + snd.initialized = false; if( sdl_dev ) { @@ -221,10 +221,10 @@ void SNDDMA_Shutdown( void ) SDL_QuitSubSystem( SDL_INIT_AUDIO ); - if( dma.buffer ) + if( snd.buffer ) { - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -238,7 +238,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; SDL_PauseAudioDevice( sdl_dev, !active ); diff --git a/engine/platform/sdl3/s_sdl3.c b/engine/platform/sdl3/s_sdl3.c index af001939..458146aa 100644 --- a/engine/platform/sdl3/s_sdl3.c +++ b/engine/platform/sdl3/s_sdl3.c @@ -28,35 +28,35 @@ static char sdl_backend_name[32]; static void SDLash_OutputCallback( void *userdata, SDL_AudioStream *stream, int additional_amount, int len ) { - const int size = dma.samples << 1; + const int size = snd.samples << 1; int pos; int wrapped; (void)userdata; (void)additional_amount; - pos = dma.samplepos << 1; + pos = snd.samplepos << 1; if( pos >= size ) - pos = dma.samplepos = 0; + pos = snd.samplepos = 0; wrapped = pos + len - size; if( wrapped < 0 ) { - SDL_PutAudioStreamData( stream, dma.buffer + pos, len ); - dma.samplepos += len >> 1; + SDL_PutAudioStreamData( stream, snd.buffer + pos, len ); + snd.samplepos += len >> 1; } else { int remaining = size - pos; - SDL_PutAudioStreamData( stream, dma.buffer + pos, remaining ); - SDL_PutAudioStreamData( stream, dma.buffer, wrapped ); - dma.samplepos = wrapped >> 1; + SDL_PutAudioStreamData( stream, snd.buffer + pos, remaining ); + SDL_PutAudioStreamData( stream, snd.buffer, wrapped ); + snd.samplepos = wrapped >> 1; } - if( dma.samplepos >= size ) - dma.samplepos = 0; + if( snd.samplepos >= size ) + snd.samplepos = 0; } /* @@ -122,18 +122,18 @@ qboolean SNDDMA_Init( void ) return false; } - dma.format.speed = SOUND_DMA_SPEED; - dma.format.channels = 2; - dma.format.width = 2; + snd.format.speed = SOUND_DMA_SPEED; + snd.format.channels = 2; + snd.format.width = 2; int samplecount = s_samplecount.value; if( !samplecount ) samplecount = 0x8000; - dma.samples = samplecount * dma.format.channels; - dma.buffer = Mem_Calloc( sndpool, dma.samples * dma.format.width ); - dma.samplepos = 0; - dma.initialized = true; + snd.samples = samplecount * snd.format.channels; + snd.buffer = Mem_Calloc( sndpool, snd.samples * snd.format.width ); + snd.samplepos = 0; + snd.initialized = true; Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL3 (%s)", SDL_GetCurrentAudioDriver( )); - dma.backendName = sdl_backend_name; + snd.backend_name = sdl_backend_name; Con_Printf( "Using audio driver: %s @ %d Hz\n", sdl_backend_name, SOUND_DMA_SPEED ); @@ -178,7 +178,7 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf( "Shutting down audio.\n" ); - dma.initialized = false; + snd.initialized = false; if( out_stream ) { @@ -189,10 +189,10 @@ void SNDDMA_Shutdown( void ) SDL_QuitSubSystem( SDL_INIT_AUDIO ); - if( dma.buffer ) + if( snd.buffer ) { - Mem_Free( dma.buffer ); - dma.buffer = NULL; + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } @@ -206,7 +206,7 @@ between a deactivate and an activate. */ void SNDDMA_Activate( qboolean active ) { - if( !dma.initialized ) + if( !snd.initialized ) return; if( active ) diff --git a/engine/platform/stub/s_stub.c b/engine/platform/stub/s_stub.c index 6bd96966..bb89ecfa 100644 --- a/engine/platform/stub/s_stub.c +++ b/engine/platform/stub/s_stub.c @@ -30,8 +30,6 @@ so it can unlock and free the data block after it has been played. ======================================================================= */ -dma_t dma; - void S_Activate( qboolean active ) { } @@ -86,11 +84,12 @@ Reset the sound device for exiting void SNDDMA_Shutdown( void ) { Con_Printf("Shutting down audio.\n"); - dma.initialized = false; + snd.initialized = false; - if (dma.buffer) { - Z_Free(dma.buffer); - dma.buffer = NULL; + if( snd.buffer ) + { + Mem_Free( snd.buffer ); + snd.buffer = NULL; } } diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index c8f8397e..b2e984e4 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -1518,7 +1518,6 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec float front, back, frac; int i, side; vec3_t mid; - mnode_t *children[2]; int numsurfaces, firstsurface; // didn't hit anything @@ -1529,18 +1528,16 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec front = PlaneDiff( start, node->plane ); back = PlaneDiff( end, node->plane ); - node_children( children, node, model ); - side = front < 0.0f; if(( back < 0.0f ) == side ) - return SV_RecursiveLightPoint( model, children[side], start, end, point_color ); + return SV_RecursiveLightPoint( model, node_child( node, side, model ), start, end, point_color ); frac = front / ( front - back ); VectorLerp( start, frac, end, mid ); // co down front side - if( SV_RecursiveLightPoint( model, children[side], start, mid, point_color )) + if( SV_RecursiveLightPoint( model, node_child( node, side, model ), start, mid, point_color )) return true; // hit something if(( back < 0.0f ) == side ) @@ -1602,7 +1599,7 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec } // go down back side - return SV_RecursiveLightPoint( model, children[!side], mid, end, point_color ); + return SV_RecursiveLightPoint( model, node_child( node, !side, model ), mid, end, point_color ); } /* diff --git a/filesystem/filesystem.c b/filesystem/filesystem.c index db02770b..e69265b9 100644 --- a/filesystem/filesystem.c +++ b/filesystem/filesystem.c @@ -747,6 +747,7 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir, qboolean if( quake ) { Q_strncpy( GameInfo->basedir, "id1", sizeof( GameInfo->basedir )); + Q_strncpy( GameInfo->falldir, "qwrap", sizeof( GameInfo->falldir )); Q_strncpy( GameInfo->title, gamedir, sizeof( GameInfo->title )); Q_strncpy( GameInfo->startmap, "start", sizeof( GameInfo->startmap )); Q_strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path )); @@ -1123,27 +1124,28 @@ static qboolean FS_CheckForQuakeGameDir( const char *gamedir ) { // if directory contain quake.rc or progs.dat it's 100% quake gamedir // quake mods probably always archived, so check pak0.pak too - const char *files[] = { "progs.dat", "quake.rc" }; - char buf[MAX_SYSPATH]; + const char *files[] = { "pak0.pak", "PAK0.PAK", "progs.dat", "quake.rc" }; int i; - // try to read pak0.pak first, most quake mods are archived - if( Q_snprintf( buf, sizeof( buf ), "%s/pak0.pak", gamedir ) > 0 ) - { - if( FS_SysFileExists( buf )) - { - if( FS_CheckForQuakePak( buf, files, sizeof( files ) / sizeof( files[0] ))) - return true; - } - } - // search it in the filesystem for( i = 0; i < sizeof( files ) / sizeof( files[0] ); i++ ) { + char buf[MAX_SYSPATH]; + if( Q_snprintf( buf, sizeof( buf ), "%s/%s", gamedir, files[i] ) > 0 ) { - if( FS_SysFileExists( buf )) + if( !FS_SysFileExists( buf )) + continue; + + if( !Q_stricmp( COM_FileExtension( buf ), "pak" )) + { + if( FS_CheckForQuakePak( buf, &files[2], sizeof( files ) / sizeof( files[0] ) - 2 )) + return true; + } + else + { return true; + } } } diff --git a/ref/gl/gl_alias.c b/ref/gl/gl_alias.c index c2ae9e6a..715d92fc 100644 --- a/ref/gl/gl_alias.c +++ b/ref/gl/gl_alias.c @@ -337,7 +337,6 @@ Mod_CreateSkinData static rgbdata_t *Mod_CreateSkinData( model_t *mod, const byte *data, int width, int height ) { static rgbdata_t skin; - char name[MAX_QPATH]; int i; skin.width = width; @@ -363,10 +362,8 @@ static rgbdata_t *Mod_CreateSkinData( model_t *mod, const byte *data, int width, } } - COM_FileBase( mod->name, name, sizeof( name )); - // for alias models only player can have remap textures - if( mod != NULL && !Q_stricmp( name, "player" )) + if( mod != NULL && !Q_stricmp( mod->name, "player" )) { texture_t *tx = NULL; int i, size; diff --git a/ref/gl/gl_cull.c b/ref/gl/gl_cull.c index 27f394a4..9316207e 100644 --- a/ref/gl/gl_cull.c +++ b/ref/gl/gl_cull.c @@ -67,20 +67,20 @@ int R_CullSurface( const msurface_t *surf, const gl_frustum_t *frustum, uint cli { cl_entity_t *e = RI.currententity; - if( !e || !surf || !surf->texinfo || !surf->texinfo->texture ) - return CULL_OTHER; - - if( r_nocull.value ) - return CULL_VISIBLE; - - // world surfaces can be culled by vis frame too - if( e == CL_GetEntityByIndex( 0 ) && surf->visframe != tr.framecount ) + if( surf->visframe != tr.framecount && e == CL_GetEntityByIndex( 0 )) return CULL_VISFRAME; - // only static ents can be culled by frustum - if( !R_StaticEntity( e )) frustum = NULL; + if( unlikely( !surf->texinfo || !surf->texinfo->texture )) + return CULL_OTHER; - if( !VectorIsNull( surf->plane->normal )) + if( unlikely( r_nocull.value )) + return CULL_VISIBLE; + + // only static ents can be culled by frustum + if( !R_StaticEntity( e )) + frustum = NULL; + + if( glState.faceCull != GL_NONE && !VectorIsNull( surf->plane->normal )) { float dist; @@ -95,35 +95,22 @@ int R_CullSurface( const msurface_t *surf, const gl_frustum_t *frustum, uint cli } else dist = PlaneDiff( tr.modelorg, surf->plane ); + if( FBitSet( surf->flags, SURF_PLANEBACK )) + dist = -dist; + if( glState.faceCull == GL_FRONT ) { - if( FBitSet( surf->flags, SURF_PLANEBACK )) - { - if( dist >= -BACKFACE_EPSILON ) - return CULL_BACKSIDE; // wrong side - } - else - { - if( dist <= BACKFACE_EPSILON ) - return CULL_BACKSIDE; // wrong side - } + if( dist <= BACKFACE_EPSILON ) + return CULL_BACKSIDE; } - else if( glState.faceCull == GL_BACK ) + else // if( glState.faceCull == GL_BACK ) { - if( FBitSet( surf->flags, SURF_PLANEBACK )) - { - if( dist <= BACKFACE_EPSILON ) - return CULL_BACKSIDE; // wrong side - } - else - { - if( dist >= -BACKFACE_EPSILON ) - return CULL_BACKSIDE; // wrong side - } + if( dist >= -BACKFACE_EPSILON ) + return CULL_BACKSIDE; } } - if( frustum && GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags )) + if( frustum && clipflags && GL_FrustumCullBox( frustum, surf->info->mins, surf->info->maxs, clipflags )) return CULL_FRUSTUM; return CULL_VISIBLE; diff --git a/ref/gl/gl_decals.c b/ref/gl/gl_decals.c index 207ff57f..c56d7895 100644 --- a/ref/gl/gl_decals.c +++ b/ref/gl/gl_decals.c @@ -697,11 +697,8 @@ static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *dec //----------------------------------------------------------------------------- static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) { - mplane_t *splitplane; - float dist; - mnode_t *children[2]; - - Assert( node != NULL ); + mplane_t *splitplane; + float dist; if( node->contents < 0 ) { @@ -711,31 +708,22 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) splitplane = node->plane; dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist; - node_children( children, node, model ); - // This is arbitrarily set to 10 right now. In an ideal world we'd have the - // exact surface but we don't so, this tells me which planes are "sort of - // close" to the gunshot -- the gunshot is actually 4 units in front of the - // wall (see dlls\weapons.cpp). We also need to check to see if the decal - // actually intersects the texture space of the surface, as this method tags - // parallel surfaces in the same node always. - // JAY: This still tags faces that aren't correct at edges because we don't - // have a surface normal if( dist > decalinfo->m_Size ) { - R_DecalNode( model, children[0], decalinfo ); + R_DecalNode( model, node_child( node, 0, model ), decalinfo ); } else if( dist < -decalinfo->m_Size ) { - R_DecalNode( model, children[1], decalinfo ); + R_DecalNode( model, node_child( node, 1, model ), decalinfo ); } else { if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE ) R_DecalNodeSurfaces( model, node, decalinfo ); - R_DecalNode( model, children[0], decalinfo ); - R_DecalNode( model, children[1], decalinfo ); + R_DecalNode( model, node_child( node, 0, model ), decalinfo ); + R_DecalNode( model, node_child( node, 1, model ), decalinfo ); } } diff --git a/ref/gl/gl_frustum.c b/ref/gl/gl_frustum.c index 0e4b2103..e3aa897e 100644 --- a/ref/gl/gl_frustum.c +++ b/ref/gl/gl_frustum.c @@ -99,15 +99,14 @@ void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yT // cull methods qboolean GL_FrustumCullBox( const gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags ) { - int iClipFlags; + int iClipFlags = userClipFlags != 0 ? userClipFlags : out->clipFlags; int i, bit; - if( r_nocull.value ) + if( unlikely( r_nocull.value )) return false; - if( userClipFlags != 0 ) - iClipFlags = userClipFlags; - else iClipFlags = out->clipFlags; + if( !iClipFlags ) + return false; for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 ) { @@ -160,15 +159,14 @@ qboolean GL_FrustumCullBox( const gl_frustum_t *out, const vec3_t mins, const ve qboolean GL_FrustumCullSphere( const gl_frustum_t *out, const vec3_t center, float radius, int userClipFlags ) { - int iClipFlags; + int iClipFlags = userClipFlags != 0 ? userClipFlags : out->clipFlags; int i, bit; - if( r_nocull.value ) + if( unlikely( r_nocull.value )) return false; - if( userClipFlags != 0 ) - iClipFlags = userClipFlags; - else iClipFlags = out->clipFlags; + if( !iClipFlags ) + return false; for( i = FRUSTUM_PLANES, bit = 1; i > 0; i--, bit <<= 1 ) { diff --git a/ref/gl/gl_image.c b/ref/gl/gl_image.c index 9e9bd39e..8f1006da 100644 --- a/ref/gl/gl_image.c +++ b/ref/gl/gl_image.c @@ -46,7 +46,12 @@ acess to array elem */ gl_texture_t *R_GetTexture( unsigned int texnum ) { - Assert( texnum < MAX_TEXTURES ); + if( texnum >= MAX_TEXTURES ) + { + gEngfuncs.Host_Error( "%s: texnum (%d) >= MAX_TEXTURES (%d)", __func__, texnum, MAX_TEXTURES ); + texnum = 0; + } + return &gl_textures[texnum]; } diff --git a/ref/gl/gl_local.h b/ref/gl/gl_local.h index 103083f3..2fe96015 100644 --- a/ref/gl/gl_local.h +++ b/ref/gl/gl_local.h @@ -249,6 +249,7 @@ typedef struct vec3_t modelorg; // relative to viewpoint // get from engine + model_t *worldmodel; world_static_t *world; cl_entity_t *entities; movevars_t *movevars; @@ -770,7 +771,7 @@ static inline int GL_MaxTextureUnits( void ) return Q_min( glConfig.max_texture_units, MAX_TEXTURE_UNITS ); } -#define WORLDMODEL (gp_cl->models[1]) +#define WORLDMODEL (tr.worldmodel) // // renderer cvars diff --git a/ref/gl/gl_rlight.c b/ref/gl/gl_rlight.c index d776f783..e63adaac 100644 --- a/ref/gl/gl_rlight.c +++ b/ref/gl/gl_rlight.c @@ -105,7 +105,6 @@ void R_MarkLights( const dlight_t *light, int bit, const mnode_t *node ) const float maxdist = light->radius * light->radius; float dist; int i; - mnode_t *children[2]; int firstsurface, numsurfaces; start: @@ -115,25 +114,25 @@ start: dist = PlaneDiff( light->origin, node->plane ); - node_children( children, node, RI.currentmodel ); - if( dist > virtual_radius ) { - node = children[0]; + node = node_child( node, 0, RI.currentmodel ); goto start; } if( dist < -virtual_radius ) { - node = children[1]; + node = node_child( node, 1, RI.currentmodel ); goto start; } + const float dist_sq = dist * dist; + // mark the polygons firstsurface = node_firstsurface( node, RI.currentmodel ); numsurfaces = node_numsurfaces( node, RI.currentmodel ); - for( i = 0; i < numsurfaces; i++ ) + for( i = 0; i < numsurfaces && dist_sq < maxdist; i++ ) { vec3_t impact; float s, t, l; @@ -160,7 +159,7 @@ start: t = bound( 0, t, info->lightextents[1] ); t = l - t; - if( s * s + t * t + dist * dist >= maxdist ) + if( s * s + t * t + dist_sq >= maxdist ) continue; if( surf->dlightframe != tr.dlightframecount ) @@ -171,8 +170,8 @@ start: else surf->dlightbits |= bit; } - R_MarkLights( light, bit, children[0] ); - R_MarkLights( light, bit, children[1] ); + R_MarkLights( light, bit, node_child( node, 0, RI.currentmodel )); + R_MarkLights( light, bit, node_child( node, 1, RI.currentmodel )); } /* @@ -236,7 +235,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, mtexinfo_t *tex; matrix3x4 tbn; vec3_t mid; - mnode_t *children[2]; int firstsurface, numsurfaces; // didn't hit anything @@ -246,7 +244,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, return false; } - node_children( children, node, model ); firstsurface = node_firstsurface( node, model ); numsurfaces = node_numsurfaces( node, model ); @@ -256,7 +253,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, side = front < 0; if(( back < 0 ) == side ) - return R_RecursiveLightPoint( model, children[side], p1f, p2f, cv, start, end ); + return R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, p2f, cv, start, end ); frac = front / ( front - back ); @@ -264,7 +261,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, midf = p1f + ( p2f - p1f ) * frac; // co down front side - if( R_RecursiveLightPoint( model, children[side], p1f, midf, cv, start, mid )) + if( R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, midf, cv, start, mid )) return true; // hit something if(( back < 0 ) == side ) @@ -366,7 +363,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, } // go down back side - return R_RecursiveLightPoint( model, children[!side], midf, p2f, cv, mid, end ); + return R_RecursiveLightPoint( model, node_child( node, !side, model ), midf, p2f, cv, mid, end ); } /* diff --git a/ref/gl/gl_rmain.c b/ref/gl/gl_rmain.c index 45c7a812..43373c2c 100644 --- a/ref/gl/gl_rmain.c +++ b/ref/gl/gl_rmain.c @@ -617,7 +617,6 @@ watertexture to grab fog values from it static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down ) { gl_texture_t *tex = NULL; - mnode_t *children[2]; // assure the initial node is not null // we could check it here, but we would rather check it @@ -655,18 +654,20 @@ static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mno // this is a regular node // traverse children - node_children( children, node, WORLDMODEL ); + mnode_t *child = node_child( node, 0, WORLDMODEL ); - if( children[0] && ( children[0] != ignore )) + if( child && ( child != ignore )) { - tex = R_RecursiveFindWaterTexture( children[0], node, true ); + tex = R_RecursiveFindWaterTexture( child, node, true ); if( tex ) return tex; } - if( children[1] && ( children[1] != ignore )) + child = node_child( node, 1, WORLDMODEL ); + + if( child && ( child != ignore )) { - tex = R_RecursiveFindWaterTexture( children[1], node, true ); - if( tex ) return tex; + tex = R_RecursiveFindWaterTexture( child, node, true ); + if( tex ) return tex; } // for down recursion, return immediately diff --git a/ref/gl/gl_rmisc.c b/ref/gl/gl_rmisc.c index c5985c0d..6b43c185 100644 --- a/ref/gl/gl_rmisc.c +++ b/ref/gl/gl_rmisc.c @@ -108,6 +108,8 @@ void R_NewMap( void ) texture_t *tx; int i; + tr.worldmodel = gp_cl->models[1]; + R_ClearDecals(); // clear all level decals R_StudioResetPlayerModels(); diff --git a/ref/gl/gl_rsurf.c b/ref/gl/gl_rsurf.c index bfa923c6..e16a0abb 100644 --- a/ref/gl/gl_rsurf.c +++ b/ref/gl/gl_rsurf.c @@ -20,6 +20,7 @@ GNU General Public License for more details. typedef struct { int allocated[BLOCK_SIZE_MAX]; + int max_height; // maximum height currently in use in the block int current_lightmap_texture; msurface_t *dynamic_surfaces; msurface_t *lightmap_surfaces[MAX_LIGHTMAPS]; @@ -653,6 +654,7 @@ static void R_SetCacheState( msurface_t *surf ) static void LM_InitBlock( void ) { memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated )); + gl_lms.max_height = 0; } static int LM_AllocBlock( int w, int h, int *x, int *y ) @@ -662,7 +664,7 @@ static int LM_AllocBlock( int w, int h, int *x, int *y ) best = BLOCK_SIZE; - for( i = 0; i < BLOCK_SIZE - w; i++ ) + for( i = 0; i < BLOCK_SIZE - w; ) { best2 = 0; @@ -679,6 +681,14 @@ static int LM_AllocBlock( int w, int h, int *x, int *y ) // this is a valid spot *x = i; *y = best = best2; + if( best == 0 ) + break; // height 0 is optimal, can't do better + i++; + } + else + { + // allocated[i+j] was too tall — no position in [i, i+j] can work + i += j + 1; } } @@ -688,20 +698,15 @@ static int LM_AllocBlock( int w, int h, int *x, int *y ) for( i = 0; i < w; i++ ) gl_lms.allocated[*x + i] = best + h; + if( best + h > gl_lms.max_height ) + gl_lms.max_height = best + h; + return true; } static void LM_UploadDynamicBlock( void ) { - int height = 0, i; - - for( i = 0; i < BLOCK_SIZE; i++ ) - { - if( gl_lms.allocated[i] > height ) - height = gl_lms.allocated[i]; - } - - pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, BLOCK_SIZE, height, GL_RGBA, GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer ); + pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, BLOCK_SIZE, gl_lms.max_height, GL_RGBA, GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer ); } static void LM_UploadBlock( qboolean dynamic ) @@ -1290,70 +1295,59 @@ static void R_RenderDecalsForSurface( msurface_t *fa, int cull_type ) static qboolean R_CheckLightMap( msurface_t *fa ) { - qboolean is_dynamic = false; int maps; - // check for lightmap modification + if( unlikely( !r_dynamic->value )) + return false; + + if( fa->dlightframe == tr.framecount ) + return true; // dlighted surfaces are always dynamic + + // check for light styles for( maps = 0; maps < MAXLIGHTMAPS && fa->styles[maps] != 255; maps++ ) { - if( tr.lightstylevalue[fa->styles[maps]] != fa->cached_light[maps] ) - goto dynamic; - } + if( tr.lightstylevalue[fa->styles[maps]] == fa->cached_light[maps] ) + continue; - // dynamic this frame or dynamic previously - if( fa->dlightframe == tr.framecount ) - { -dynamic: - // NOTE: at this point we have only valid textures - if( r_dynamic->value ) - is_dynamic = true; - } - - if( is_dynamic ) - { const int style = fa->styles[maps]; - if( maps < MAXLIGHTMAPS && ( style >= 32 || style == 0 || style == 20 ) && fa->dlightframe != tr.framecount ) - { - byte temp[132*132*4]; - mextrasurf_t *info = fa->info; - int sample_size; - int smax, tmax; + // flickering light styles can go to dynamic chain + if( !( style >= 32 || style == 0 || style == 20 )) + return true; - sample_size = gEngfuncs.Mod_SampleSizeForFace( fa ); - smax = ( info->lightextents[0] / sample_size ) + 1; - tmax = ( info->lightextents[1] / sample_size ) + 1; + byte temp[132*132*4]; + mextrasurf_t *info = fa->info; + int sample_size = gEngfuncs.Mod_SampleSizeForFace( fa ); + int smax = ( info->lightextents[0] / sample_size ) + 1; + int tmax = ( info->lightextents[1] / sample_size ) + 1; - if( smax < 132 && tmax < 132 ) - R_BuildLightMap( fa, temp, smax * 4, true ); - else - { - smax = Q_min( smax, 132 ); - tmax = Q_min( tmax, 132 ); - memset( temp, 255, sizeof( temp )); - //Host_MapDesignError( "%s: bad surface extents: %d %d", __func__, fa->extents[0], fa->extents[1] ); - } - - R_SetCacheState( fa ); - -#if XASH_WES - GL_Bind( XASH_TEXTURE1, tr.lightmapTextures[fa->lightmaptexturenum] ); - pglTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE ); -#else - GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] ); -#endif - - pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, temp ); - -#if XASH_WES - GL_SelectTexture( XASH_TEXTURE0 ); -#endif - } + if( smax < 132 && tmax < 132 ) + R_BuildLightMap( fa, temp, smax * 4, true ); else - return true; // add to dynamic chain + { + smax = Q_min( smax, 132 ); + tmax = Q_min( tmax, 132 ); + memset( temp, 255, sizeof( temp )); + //Host_MapDesignError( "%s: bad surface extents: %d %d", __func__, fa->extents[0], fa->extents[1] ); + } + + R_SetCacheState( fa ); + +#if XASH_WES + GL_Bind( XASH_TEXTURE1, tr.lightmapTextures[fa->lightmaptexturenum] ); + pglTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE ); +#else + GL_Bind( XASH_TEXTURE0, tr.lightmapTextures[fa->lightmaptexturenum] ); +#endif + pglTexSubImage2D( GL_TEXTURE_2D, 0, fa->light_s, fa->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, temp ); + +#if XASH_WES + GL_SelectTexture( XASH_TEXTURE0 ); +#endif + return false; } - return false; // updated + return false; // no change } static void R_RenderLightmapForSurface( msurface_t *fa ) @@ -2091,7 +2085,7 @@ void R_GenerateVBO( void ) if( surf->lightmaptexturenum != k ) continue; - if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) ) + if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_TRANSPARENT ) ) continue; if( R_TextureAnimation( surf ) != world->textures[j] ) @@ -2162,7 +2156,7 @@ void R_GenerateVBO( void ) if( surf->lightmaptexturenum != k ) continue; - if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) ) + if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_TRANSPARENT ) ) continue; if( R_TextureAnimation( surf ) != world->textures[j] ) @@ -3403,14 +3397,6 @@ R_RecursiveWorldNode */ static void R_RecursiveWorldNode( mnode_t *node, uint clipflags ) { - int i, clipped; - msurface_t *surf, **mark; - mleaf_t *pleaf; - int c, side; - float dot; - mnode_t *children[2]; - int numsurfaces, firstsurface; - loc0: if( node->contents == CONTENTS_SOLID ) return; // hit a solid leaf @@ -3420,14 +3406,14 @@ loc0: if( clipflags && !r_nocull.value ) { - for( i = 0; i < 6; i++ ) + for( int i = 0; i < 6; i++ ) { const mplane_t *p = &RI.frustum.planes[i]; if( !FBitSet( clipflags, BIT( i ))) continue; - clipped = BOX_ON_PLANE_SIDE( node->minmaxs, node->minmaxs + 3, p ); + int clipped = BOX_ON_PLANE_SIDE( node->minmaxs, node->minmaxs + 3, p ); if( clipped == 2 ) return; if( clipped == 1 ) ClearBits( clipflags, BIT( i )); } @@ -3436,19 +3422,11 @@ loc0: // if a leaf node, draw stuff if( node->contents < 0 ) { - pleaf = (mleaf_t *)node; + mleaf_t *pleaf = (mleaf_t *)node; + msurface_t **mark = pleaf->firstmarksurface; - mark = pleaf->firstmarksurface; - c = pleaf->nummarksurfaces; - - if( c ) - { - do - { - (*mark)->visframe = tr.framecount; - mark++; - } while( --c ); - } + for( int i = 0; i < pleaf->nummarksurfaces; i++ ) + mark[i]->visframe = tr.framecount; // deal with model fragments in this leaf if( pleaf->efrags ) @@ -3461,19 +3439,20 @@ loc0: // node is just a decision point, so go down the apropriate sides // find which side of the node we are on - dot = PlaneDiff( tr.modelorg, node->plane ); - side = (dot >= 0.0f) ? 0 : 1; + float dot = PlaneDiff( tr.modelorg, node->plane ); + int side = (dot >= 0.0f) ? 0 : 1; // recurse down the children, front side first - node_children( children, node, WORLDMODEL ); - R_RecursiveWorldNode( children[side], clipflags ); + R_RecursiveWorldNode( node_child( node, side, WORLDMODEL ), clipflags ); - firstsurface = node_firstsurface( node, WORLDMODEL ); - numsurfaces = node_numsurfaces( node, WORLDMODEL ); + int firstsurface = node_firstsurface( node, WORLDMODEL ); + int numsurfaces = node_numsurfaces( node, WORLDMODEL ); // draw stuff - for( c = numsurfaces, surf = WORLDMODEL->surfaces + firstsurface; c; c--, surf++ ) + for( int i = firstsurface; i < firstsurface + numsurfaces; i++ ) { + msurface_t *surf = &WORLDMODEL->surfaces[i]; + if( R_CullSurface( surf, &RI.frustum, clipflags )) continue; @@ -3491,7 +3470,7 @@ loc0: } // recurse down the back side - node = children[!side]; + node = node_child( node, !side, WORLDMODEL ); goto loc0; } @@ -3567,7 +3546,6 @@ static void R_DrawWorldTopView( mnode_t *node, uint clipflags ) do { - mnode_t *children[2]; int numsurfaces, firstsurface; if( node->contents == CONTENTS_SOLID ) @@ -3625,9 +3603,8 @@ static void R_DrawWorldTopView( mnode_t *node, uint clipflags ) } // recurse down both children, we don't care the order... - node_children( children, node, WORLDMODEL ); - R_DrawWorldTopView( children[0], clipflags ); - node = children[1]; + R_DrawWorldTopView( node_child( node, 0, WORLDMODEL ), clipflags ); + node = node_child( node, 1, WORLDMODEL ); } while( node ); } diff --git a/ref/soft/r_bsp.c b/ref/soft/r_bsp.c index e1f238d5..4678a20d 100644 --- a/ref/soft/r_bsp.c +++ b/ref/soft/r_bsp.c @@ -559,7 +559,6 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags ) } else { - mnode_t *children[2]; int firstsurface; // node is just a decision point, so go down the apropriate sides @@ -589,8 +588,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags ) side = 1; // recurse down the children, front side first - node_children( children, node, WORLDMODEL ); - R_RecursiveWorldNode( children[side], clipflags ); + R_RecursiveWorldNode( node_child( node, side, WORLDMODEL ), clipflags ); // draw stuff c = node_numsurfaces( node, WORLDMODEL ); @@ -634,7 +632,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int clipflags ) } // recurse down the back side - R_RecursiveWorldNode( children[!side], clipflags ); + R_RecursiveWorldNode( node_child( node, !side, WORLDMODEL ), clipflags ); } } diff --git a/ref/soft/r_decals.c b/ref/soft/r_decals.c index 302bc535..6333d1b6 100644 --- a/ref/soft/r_decals.c +++ b/ref/soft/r_decals.c @@ -705,10 +705,7 @@ static void R_DecalNodeSurfaces( model_t *model, mnode_t *node, decalinfo_t *dec static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) { mplane_t *splitplane; - float dist; - mnode_t *children[2]; - - Assert( node != NULL ); + float dist; if( node->contents < 0 ) { @@ -718,31 +715,22 @@ static void R_DecalNode( model_t *model, mnode_t *node, decalinfo_t *decalinfo ) splitplane = node->plane; dist = DotProduct( decalinfo->m_Position, splitplane->normal ) - splitplane->dist; - node_children( children, node, model ); - // This is arbitrarily set to 10 right now. In an ideal world we'd have the - // exact surface but we don't so, this tells me which planes are "sort of - // close" to the gunshot -- the gunshot is actually 4 units in front of the - // wall (see dlls\weapons.cpp). We also need to check to see if the decal - // actually intersects the texture space of the surface, as this method tags - // parallel surfaces in the same node always. - // JAY: This still tags faces that aren't correct at edges because we don't - // have a surface normal if( dist > decalinfo->m_Size ) { - R_DecalNode( model, children[0], decalinfo ); + R_DecalNode( model, node_child( node, 0, model ), decalinfo ); } else if( dist < -decalinfo->m_Size ) { - R_DecalNode( model, children[1], decalinfo ); + R_DecalNode( model, node_child( node, 1, model ), decalinfo ); } else { if( dist < DECAL_DISTANCE && dist > -DECAL_DISTANCE ) R_DecalNodeSurfaces( model, node, decalinfo ); - R_DecalNode( model, children[0], decalinfo ); - R_DecalNode( model, children[1], decalinfo ); + R_DecalNode( model, node_child( node, 0, model ), decalinfo ); + R_DecalNode( model, node_child( node, 1, model ), decalinfo ); } } diff --git a/ref/soft/r_light.c b/ref/soft/r_light.c index 1b4b936e..81acf1bc 100644 --- a/ref/soft/r_light.c +++ b/ref/soft/r_light.c @@ -107,7 +107,6 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node ) float dist; msurface_t *surf; int i; - mnode_t *children[2]; int firstsurface, numsurfaces; if( !node || node->contents < 0 ) @@ -115,18 +114,17 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node ) dist = PlaneDiff( light->origin, node->plane ); - node_children( children, node, RI.currentmodel ); firstsurface = node_firstsurface( node, RI.currentmodel ); numsurfaces = node_numsurfaces( node, RI.currentmodel ); if( dist > light->radius ) { - R_MarkLights( light, bit, children[0] ); + R_MarkLights( light, bit, node_child( node, 0, RI.currentmodel )); return; } if( dist < -light->radius ) { - R_MarkLights( light, bit, children[1] ); + R_MarkLights( light, bit, node_child( node, 1, RI.currentmodel )); return; } @@ -146,8 +144,8 @@ void R_MarkLights( dlight_t *light, int bit, mnode_t *node ) surf->dlightbits |= bit; } - R_MarkLights( light, bit, children[0] ); - R_MarkLights( light, bit, children[1] ); + R_MarkLights( light, bit, node_child( node, 0, RI.currentmodel )); + R_MarkLights( light, bit, node_child( node, 1, RI.currentmodel )); } /* @@ -207,7 +205,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, msurface_t *surf; matrix3x4 tbn; vec3_t mid; - mnode_t *children[2]; int firstsurface, numsurfaces; // didn't hit anything @@ -217,7 +214,6 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, return false; } - node_children( children, node, model ); firstsurface = node_firstsurface( node, model ); numsurfaces = node_numsurfaces( node, model ); @@ -227,7 +223,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, side = front < 0; if(( back < 0 ) == side ) - return R_RecursiveLightPoint( model, children[side], p1f, p2f, cv, start, end ); + return R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, p2f, cv, start, end ); frac = front / ( front - back ); @@ -235,7 +231,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, midf = p1f + ( p2f - p1f ) * frac; // co down front side - if( R_RecursiveLightPoint( model, children[side], p1f, midf, cv, start, mid )) + if( R_RecursiveLightPoint( model, node_child( node, side, model ), p1f, midf, cv, start, mid )) return true; // hit something if(( back < 0 ) == side ) @@ -337,7 +333,7 @@ static qboolean R_RecursiveLightPoint( model_t *model, mnode_t *node, float p1f, } // go down back side - return R_RecursiveLightPoint( model, children[!side], midf, p2f, cv, mid, end ); + return R_RecursiveLightPoint( model, node_child( node, !side, model ), midf, p2f, cv, mid, end ); } /* diff --git a/scripts/ios/buildhlsdk.sh b/scripts/ios/buildhlsdk.sh index 7bb6a7e2..015109ee 100755 --- a/scripts/ios/buildhlsdk.sh +++ b/scripts/ios/buildhlsdk.sh @@ -12,7 +12,7 @@ else git clone --recursive https://github.com/FWGS/hlsdk-portable -b "$1" "$MODPATH" fi -mkdir ../../build/ios || exit 1 +mkdir -p ../../build/ios || exit 1 IOSDIR=$(realpath ../../build/ios) cd "$MODPATH" || exit 1 diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py index 62a4c057..f00f9237 100644 --- a/scripts/waifulib/xcompile.py +++ b/scripts/waifulib/xcompile.py @@ -20,7 +20,7 @@ import os import sys ANDROID_NDK_ENVVARS = ['ANDROID_NDK_HOME', 'ANDROID_NDK'] -ANDROID_NDK_SUPPORTED = [10, 19, 20, 23, 25, 27, 28, 29] +ANDROID_NDK_SUPPORTED = [10, 19, 20, 23, 25, 27, 28, 29, 30] ANDROID_NDK_HARDFP_MAX = 11 # latest version that supports hardfp ANDROID_NDK_GCC_MAX = 17 # latest NDK that ships with GCC ANDROID_NDK_UNIFIED_SYSROOT_MIN = 15 @@ -35,6 +35,7 @@ ANDROID_NDK_API_MIN = { 27: 19, 28: 21, 29: 21, + 30: 21, } # minimal API level ndk revision supports ANDROID_STPCPY_API_MIN = 21 # stpcpy() introduced in SDK 21