diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a68ffc..0bb384c 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) @@ -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) @@ -75,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 @@ -127,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") @@ -136,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 @@ -155,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) @@ -166,6 +182,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 (D3_COMPILER_IS_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 +205,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 +224,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 @@ -293,7 +323,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:") @@ -563,7 +595,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() 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/Entity.cpp b/d3xp/Entity.cpp index 0e87a6b..bc8ef0f 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/d3xp/Game_local.cpp b/d3xp/Game_local.cpp index c5a657b..2a267ee 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/Player.cpp b/d3xp/Player.cpp index 19a297b..d1ac294 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/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/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/d3xp/ai/AI_pathing.cpp b/d3xp/ai/AI_pathing.cpp index 4b043dc..a57a24e 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; @@ -1338,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/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/d3xp/gamesys/SysCmds.cpp b/d3xp/gamesys/SysCmds.cpp index bcdcfbd..8b812d5 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/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/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/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/Entity.cpp b/game/Entity.cpp index 0a2531d..17cf0f6 100644 --- a/game/Entity.cpp +++ b/game/Entity.cpp @@ -4237,6 +4237,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/Game_local.cpp b/game/Game_local.cpp index d2cef5b..885f420 100644 --- a/game/Game_local.cpp +++ b/game/Game_local.cpp @@ -1186,7 +1186,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 47c56b6..8768afb 100644 --- a/game/Game_network.cpp +++ b/game/Game_network.cpp @@ -733,7 +733,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/Moveable.cpp b/game/Moveable.cpp index 8ed263d..77c9fb5 100644 --- a/game/Moveable.cpp +++ b/game/Moveable.cpp @@ -987,6 +987,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/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/Player.cpp b/game/Player.cpp index a56ec76..48ce68d 100644 --- a/game/Player.cpp +++ b/game/Player.cpp @@ -5153,6 +5153,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/Projectile.cpp b/game/Projectile.cpp index 2e085bb..437c885 100644 --- a/game/Projectile.cpp +++ b/game/Projectile.cpp @@ -161,6 +161,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/Pvs.cpp b/game/Pvs.cpp index 8db643f..0cc7499 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/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 ) { diff --git a/game/Weapon.cpp b/game/Weapon.cpp index de786f0..4b13312 100644 --- a/game/Weapon.cpp +++ b/game/Weapon.cpp @@ -458,12 +458,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 ); @@ -521,6 +530,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 ); diff --git a/game/ai/AI_pathing.cpp b/game/ai/AI_pathing.cpp index 9c961a9..57f38eb 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; @@ -1341,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/anim/Anim_Blend.cpp b/game/anim/Anim_Blend.cpp index dfed202..c41d719 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(); } diff --git a/game/gamesys/SysCmds.cpp b/game/gamesys/SysCmds.cpp index 1e83b03..8df362b 100644 --- a/game/gamesys/SysCmds.cpp +++ b/game/gamesys/SysCmds.cpp @@ -1294,7 +1294,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 ) ); } /* @@ -1897,7 +1897,7 @@ static void PrintFloat( float f ) { buf[i] = ' '; } buf[i] = '\0'; - gameLocal.Printf( buf ); + gameLocal.Printf( "%s", buf ); } /* diff --git a/game/gamesys/SysCvar.cpp b/game/gamesys/SysCvar.cpp index 44cbd59..50a9039 100644 --- a/game/gamesys/SysCvar.cpp +++ b/game/gamesys/SysCvar.cpp @@ -232,7 +232,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/script/Script_Thread.cpp b/game/script/Script_Thread.cpp index fb83fc4..e547a6f 100644 --- a/game/script/Script_Thread.cpp +++ b/game/script/Script_Thread.cpp @@ -839,7 +839,7 @@ void idThread::Error( const char *fmt, ... ) const { vsprintf( text, fmt, argptr ); va_end( argptr ); - interpreter.Error( text ); + interpreter.Error( "%s", text ); } /* @@ -855,7 +855,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/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/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 { diff --git a/idlib/Parser.cpp b/idlib/Parser.cpp index 86a57d3..dedf5cc 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 ); } } @@ -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; 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/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.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(" "); } 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; 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 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 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 );