From c83c4192ea59068c95fc0f6f804c41a821551aed Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Mon, 31 Oct 2022 03:16:16 +0100 Subject: [PATCH 01/17] StartSoundShader() event: special-case for soundName "", refs #494 Some level scripts in d3xp (erebus4, erebus4, phobos2) use $entity.startSoundShader( "", SND_CHANNEL_BODY ); (or whatever channel) to stop the sound currently playing there. With s_playDefaultSound 1 that results in a beep.. Added a special case to that event implementation to call StopSound() instead when the soundName is "" (or NULL) --- d3xp/Entity.cpp | 8 ++++++++ game/Entity.cpp | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/d3xp/Entity.cpp b/d3xp/Entity.cpp index ec636a6..c641fde 100644 --- a/d3xp/Entity.cpp +++ b/d3xp/Entity.cpp @@ -4171,6 +4171,14 @@ idEntity::Event_StartSoundShader ================ */ void idEntity::Event_StartSoundShader( const char *soundName, int channel ) { + // DG: at least some map scripts in d3xp seem to use $ent.startSoundShader( "", SND_CHANNEL_whatever ); + // to stop a playing sound. special-casing this to avoid playing beep sound (if s_playDefaultSound 1) + if ( soundName == NULL || soundName[0] == '\0' ) { + StopSound( (s_channelType)channel, false ); + idThread::ReturnFloat( 0.0f ); + return; + } + int length; StartSoundShader( declManager->FindSound( soundName ), (s_channelType)channel, 0, false, &length ); diff --git a/game/Entity.cpp b/game/Entity.cpp index 8ae5f13..1983a4c 100644 --- a/game/Entity.cpp +++ b/game/Entity.cpp @@ -4062,6 +4062,14 @@ idEntity::Event_StartSoundShader ================ */ void idEntity::Event_StartSoundShader( const char *soundName, int channel ) { + // DG: at least some map scripts in d3xp seem to use $ent.startSoundShader( "", SND_CHANNEL_whatever ); + // to stop a playing sound. special-casing this to avoid playing beep sound (if s_playDefaultSound 1) + if ( soundName == NULL || soundName[0] == '\0' ) { + StopSound( (s_channelType)channel, false ); + idThread::ReturnFloat( 0.0f ); + return; + } + int length; StartSoundShader( declManager->FindSound( soundName ), (s_channelType)channel, 0, false, &length ); From e5c23adf73c28f86400729ddf90d01886ded3780 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 22 Jun 2021 22:39:02 +0200 Subject: [PATCH 02/17] Fix some ubsan warnings --- d3xp/SmokeParticles.cpp | 2 +- game/SmokeParticles.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/d3xp/SmokeParticles.cpp b/d3xp/SmokeParticles.cpp index 710baec..4c63357 100644 --- a/d3xp/SmokeParticles.cpp +++ b/d3xp/SmokeParticles.cpp @@ -222,7 +222,7 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS int finalParticleTime = stage->cycleMsec * stage->spawnBunching; int deltaMsec = gameLocal.time - systemStartTime; - int nowCount, prevCount; + int nowCount=0, prevCount=0; if ( finalParticleTime == 0 ) { // if spawnBunching is 0, they will all come out at once if ( gameLocal.time == systemStartTime ) { diff --git a/game/SmokeParticles.cpp b/game/SmokeParticles.cpp index e63307d..b0867a7 100644 --- a/game/SmokeParticles.cpp +++ b/game/SmokeParticles.cpp @@ -207,7 +207,7 @@ bool idSmokeParticles::EmitSmoke( const idDeclParticle *smoke, const int systemS int finalParticleTime = stage->cycleMsec * stage->spawnBunching; int deltaMsec = gameLocal.time - systemStartTime; - int nowCount, prevCount; + int nowCount=0, prevCount=0; if ( finalParticleTime == 0 ) { // if spawnBunching is 0, they will all come out at once if ( gameLocal.time == systemStartTime ) { From 0bfc51f55e030d355225265f80e60c0a0bba2733 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 6 Nov 2022 18:12:54 +0100 Subject: [PATCH 03/17] Fix renderlights loaded from savegames aliasing other lights Some entities wrote the handle from gameRenderWorld->AddLightDef() into savegames and reused it after restoring it. That's a bad idea, because at that point the handle most likely belongs to something else (likely some idLight). The most visible issue this can create is that the flashlight may not work correctly after loading a savegame with flashlight on, when it happens to alias a light that's updated each frame to (mostly) being off.. The correct way to handle this (THAT FOR SOME REASON WAS ALREADY IMPLEMENTED IN D3XP BUT NOT THE BASE GAME - WHY?!) is to get a fresh handle with AddLightDef() when restoring a savegame - unless the handle was -1, which means that the light didn't exist when saving. fixes #495 --- game/Moveable.cpp | 9 +++++++++ game/Projectile.cpp | 5 +++++ game/Weapon.cpp | 14 +++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/game/Moveable.cpp b/game/Moveable.cpp index e13ecd6..e3458b3 100644 --- a/game/Moveable.cpp +++ b/game/Moveable.cpp @@ -810,6 +810,15 @@ void idExplodingBarrel::Restore( idRestoreGame *savefile ) { savefile->ReadInt( particleTime ); savefile->ReadInt( lightTime ); savefile->ReadFloat( time ); + + // DG: enforce getting fresh handle, else this may be tied to an unrelated light! + if ( lightDefHandle != -1 ) { + lightDefHandle = gameRenderWorld->AddLightDef( &light ); + } + // DG: same for render entity + if ( particleModelDefHandle != -1 ) { + particleModelDefHandle = gameRenderWorld->AddEntityDef( &particleRenderEntity ); + } } /* diff --git a/game/Projectile.cpp b/game/Projectile.cpp index c353ca0..6460ae0 100644 --- a/game/Projectile.cpp +++ b/game/Projectile.cpp @@ -157,6 +157,11 @@ void idProjectile::Restore( idRestoreGame *savefile ) { savefile->ReadRenderLight( renderLight ); savefile->ReadInt( (int &)lightDefHandle ); + // DG: enforce getting fresh handle, else this may be tied to an unrelated light! + if ( lightDefHandle != -1 ) { + lightDefHandle = gameRenderWorld->AddLightDef( &renderLight ); + } + savefile->ReadVec3( lightOffset ); savefile->ReadInt( lightStartTime ); savefile->ReadInt( lightEndTime ); diff --git a/game/Weapon.cpp b/game/Weapon.cpp index a381ae2..727e061 100644 --- a/game/Weapon.cpp +++ b/game/Weapon.cpp @@ -453,12 +453,21 @@ void idWeapon::Restore( idRestoreGame *savefile ) { savefile->ReadInt( guiLightHandle ); savefile->ReadRenderLight( guiLight ); - + // DG: we need to get a fresh handle, otherwise this will be tied to a completely unrelated light! + if ( guiLightHandle != -1 ) { + guiLightHandle = gameRenderWorld->AddLightDef( &guiLight ); + } savefile->ReadInt( muzzleFlashHandle ); savefile->ReadRenderLight( muzzleFlash ); + if ( muzzleFlashHandle != -1 ) { // DG: enforce getting fresh handle + muzzleFlashHandle = gameRenderWorld->AddLightDef( &muzzleFlash ); + } savefile->ReadInt( worldMuzzleFlashHandle ); savefile->ReadRenderLight( worldMuzzleFlash ); + if ( worldMuzzleFlashHandle != -1 ) { // DG: enforce getting fresh handle + worldMuzzleFlashHandle = gameRenderWorld->AddLightDef( &worldMuzzleFlash ); + } savefile->ReadVec3( flashColor ); savefile->ReadInt( muzzleFlashEnd ); @@ -516,6 +525,9 @@ void idWeapon::Restore( idRestoreGame *savefile ) { savefile->ReadInt( nozzleGlowHandle ); savefile->ReadRenderLight( nozzleGlow ); + if ( nozzleGlowHandle != -1 ) { // DG: enforce getting fresh handle + nozzleGlowHandle = gameRenderWorld->AddLightDef( &nozzleGlow ); + } savefile->ReadVec3( nozzleGlowColor ); savefile->ReadMaterial( nozzleGlowShader ); From f17741ba8443b2531dc6a5ae841b42677958539c Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 29 Dec 2022 05:38:13 +0100 Subject: [PATCH 04/17] Fix -Wformat-security warnings - thanks James Addison! This is based on https://github.com/dhewm/dhewm3/pull/500 by https://github.com/jayaddison See also https://github.com/blendogames/quadrilateralcowboy/pull/4 --- d3xp/Game_local.cpp | 2 +- d3xp/Game_network.cpp | 2 +- d3xp/MultiplayerGame.cpp | 22 +++++++++++----------- d3xp/gamesys/SysCmds.cpp | 4 ++-- d3xp/script/Script_Thread.cpp | 4 ++-- game/Game_local.cpp | 2 +- game/Game_network.cpp | 2 +- game/MultiplayerGame.cpp | 29 +++++++++++++++-------------- game/gamesys/SysCmds.cpp | 4 ++-- game/script/Script_Thread.cpp | 4 ++-- idlib/Parser.cpp | 4 ++-- idlib/math/Simd.cpp | 2 +- 12 files changed, 41 insertions(+), 40 deletions(-) diff --git a/d3xp/Game_local.cpp b/d3xp/Game_local.cpp index 0489186..0b1252e 100644 --- a/d3xp/Game_local.cpp +++ b/d3xp/Game_local.cpp @@ -1222,7 +1222,7 @@ bool idGameLocal::NextMap( void ) { int i; if ( !g_mapCycle.GetString()[0] ) { - Printf( common->GetLanguageDict()->GetString( "#str_04294" ) ); + Printf( "%s", common->GetLanguageDict()->GetString( "#str_04294" ) ); return false; } if ( fileSystem->ReadFile( g_mapCycle.GetString(), NULL, NULL ) < 0 ) { diff --git a/d3xp/Game_network.cpp b/d3xp/Game_network.cpp index 7c3bb14..1fd7023 100644 --- a/d3xp/Game_network.cpp +++ b/d3xp/Game_network.cpp @@ -734,7 +734,7 @@ void idGameLocal::NetworkEventWarning( const entityNetEvent_t *event, const char va_end( argptr ); idStr::Append( buf, sizeof(buf), "\n" ); - common->DWarning( buf ); + common->DWarning( "%s", buf ); } /* diff --git a/d3xp/MultiplayerGame.cpp b/d3xp/MultiplayerGame.cpp index ec9dfa8..4af570c 100644 --- a/d3xp/MultiplayerGame.cpp +++ b/d3xp/MultiplayerGame.cpp @@ -2847,10 +2847,10 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int AddChatLine( common->GetLanguageDict()->GetString( "#str_04289" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); break; case MSG_VOTE: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04288" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04288" ) ); break; case MSG_SUDDENDEATH: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04287" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04287" ) ); break; case MSG_FORCEREADY: AddChatLine( common->GetLanguageDict()->GetString( "#str_04286" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); @@ -2862,7 +2862,7 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int AddChatLine( common->GetLanguageDict()->GetString( "#str_04285" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); break; case MSG_TIMELIMIT: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04284" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04284" ) ); break; case MSG_FRAGLIMIT: if ( gameLocal.gameType == GAME_LASTMAN ) { @@ -2877,7 +2877,7 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int AddChatLine( common->GetLanguageDict()->GetString( "#str_04280" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), parm2 ? common->GetLanguageDict()->GetString( "#str_02500" ) : common->GetLanguageDict()->GetString( "#str_02499" ) ); break; case MSG_HOLYSHIT: - AddChatLine( common->GetLanguageDict()->GetString( "#str_06732" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_06732" ) ); break; #ifdef CTF case MSG_POINTLIMIT: @@ -2903,9 +2903,9 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int break; if ( gameLocal.GetLocalPlayer()->team != parm1 ) { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11103" ) ); // your team + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_11103" ) ); // your team } else { - AddChatLine( common->GetLanguageDict()->GetString( "#str_11104" ) ); // enemy + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_11104" ) ); // enemy } break; @@ -3262,7 +3262,7 @@ void idMultiplayerGame::ClientStartVote( int clientNum, const char *_voteString } voteString = _voteString; - AddChatLine( va( common->GetLanguageDict()->GetString( "#str_04279" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ) ); + AddChatLine( common->GetLanguageDict()->GetString( "#str_04279" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ); gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE ] ); if ( clientNum == gameLocal.localClientNum ) { voted = true; @@ -3302,14 +3302,14 @@ void idMultiplayerGame::ClientUpdateVote( vote_result_t status, int yesCount, in switch ( status ) { case VOTE_FAILED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04278" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04278" ) ); gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_FAILED ] ); if ( gameLocal.isClient ) { vote = VOTE_NONE; } break; case VOTE_PASSED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04277" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04277" ) ); gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_PASSED ] ); break; case VOTE_RESET: @@ -3318,7 +3318,7 @@ void idMultiplayerGame::ClientUpdateVote( vote_result_t status, int yesCount, in } break; case VOTE_ABORTED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04276" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04276" ) ); if ( gameLocal.isClient ) { vote = VOTE_NONE; } @@ -3856,7 +3856,7 @@ void idMultiplayerGame::ToggleSpectate( void ) { if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) { cvarSystem->SetCVarString( "ui_spectate", "Spectate" ); } else { - gameLocal.mpGame.AddChatLine( common->GetLanguageDict()->GetString( "#str_06747" ) ); + gameLocal.mpGame.AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_06747" ) ); } } } diff --git a/d3xp/gamesys/SysCmds.cpp b/d3xp/gamesys/SysCmds.cpp index 9871fe0..cc63b8f 100644 --- a/d3xp/gamesys/SysCmds.cpp +++ b/d3xp/gamesys/SysCmds.cpp @@ -691,7 +691,7 @@ Cmd_AddChatLine_f ================== */ static void Cmd_AddChatLine_f( const idCmdArgs &args ) { - gameLocal.mpGame.AddChatLine( args.Argv( 1 ) ); + gameLocal.mpGame.AddChatLine( "%s", args.Argv( 1 ) ); } /* @@ -1294,7 +1294,7 @@ static void PrintFloat( float f ) { buf[i] = ' '; } buf[i] = '\0'; - gameLocal.Printf( buf ); + gameLocal.Printf( "%s", buf ); } /* diff --git a/d3xp/script/Script_Thread.cpp b/d3xp/script/Script_Thread.cpp index cb82633..28becac 100644 --- a/d3xp/script/Script_Thread.cpp +++ b/d3xp/script/Script_Thread.cpp @@ -817,7 +817,7 @@ void idThread::Error( const char *fmt, ... ) const { vsprintf( text, fmt, argptr ); va_end( argptr ); - interpreter.Error( text ); + interpreter.Error( "%s", text ); } /* @@ -833,7 +833,7 @@ void idThread::Warning( const char *fmt, ... ) const { vsprintf( text, fmt, argptr ); va_end( argptr ); - interpreter.Warning( text ); + interpreter.Warning( "%s", text ); } /* diff --git a/game/Game_local.cpp b/game/Game_local.cpp index ae1eb86..a2cefa6 100644 --- a/game/Game_local.cpp +++ b/game/Game_local.cpp @@ -1084,7 +1084,7 @@ bool idGameLocal::NextMap( void ) { int i; if ( !g_mapCycle.GetString()[0] ) { - Printf( common->GetLanguageDict()->GetString( "#str_04294" ) ); + Printf( "%s", common->GetLanguageDict()->GetString( "#str_04294" ) ); return false; } if ( fileSystem->ReadFile( g_mapCycle.GetString(), NULL, NULL ) < 0 ) { diff --git a/game/Game_network.cpp b/game/Game_network.cpp index d7e2268..5e24df7 100644 --- a/game/Game_network.cpp +++ b/game/Game_network.cpp @@ -720,7 +720,7 @@ void idGameLocal::NetworkEventWarning( const entityNetEvent_t *event, const char va_end( argptr ); idStr::Append( buf, sizeof(buf), "\n" ); - common->DWarning( buf ); + common->DWarning( "%s", buf ); } /* diff --git a/game/MultiplayerGame.cpp b/game/MultiplayerGame.cpp index 94a0aff..11cce5e 100644 --- a/game/MultiplayerGame.cpp +++ b/game/MultiplayerGame.cpp @@ -554,11 +554,12 @@ const char *idMultiplayerGame::GameTime() { ms = 0; } - s = ms / 1000; - m = s / 60; - s -= m * 60; - t = s / 10; - s -= t * 10; + s = ms / 1000; // => s <= 2 147 483 (INT_MAX / 1000) + m = s / 60; // => m <= 35 791 + s -= m * 60; // => s < 60 + t = s / 10; // => t < 6 + s -= t * 10; // => s < 10 + // writing <= 5 for m + 3 bytes for ":ts" + 1 byte for \0 => 16 bytes is enough sprintf( buff, "%i:%i%i", m, t, s ); } @@ -2221,10 +2222,10 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int AddChatLine( common->GetLanguageDict()->GetString( "#str_04289" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); break; case MSG_VOTE: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04288" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04288" ) ); break; case MSG_SUDDENDEATH: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04287" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04287" ) ); break; case MSG_FORCEREADY: AddChatLine( common->GetLanguageDict()->GetString( "#str_04286" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); @@ -2236,7 +2237,7 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int AddChatLine( common->GetLanguageDict()->GetString( "#str_04285" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ) ); break; case MSG_TIMELIMIT: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04284" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04284" ) ); break; case MSG_FRAGLIMIT: if ( gameLocal.gameType == GAME_LASTMAN ) { @@ -2251,7 +2252,7 @@ void idMultiplayerGame::PrintMessageEvent( int to, msg_evt_t evt, int parm1, int AddChatLine( common->GetLanguageDict()->GetString( "#str_04280" ), gameLocal.userInfo[ parm1 ].GetString( "ui_name" ), parm2 ? common->GetLanguageDict()->GetString( "#str_02500" ) : common->GetLanguageDict()->GetString( "#str_02499" ) ); break; case MSG_HOLYSHIT: - AddChatLine( common->GetLanguageDict()->GetString( "#str_06732" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_06732" ) ); break; default: gameLocal.DPrintf( "PrintMessageEvent: unknown message type %d\n", evt ); @@ -2570,7 +2571,7 @@ void idMultiplayerGame::ClientStartVote( int clientNum, const char *_voteString } voteString = _voteString; - AddChatLine( va( common->GetLanguageDict()->GetString( "#str_04279" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ) ); + AddChatLine( common->GetLanguageDict()->GetString( "#str_04279" ), gameLocal.userInfo[ clientNum ].GetString( "ui_name" ) ); gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE ] ); if ( clientNum == gameLocal.localClientNum ) { voted = true; @@ -2610,14 +2611,14 @@ void idMultiplayerGame::ClientUpdateVote( vote_result_t status, int yesCount, in switch ( status ) { case VOTE_FAILED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04278" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04278" ) ); gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_FAILED ] ); if ( gameLocal.isClient ) { vote = VOTE_NONE; } break; case VOTE_PASSED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04277" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04277" ) ); gameSoundWorld->PlayShaderDirectly( GlobalSoundStrings[ SND_VOTE_PASSED ] ); break; case VOTE_RESET: @@ -2626,7 +2627,7 @@ void idMultiplayerGame::ClientUpdateVote( vote_result_t status, int yesCount, in } break; case VOTE_ABORTED: - AddChatLine( common->GetLanguageDict()->GetString( "#str_04276" ) ); + AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_04276" ) ); if ( gameLocal.isClient ) { vote = VOTE_NONE; } @@ -3122,7 +3123,7 @@ void idMultiplayerGame::ToggleSpectate( void ) { if ( gameLocal.serverInfo.GetBool( "si_spectators" ) ) { cvarSystem->SetCVarString( "ui_spectate", "Spectate" ); } else { - gameLocal.mpGame.AddChatLine( common->GetLanguageDict()->GetString( "#str_06747" ) ); + gameLocal.mpGame.AddChatLine( "%s", common->GetLanguageDict()->GetString( "#str_06747" ) ); } } } diff --git a/game/gamesys/SysCmds.cpp b/game/gamesys/SysCmds.cpp index 732d506..105ff57 100644 --- a/game/gamesys/SysCmds.cpp +++ b/game/gamesys/SysCmds.cpp @@ -622,7 +622,7 @@ Cmd_AddChatLine_f ================== */ static void Cmd_AddChatLine_f( const idCmdArgs &args ) { - gameLocal.mpGame.AddChatLine( args.Argv( 1 ) ); + gameLocal.mpGame.AddChatLine( "%s", args.Argv( 1 ) ); } /* @@ -1225,7 +1225,7 @@ static void PrintFloat( float f ) { buf[i] = ' '; } buf[i] = '\0'; - gameLocal.Printf( buf ); + gameLocal.Printf( "%s", buf ); } /* diff --git a/game/script/Script_Thread.cpp b/game/script/Script_Thread.cpp index 58daa5d..3aa8054 100644 --- a/game/script/Script_Thread.cpp +++ b/game/script/Script_Thread.cpp @@ -795,7 +795,7 @@ void idThread::Error( const char *fmt, ... ) const { vsprintf( text, fmt, argptr ); va_end( argptr ); - interpreter.Error( text ); + interpreter.Error( "%s", text ); } /* @@ -811,7 +811,7 @@ void idThread::Warning( const char *fmt, ... ) const { vsprintf( text, fmt, argptr ); va_end( argptr ); - interpreter.Warning( text ); + interpreter.Warning( "%s", text ); } /* diff --git a/idlib/Parser.cpp b/idlib/Parser.cpp index 86a57d3..4ef2b50 100644 --- a/idlib/Parser.cpp +++ b/idlib/Parser.cpp @@ -326,7 +326,7 @@ void idParser::Error( const char *str, ... ) const { vsprintf(text, str, ap); va_end(ap); if ( idParser::scriptstack ) { - idParser::scriptstack->Error( text ); + idParser::scriptstack->Error( "%s", text ); } } @@ -343,7 +343,7 @@ void idParser::Warning( const char *str, ... ) const { vsprintf(text, str, ap); va_end(ap); if ( idParser::scriptstack ) { - idParser::scriptstack->Warning( text ); + idParser::scriptstack->Warning( "%s", text ); } } diff --git a/idlib/math/Simd.cpp b/idlib/math/Simd.cpp index 7fbad1e..6cbdae1 100644 --- a/idlib/math/Simd.cpp +++ b/idlib/math/Simd.cpp @@ -213,7 +213,7 @@ PrintClocks void PrintClocks( const char *string, int dataCount, int clocks, int otherClocks = 0 ) { int i; - idLib::common->Printf( string ); + idLib::common->Printf( "%s", string ); for ( i = idStr::LengthWithoutColors(string); i < 48; i++ ) { idLib::common->Printf(" "); } From b3d5571e67cf11b374aca5ca0668ae9241eca0e1 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 5 Jan 2023 04:57:54 +0100 Subject: [PATCH 05/17] Don't use "register" keyword, it was deprecated in C++11 .. and even removed in C++17 - and before that it probably didn't do much in most compilers --- idlib/Lib.cpp | 2 +- idlib/hashing/MD5.cpp | 2 +- idlib/math/Simd_Generic.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/idlib/Lib.cpp b/idlib/Lib.cpp index 3c83bae..8433095 100644 --- a/idlib/Lib.cpp +++ b/idlib/Lib.cpp @@ -300,7 +300,7 @@ RESULTS Reverses the byte order in each of elcount elements. ===================================================================== */ ID_INLINE static void RevBytesSwap( void *bp, int elsize, int elcount ) { - register unsigned char *p, *q; + unsigned char *p, *q; p = ( unsigned char * ) bp; diff --git a/idlib/hashing/MD5.cpp b/idlib/hashing/MD5.cpp index de9f855..f4f9836 100644 --- a/idlib/hashing/MD5.cpp +++ b/idlib/hashing/MD5.cpp @@ -54,7 +54,7 @@ the data and converts bytes into longwords for this routine. ================= */ void MD5_Transform( unsigned int state[4], unsigned int in[16] ) { - register unsigned int a, b, c, d; + unsigned int a, b, c, d; a = state[0]; b = state[1]; diff --git a/idlib/math/Simd_Generic.cpp b/idlib/math/Simd_Generic.cpp index c20f6a4..9ce25f6 100644 --- a/idlib/math/Simd_Generic.cpp +++ b/idlib/math/Simd_Generic.cpp @@ -1802,7 +1802,7 @@ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolve( const idMatX &L, float *x lptr = L[skip]; int i, j; - register double s0, s1, s2, s3; + double s0, s1, s2, s3; for ( i = skip; i < n; i++ ) { s0 = lptr[0] * x[0]; @@ -1928,7 +1928,7 @@ void VPCALL idSIMD_Generic::MatX_LowerTriangularSolveTranspose( const idMatX &L, } int i, j; - register double s0, s1, s2, s3; + double s0, s1, s2, s3; float *xptr; lptr = L.ToFloatPtr() + n * nc + n - 4; From ed41db9c3e0e187baa4b705956ef89302f613353 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 5 Jan 2023 06:21:07 +0100 Subject: [PATCH 06/17] Fix GCC -W(maybe-)uninitialized warnings that at least kinda had a point --- idlib/geometry/Surface_Patch.cpp | 7 ++++++- idlib/geometry/Winding.cpp | 15 +++++++++++++-- idlib/geometry/Winding2D.cpp | 11 +++++++++++ idlib/math/Simd_SSE.cpp | 8 ++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/idlib/geometry/Surface_Patch.cpp b/idlib/geometry/Surface_Patch.cpp index 6f6f744..f898c50 100644 --- a/idlib/geometry/Surface_Patch.cpp +++ b/idlib/geometry/Surface_Patch.cpp @@ -224,6 +224,7 @@ idSurface_Patch::LerpVert ============ */ void idSurface_Patch::LerpVert( const idDrawVert &a, const idDrawVert &b, idDrawVert &out ) const { + // DG: TODO: what about out.tangent and out.color ? out.xyz[0] = 0.5f * ( a.xyz[0] + b.xyz[0] ); out.xyz[1] = 0.5f * ( a.xyz[1] + b.xyz[1] ); out.xyz[2] = 0.5f * ( a.xyz[2] + b.xyz[2] ); @@ -554,7 +555,11 @@ idSurface_Patch::Subdivide */ void idSurface_Patch::Subdivide( float maxHorizontalError, float maxVerticalError, float maxLength, bool genNormals ) { int i, j, k, l; - idDrawVert prev, next, mid; + // DG: to shut up GCC (maybe-)uninitialized warnings, initialize prev, next and mid + // (maybe the warnings were at least partly correct, because .tangent and .color aren't set by idSurface_Patch::LerpVert()) + idDrawVert prev; + prev.Clear(); + idDrawVert next = prev, mid = prev; idVec3 prevxyz, nextxyz, midxyz; idVec3 delta; float maxHorizontalErrorSqr, maxVerticalErrorSqr, maxLengthSqr; diff --git a/idlib/geometry/Winding.cpp b/idlib/geometry/Winding.cpp index 5f38423..2def85f 100644 --- a/idlib/geometry/Winding.cpp +++ b/idlib/geometry/Winding.cpp @@ -102,7 +102,12 @@ int idWinding::Split( const idPlane &plane, const float epsilon, idWinding **fro idWinding * f, *b; int maxpts; - assert( this ); + assert( this && numPoints > 0); + + // DG: unlikely, but makes sure we don't use uninitialized memory below + if ( numPoints == 0 ) { + return 0; // it's not like the callers check the return value anyway.. + } dists = (float *) _alloca( (numPoints+4) * sizeof( float ) ); sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) ); @@ -245,7 +250,13 @@ idWinding *idWinding::Clip( const idPlane &plane, const float epsilon, const boo idVec5 mid; int maxpts; - assert( this ); + assert( this && numPoints > 0 ); + + // DG: this shouldn't happen, probably, but if it does we'd use uninitialized memory below + if ( numPoints == 0 ) { + delete this; + return NULL; + } dists = (float *) _alloca( (numPoints+4) * sizeof( float ) ); sides = (byte *) _alloca( (numPoints+4) * sizeof( byte ) ); diff --git a/idlib/geometry/Winding2D.cpp b/idlib/geometry/Winding2D.cpp index 8978f1d..bb02e6d 100644 --- a/idlib/geometry/Winding2D.cpp +++ b/idlib/geometry/Winding2D.cpp @@ -92,6 +92,12 @@ void idWinding2D::ExpandForAxialBox( const idVec2 bounds[2] ) { assert( numPlanes < MAX_POINTS_ON_WINDING_2D ); planes[numPlanes++] = plane; } + + // DG: make sure planes[] isn't used uninitialized and with index -1 below + if ( numPlanes == 0 ) { + return; + } + if ( GetAxialBevel( planes[numPlanes-1], planes[0], p[0], bevel ) ) { planes[numPlanes++] = bevel; } @@ -259,6 +265,11 @@ bool idWinding2D::ClipInPlace( const idVec3 &plane, const float epsilon, const b float dot, dists[MAX_POINTS_ON_WINDING_2D+1]; idVec2 *p1, *p2, mid, newPoints[MAX_POINTS_ON_WINDING_2D+4]; + // DG: avoid all kinds of unitialized usages below + if ( numPoints == 0 ) { + return false; + } + counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; for ( i = 0; i < numPoints; i++ ) { diff --git a/idlib/math/Simd_SSE.cpp b/idlib/math/Simd_SSE.cpp index 609cb59..a9dad8b 100644 --- a/idlib/math/Simd_SSE.cpp +++ b/idlib/math/Simd_SSE.cpp @@ -456,6 +456,14 @@ void VPCALL idSIMD_SSE::Dot( float *dst, const idVec3 &constant, const idPlane * char *dst_p; __m128 xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7; + // DG: GCC and clang warn about xmm1-4 maybe being used uninitialized below. + // according to https://stackoverflow.com/a/18749079 the initialization + // code is generated anyway, so make it explicit to shut up the warning + xmm1 = _mm_setzero_ps(); + xmm2 = _mm_setzero_ps(); + xmm3 = _mm_setzero_ps(); + xmm4 = _mm_setzero_ps(); + /* mov eax, count mov edi, constant From 1f3b514ba3db66be99f15f0f3a7653eb8394e0a2 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 5 Jan 2023 07:54:41 +0100 Subject: [PATCH 07/17] Work around false positive GCC -W(maybe-)uninitialized warnings shouldn't hurt too much, and the R_IssueEntityDefCallback() code even is a bit better now --- d3xp/ai/AI_pathing.cpp | 7 ++++--- game/ai/AI_pathing.cpp | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/d3xp/ai/AI_pathing.cpp b/d3xp/ai/AI_pathing.cpp index 4b043dc..a9825bd 100644 --- a/d3xp/ai/AI_pathing.cpp +++ b/d3xp/ai/AI_pathing.cpp @@ -155,7 +155,7 @@ GetPointOutsideObstacles void GetPointOutsideObstacles( const obstacle_t *obstacles, const int numObstacles, idVec2 &point, int *obstacle, int *edgeNum ) { int i, j, k, n, bestObstacle, bestEdgeNum, queueStart, queueEnd, edgeNums[2]; float d, bestd, scale[2]; - idVec3 plane, bestPlane; + idVec3 plane, bestPlane(0.0f, 0.0f, 0.0f); // DG: init it to shut up compiler idVec2 newPoint, dir, bestPoint; int *queue; bool *obstacleVisited; @@ -1128,7 +1128,8 @@ idAI::PredictPath */ bool idAI::PredictPath( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path ) { int i, j, step, numFrames, curFrameTime; - idVec3 delta, curStart, curEnd, curVelocity, lastEnd, stepUp, tmpStart; + idVec3 delta, curStart, curEnd, curVelocity, lastEnd, tmpStart; + idVec3 stepUp(0,0,0); // DG: init this to get rid of compiler warning idVec3 gravity, gravityDir, invGravityDir; float maxStepHeight, minFloorCos; pathTrace_t trace; @@ -1183,7 +1184,7 @@ bool idAI::PredictPath( const idEntity *ent, const idAAS *aas, const idVec3 &sta return true; } - if ( step ) { + if ( step != 0 ) { // step down at end point tmpStart = trace.endPos; diff --git a/game/ai/AI_pathing.cpp b/game/ai/AI_pathing.cpp index 9c961a9..8c19de3 100644 --- a/game/ai/AI_pathing.cpp +++ b/game/ai/AI_pathing.cpp @@ -157,7 +157,7 @@ GetPointOutsideObstacles void GetPointOutsideObstacles( const obstacle_t *obstacles, const int numObstacles, idVec2 &point, int *obstacle, int *edgeNum ) { int i, j, k, n, bestObstacle, bestEdgeNum, queueStart, queueEnd, edgeNums[2]; float d, bestd, scale[2]; - idVec3 plane, bestPlane; + idVec3 plane, bestPlane(0.0f, 0.0f, 0.0f); // DG: init it to shut up compiler idVec2 newPoint, dir, bestPoint; int *queue; bool *obstacleVisited; @@ -1131,7 +1131,8 @@ idAI::PredictPath */ bool idAI::PredictPath( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path ) { int i, j, step, numFrames, curFrameTime; - idVec3 delta, curStart, curEnd, curVelocity, lastEnd, stepUp, tmpStart; + idVec3 delta, curStart, curEnd, curVelocity, lastEnd, tmpStart; + idVec3 stepUp(0,0,0); // DG: init this to get rid of compiler warning idVec3 gravity, gravityDir, invGravityDir; float maxStepHeight, minFloorCos; pathTrace_t trace; From d7d46c5ab4db3afb4863a78078eba3430467c732 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 5 Jan 2023 09:05:52 +0100 Subject: [PATCH 08/17] Fix date/time handling in idParser::ExpandBuiltinDefine() this was so broken, I think if anyone ever tried to use __DATE__ or __TIME__ it must've crashed, either from free(curtime) (which was the return value of ctime()) or from things like token[7] = NULL when token was a pointer (to a single element!). I think it could work now. Also fixed potential memory leaks in cases that don't "return" anything --- idlib/Parser.cpp | 58 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/idlib/Parser.cpp b/idlib/Parser.cpp index 4ef2b50..dedf5cc 100644 --- a/idlib/Parser.cpp +++ b/idlib/Parser.cpp @@ -669,6 +669,31 @@ define_t *idParser::CopyFirstDefine( void ) { return NULL; } +// simple abstraction around localtime()/localtime_r() or whatever +static bool my_localtime(const time_t* t, struct tm* ts) +{ + // TODO: does any non-windows platform not support localtime_r()? + // then add them here (or handle them specially with their own #elif) +#ifdef _WIN32 + // localtime() is C89 so it should be available everywhere, but it *may* not be threadsafe. + // It *is* threadsafe on Windows though (there it returns a thread-local variable). + // (yes, Windows has localtime_s(), but it's unclear if MinGW supports that + // or localtime_r() and in the end, *on Windows* localtime() is safe so use it) + + struct tm* tmp = localtime(t); + if(tmp != NULL) { + *ts = *tmp; + return true; + } +#else // localtime_r() assumed available, use it (all Unix-likes incl. macOS support it, AROS as well) + if(localtime_r(t, ts) != NULL) + return true; +#endif + // if we get here, the localtime() (or localtime_r() or whatever) call failed + memset(ts, 0, sizeof(*ts)); // make sure ts has deterministic content + return false; +} + /* ================ idParser::ExpandBuiltinDefine @@ -677,7 +702,6 @@ idParser::ExpandBuiltinDefine int idParser::ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken **firsttoken, idToken **lasttoken ) { idToken *token; ID_TIME_T t; - char *curtime; char buf[MAX_STRING_CHARS]; token = new idToken(deftoken); @@ -709,14 +733,15 @@ int idParser::ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken } case BUILTIN_DATE: { t = time(NULL); - curtime = ctime(&t); - (*token) = "\""; - token->Append( curtime+4 ); - token[7] = NULL; - token->Append( curtime+20 ); - token[10] = NULL; - token->Append( "\"" ); - free(curtime); + // DG: apparently this was supposed to extract the date part of "Wed Jun 30 21:49:08 1993\n" + // (like "Jun 30 1993") - it was both ugly and broken before I changed it, though + // Originally it copied stuff out of ctime(), which is ugly but ok, but also + // free'd the returned value (wrong) and tried to modify token in ways that should've crashed + // (like token[7] = NULL; which should've been (*token)[7] = '\0';) + struct tm ts; + my_localtime(&t, &ts); + strftime(buf, sizeof(buf), "\"%b %d %Y\"", &ts); + (*token) = buf; token->type = TT_STRING; token->subtype = token->Length(); token->line = deftoken->line; @@ -728,12 +753,13 @@ int idParser::ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken } case BUILTIN_TIME: { t = time(NULL); - curtime = ctime(&t); - (*token) = "\""; - token->Append( curtime+11 ); - token[8] = NULL; - token->Append( "\"" ); - free(curtime); + // DG: apparently this was supposed to extract the time part of "Wed Jun 30 21:49:08 1993\n" + // (like "21:49:08") - it was both ugly and broken before I changed it, though + // (had basicaly the same problems as BUILTIN_DATE) + struct tm ts; + my_localtime(&t, &ts); + strftime(buf, sizeof(buf), "\"%H:%M:%S\"", &ts); + (*token) = buf; token->type = TT_STRING; token->subtype = token->Length(); token->line = deftoken->line; @@ -745,11 +771,13 @@ int idParser::ExpandBuiltinDefine( idToken *deftoken, define_t *define, idToken } case BUILTIN_STDC: { idParser::Warning( "__STDC__ not supported\n" ); + delete token; // DG: we probably shouldn't leak it, right? *firsttoken = NULL; *lasttoken = NULL; break; } default: { + delete token; // DG: we probably shouldn't leak it, right? *firsttoken = NULL; *lasttoken = NULL; break; From 51064bef93e2e630b2d6cb4c6137aebb681806b8 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 5 Jan 2023 08:07:51 +0100 Subject: [PATCH 09/17] Fix/work around other misc. compiler warnings or, in the case of AF.cpp, at least comment on them I think this fixes most of the remaining "interesting" GCC 12 on Linux warnings --- d3xp/AF.cpp | 5 +++++ d3xp/Pvs.cpp | 3 ++- d3xp/anim/Anim_Blend.cpp | 4 +++- game/AF.cpp | 5 +++++ game/Pvs.cpp | 3 ++- game/anim/Anim_Blend.cpp | 4 +++- 6 files changed, 20 insertions(+), 4 deletions(-) diff --git a/d3xp/AF.cpp b/d3xp/AF.cpp index e527b14..1a97edc 100644 --- a/d3xp/AF.cpp +++ b/d3xp/AF.cpp @@ -892,6 +892,11 @@ bool idAF::Load( idEntity *ent, const char *fileName ) { for ( i = 0; i < physicsObj.GetNumConstraints(); i++ ) { idAFConstraint *constraint = physicsObj.GetConstraint( i ); for ( j = 0; j < file->constraints.Num(); j++ ) { + // DG: FIXME: GCC rightfully complains that file->constraints[j]->type and constraint->GetType() + // are of different enum types, and their values are different in some cases: + // CONSTRAINT_HINGESTEERING has no DECLAF_CONSTRAINT_ equivalent, + // and thus DECLAF_CONSTRAINT_SLIDER != CONSTRAINT_SLIDER (5 != 6) + // and DECLAF_CONSTRAINT_SPRING != CONSTRAINT_SPRING (6 != 10) if ( file->constraints[j]->name.Icmp( constraint->GetName() ) == 0 && file->constraints[j]->type == constraint->GetType() ) { break; diff --git a/d3xp/Pvs.cpp b/d3xp/Pvs.cpp index 46e16f1..4894eb1 100644 --- a/d3xp/Pvs.cpp +++ b/d3xp/Pvs.cpp @@ -872,7 +872,8 @@ void idPVS::Shutdown( void ) { delete[] areaPVS; areaPVS = NULL; } - if ( currentPVS ) { + // if ( currentPVS ) - DG: can't be NULL + { for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) { delete[] currentPVS[i].pvs; currentPVS[i].pvs = NULL; diff --git a/d3xp/anim/Anim_Blend.cpp b/d3xp/anim/Anim_Blend.cpp index da1249a..7df2552 100644 --- a/d3xp/anim/Anim_Blend.cpp +++ b/d3xp/anim/Anim_Blend.cpp @@ -172,7 +172,7 @@ index 0 will never be NULL. Any anim >= NumAnims will return NULL. ===================== */ const idMD5Anim *idAnim::MD5Anim( int num ) const { - if ( anims == NULL || anims[0] == NULL ) { + if ( anims[0] == NULL ) { return NULL; } return anims[ num ]; @@ -3057,6 +3057,7 @@ idDeclModelDef::NumJointsOnChannel int idDeclModelDef::NumJointsOnChannel( int channel ) const { if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) { gameLocal.Error( "idDeclModelDef::NumJointsOnChannel : channel out of range" ); + return 0; // unreachable, (Error() doesn't return) just to shut up compiler } return channelJoints[ channel ].Num(); } @@ -3069,6 +3070,7 @@ idDeclModelDef::GetChannelJoints const int * idDeclModelDef::GetChannelJoints( int channel ) const { if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) { gameLocal.Error( "idDeclModelDef::GetChannelJoints : channel out of range" ); + return NULL; // unreachable, (Error() doesn't return) just to shut up compiler } return channelJoints[ channel ].Ptr(); } diff --git a/game/AF.cpp b/game/AF.cpp index e527b14..1a97edc 100644 --- a/game/AF.cpp +++ b/game/AF.cpp @@ -892,6 +892,11 @@ bool idAF::Load( idEntity *ent, const char *fileName ) { for ( i = 0; i < physicsObj.GetNumConstraints(); i++ ) { idAFConstraint *constraint = physicsObj.GetConstraint( i ); for ( j = 0; j < file->constraints.Num(); j++ ) { + // DG: FIXME: GCC rightfully complains that file->constraints[j]->type and constraint->GetType() + // are of different enum types, and their values are different in some cases: + // CONSTRAINT_HINGESTEERING has no DECLAF_CONSTRAINT_ equivalent, + // and thus DECLAF_CONSTRAINT_SLIDER != CONSTRAINT_SLIDER (5 != 6) + // and DECLAF_CONSTRAINT_SPRING != CONSTRAINT_SPRING (6 != 10) if ( file->constraints[j]->name.Icmp( constraint->GetName() ) == 0 && file->constraints[j]->type == constraint->GetType() ) { break; diff --git a/game/Pvs.cpp b/game/Pvs.cpp index 16e845a..4536710 100644 --- a/game/Pvs.cpp +++ b/game/Pvs.cpp @@ -872,7 +872,8 @@ void idPVS::Shutdown( void ) { delete[] areaPVS; areaPVS = NULL; } - if ( currentPVS ) { + // if ( currentPVS ) - DG: can't be NULL + { for ( int i = 0; i < MAX_CURRENT_PVS; i++ ) { delete[] currentPVS[i].pvs; currentPVS[i].pvs = NULL; diff --git a/game/anim/Anim_Blend.cpp b/game/anim/Anim_Blend.cpp index 0cbd4af..3f25a3d 100644 --- a/game/anim/Anim_Blend.cpp +++ b/game/anim/Anim_Blend.cpp @@ -172,7 +172,7 @@ index 0 will never be NULL. Any anim >= NumAnims will return NULL. ===================== */ const idMD5Anim *idAnim::MD5Anim( int num ) const { - if ( anims == NULL || anims[0] == NULL ) { + if ( anims[0] == NULL ) { return NULL; } return anims[ num ]; @@ -2971,6 +2971,7 @@ idDeclModelDef::NumJointsOnChannel int idDeclModelDef::NumJointsOnChannel( int channel ) const { if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) { gameLocal.Error( "idDeclModelDef::NumJointsOnChannel : channel out of range" ); + return 0; // unreachable, (Error() doesn't return) just to shut up compiler } return channelJoints[ channel ].Num(); } @@ -2983,6 +2984,7 @@ idDeclModelDef::GetChannelJoints const int * idDeclModelDef::GetChannelJoints( int channel ) const { if ( ( channel < 0 ) || ( channel >= ANIM_NumAnimChannels ) ) { gameLocal.Error( "idDeclModelDef::GetChannelJoints : channel out of range" ); + return NULL; // unreachable, (Error() doesn't return) just to shut up compiler } return channelJoints[ channel ].Ptr(); } From c6d780b21ba65fae989f789c776ab19b1efc8d19 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 11 Jan 2023 16:16:34 +0000 Subject: [PATCH 10/17] Fixup: typo: 'hiehgt' -> 'height' in a few places around the codebase --- d3xp/ai/AI_pathing.cpp | 2 +- d3xp/gamesys/SysCvar.cpp | 2 +- game/ai/AI_pathing.cpp | 2 +- game/gamesys/SysCvar.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/d3xp/ai/AI_pathing.cpp b/d3xp/ai/AI_pathing.cpp index a9825bd..a57a24e 100644 --- a/d3xp/ai/AI_pathing.cpp +++ b/d3xp/ai/AI_pathing.cpp @@ -1339,7 +1339,7 @@ static int Ballistics( const idVec3 &start, const idVec3 &end, float speed, floa ===================== HeightForTrajectory -Returns the maximum hieght of a given trajectory +Returns the maximum height of a given trajectory ===================== */ #if 0 diff --git a/d3xp/gamesys/SysCvar.cpp b/d3xp/gamesys/SysCvar.cpp index f2bb0b7..b57abda 100644 --- a/d3xp/gamesys/SysCvar.cpp +++ b/d3xp/gamesys/SysCvar.cpp @@ -293,7 +293,7 @@ idCVar rb_showVelocity( "rb_showVelocity", "0", CVAR_GAME | CVAR_BOOL, "s idCVar rb_showActive( "rb_showActive", "0", CVAR_GAME | CVAR_BOOL, "show rigid bodies that are not at rest" ); // The default values for player movement cvars are set in def/player.def -idCVar pm_jumpheight( "pm_jumpheight", "48", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "approximate hieght the player can jump" ); +idCVar pm_jumpheight( "pm_jumpheight", "48", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "approximate height the player can jump" ); idCVar pm_stepsize( "pm_stepsize", "16", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "maximum height the player can step up without jumping" ); idCVar pm_crouchspeed( "pm_crouchspeed", "80", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while crouched" ); idCVar pm_walkspeed( "pm_walkspeed", "140", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while walking" ); diff --git a/game/ai/AI_pathing.cpp b/game/ai/AI_pathing.cpp index 8c19de3..57f38eb 100644 --- a/game/ai/AI_pathing.cpp +++ b/game/ai/AI_pathing.cpp @@ -1342,7 +1342,7 @@ static int Ballistics( const idVec3 &start, const idVec3 &end, float speed, floa ===================== HeightForTrajectory -Returns the maximum hieght of a given trajectory +Returns the maximum height of a given trajectory ===================== */ #if 0 diff --git a/game/gamesys/SysCvar.cpp b/game/gamesys/SysCvar.cpp index 7aad60d..e2d64e7 100644 --- a/game/gamesys/SysCvar.cpp +++ b/game/gamesys/SysCvar.cpp @@ -231,7 +231,7 @@ idCVar rb_showVelocity( "rb_showVelocity", "0", CVAR_GAME | CVAR_BOOL, "s idCVar rb_showActive( "rb_showActive", "0", CVAR_GAME | CVAR_BOOL, "show rigid bodies that are not at rest" ); // The default values for player movement cvars are set in def/player.def -idCVar pm_jumpheight( "pm_jumpheight", "48", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "approximate hieght the player can jump" ); +idCVar pm_jumpheight( "pm_jumpheight", "48", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "approximate height the player can jump" ); idCVar pm_stepsize( "pm_stepsize", "16", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "maximum height the player can step up without jumping" ); idCVar pm_crouchspeed( "pm_crouchspeed", "80", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while crouched" ); idCVar pm_walkspeed( "pm_walkspeed", "140", CVAR_GAME | CVAR_NETWORKSYNC | CVAR_FLOAT, "speed the player can move while walking" ); From b3558f550dd8a662fbcd2b4953290c10a49e3878 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 2 Mar 2023 18:04:48 +0100 Subject: [PATCH 11/17] Fix MSVC non-Release builds (_alloca()/assert() didn't play nice) --- idlib/Lib.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/idlib/Lib.h b/idlib/Lib.h index 90287ba..5b2e999 100644 --- a/idlib/Lib.h +++ b/idlib/Lib.h @@ -125,7 +125,8 @@ int IntForSixtets( byte *in ); #ifdef _DEBUG void AssertFailed( const char *file, int line, const char *expression ); #undef assert -#define assert( X ) if ( X ) { } else AssertFailed( __FILE__, __LINE__, #X ) +// DG: change assert to use ?: so I can use it in _alloca()/_alloca16() (MSVC didn't like if() in there) +#define assert( X ) (X) ? 1 : (AssertFailed( __FILE__, __LINE__, #X ), 0) #endif class idException { From bad9c08c3f04d63ce7f0b968886f9f808e5367ab Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 17 Mar 2024 04:03:27 +0100 Subject: [PATCH 12/17] Make Sys_SetInteractiveIngameGuiActive() work better it could happen that UIs are added to the internal list twice, and also that the last UI wasn't removed from the list when a new one was focused fast enough. That should work better now, I hope I didn't break anything.. --- d3xp/Player.cpp | 5 +++++ game/Player.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/d3xp/Player.cpp b/d3xp/Player.cpp index 718a8cc..df2fbd2 100644 --- a/d3xp/Player.cpp +++ b/d3xp/Player.cpp @@ -5526,6 +5526,11 @@ void idPlayer::UpdateFocus( void ) { if ( focusGUIent && focusUI ) { if ( !oldFocus || oldFocus != focusGUIent ) { + // DG: tell the old UI it isn't focused anymore + if ( oldFocus != NULL && oldUI != NULL ) { + command = oldUI->Activate( false, gameLocal.time ); + // TODO: HandleGuiCommands( oldFocus, command ); ? + } // DG end command = focusUI->Activate( true, gameLocal.time ); HandleGuiCommands( focusGUIent, command ); StartSound( "snd_guienter", SND_CHANNEL_ANY, 0, false, NULL ); diff --git a/game/Player.cpp b/game/Player.cpp index 45c9f8d..8308c96 100644 --- a/game/Player.cpp +++ b/game/Player.cpp @@ -4545,6 +4545,11 @@ void idPlayer::UpdateFocus( void ) { if ( focusGUIent && focusUI ) { if ( !oldFocus || oldFocus != focusGUIent ) { + // DG: tell the old UI it isn't focused anymore + if ( oldFocus != NULL && oldUI != NULL ) { + command = oldUI->Activate( false, gameLocal.time ); + // TODO: HandleGuiCommands( oldFocus, command ); ? + } // DG end command = focusUI->Activate( true, gameLocal.time ); HandleGuiCommands( focusGUIent, command ); StartSound( "snd_guienter", SND_CHANNEL_ANY, 0, false, NULL ); From d27f2c2c4077adcaa4bb50c0cd9dcd10960b2aa9 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Mon, 18 Mar 2024 23:03:05 +0100 Subject: [PATCH 13/17] Sync sys/platform.h, incl. Workaround for MCST-LCC compiler Workaround for MCST-LCC compiler < 1.28 version mcst-lcc < 1.28 does not support __builtin_alloca_with_align() Ref: http://mcst.ru/lcc --- sys/platform.h | 76 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/sys/platform.h b/sys/platform.h index d9a9a5b..1beb68b 100644 --- a/sys/platform.h +++ b/sys/platform.h @@ -32,6 +32,16 @@ If you have questions concerning this license or the applicable additional terms #include "config.h" #include "framework/BuildDefines.h" +#ifdef _WIN32 +#include // _alloca() +#endif + +// NOTE: By default Win32 uses a 1MB stack. Doom3 1.3.1 uses 4MB (probably set after compiling with EDITBIN /STACK +// dhewm3 now uses a 8MB stack, set with a linker flag in CMakeLists.txt (/STACK:8388608 for MSVC, -Wl,--stack,8388608 for mingw) +// Linux has a 8MB stack by default, and so does macOS, at least for the main thread +// anyway, a 2MB limit alloca should be safe even when using it multiple times in the same function +#define ID_MAX_ALLOCA_SIZE 2097152 // 2MB + /* =============================================================================== @@ -40,7 +50,7 @@ If you have questions concerning this license or the applicable additional terms =============================================================================== */ -// Win32 +// AROS #if defined(__AROS__) #define _alloca alloca @@ -71,7 +81,14 @@ If you have questions concerning this license or the applicable additional terms // Win32 #if defined(WIN32) || defined(_WIN32) -#define _alloca16( x ) ((void *)((((uintptr_t)_alloca( (x)+15 )) + 15) & ~15)) +#ifdef __MINGW32__ + #undef _alloca // in mingw _alloca is a #define + #define _alloca16( x ) ( (assert((x)= 1.28 + #define _alloca16( x ) ( ({assert((x) #endif -#if defined(__MINGW32__) - #include -#endif #include #include #include @@ -200,6 +250,18 @@ If you have questions concerning this license or the applicable additional terms #undef FindText // stupid namespace poluting Microsoft monkeys #endif +// Apple legacy +#ifdef __APPLE__ +#include +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +#if __MAC_OS_X_VERSION_MIN_REQUIRED == 1040 +#define OSX_TIGER +#elif __MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#define OSX_LEOPARD +#endif +#endif +#endif + #define ID_TIME_T time_t typedef unsigned char byte; // 8 bits From 0aec4475c7107b52af134dedb597251c59ecf6a6 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Mon, 18 Mar 2024 21:13:51 +0100 Subject: [PATCH 14/17] merge sys_public.h changes for gamepad support not sure if any of this is relevant for mods, but shouldn't hurt.. --- sys/sys_public.h | 65 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/sys/sys_public.h b/sys/sys_public.h index b1d68e2..8d5116f 100644 --- a/sys/sys_public.h +++ b/sys/sys_public.h @@ -44,12 +44,12 @@ typedef enum { } cpuidSimd_t; typedef enum { - AXIS_SIDE, - AXIS_FORWARD, - AXIS_UP, - AXIS_ROLL, - AXIS_YAW, - AXIS_PITCH, + AXIS_LEFT_X, + AXIS_LEFT_Y, + AXIS_RIGHT_X, + AXIS_RIGHT_Y, + AXIS_LEFT_TRIG, + AXIS_RIGHT_TRIG, MAX_JOYSTICK_AXIS } joystickAxis_t; @@ -57,9 +57,9 @@ typedef enum { SE_NONE, // evTime is still valid SE_KEY, // evValue is a key code, evValue2 is the down flag SE_CHAR, // evValue is an ascii char - SE_MOUSE, // evValue and evValue2 are reletive signed x / y moves + SE_MOUSE, // evValue and evValue2 are relative signed x / y moves SE_MOUSE_ABS, // evValue and evValue2 are absolute x / y coordinates in the window - SE_JOYSTICK_AXIS, // evValue is an axis number and evValue2 is the current state (-127 to 127) + SE_JOYSTICK, // evValue is an axis number and evValue2 is the current state (-127 to 127) SE_CONSOLE // evPtr is a char*, from typing something at a non-game console } sysEventType_t; @@ -77,10 +77,52 @@ typedef enum { M_DELTAZ } sys_mEvents; +typedef enum { + J_ACTION_FIRST, + // these names are similar to the SDL3 SDL_GamepadButton names + J_BTN_SOUTH = J_ACTION_FIRST, // bottom face button, like Xbox A + J_BTN_EAST, // right face button, like Xbox B + J_BTN_WEST, // left face button, like Xbox X + J_BTN_NORTH, // top face button, like Xbox Y + J_BTN_BACK, + J_BTN_GUIDE, // Note: this one should probably not be used? + J_BTN_START, + J_BTN_LSTICK, // press left stick + J_BTN_RSTICK, // press right stick + J_BTN_LSHOULDER, + J_BTN_RSHOULDER, + + J_DPAD_UP, + J_DPAD_DOWN, + J_DPAD_LEFT, + J_DPAD_RIGHT, + + J_BTN_MISC1, // Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button) + J_BTN_RPADDLE1, // Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1) + J_BTN_LPADDLE1, // Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3) + J_BTN_RPADDLE2, // Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2) + J_BTN_LPADDLE2, // Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4) + + J_ACTION_MAX = J_BTN_LPADDLE2, + // leaving some space here for about 12 additional J_ACTIONs, if needed + + J_AXIS_MIN = 32, + J_AXIS_LEFT_X = J_AXIS_MIN + AXIS_LEFT_X, + J_AXIS_LEFT_Y = J_AXIS_MIN + AXIS_LEFT_Y, + J_AXIS_RIGHT_X = J_AXIS_MIN + AXIS_RIGHT_X, + J_AXIS_RIGHT_Y = J_AXIS_MIN + AXIS_RIGHT_Y, + J_AXIS_LEFT_TRIG = J_AXIS_MIN + AXIS_LEFT_TRIG, + J_AXIS_RIGHT_TRIG = J_AXIS_MIN + AXIS_RIGHT_TRIG, + + J_AXIS_MAX = J_AXIS_MIN + MAX_JOYSTICK_AXIS - 1, + + MAX_JOY_EVENT +} sys_jEvents; + struct sysEvent_t { sysEventType_t evType; - int evValue; - int evValue2; + int evValue; // for keys: K_* or ASCII code; for joystick: axis; for mouse: mouseX + int evValue2; // for keys: 0/1 for up/down; for axis: value; for mouse: mouseY int evPtrLength; // bytes of data pointed to by evPtr, for journaling void * evPtr; // this must be manually freed if not NULL }; @@ -102,6 +144,7 @@ void Sys_Quit( void ); // note that this isn't journaled... char * Sys_GetClipboardData( void ); +void Sys_FreeClipboardData( char* data ); void Sys_SetClipboardData( const char *string ); // will go to the various text consoles @@ -296,7 +339,7 @@ typedef int (*xthread_t)( void * ); typedef struct { const char *name; SDL_Thread *threadHandle; - unsigned int threadId; + unsigned long threadId; } xthreadInfo; void Sys_CreateThread( xthread_t function, void *parms, xthreadInfo &info, const char *name ); From b3c1ddd5d789d91f6b034f15586f165543e55c37 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 19 Mar 2024 01:26:35 +0100 Subject: [PATCH 15/17] CMake: Add GCC/clang-specific options: ASAN, FORCE_COLORED_OUTPUT -DASAN=ON enables the Address Sanitizer (ASan), if supported -DFORCE_COLORED_OUTPUT=ON forces GCC or Clang to use colors in their messages, useful when building with ninja Both options default to OFF (though when building with make in a suitable terminal, GCC and clang automatically use colors) (no UBSAN, that requires hardlinking the game with the executable, which is not possible in the SDK..) --- CMakeLists.txt | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1079c1..414cf77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,11 @@ set(D3XP_DEFS "GAME_DLL;_D3XP;CTF" CACHE STRING "Compiler definitions for the mo option(ONATIVE "Optimize for the host CPU" OFF) +if(NOT MSVC) # GCC/clang or compatible, hopefully + option(FORCE_COLORED_OUTPUT "Always produce ANSI-colored compiler warnings/errors (GCC/Clang only; esp. useful with ninja)." OFF) + option(ASAN "Enable GCC/Clang Adress Sanitizer (ASan)" OFF) # TODO: MSVC might also support this, somehow? +endif() + set(src_game_mod # add additional .cpp files of your mod in game/ # (that you added to the ones already existant in the SDK/in dhewm3) @@ -166,6 +171,14 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") add_compile_options(-march=pentium3) endif() + if(FORCE_COLORED_OUTPUT) + if(CMAKE_COMPILER_IS_GNUCC) + add_compile_options (-fdiagnostics-color=always) + elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + add_compile_options (-fcolor-diagnostics) + endif () + endif () + set(CMAKE_C_FLAGS_DEBUG "-g -D_DEBUG -O0") set(CMAKE_C_FLAGS_DEBUGALL "-g -ggdb -D_DEBUG") set(CMAKE_C_FLAGS_PROFILE "-g -ggdb -D_DEBUG -O1 -fno-omit-frame-pointer") @@ -181,6 +194,13 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") # (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100839) add_compile_options(-ffp-contract=off) + if(ASAN) + # if this doesn't work, ASan might not be available on your platform, don't set ASAN then.. + add_compile_options(-fsanitize=address) + # TODO: do we need to link against libasan or sth? or is it enough if dhewm3 executable does? + # set(ldflags ${ldflags} -fsanitize=address) + endif() + if(NOT AROS) CHECK_CXX_COMPILER_FLAG("-fvisibility=hidden" cxx_has_fvisibility) if(NOT cxx_has_fvisibility) @@ -193,7 +213,6 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") add_compile_options(-Wno-sign-compare) add_compile_options(-Wno-switch) add_compile_options(-Wno-strict-overflow) - add_compile_options(-Wno-format-security) if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) # ‘void* memset(void*, int, size_t)’ clearing an object of type ‘struct refSound_t’ with no trivial copy-assignment; use assignment or value-initialization instead From 34db181b409885823e371a3a45bb212fe5ea4a31 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 19 Mar 2024 01:38:57 +0100 Subject: [PATCH 16/17] Fix build with Visual Studio's builtin CMake support For some reason MSVCs integrated CMake doesn't set CMAKE_GENERATOR_PLATFORM so my CPU arch detection magic in CMakeLists.txt didn't work in that case.. Now (when using MSVC) the CPU architecture (D3_ARCH) is set in neo/sys/platform.h instead (NOTE: the sys/platform.h part was merged in "Sync sys/platform.h, incl. Workaround for MCST-LCC compiler"). --- CMakeLists.txt | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 414cf77..96e9040 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8 FATAL_ERROR) +cmake_minimum_required(VERSION 2.8...3.22 FATAL_ERROR) project(dhewm3sdk) option(BASE "Build the base (game/) game code" ON) @@ -80,21 +80,9 @@ if(NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL CMAKE_HOST_SYSTEM_PROCESSOR)) # special case: cross-compiling, here CMAKE_SYSTEM_PROCESSOR should be correct, hopefully # (just leave cpu at ${CMAKE_SYSTEM_PROCESSOR}) elseif(MSVC) - message(STATUS "CMAKE_GENERATOR_PLATFORM: ${CMAKE_GENERATOR_PLATFORM}") - if(CMAKE_GENERATOR_PLATFORM STREQUAL "Win32") - set(cpu "x86") - elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x64") - set(cpu "x86_64") - elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM") - # at least on RPi 32bit, gcc -dumpmachine outputs "arm-linux-gnueabihf", - # so we'll use "arm" there => use the same for 32bit ARM on MSVC - set(cpu "arm") - elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64") - set(cpu "arm64") - else() - message(FATAL_ERROR "Unknown Target CPU/platform ${CMAKE_GENERATOR_PLATFORM}") - endif() - message(STATUS " => CPU architecture extracted from that: \"${cpu}\"") + # because all this wasn't ugly enough, it turned out that, unlike standalone CMake, Visual Studio's + # integrated CMake doesn't set CMAKE_GENERATOR_PLATFORM, so I gave up on guessing the CPU arch here + # and moved the CPU detection to MSVC-specific code in neo/sys/platform.h else() # not MSVC and not cross-compiling, assume GCC or clang (-compatible), seems to work for MinGW as well execute_process(COMMAND ${CMAKE_C_COMPILER} "-dumpmachine" RESULT_VARIABLE cc_dumpmachine_res @@ -132,8 +120,6 @@ elseif(cpu MATCHES "[aA][rR][mM].*") # some kind of arm.. endif() endif() -add_definitions(-DD3_ARCH="${cpu}" -DD3_SIZEOFPTR=${CMAKE_SIZEOF_VOID_P}) - # target os if(APPLE) set(os "macosx") @@ -141,14 +127,22 @@ else() string(TOLOWER "${CMAKE_SYSTEM_NAME}" os) endif() -add_definitions(-DD3_OSTYPE="${os}") +add_definitions(-DD3_OSTYPE="${os}" -DD3_SIZEOFPTR=${CMAKE_SIZEOF_VOID_P}) -message(STATUS "Setting -DD3_ARCH=\"${cpu}\" -DD3_SIZEOFPTR=${CMAKE_SIZEOF_VOID_P} -DD3_OSTYPE=\"${os}\" ") +if(MSVC) + # for MSVC D3_ARCH is set in code (in neo/sys/platform.h) + message(STATUS "Setting -DD3_SIZEOFPTR=${CMAKE_SIZEOF_VOID_P} -DD3_OSTYPE=\"${os}\" - NOT setting D3_ARCH, because we're targeting MSVC (VisualC++)") + # make sure ${cpu} isn't (cant't be) used by CMake when building with MSVC + unset(cpu) +else() + add_definitions(-DD3_ARCH="${cpu}") + message(STATUS "Setting -DD3_ARCH=\"${cpu}\" -DD3_SIZEOFPTR=${CMAKE_SIZEOF_VOID_P} -DD3_OSTYPE=\"${os}\" ") -if(cpu MATCHES ".*64.*" AND NOT CMAKE_SIZEOF_VOID_P EQUAL 8) - # tough luck if some CPU architecture has "64" in its name but uses 32bit pointers - message(SEND_ERROR "CMake thinks sizeof(void*) == 4, but the target CPU looks like a 64bit CPU!") - message(FATAL_ERROR "If you're building in a 32bit chroot on a 64bit host, switch to it with 'linux32 chroot' or at least call cmake with linux32 (or your OSs equivalent)!") + if(cpu MATCHES ".*64.*" AND NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + # tough luck if some CPU architecture has "64" in its name but uses 32bit pointers + message(SEND_ERROR "CMake thinks sizeof(void*) == 4, but the target CPU ${cpu} looks like a 64bit CPU!") + message(FATAL_ERROR "If you're building in a 32bit chroot on a 64bit host, switch to it with 'linux32 chroot' or at least call cmake with linux32 (or your OSs equivalent)!") + endif() endif() # build type @@ -312,7 +306,9 @@ configure_file( "${CMAKE_BINARY_DIR}/config.h" ) +if(NOT MSVC) message(STATUS "Building ${CMAKE_BUILD_TYPE} for ${os}-${cpu}") +endif() if(NOT APPLE AND NOT WIN32) message(STATUS "The install target will use the following directories:") From 94b42895270a03d0fa8841b10f171a0d6c80aee2 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 19 Mar 2024 01:53:53 +0100 Subject: [PATCH 17/17] CMake: Detect all variations of the clang compiler (hopefully) According to https://cmake.org/cmake/help/v3.26/variable/CMAKE_LANG_COMPILER_ID.html there's at least "Clang" (plain LLVM clang), "AppleClang", "ARMClang", "FujitsuClang", "XLClang" and "IBMClang" (both of which are variations of the clang/llvm-based IBM XL compiler). This should detect all of them (I hope they all behave close enough to normal clang to work..) There's also "IntelLLVM", but I have no idea if that's based on Clang or does its own thing based on LLVM.. I also doubt dhewm3 will ever be built with any other clang-derivate than "Clang" and "AppleClang" :-p fixes #510 --- CMakeLists.txt | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 96e9040..f95fc93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,8 +154,25 @@ endif() include(CheckCXXCompilerFlag) include(TestBigEndian) +set(D3_COMPILER_IS_CLANG FALSE) +set(D3_COMPILER_IS_GCC_OR_CLANG FALSE) + +if(NOT MSVC) + # check if this is some kind of clang (Clang, AppleClang, whatever) + # (convert compiler ID to lowercase so we match Clang, clang, AppleClang etc, regardless of case) + string(TOLOWER ${CMAKE_CXX_COMPILER_ID} compiler_id_lower) + if(compiler_id_lower MATCHES ".*clang.*") + message(STATUS "Compiler \"${CMAKE_CXX_COMPILER_ID}\" detected as some kind of clang") + set(D3_COMPILER_IS_CLANG TRUE) + set(D3_COMPILER_IS_GCC_OR_CLANG TRUE) + elseif(CMAKE_COMPILER_IS_GNUCC) + set(D3_COMPILER_IS_GCC_OR_CLANG TRUE) + endif() + unset(compiler_id_lower) +endif() # NOT MSVC + # compiler specific flags -if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") +if(D3_COMPILER_IS_GCC_OR_CLANG) add_compile_options(-pipe) add_compile_options(-Wall) @@ -168,7 +185,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") if(FORCE_COLORED_OUTPUT) if(CMAKE_COMPILER_IS_GNUCC) add_compile_options (-fdiagnostics-color=always) - elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + elseif (D3_COMPILER_IS_CLANG) add_compile_options (-fcolor-diagnostics) endif () endif () @@ -567,7 +584,7 @@ if (AROS) set(AROS_ARCH ${CMAKE_SYSTEM_PROCESSOR}) endif() else() - if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT MINGW) + if(D3_COMPILER_IS_GCC_OR_CLANG AND NOT MINGW) set_target_properties(idlib PROPERTIES COMPILE_FLAGS "-fPIC") endif() endif()