From 9790f41789f3564d8bfa7c1149c9310a32010de1 Mon Sep 17 00:00:00 2001 From: slipher Date: Tue, 22 Oct 2024 21:49:43 -0500 Subject: [PATCH 01/66] Start for-0.56.0/sync branch --- src/common/IPC/Common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/IPC/Common.h b/src/common/IPC/Common.h index 818fe807f2..7041b54c2f 100644 --- a/src/common/IPC/Common.h +++ b/src/common/IPC/Common.h @@ -81,7 +81,7 @@ namespace IPC { // This should be manually set to true when starting a 'for-X.Y.Z/sync' branch. // This should be set to false by update-version-number.py when a (major) release is created. - constexpr bool DAEMON_HAS_COMPATIBILITY_BREAKING_SYSCALL_CHANGES = false; + constexpr bool DAEMON_HAS_COMPATIBILITY_BREAKING_SYSCALL_CHANGES = true; /* * The messages sent between the VM and the engine are defined by a numerical From 212b4e1e7dd04d65bd39b193c03faad4bd421a80 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 10 Nov 2024 02:51:39 +0300 Subject: [PATCH 02/66] NUKE unused IPC calls --- src/engine/client/cg_msgdef.h | 30 +------------------ src/engine/client/cl_cgame.cpp | 41 -------------------------- src/engine/qcommon/cmd.cpp | 12 -------- src/engine/qcommon/qcommon.h | 2 -- src/shared/client/cg_api.cpp | 54 ---------------------------------- src/shared/client/cg_api.h | 5 ---- 6 files changed, 1 insertion(+), 143 deletions(-) diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 37e0c8ec37..2f62dcda66 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -132,16 +132,13 @@ enum cgameImport_t // Misc CG_SENDCLIENTCOMMAND, CG_UPDATESCREEN, - CG_CM_MARKFRAGMENTS, CG_CM_BATCHMARKFRAGMENTS, CG_GETCURRENTSNAPSHOTNUMBER, CG_GETSNAPSHOT, CG_GETCURRENTCMDNUMBER, CG_GETUSERCMD, CG_SETUSERCMDVALUE, - CG_GET_ENTITY_TOKEN, CG_REGISTER_BUTTON_COMMANDS, - CG_QUOTESTRING, CG_NOTIFY_TEAMCHANGE, CG_PREPAREKEYUP, @@ -167,7 +164,6 @@ enum cgameImport_t CG_R_GETSHADERNAMEFROMHANDLE, CG_R_SCISSOR_ENABLE, CG_R_SCISSOR_SET, - CG_R_INPVVS, CG_R_LOADWORLDMAP, CG_R_REGISTERMODEL, CG_R_REGISTERSKIN, @@ -191,7 +187,6 @@ enum cgameImport_t CG_R_MODELBOUNDS, CG_R_LERPTAG, CG_R_REMAP_SHADER, - CG_R_INPVS, CG_R_BATCHINPVS, CG_R_LIGHTFORPOINT, CG_R_REGISTERANIMATION, @@ -244,11 +239,7 @@ using SendClientCommandMsg = IPC::SyncMessage< using UpdateScreenMsg = IPC::SyncMessage< IPC::Message> >; -// TODO can move to VM too ? -using CMMarkFragmentsMsg = IPC::SyncMessage< - IPC::Message, std::vector>, std::array, int, int>, - IPC::Reply>, std::vector> ->; +// TODO can move to VM too? using CMBatchMarkFragments = IPC::SyncMessage< IPC::Message< IPC::Id, @@ -276,17 +267,7 @@ using GetUserCmdMsg = IPC::SyncMessage< IPC::Reply >; using SetUserCmdValueMsg = IPC::Message, int, int, float>; -// TODO what? -using CgGetEntityTokenMsg = IPC::SyncMessage< - IPC::Message, int>, - IPC::Reply ->; using RegisterButtonCommandsMsg = IPC::Message, std::string>; -// TODO using Command.h for that ? -using QuoteStringMsg = IPC::SyncMessage< - IPC::Message, int, std::string>, - IPC::Reply ->; using NotifyTeamChangeMsg = IPC::SyncMessage< IPC::Message, int> >; @@ -326,11 +307,6 @@ namespace Render { IPC::Message, int>, IPC::Reply >; - // TODO not a renderer call, handle in CM in the VM? - using InPVVSMsg = IPC::SyncMessage< - IPC::Message, std::array, std::array>, - IPC::Reply - >; // TODO is it really async? using LoadWorldMapMsg = IPC::Message, std::string>; using RegisterModelMsg = IPC::SyncMessage< @@ -355,10 +331,6 @@ namespace Render { >; using RemapShaderMsg = IPC::Message, std::string, std::string, std::string>; // TODO not a renderer call, handle in CM in the VM? - using InPVSMsg = IPC::SyncMessage< - IPC::Message, std::array, std::array>, - IPC::Reply - >; using BatchInPVSMsg = IPC::SyncMessage< IPC::Message, diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 23f9325064..5e157ddb90 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1091,17 +1091,6 @@ void CGameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& cha }); break; - case CG_CM_MARKFRAGMENTS: - // TODO wow this is very ugly and expensive, find something better? - // plus we have a lot of const casts for the vector buffers - IPC::HandleMsg(channel, std::move(reader), [this] (std::vector> points, std::array projection, int maxPoints, int maxFragments, std::vector>& pointBuffer, std::vector& fragmentBuffer) { - pointBuffer.resize(maxPoints); - fragmentBuffer.resize(maxFragments); - int numFragments = re.MarkFragments(points.size(), (vec3_t*)points.data(), projection.data(), maxPoints, (float*) pointBuffer.data(), maxFragments, fragmentBuffer.data()); - fragmentBuffer.resize(numFragments); - }); - break; - case CG_CM_BATCHMARKFRAGMENTS: IPC::HandleMsg(channel, std::move(reader), [this] ( unsigned maxPoints, @@ -1174,30 +1163,12 @@ void CGameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& cha }); break; - case CG_GET_ENTITY_TOKEN: - IPC::HandleMsg(channel, std::move(reader), [this] (int len, bool& res, std::string& token) { - std::unique_ptr buffer(new char[len]); - buffer[0] = '\0'; - res = re.GetEntityToken(buffer.get(), len); - token.assign(buffer.get()); - }); - break; - case CG_REGISTER_BUTTON_COMMANDS: IPC::HandleMsg(channel, std::move(reader), [this] (const std::string& commands) { CL_RegisterButtonCommands(commands.c_str()); }); break; - case CG_QUOTESTRING: - IPC::HandleMsg(channel, std::move(reader), [this] (int len, const std::string& input, std::string& output) { - std::unique_ptr buffer(new char[len]); - buffer[0] = '\0'; - Cmd_QuoteStringBuffer(input.c_str(), buffer.get(), len); - output.assign(buffer.get()); - }); - break; - case CG_NOTIFY_TEAMCHANGE: IPC::HandleMsg(channel, std::move(reader), [this] (int team) { CL_OnTeamChanged(team); @@ -1232,12 +1203,6 @@ void CGameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& cha }); break; - case CG_R_INPVVS: - IPC::HandleMsg(channel, std::move(reader), [this] (const std::array& p1, const std::array& p2, bool& res) { - res = re.inPVVS(p1.data(), p2.data()); - }); - break; - case CG_R_LOADWORLDMAP: IPC::HandleMsg(channel, std::move(reader), [this] (const std::string& mapName) { re.SetWorldVisData(CM_ClusterPVS(-1)); @@ -1281,12 +1246,6 @@ void CGameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& cha }); break; - case CG_R_INPVS: - IPC::HandleMsg(channel, std::move(reader), [this] (const std::array& p1, const std::array& p2, bool& res) { - res = re.inPVS(p1.data(), p2.data()); - }); - break; - case CG_R_BATCHINPVS: IPC::HandleMsg(channel, std::move(reader), [this] ( const std::array& origin, diff --git a/src/engine/qcommon/cmd.cpp b/src/engine/qcommon/cmd.cpp index d9b55aa1b2..ebae403dcf 100644 --- a/src/engine/qcommon/cmd.cpp +++ b/src/engine/qcommon/cmd.cpp @@ -398,18 +398,6 @@ const char *Cmd_QuoteString( const char *in ) return EscapeString( in, true ); } -/* -============ -Cmd_QuoteStringBuffer - -Cmd_QuoteString for VM usage -============ -*/ -void Cmd_QuoteStringBuffer( const char *in, char *buffer, int size ) -{ - Q_strncpyz( buffer, Cmd_QuoteString( in ), size ); -} - /* =================== Cmd_UnquoteString diff --git a/src/engine/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index 1dbdf3e0e7..c5df5d5740 100644 --- a/src/engine/qcommon/qcommon.h +++ b/src/engine/qcommon/qcommon.h @@ -322,8 +322,6 @@ char *Cmd_ArgsFrom( int arg ); const char *Cmd_QuoteString( const char *in ); const char *Cmd_UnquoteString( const char *in ); -void Cmd_QuoteStringBuffer( const char *in, char *buffer, int size ); - // The functions that execute commands get their parameters with these // functions. Cmd_Argv () will return an empty string, not a nullptr // if arg >= argc, so string operations are always safe. diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index 1f1892df2c..eb647e5592 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -49,24 +49,6 @@ void trap_UpdateScreen() VM::SendMsg(); } -int trap_CM_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) -{ - if (!numPoints) return 0; - - std::vector> mypoints(numPoints); - std::array myproj; - memcpy(mypoints.data(), points, sizeof(float) * 3 * numPoints); - VectorCopy(projection, myproj); - - std::vector> mypointBuffer; - std::vector myfragmentBuffer; - VM::SendMsg(mypoints, myproj, maxPoints, maxFragments, mypointBuffer, myfragmentBuffer); - - memcpy(pointBuffer, mypointBuffer.data(), sizeof(float) * 3 * maxPoints); - std::copy(myfragmentBuffer.begin(), myfragmentBuffer.end(), fragmentBuffer); - return myfragmentBuffer.size(); -} - void trap_CM_BatchMarkFragments( unsigned maxPoints, //per mark unsigned maxFragments, //per mark @@ -135,27 +117,11 @@ void trap_SetUserCmdValue( int stateValue, int flags, float sensitivityScale ) VM::SendMsg(stateValue, flags, sensitivityScale); } -bool trap_GetEntityToken( char *buffer, int bufferSize ) -{ - bool res; - std::string token; - VM::SendMsg(bufferSize, res, token); - Q_strncpyz(buffer, token.c_str(), bufferSize); - return res; -} - void trap_RegisterButtonCommands( const char *cmds ) { VM::SendMsg(cmds); } -void trap_QuoteString( const char *str, char *buffer, int size ) -{ - std::string quoted; - VM::SendMsg(size, str, quoted); - Q_strncpyz(buffer, quoted.c_str(), size); -} - void trap_notify_onTeamChange( int newTeam ) { VM::SendMsg(newTeam); @@ -291,16 +257,6 @@ void trap_R_ScissorSet( int x, int y, int w, int h ) cmdBuffer.SendMsg(x, y, w, h); } -bool trap_R_inPVVS( const vec3_t p1, const vec3_t p2 ) -{ - bool res; - std::array myp1, myp2; - VectorCopy(p1, myp1); - VectorCopy(p2, myp2); - VM::SendMsg(myp1, myp2, res); - return res; -} - void trap_R_LoadWorldMap( const char *mapname ) { VM::SendMsg(mapname); @@ -459,16 +415,6 @@ void trap_R_RemapShader( const char *oldShader, const char *newShader, const cha VM::SendMsg(oldShader, newShader, timeOffset); } -bool trap_R_inPVS( const vec3_t p1, const vec3_t p2 ) -{ - bool res; - std::array myp1, myp2; - VectorCopy(p1, myp1); - VectorCopy(p2, myp2); - VM::SendMsg(myp1, myp2, res); - return res; -} - std::vector trap_R_BatchInPVS( const vec3_t origin, const std::vector>& posEntities ) diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index 6146d28ad7..6f1e616643 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -43,7 +43,6 @@ extern IPC::CommandBufferClient cmdBuffer; void trap_SendClientCommand( const char *s ); void trap_UpdateScreen(); -int trap_CM_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ); void trap_CM_BatchMarkFragments( unsigned maxPoints, @@ -101,16 +100,13 @@ std::vector trap_Key_KeysDown( const std::vector& keys ); void trap_SetMouseMode( MouseMode mode ); void trap_S_StopBackgroundTrack(); void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ); -bool trap_GetEntityToken( char *buffer, int bufferSize ); std::vector> trap_Key_GetKeysForBinds(int team, const std::vector& binds); int trap_Key_GetCharForScancode( int scancode ); -bool trap_R_inPVS( const vec3_t p1, const vec3_t p2 ); std::vector trap_R_BatchInPVS( const vec3_t origin, const std::vector>& posEntities ); -bool trap_R_inPVVS( const vec3_t p1, const vec3_t p2 ); int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); qhandle_t trap_R_RegisterAnimation( const char *name ); int trap_R_BuildSkeleton( refSkeleton_t *skel, qhandle_t anim, int startFrame, int endFrame, float frac, bool clearOrigin ); @@ -119,7 +115,6 @@ int trap_R_BoneIndex( qhandle_t hModel, const char *boneName ); int trap_R_AnimNumFrames( qhandle_t hAnim ); int trap_R_AnimFrameRate( qhandle_t hAnim ); void trap_RegisterButtonCommands( const char *cmds ); -void trap_QuoteString( const char *, char*, int ); void trap_notify_onTeamChange( int newTeam ); qhandle_t trap_RegisterVisTest(); void trap_AddVisTestToScene( qhandle_t hTest, const vec3_t pos, From 5b8cb6d2bedbd3cfa295187b19c9f5b59e87333d Mon Sep 17 00:00:00 2001 From: slipher Date: Tue, 4 Jun 2024 13:41:55 -0500 Subject: [PATCH 03/66] Add trap_GetPings; remove ping from playerstate --- src/engine/qcommon/q_shared.h | 1 - src/engine/server/sg_msgdef.h | 5 +++++ src/engine/server/sv_main.cpp | 4 ---- src/engine/server/sv_sgame.cpp | 10 ++++++++++ src/shared/server/sg_api.cpp | 9 +++++++++ src/shared/server/sg_api.h | 1 + 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index e5e6a2b1f4..bb3770cd79 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -1928,7 +1928,6 @@ union OpaquePlayerState { struct { // These fields must be identical to ones at the start of playerState_t vec3_t origin; - int ping; // shouldn't even be here? int persistant[16]; int viewheight; int clientNum; diff --git a/src/engine/server/sg_msgdef.h b/src/engine/server/sg_msgdef.h index 73b2239a37..a5b45d8d15 100644 --- a/src/engine/server/sg_msgdef.h +++ b/src/engine/server/sg_msgdef.h @@ -45,6 +45,7 @@ enum gameImport_t G_GEN_FINGERPRINT, G_GET_PLAYER_PUBKEY, G_GET_TIME_STRING, + G_GET_PINGS, BOT_ALLOCATE_CLIENT, BOT_FREE_CLIENT, @@ -102,6 +103,10 @@ using GetTimeStringMsg = IPC::SyncMessage< IPC::Message, int, std::string, qtime_t>, IPC::Reply >; +using GetPingsMsg = IPC::SyncMessage< + IPC::Message>, + IPC::Reply> +>; using BotAllocateClientMsg = IPC::SyncMessage< IPC::Message>, diff --git a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp index 1fc7ec2096..e35f6da21c 100644 --- a/src/engine/server/sv_main.cpp +++ b/src/engine/server/sv_main.cpp @@ -1210,10 +1210,6 @@ void SV_CalcPings() cl->ping = 999; } } - - // let the game module know about the ping - OpaquePlayerState* ps = SV_GameClientNum( i ); - ps->ping = cl->ping; } } diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index 8e7eb5b596..9498b2fe15 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -564,6 +564,16 @@ void GameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& chan }); break; + case G_GET_PINGS: + IPC::HandleMsg(channel, std::move(reader), [this](std::vector& pings) { + int count = sv_maxclients->integer; + pings.resize(count); + for (int i = 0; i < count; i++) { + pings[i] = svs.clients[i].ping; + } + }); + break; + case BOT_ALLOCATE_CLIENT: IPC::HandleMsg(channel, std::move(reader), [this](int& output) { output = SV_BotAllocateClient(); diff --git a/src/shared/server/sg_api.cpp b/src/shared/server/sg_api.cpp index faf17a9af0..27768fe553 100644 --- a/src/shared/server/sg_api.cpp +++ b/src/shared/server/sg_api.cpp @@ -144,6 +144,15 @@ void trap_GetTimeString(char *buffer, int size, const char *format, const qtime_ Q_strncpyz(buffer, text.c_str(), size); } +// length of returned vector is sv_maxclients +std::vector trap_GetPings() +{ + std::vector pings; + VM::SendMsg(pings); + return pings; +} + + int trap_BotAllocateClient() { int res; diff --git a/src/shared/server/sg_api.h b/src/shared/server/sg_api.h index cd7a08be88..9042f19b7c 100644 --- a/src/shared/server/sg_api.h +++ b/src/shared/server/sg_api.h @@ -53,5 +53,6 @@ int trap_RSA_GenerateMessage( const char *public_key, char *clearte void trap_GenFingerprint( const char *pubkey, int size, char *buffer, int bufsize ); void trap_GetPlayerPubkey( int clientNum, char *pubkey, int size ); void trap_GetTimeString( char *buffer, int size, const char *format, const qtime_t *tm ); +std::vector trap_GetPings(); #endif From 47400a200c84c9054903b8e5707374f1b372286f Mon Sep 17 00:00:00 2001 From: slipher Date: Tue, 4 Jun 2024 14:37:12 -0500 Subject: [PATCH 04/66] Make shared memory player state pointers const --- src/engine/qcommon/msg.cpp | 19 +++++++++---------- src/engine/qcommon/qcommon.h | 4 ++-- src/engine/server/server.h | 10 +++++----- src/engine/server/sv_ccmds.cpp | 2 +- src/engine/server/sv_main.cpp | 2 +- src/engine/server/sv_sgame.cpp | 10 +++++----- src/engine/server/sv_snapshot.cpp | 2 +- 7 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/engine/qcommon/msg.cpp b/src/engine/qcommon/msg.cpp index c2a8308607..ed72b56b15 100644 --- a/src/engine/qcommon/msg.cpp +++ b/src/engine/qcommon/msg.cpp @@ -1336,10 +1336,10 @@ MSG_WriteDeltaPlayerstate ============= */ -void MSG_WriteDeltaPlayerstate( msg_t *msg, OpaquePlayerState *from, OpaquePlayerState *to ) +void MSG_WriteDeltaPlayerstate( + msg_t *msg, const OpaquePlayerState *from, const OpaquePlayerState *to ) { int lc; - int *fromF, *toF; float fullFloat; int trunc; int startBit, endBit; @@ -1383,8 +1383,8 @@ void MSG_WriteDeltaPlayerstate( msg_t *msg, OpaquePlayerState *from, OpaquePlaye for ( int i = 0; i < numFields; i++ ) { netField_t* field = &playerStateFields[i]; - fromF = ( int * )( ( byte * ) from + field->offset ); - toF = ( int * )( ( byte * ) to + field->offset ); + auto fromF = reinterpret_cast( reinterpret_cast( from ) + field->offset ); + auto toF = reinterpret_cast( reinterpret_cast( to ) + field->offset ); if (field->bits == STATS_GROUP_FIELD ? memcmp(fromF, toF, sizeof(int) * STATS_GROUP_NUM_STATS) @@ -1401,8 +1401,8 @@ void MSG_WriteDeltaPlayerstate( msg_t *msg, OpaquePlayerState *from, OpaquePlaye for ( int i = 0; i < lc; i++ ) { netField_t* field = &playerStateFields[i]; - fromF = ( int * )( ( byte * ) from + field->offset ); - toF = ( int * )( ( byte * ) to + field->offset ); + auto fromF = reinterpret_cast( reinterpret_cast( from ) + field->offset ); + auto toF = reinterpret_cast( reinterpret_cast( to ) + field->offset ); if (field->bits == STATS_GROUP_FIELD) { @@ -1486,12 +1486,11 @@ static void ReadStatsGroup(msg_t* msg, int* to, const netField_t& field) MSG_ReadDeltaPlayerstate =================== */ -void MSG_ReadDeltaPlayerstate( msg_t *msg, OpaquePlayerState *from, OpaquePlayerState *to ) +void MSG_ReadDeltaPlayerstate( msg_t *msg, const OpaquePlayerState *from, OpaquePlayerState *to ) { int lc; int startBit, endBit; int print; - int *fromF, *toF; int trunc; if (playerStateFields.empty()) @@ -1537,8 +1536,8 @@ void MSG_ReadDeltaPlayerstate( msg_t *msg, OpaquePlayerState *from, OpaquePlayer for ( int i = 0; i < lc; i++ ) { netField_t* field = &playerStateFields[i]; - fromF = ( int * )( ( byte * ) from + field->offset ); - toF = ( int * )( ( byte * ) to + field->offset ); + auto fromF = reinterpret_cast( reinterpret_cast( from ) + field->offset ); + auto toF = reinterpret_cast( reinterpret_cast( to ) + field->offset ); if ( !MSG_ReadBits( msg, 1 ) ) { diff --git a/src/engine/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index c5df5d5740..6e8a60a886 100644 --- a/src/engine/qcommon/qcommon.h +++ b/src/engine/qcommon/qcommon.h @@ -96,8 +96,8 @@ void MSG_WriteDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, void MSG_ReadDeltaEntity( msg_t *msg, const entityState_t *from, entityState_t *to, int number ); void MSG_InitNetcodeTables(NetcodeTable playerStateTable, int playerStateSize); -void MSG_WriteDeltaPlayerstate( msg_t *msg, OpaquePlayerState *from, OpaquePlayerState *to ); -void MSG_ReadDeltaPlayerstate( msg_t *msg, OpaquePlayerState *from, OpaquePlayerState *to ); +void MSG_WriteDeltaPlayerstate( msg_t *msg, const OpaquePlayerState *from, const OpaquePlayerState *to ); +void MSG_ReadDeltaPlayerstate( msg_t *msg, const OpaquePlayerState *from, OpaquePlayerState *to ); //============================================================================ diff --git a/src/engine/server/server.h b/src/engine/server/server.h index bed3e0b3db..e76c8148e4 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -82,12 +82,12 @@ struct server_t const char *entityParsePoint; // used during game VM init // the game virtual machine will update these on init and changes - sharedEntity_t *gentities; - int gentitySize; + byte *gentities; // points to the sgame's array of gentity_t + int gentitySize; // >= sizeof(sharedEntity_t) - game can have unlimited amount of private data int num_entities; // current number, <= MAX_GENTITIES - OpaquePlayerState *gameClients; - int gameClientSize; // will be > sizeof(playerState_t) due to game private data + const byte *gameClients; // points to the sgame's array of playerState_t in shared memory + int gameClientSize; // will be <= sizeof(OpaquePlayerState) int restartTime; int time; @@ -393,7 +393,7 @@ void SV_SendClientIdle( client_t *client ); // sv_sgame.c // sharedEntity_t *SV_GentityNum( int num ); -OpaquePlayerState *SV_GameClientNum( int num ); +const OpaquePlayerState *SV_GameClientNum( int num ); svEntity_t *SV_SvEntityForGentity( sharedEntity_t *gEnt ); void SV_InitGameProgs(); diff --git a/src/engine/server/sv_ccmds.cpp b/src/engine/server/sv_ccmds.cpp index e8f0be37a2..08b926f9ea 100644 --- a/src/engine/server/sv_ccmds.cpp +++ b/src/engine/server/sv_ccmds.cpp @@ -338,7 +338,7 @@ class StatusCmd: public Cmd::StaticCmd connection = "ERROR"; } } - OpaquePlayerState* ps = SV_GameClientNum( i ); + const OpaquePlayerState* ps = SV_GameClientNum( i ); const char *address = NET_AdrToString( cl.netchan.remoteAddress ); diff --git a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp index e35f6da21c..eb47db562e 100644 --- a/src/engine/server/sv_main.cpp +++ b/src/engine/server/sv_main.cpp @@ -496,7 +496,7 @@ static void SVC_Status( const netadr_t& from, const Cmd::Args& args ) if ( cl->state >= clientState_t::CS_CONNECTED ) { - OpaquePlayerState* ps = SV_GameClientNum( i ); + const OpaquePlayerState* ps = SV_GameClientNum( i ); status += Str::Format( "%i %i \"%s\"\n", ps->persistant[ PERS_SCORE ], cl->ping, cl->name ); } } diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index 9498b2fe15..7de233054b 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -60,10 +60,10 @@ sharedEntity_t *SV_GentityNum( int num ) Sys::Drop( "SV_GentityNum: bad num %d", num ); } - return ( sharedEntity_t * )( ( byte * ) sv.gentities + sv.gentitySize * ( num ) ); + return reinterpret_cast( sv.gentities + sv.gentitySize * num ); } -OpaquePlayerState *SV_GameClientNum( int num ) +const OpaquePlayerState *SV_GameClientNum( int num ) { if ( num < 0 || num >= sv_maxclients->integer || sv.gameClients == nullptr ) { @@ -194,12 +194,12 @@ void SV_LocateGameData( const IPC::SharedMemory& shmRegion, int numGEntities, in if ( int64_t(shmRegion.GetSize()) < int64_t(MAX_GENTITIES) * sizeofGEntity_t + int64_t(sv_maxclients->integer) * sizeofGameClient ) Sys::Drop( "SV_LocateGameData: Shared memory region too small" ); - char* base = static_cast(shmRegion.GetBase()); - sv.gentities = reinterpret_cast(base); + byte* base = static_cast(shmRegion.GetBase()); + sv.gentities = base; sv.gentitySize = sizeofGEntity_t; sv.num_entities = numGEntities; - sv.gameClients = reinterpret_cast(base + MAX_GENTITIES * size_t(sizeofGEntity_t)); + sv.gameClients = base + MAX_GENTITIES * size_t(sizeofGEntity_t); sv.gameClientSize = sizeofGameClient; } diff --git a/src/engine/server/sv_snapshot.cpp b/src/engine/server/sv_snapshot.cpp index 8063e7be7b..b0732dac57 100644 --- a/src/engine/server/sv_snapshot.cpp +++ b/src/engine/server/sv_snapshot.cpp @@ -690,7 +690,7 @@ static void SV_BuildClientSnapshot( client_t *client ) } // grab the current playerState_t - OpaquePlayerState* ps = SV_GameClientNum( client - svs.clients ); + const OpaquePlayerState* ps = SV_GameClientNum( client - svs.clients ); memcpy(&frame->ps, ps, sizeof(frame->ps)); // never send client's own entity, because it can From 39c289ef5e8712ca15c61982ff3fff27dd9a9234 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 26 Jan 2025 16:05:23 +0300 Subject: [PATCH 05/66] NUKE unsued MAX_DLIGHTS --- src/engine/renderer/tr_types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index e00a2cd016..73f96da3b9 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -52,7 +52,6 @@ using bool8_t = uint8_t; #define MAX_WEIGHTS 4 // GPU vertex skinning limit, never change this without rewriting many GLSL shaders // XreaL END -#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces #define MAX_ENTITIES MAX_REF_ENTITIES // RB: for compatibility // renderfx flags From 75ef91a33a41e1f857448f45b6102f6001bdbb3c Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 26 Jan 2025 16:10:07 +0300 Subject: [PATCH 06/66] NUKE unused RF_WRAP_FRAMES and RF_FORCENOLOD --- src/engine/renderer/tr_mesh.cpp | 15 +-------------- src/engine/renderer/tr_types.h | 5 +---- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/engine/renderer/tr_mesh.cpp b/src/engine/renderer/tr_mesh.cpp index 8aefcda50b..9168c488a3 100644 --- a/src/engine/renderer/tr_mesh.cpp +++ b/src/engine/renderer/tr_mesh.cpp @@ -262,21 +262,8 @@ void R_AddMDVSurfaces( trRefEntity_t *ent ) personalModel = ( ent->e.renderfx & RF_THIRD_PERSON ) && tr.viewParms.portalLevel == 0; - if ( ent->e.renderfx & RF_WRAP_FRAMES ) - { - ent->e.frame %= tr.currentModel->mdv[ 0 ]->numFrames; - ent->e.oldframe %= tr.currentModel->mdv[ 0 ]->numFrames; - } - // compute LOD - if ( ent->e.renderfx & RF_FORCENOLOD ) - { - lod = 0; - } - else - { - lod = R_ComputeLOD( ent ); - } + lod = R_ComputeLOD( ent ); // Validate the frames so there is no chance of a crash. // This will write directly into the entity structure, so diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 73f96da3b9..42d23962d2 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -65,10 +65,7 @@ using bool8_t = uint8_t; // for lighting. This allows entities to sink into the floor // with their origin going solid, and allows all parts of a // player to get the same lighting -#define RF_WRAP_FRAMES 0x000080 // mod the model frames by the maxframes to allow continuous -// animation without needing to know the frame count -#define RF_FORCENOLOD 0x000400 -#define RF_SWAPCULL 0x000800 // swap CT_FRONT_SIDED and CT_BACK_SIDED +#define RF_SWAPCULL 0x000040 // swap CT_FRONT_SIDED and CT_BACK_SIDED // refdef flags #define RDF_NOWORLDMODEL ( 1 << 0 ) // used for player configuration screen From f66d9d012f500f4be0dfd2a8255c119d4827ce7a Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 26 Jan 2025 16:11:42 +0300 Subject: [PATCH 07/66] NUKE unused RDF_NOSHADOWS, RDF_UNDERWATER, and RDF_DRAWINGSKY --- src/engine/renderer/tr_types.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 42d23962d2..d4a37e3e0d 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -69,19 +69,14 @@ using bool8_t = uint8_t; // refdef flags #define RDF_NOWORLDMODEL ( 1 << 0 ) // used for player configuration screen -#define RDF_NOSHADOWS ( 1 << 1 ) // force renderer to use faster lighting only path -#define RDF_HYPERSPACE ( 1 << 2 ) // teleportation effect +#define RDF_HYPERSPACE ( 1 << 1 ) // teleportation effect // Rafael -#define RDF_SKYBOXPORTAL ( 1 << 3 ) - -//----(SA) -#define RDF_UNDERWATER ( 1 << 4 ) // so the renderer knows to use underwater fog when the player is underwater -#define RDF_DRAWINGSKY ( 1 << 5 ) +#define RDF_SKYBOXPORTAL ( 1 << 2 ) // XreaL BEGIN -#define RDF_NOCUBEMAP ( 1 << 7 ) // RB: don't use cubemaps -#define RDF_NOBLOOM ( 1 << 8 ) // RB: disable bloom. useful for HUD models +#define RDF_NOCUBEMAP ( 1 << 3 ) // RB: don't use cubemaps +#define RDF_NOBLOOM ( 1 << 4 ) // RB: disable bloom. useful for HUD models // XreaL END #define MAX_ALTSHADERS 64 // alternative shaders ('when ') – selection controlled from cgame From c83ffe247d42b9dad4c2a1f574d2d6190037d6a1 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 9 Nov 2024 18:57:57 +0300 Subject: [PATCH 08/66] NUKE random dynamic light scaling --- src/engine/renderer/tr_backend.cpp | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index cad421577e..29983d06d9 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -5310,18 +5310,18 @@ const RenderCommand *GradientPicCommand::ExecuteSelf( ) const RB_SetupLights ============= */ -const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const +const RenderCommand *SetupLightsCommand::ExecuteSelf() const { - int numLights; GLenum bufferTarget = glConfig2.uniformBufferObjectAvailable ? GL_UNIFORM_BUFFER : GL_PIXEL_UNPACK_BUFFER; GLimp_LogComment( "--- SetupLightsCommand::ExecuteSelf ---\n" ); - if( (numLights = refdef.numLights) > 0 ) { + const int numLights = refdef.numLights; + if( numLights ) { shaderLight_t *buffer; glBindBuffer( bufferTarget, tr.dlightUBO ); - buffer = (shaderLight_t *)glMapBufferRange( bufferTarget, + buffer = (shaderLight_t *) glMapBufferRange( bufferTarget, 0, numLights * sizeof( shaderLight_t ), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT ); @@ -5334,20 +5334,20 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const VectorCopy( light->l.origin, buffer[i].center ); buffer[i].radius = light->l.radius; - VectorScale( light->l.color, 4.0f * light->l.scale, buffer[i].color ); + VectorScale( light->l.color, light->l.scale, buffer[i].color ); + buffer[i].type = Util::ordinal( light->l.rlType ); switch( light->l.rlType ) { - case refLightType_t::RL_PROJ: - VectorCopy( light->l.projTarget, - buffer[i].direction ); - buffer[i].angle = cosf( atan2f( VectorLength( light->l.projUp), VectorLength( light->l.projTarget ) ) ); - break; - case refLightType_t::RL_DIRECTIONAL: - VectorCopy( light->l.projTarget, - buffer[i].direction ); - break; - default: - break; + + case refLightType_t::RL_PROJ: + VectorCopy( light->l.projTarget, buffer[i].direction ); + buffer[i].angle = cosf( atan2f( VectorLength( light->l.projUp), VectorLength( light->l.projTarget ) ) ); + break; + case refLightType_t::RL_DIRECTIONAL: + VectorCopy( light->l.projTarget, buffer[i].direction ); + break; + default: + break; } } From 8f084c975d1df2f3e6277d2d39ba90e31bdace29 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 9 Nov 2024 18:58:21 +0300 Subject: [PATCH 09/66] NUKE r_lightScale This was a cheat cvar used for dynamic lights that have no intensity set, and set to 2.0 for absolutely no reason whatsoever. --- src/engine/renderer/tr_init.cpp | 2 -- src/engine/renderer/tr_local.h | 1 - src/engine/renderer/tr_scene.cpp | 2 +- src/engine/renderer/tr_types.h | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 1354bbc132..1d6a9058cc 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -219,7 +219,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Cvar::Range> r_forceAmbient( "r_forceAmbient", "Minimal light amount in lightGrid", Cvar::NONE, 0.125f, 0.0f, 0.3f ); Cvar::Cvar r_ambientScale( "r_ambientScale", "Scale lightGrid produced by ambientColor keyword by this much", Cvar::CHEAT, 1.0 ); - cvar_t *r_lightScale; cvar_t *r_debugSort; cvar_t *r_printShaders; @@ -1193,7 +1192,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_facePlaneCull = Cvar_Get( "r_facePlaneCull", "1", 0 ); Cvar::Latch( r_ambientScale ); - r_lightScale = Cvar_Get( "r_lightScale", "2", CVAR_CHEAT ); r_vboFaces = Cvar_Get( "r_vboFaces", "1", CVAR_CHEAT ); r_vboCurves = Cvar_Get( "r_vboCurves", "1", CVAR_CHEAT ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 3bf09cf9e7..b9db33523a 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2891,7 +2891,6 @@ enum class shaderProfilerRenderSubGroupsMode { extern Cvar::Range> r_forceAmbient; extern Cvar::Cvar r_ambientScale; - extern cvar_t *r_lightScale; extern Cvar::Cvar r_drawSky; // Controls whether sky should be drawn or cleared. extern Cvar::Range> r_realtimeLightingRenderer; diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index aa02565b4a..2dc5645b08 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -355,7 +355,7 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit void RE_AddDynamicLightToSceneQ3A( const vec3_t org, float radius, float r, float g, float b ) { - RE_AddDynamicLightToSceneET( org, radius, r_lightScale->value, r, g, b, 0, 0 ); + RE_AddDynamicLightToSceneET( org, radius, 1.0, r, g, b, 0, 0 ); } static void RE_RenderCubeProbeFace( const refdef_t* originalRefdef ) { diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index d4a37e3e0d..a8e2d2cf8a 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -234,7 +234,7 @@ struct refLight_t vec3_t center; vec3_t color; // range from 0.0 to 1.0, should be color normalized - float scale; // r_lightScale if not set + float scale; // omni-directional light specific float radius; From c2466d119e5c34a4ae8fd461da557621321f2828 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 9 Nov 2024 19:20:39 +0300 Subject: [PATCH 10/66] NUKE RE_AddDynamicLightToSceneQ3A(), rename RE_AddDynamicLightToSceneET() to RE_AddDynamicLightToScene() These were largely doing the same thing, use just one function instead. --- src/engine/client/cl_cgame.cpp | 6 +++--- src/engine/null/null_renderer.cpp | 5 ++--- src/engine/renderer/tr_init.cpp | 4 ++-- src/engine/renderer/tr_local.h | 3 +-- src/engine/renderer/tr_public.h | 5 ++--- src/engine/renderer/tr_scene.cpp | 7 +------ 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 5e157ddb90..6f8afc25e6 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1627,13 +1627,13 @@ void CGameVM::CmdBuffer::HandleCommandBufferSyscall(int major, int minor, Util:: case CG_R_ADDLIGHTTOSCENE: HandleMsg(std::move(reader), [this] (const std::array& point, float radius, float intensity, float r, float g, float b, int shader, int flags) { - re.AddLightToScene(point.data(), radius, intensity, r, g, b, shader, flags); + re.AddLightToScene(point.data(), radius, intensity, r, g, b, flags); }); break; case CG_R_ADDADDITIVELIGHTTOSCENE: - HandleMsg(std::move(reader), [this] (const std::array& point, float intensity, float r, float g, float b) { - re.AddAdditiveLightToScene(point.data(), intensity, r, g, b); + HandleMsg(std::move(reader), [this] (const std::array& point, float radius, float r, float g, float b) { + re.AddAdditiveLightToScene(point.data(), radius, 1.0, r, g, b, 0); }); break; diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index 9e4b6e24c0..fcdaf87ccf 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -86,8 +86,7 @@ int R_LightForPoint( vec3_t, vec3_t, vec3_t, vec3_t ) } void RE_AddPolyToScene( qhandle_t, int, const polyVert_t* ) { } void RE_AddPolysToScene( qhandle_t, int, const polyVert_t*, int ) { } -void RE_AddLightToScene( const vec3_t, float, float, float, float, float, qhandle_t, int ) { } -void RE_AddLightToSceneQ3A( const vec3_t, float, float, float, float ) { } +void RE_AddLightToScene( const vec3_t, float, float, float, float, float, int ) { } void RE_RenderScene( const refdef_t* ) { } void RE_SetColor( const Color::Color& ) { } void RE_SetClipRegion( const float* ) { } @@ -227,7 +226,7 @@ refexport_t *GetRefAPI( int, refimport_t* ) re.AddPolysToScene = RE_AddPolysToScene; // done. re.AddLightToScene = RE_AddLightToScene; - re.AddAdditiveLightToScene = RE_AddLightToSceneQ3A; + re.AddAdditiveLightToScene = RE_AddLightToScene; re.RenderScene = RE_RenderScene; diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 1d6a9058cc..b62fa93a85 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1654,8 +1654,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p re.AddPolysToScene = RE_AddPolysToScene; re.LightForPoint = R_LightForPoint; - re.AddLightToScene = RE_AddDynamicLightToSceneET; - re.AddAdditiveLightToScene = RE_AddDynamicLightToSceneQ3A; + re.AddLightToScene = RE_AddDynamicLightToScene; + re.AddAdditiveLightToScene = RE_AddDynamicLightToScene; re.RenderScene = RE_RenderScene; diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index b9db33523a..3ad48cbd7d 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -3690,8 +3690,7 @@ inline bool checkGLErrors() void RE_AddPolyToSceneET( qhandle_t hShader, int numVerts, const polyVert_t *verts ); void RE_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ); - void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensity, float r, float g, float b, qhandle_t hShader, int flags ); - void RE_AddDynamicLightToSceneQ3A( const vec3_t org, float intensity, float r, float g, float b ); + void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ); void RE_RenderScene( const refdef_t *fd ); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 038c069489..d5cb3313b3 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -200,10 +200,9 @@ struct refexport_t void ( *AddPolyToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts ); void ( *AddPolysToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ); - void ( *AddLightToScene )( const vec3_t org, float radius, float intensity, float r, float g, float b, - qhandle_t hShader, int flags ); + void ( *AddLightToScene )( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ); - void ( *AddAdditiveLightToScene )( const vec3_t org, float intensity, float r, float g, float b ); + void ( *AddAdditiveLightToScene )( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ); void ( *RenderScene )( const refdef_t *fd ); diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index 2dc5645b08..ba568cb82c 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -285,7 +285,7 @@ RE_AddDynamicLightToScene ydnar: modified dlight system to support separate radius and intensity ===================== */ -void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensity, float r, float g, float b, qhandle_t, int flags ) +void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ) { trRefLight_t *light; @@ -353,11 +353,6 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit light->l.scale = intensity; } -void RE_AddDynamicLightToSceneQ3A( const vec3_t org, float radius, float r, float g, float b ) -{ - RE_AddDynamicLightToSceneET( org, radius, 1.0, r, g, b, 0, 0 ); -} - static void RE_RenderCubeProbeFace( const refdef_t* originalRefdef ) { const size_t globalID = r_showCubeProbeFace.Get(); const size_t probeID = globalID / 6; From 2d50877ac0923daa7f057d1e6176cdf7f806666e Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 9 Nov 2024 19:26:01 +0300 Subject: [PATCH 11/66] NUKE trap_R_AddAdditiveLightToScene() This has largely the same functionality as trap_R_AddLightToScene(). --- src/engine/client/cg_msgdef.h | 2 -- src/engine/client/cl_cgame.cpp | 6 ------ src/engine/null/null_renderer.cpp | 1 - src/engine/renderer/tr_init.cpp | 1 - src/engine/renderer/tr_public.h | 2 -- src/shared/client/cg_api.cpp | 7 ------- src/shared/client/cg_api.h | 1 - 7 files changed, 20 deletions(-) diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 2f62dcda66..800dafcada 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -174,7 +174,6 @@ enum cgameImport_t CG_R_ADDPOLYTOSCENE, CG_R_ADDPOLYSTOSCENE, CG_R_ADDLIGHTTOSCENE, - CG_R_ADDADDITIVELIGHTTOSCENE, CG_R_RENDERSCENE, CG_R_ADD2DPOLYSINDEXED, CG_R_SETMATRIXTRANSFORM, @@ -388,7 +387,6 @@ namespace Render { using AddPolyToSceneMsg = IPC::Message, int, std::vector>; using AddPolysToSceneMsg = IPC::Message, int, std::vector, int, int>; using AddLightToSceneMsg = IPC::Message, std::array, float, float, float, float, float, int, int>; - using AddAdditiveLightToSceneMsg = IPC::Message, std::array, float, float, float, float>; using SetColorMsg = IPC::Message, Color::Color>; using SetClipRegionMsg = IPC::Message, std::array>; using ResetClipRegionMsg = IPC::Message>; diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 6f8afc25e6..973c29bc10 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1631,12 +1631,6 @@ void CGameVM::CmdBuffer::HandleCommandBufferSyscall(int major, int minor, Util:: }); break; - case CG_R_ADDADDITIVELIGHTTOSCENE: - HandleMsg(std::move(reader), [this] (const std::array& point, float radius, float r, float g, float b) { - re.AddAdditiveLightToScene(point.data(), radius, 1.0, r, g, b, 0); - }); - break; - case CG_R_SETCOLOR: HandleMsg(std::move(reader), [this] (const Color::Color& color) { re.SetColor(color); diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index fcdaf87ccf..2c03a5d507 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -226,7 +226,6 @@ refexport_t *GetRefAPI( int, refimport_t* ) re.AddPolysToScene = RE_AddPolysToScene; // done. re.AddLightToScene = RE_AddLightToScene; - re.AddAdditiveLightToScene = RE_AddLightToScene; re.RenderScene = RE_RenderScene; diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index b62fa93a85..4585331548 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1655,7 +1655,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p re.LightForPoint = R_LightForPoint; re.AddLightToScene = RE_AddDynamicLightToScene; - re.AddAdditiveLightToScene = RE_AddDynamicLightToScene; re.RenderScene = RE_RenderScene; diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index d5cb3313b3..1f384080f8 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -202,8 +202,6 @@ struct refexport_t void ( *AddLightToScene )( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ); - void ( *AddAdditiveLightToScene )( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ); - void ( *RenderScene )( const refdef_t *fd ); void ( *SetColor )( const Color::Color& rgba ); // nullptr = 1,1,1,1 diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index c0df4cca4a..75649f9a23 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -353,13 +353,6 @@ void trap_R_AddLightToScene( const vec3_t org, float radius, float intensity, fl cmdBuffer.SendMsg(myorg, radius, intensity, r, g, b, hShader, flags); } -void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) -{ - std::array myorg; - VectorCopy(org, myorg); - cmdBuffer.SendMsg(myorg, intensity, r, g, b); -} - void trap_R_RenderScene( const refdef_t *fd ) { cmdBuffer.SendMsg(*fd); diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index 6f1e616643..be431207e3 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -69,7 +69,6 @@ void trap_R_AddRefEntityToScene( const refEntity_t *re ); void trap_R_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts ); void trap_R_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ); void trap_R_AddLightToScene( const vec3_t org, float radius, float intensity, float r, float g, float b, qhandle_t hShader, int flags ); -void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); void trap_R_Add2dPolysIndexedToScene( const polyVert_t *polys, int numVerts, const int *indexes, int numIndexes, int trans_x, int trans_y, qhandle_t shader ); void trap_R_SetMatrixTransform( const matrix_t matrix ); void trap_R_ResetMatrixTransform(); From dc1cda749d58d1e8902b68f8de72b259d7e28d04 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 9 Nov 2024 19:48:07 +0300 Subject: [PATCH 12/66] Remove unused shader from trap_R_AddLightToScene() --- src/engine/client/cg_msgdef.h | 2 +- src/engine/client/cl_cgame.cpp | 2 +- src/shared/client/cg_api.cpp | 6 +++--- src/shared/client/cg_api.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 800dafcada..6afae4a4e2 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -386,7 +386,7 @@ namespace Render { using AddRefEntityToSceneMsg = IPC::Message, refEntity_t>; using AddPolyToSceneMsg = IPC::Message, int, std::vector>; using AddPolysToSceneMsg = IPC::Message, int, std::vector, int, int>; - using AddLightToSceneMsg = IPC::Message, std::array, float, float, float, float, float, int, int>; + using AddLightToSceneMsg = IPC::Message, std::array, float, float, float, float, float, int>; using SetColorMsg = IPC::Message, Color::Color>; using SetClipRegionMsg = IPC::Message, std::array>; using ResetClipRegionMsg = IPC::Message>; diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 973c29bc10..f8dee831d0 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1626,7 +1626,7 @@ void CGameVM::CmdBuffer::HandleCommandBufferSyscall(int major, int minor, Util:: break; case CG_R_ADDLIGHTTOSCENE: - HandleMsg(std::move(reader), [this] (const std::array& point, float radius, float intensity, float r, float g, float b, int shader, int flags) { + HandleMsg(std::move(reader), [this] (const std::array& point, float radius, float intensity, float r, float g, float b, int flags) { re.AddLightToScene(point.data(), radius, intensity, r, g, b, flags); }); break; diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index 75649f9a23..db0f0ba676 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -346,11 +346,11 @@ void trap_R_ResetMatrixTransform() cmdBuffer.SendMsg(); } -void trap_R_AddLightToScene( const vec3_t org, float radius, float intensity, float r, float g, float b, qhandle_t hShader, int flags ) +void trap_R_AddLightToScene( const vec3_t origin, float radius, float intensity, float r, float g, float b, int flags ) { std::array myorg; - VectorCopy(org, myorg); - cmdBuffer.SendMsg(myorg, radius, intensity, r, g, b, hShader, flags); + VectorCopy( origin, myorg ); + cmdBuffer.SendMsg(myorg, radius, intensity, r, g, b, flags); } void trap_R_RenderScene( const refdef_t *fd ) diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index be431207e3..95ef011830 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -68,7 +68,7 @@ void trap_R_ClearScene(); void trap_R_AddRefEntityToScene( const refEntity_t *re ); void trap_R_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts ); void trap_R_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ); -void trap_R_AddLightToScene( const vec3_t org, float radius, float intensity, float r, float g, float b, qhandle_t hShader, int flags ); +void trap_R_AddLightToScene( const vec3_t origin, float radius, float intensity, float r, float g, float b, int flags ); void trap_R_Add2dPolysIndexedToScene( const polyVert_t *polys, int numVerts, const int *indexes, int numIndexes, int trans_x, int trans_y, qhandle_t shader ); void trap_R_SetMatrixTransform( const matrix_t matrix ); void trap_R_ResetMatrixTransform(); From 6f385f6602541853b7ff1e81116d0014f7dab30a Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 10 Nov 2024 11:27:48 +0300 Subject: [PATCH 13/66] Move some early returns before we actually access data --- src/engine/renderer/tr_scene.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index ba568cb82c..5cdaa548a2 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -299,14 +299,6 @@ void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, return; } - // set last lights restrictInteractionEnd if needed - if ( r_numLights > r_firstSceneLight ) { - light = &backEndData[ tr.smpFrame ]->lights[ r_numLights - 1 ]; - if( light->restrictInteractionFirst >= 0 ) { - light->restrictInteractionLast = r_numEntities - r_firstSceneEntity - 1; - } - } - if ( r_numLights >= MAX_REF_LIGHTS ) { return; @@ -317,6 +309,14 @@ void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, return; } + // set last lights restrictInteractionEnd if needed + if ( r_numLights > r_firstSceneLight ) { + light = &backEndData[ tr.smpFrame ]->lights[ r_numLights - 1 ]; + if( light->restrictInteractionFirst >= 0 ) { + light->restrictInteractionLast = r_numEntities - r_firstSceneEntity - 1; + } + } + light = &backEndData[ tr.smpFrame ]->lights[ r_numLights++ ]; light->l.rlType = refLightType_t::RL_OMNI; From 6538ceb59daf7938563a4fd3606135dbd1edd4d6 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 10 Nov 2024 11:54:52 +0300 Subject: [PATCH 14/66] NUKE light intensity/scale This was only used to scale the light's colour, just multiply the colour with it earlier on instead. --- src/engine/client/cg_msgdef.h | 2 +- src/engine/client/cl_cgame.cpp | 4 ++-- src/engine/null/null_renderer.cpp | 2 +- src/engine/renderer/tr_backend.cpp | 2 +- src/engine/renderer/tr_local.h | 2 +- src/engine/renderer/tr_public.h | 2 +- src/engine/renderer/tr_scene.cpp | 14 ++++++-------- src/engine/renderer/tr_shade.cpp | 6 +++--- src/engine/renderer/tr_types.h | 4 +--- src/shared/client/cg_api.cpp | 2 +- 10 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 6afae4a4e2..81b9488279 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -386,7 +386,7 @@ namespace Render { using AddRefEntityToSceneMsg = IPC::Message, refEntity_t>; using AddPolyToSceneMsg = IPC::Message, int, std::vector>; using AddPolysToSceneMsg = IPC::Message, int, std::vector, int, int>; - using AddLightToSceneMsg = IPC::Message, std::array, float, float, float, float, float, int>; + using AddLightToSceneMsg = IPC::Message, std::array, float, float, float, float, int>; using SetColorMsg = IPC::Message, Color::Color>; using SetClipRegionMsg = IPC::Message, std::array>; using ResetClipRegionMsg = IPC::Message>; diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index f8dee831d0..b3190f0b73 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1626,8 +1626,8 @@ void CGameVM::CmdBuffer::HandleCommandBufferSyscall(int major, int minor, Util:: break; case CG_R_ADDLIGHTTOSCENE: - HandleMsg(std::move(reader), [this] (const std::array& point, float radius, float intensity, float r, float g, float b, int flags) { - re.AddLightToScene(point.data(), radius, intensity, r, g, b, flags); + HandleMsg(std::move(reader), [this] (const std::array& point, float radius, float r, float g, float b, int flags) { + re.AddLightToScene(point.data(), radius, r, g, b, flags); }); break; diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index 2c03a5d507..df371ea00b 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -86,7 +86,7 @@ int R_LightForPoint( vec3_t, vec3_t, vec3_t, vec3_t ) } void RE_AddPolyToScene( qhandle_t, int, const polyVert_t* ) { } void RE_AddPolysToScene( qhandle_t, int, const polyVert_t*, int ) { } -void RE_AddLightToScene( const vec3_t, float, float, float, float, float, int ) { } +void RE_AddLightToScene( const vec3_t, float, float, float, float, int ) { } void RE_RenderScene( const refdef_t* ) { } void RE_SetColor( const Color::Color& ) { } void RE_SetClipRegion( const float* ) { } diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 29983d06d9..e3cd626597 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -5334,7 +5334,7 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf() const VectorCopy( light->l.origin, buffer[i].center ); buffer[i].radius = light->l.radius; - VectorScale( light->l.color, light->l.scale, buffer[i].color ); + VectorCopy( light->l.color, buffer[i].color ); buffer[i].type = Util::ordinal( light->l.rlType ); switch( light->l.rlType ) { diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 3ad48cbd7d..7256e047df 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -3690,7 +3690,7 @@ inline bool checkGLErrors() void RE_AddPolyToSceneET( qhandle_t hShader, int numVerts, const polyVert_t *verts ); void RE_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ); - void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ); + void RE_AddDynamicLightToScene( const vec3_t org, float radius, float r, float g, float b, int flags ); void RE_RenderScene( const refdef_t *fd ); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 1f384080f8..526b80ebba 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -200,7 +200,7 @@ struct refexport_t void ( *AddPolyToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts ); void ( *AddPolysToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ); - void ( *AddLightToScene )( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ); + void ( *AddLightToScene )( const vec3_t org, float radius, float r, float g, float b, int flags ); void ( *RenderScene )( const refdef_t *fd ); diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index 5cdaa548a2..5f01bf8ca5 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -285,10 +285,8 @@ RE_AddDynamicLightToScene ydnar: modified dlight system to support separate radius and intensity ===================== */ -void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, float r, float g, float b, int flags ) +void RE_AddDynamicLightToScene( const vec3_t org, float radius, float r, float g, float b, int flags ) { - trRefLight_t *light; - if ( !glConfig2.realtimeLighting || !r_drawDynamicLights.Get() ) { return; @@ -304,11 +302,12 @@ void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, return; } - if ( intensity <= 0 || radius <= 0 ) + if ( radius <= 0 ) { return; } + trRefLight_t* light; // set last lights restrictInteractionEnd if needed if ( r_numLights > r_firstSceneLight ) { light = &backEndData[ tr.smpFrame ]->lights[ r_numLights - 1 ]; @@ -347,10 +346,9 @@ void RE_AddDynamicLightToScene( const vec3_t org, float radius, float intensity, light->additive = true; - if( light->l.inverseShadows ) - light->l.scale = -intensity; - else - light->l.scale = intensity; + if ( light->l.inverseShadows ) { + VectorNegate( light->l.color, light->l.color ); + } } static void RE_RenderCubeProbeFace( const refdef_t* originalRefdef ) { diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index b66f4c298e..a0d1a50ae1 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -1382,7 +1382,7 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, gl_forwardLightingShader_omniXYZ->SetUniform_LightOrigin( lightOrigin ); gl_forwardLightingShader_omniXYZ->SetUniform_LightColor( lightColor.ToArray() ); gl_forwardLightingShader_omniXYZ->SetUniform_LightRadius( light->sphereRadius ); - gl_forwardLightingShader_omniXYZ->SetUniform_LightScale( light->l.scale ); + gl_forwardLightingShader_omniXYZ->SetUniform_LightScale( 1.0 ); gl_forwardLightingShader_omniXYZ->SetUniform_LightAttenuationMatrix( light->attenuationMatrix2 ); GL_CheckErrors(); @@ -1557,7 +1557,7 @@ static void Render_forwardLighting_DBS_proj( shaderStage_t *pStage, gl_forwardLightingShader_projXYZ->SetUniform_LightOrigin( lightOrigin ); gl_forwardLightingShader_projXYZ->SetUniform_LightColor( lightColor.ToArray() ); gl_forwardLightingShader_projXYZ->SetUniform_LightRadius( light->sphereRadius ); - gl_forwardLightingShader_projXYZ->SetUniform_LightScale( light->l.scale ); + gl_forwardLightingShader_projXYZ->SetUniform_LightScale( 1.0 ); gl_forwardLightingShader_projXYZ->SetUniform_LightAttenuationMatrix( light->attenuationMatrix2 ); GL_CheckErrors(); @@ -1735,7 +1735,7 @@ static void Render_forwardLighting_DBS_directional( shaderStage_t *pStage, trRef gl_forwardLightingShader_directionalSun->SetUniform_LightDir( lightDirection ); gl_forwardLightingShader_directionalSun->SetUniform_LightColor( lightColor.ToArray() ); gl_forwardLightingShader_directionalSun->SetUniform_LightRadius( light->sphereRadius ); - gl_forwardLightingShader_directionalSun->SetUniform_LightScale( light->l.scale ); + gl_forwardLightingShader_directionalSun->SetUniform_LightScale( 1.0 ); gl_forwardLightingShader_directionalSun->SetUniform_LightAttenuationMatrix( light->attenuationMatrix2 ); GL_CheckErrors(); diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index a8e2d2cf8a..3746d33eed 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -232,9 +232,7 @@ struct refLight_t vec3_t origin; quat_t rotation; vec3_t center; - vec3_t color; // range from 0.0 to 1.0, should be color normalized - - float scale; + vec3_t color; // should be color normalized // omni-directional light specific float radius; diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index db0f0ba676..982f74ced2 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -350,7 +350,7 @@ void trap_R_AddLightToScene( const vec3_t origin, float radius, float intensity, { std::array myorg; VectorCopy( origin, myorg ); - cmdBuffer.SendMsg(myorg, radius, intensity, r, g, b, flags); + cmdBuffer.SendMsg(myorg, radius, r * intensity, g * intensity, b * intensity, flags); } void trap_R_RenderScene( const refdef_t *fd ) From d8138f0d3314c7d4a9b5c4e70dc5d53a5fa1273a Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Wed, 29 Jan 2025 19:27:42 +0000 Subject: [PATCH 15/66] sync for-0.56.0/sync submodules --- libs/crunch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/crunch b/libs/crunch index 573d3ffe7b..af386c17ff 160000 --- a/libs/crunch +++ b/libs/crunch @@ -1 +1 @@ -Subproject commit 573d3ffe7b358ad9b1f9bc743bc69bd088cf3c40 +Subproject commit af386c17ff3321961d4b675fa40b4f986acd4231 From febf807a68d45d395a213ba6812911694767d9e0 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Thu, 6 Feb 2025 03:19:13 +0300 Subject: [PATCH 16/66] Fix bad merge with sv_maxClients --- src/engine/server/sv_sgame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index 5cf548e579..e6daef925e 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -566,7 +566,7 @@ void GameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& chan case G_GET_PINGS: IPC::HandleMsg(channel, std::move(reader), [this](std::vector& pings) { - int count = sv_maxclients->integer; + int count = sv_maxClients.Get(); pings.resize(count); for (int i = 0; i < count; i++) { pings[i] = svs.clients[i].ping; From cee882d96c8e3d2bc21e905c12b7e65bcb1fcf80 Mon Sep 17 00:00:00 2001 From: slipher Date: Sun, 2 Feb 2025 20:14:00 -0600 Subject: [PATCH 17/66] Clean up "nettype" from server info for cgame This field is 1 if a server responded via IPv4 or 2 if via IPv6. Define an enum for this and don't use netadrtype_t (whose values don't match). In ping_t / serverInfo_t define a struct field instead of stuffing it in the info string. --- src/engine/client/cg_api.h | 7 +++++ src/engine/client/cl_cgame.cpp | 2 +- src/engine/client/cl_serverlist.cpp | 42 ++++++++++++++++------------- src/engine/client/client.h | 2 +- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/engine/client/cg_api.h b/src/engine/client/cg_api.h index ff034d5fa1..b9b4e74fd7 100644 --- a/src/engine/client/cg_api.h +++ b/src/engine/client/cg_api.h @@ -80,6 +80,13 @@ enum class MouseMode SystemCursor, // The input is sent as positions, the cursor should be rendered by the system }; +enum class serverResponseProtocol_t : uint8_t +{ + UNKNOWN, + IP4, + IP6, +}; + using markMsgInput_t = std::pair< std::vector>, // points std::array // projection diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index a16b77bda4..816a7d6145 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -435,7 +435,7 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) Info_SetValueForKey( info, "minping", va( "%i", server->minPing ), false ); Info_SetValueForKey( info, "maxping", va( "%i", server->maxPing ), false ); Info_SetValueForKey( info, "game", server->game, false ); - Info_SetValueForKey( info, "nettype", Util::enum_str(server->netType), false ); + Info_SetValueForKey( info, "nettype", Util::enum_str( server->responseProto ), false ); Info_SetValueForKey( info, "addr", Net::AddressToString( server->adr, true ).c_str(), false ); Info_SetValueForKey( info, "needpass", va( "%i", server->needpass ), false ); // NERVE - SMF Info_SetValueForKey( info, "gamename", server->gameName, false ); // Arnout diff --git a/src/engine/client/cl_serverlist.cpp b/src/engine/client/cl_serverlist.cpp index 0daf49cb4a..4c281efdb0 100644 --- a/src/engine/client/cl_serverlist.cpp +++ b/src/engine/client/cl_serverlist.cpp @@ -67,6 +67,7 @@ struct ping_t int start; int time; char challenge[ 9 ]; // 8-character challenge string + serverResponseProtocol_t responseProto; char info[ MAX_INFO_STRING ]; }; @@ -92,7 +93,7 @@ static void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) server->pingAttempts = 0; server->ping = -1; server->game[ 0 ] = '\0'; - server->netType = netadrtype_t::NA_BOT; + server->responseProto = serverResponseProtocol_t::UNKNOWN; } /* @@ -485,7 +486,9 @@ void CL_ServersResponsePacket( const netadr_t *from, msg_t *msg, bool extended ) parsed_count, numservers, duplicate_count, count ); } -static void CL_SetServerInfo( serverInfo_t *server, const char *info, pingStatus_t pingStatus, int ping ) +static void CL_SetServerInfo( + serverInfo_t *server, const char *info, + serverResponseProtocol_t proto, pingStatus_t pingStatus, int ping ) { if ( info ) { @@ -496,18 +499,20 @@ static void CL_SetServerInfo( serverInfo_t *server, const char *info, pingStatus Q_strncpyz( server->mapName, Info_ValueForKey( info, "mapname" ), MAX_NAME_LENGTH ); server->maxClients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); Q_strncpyz( server->game, Info_ValueForKey( info, "game" ), MAX_NAME_LENGTH ); - server->netType = Util::enum_cast(atoi(Info_ValueForKey(info, "nettype"))); server->minPing = atoi( Info_ValueForKey( info, "minping" ) ); server->maxPing = atoi( Info_ValueForKey( info, "maxping" ) ); server->needpass = atoi( Info_ValueForKey( info, "g_needpass" ) ); // NERVE - SMF Q_strncpyz( server->gameName, Info_ValueForKey( info, "gamename" ), MAX_NAME_LENGTH ); // Arnout } + server->responseProto = proto; server->pingStatus = pingStatus; server->ping = ping; } -static void CL_SetServerInfoByAddress( const netadr_t& from, const char *info, pingStatus_t pingStatus, int ping ) +static void CL_SetServerInfoByAddress( + const netadr_t& from, const char *info, + serverResponseProtocol_t proto, pingStatus_t pingStatus, int ping ) { int i; @@ -515,7 +520,7 @@ static void CL_SetServerInfoByAddress( const netadr_t& from, const char *info, p { if ( NET_CompareAdr( from, cls.localServers[ i ].adr ) ) { - CL_SetServerInfo( &cls.localServers[ i ], info, pingStatus, ping ); + CL_SetServerInfo( &cls.localServers[ i ], info, proto, pingStatus, ping ); } } @@ -523,7 +528,7 @@ static void CL_SetServerInfoByAddress( const netadr_t& from, const char *info, p { if ( NET_CompareAdr( from, cls.globalServers[ i ].adr ) ) { - CL_SetServerInfo( &cls.globalServers[ i ], info, pingStatus, ping ); + CL_SetServerInfo( &cls.globalServers[ i ], info, proto, pingStatus, ping ); } } } @@ -535,7 +540,7 @@ CL_ServerInfoPacket */ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) { - int i, type; + int i; char info[ MAX_INFO_STRING ]; // char* str; char *infoString; @@ -582,27 +587,24 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) Q_strncpyz( cl_pinglist[ i ].info, infoString, sizeof( cl_pinglist[ i ].info ) ); // tack on the net type - // NOTE: make sure these types are in sync with the netnames strings in the UI switch ( from.type ) { case netadrtype_t::NA_BROADCAST: case netadrtype_t::NA_IP: - //str = "udp"; - type = 1; + cl_pinglist[ i ].responseProto = serverResponseProtocol_t::IP4; break; case netadrtype_t::NA_IP6: - type = 2; + cl_pinglist[ i ].responseProto = serverResponseProtocol_t::IP6; break; default: - //str = "???"; - type = 0; + cl_pinglist[ i ].responseProto = serverResponseProtocol_t::UNKNOWN; break; } - Info_SetValueForKey( cl_pinglist[ i ].info, "nettype", va( "%d", type ), false ); - CL_SetServerInfoByAddress( from, infoString, pingStatus_t::COMPLETE, cl_pinglist[ i ].time ); + CL_SetServerInfoByAddress( from, infoString, cl_pinglist[ i ].responseProto, + pingStatus_t::COMPLETE, cl_pinglist[ i ].time ); return; } @@ -649,7 +651,7 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) cls.localServers[ i ].pingStatus = pingStatus_t::WAITING; cls.localServers[ i ].pingAttempts = 0; cls.localServers[ i ].game[ 0 ] = '\0'; - cls.localServers[ i ].netType = from.type; + cls.localServers[ i ].responseProto = serverResponseProtocol_t::UNKNOWN; cls.localServers[ i ].needpass = 0; cls.localServers[ i ].gameName[ 0 ] = '\0'; // Arnout @@ -851,7 +853,10 @@ static pingStatus_t CL_GetPing( int n ) } } - CL_SetServerInfoByAddress( cl_pinglist[ n ].adr, cl_pinglist[ n ].info, status, time ); + // FIXME: do we really need to call this again? CL_ServerInfoPacket already calls it + // at the moment the ping response arrives + CL_SetServerInfoByAddress( cl_pinglist[ n ].adr, cl_pinglist[ n ].info, + cl_pinglist[ n ].responseProto, status, time ); return status; } @@ -1002,7 +1007,8 @@ void CL_Ping_f() pingptr->time = -1; GeneratePingChallenge( *pingptr ); - CL_SetServerInfoByAddress( pingptr->adr, nullptr, pingStatus_t::WAITING, 0 ); + CL_SetServerInfoByAddress( pingptr->adr, nullptr, serverResponseProtocol_t::UNKNOWN, + pingStatus_t::WAITING, 0 ); Net::OutOfBandPrint( netsrc_t::NS_CLIENT, to, "getinfo %s", pingptr->challenge ); } diff --git a/src/engine/client/client.h b/src/engine/client/client.h index c9890560b6..e795380e60 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -259,7 +259,7 @@ struct serverInfo_t char mapName[ MAX_NAME_LENGTH ]; char game[ MAX_NAME_LENGTH ]; char label[ MAX_FEATLABEL_CHARS ]; // for featured servers, nullptr otherwise - netadrtype_t netType; + serverResponseProtocol_t responseProto; int clients; int bots; int maxClients; From d4d990847565fd1d80adcd46ffe6787636255b71 Mon Sep 17 00:00:00 2001 From: slipher Date: Sun, 2 Feb 2025 21:03:20 -0600 Subject: [PATCH 18/66] cgame ABI: give all server info, not just selected fields When the cgame calls trap_LAN_GetServerInfo, pass it the server's entire info string, not just some hard-coded fields. That way we can start using new fields in the server browser without an engine change. Also separate info about the server which does not come from the infostring into a trustedServerInfo_t struct, instead of mixing it into the info string. --- src/engine/client/cg_api.h | 11 ++++++++ src/engine/client/cg_msgdef.h | 4 +-- src/engine/client/cl_cgame.cpp | 41 +++++++---------------------- src/engine/client/cl_serverlist.cpp | 30 ++------------------- src/engine/client/client.h | 13 +-------- src/shared/client/cg_api.cpp | 6 ++--- src/shared/client/cg_api.h | 2 +- 7 files changed, 29 insertions(+), 78 deletions(-) diff --git a/src/engine/client/cg_api.h b/src/engine/client/cg_api.h index b9b4e74fd7..023dc7a9c0 100644 --- a/src/engine/client/cg_api.h +++ b/src/engine/client/cg_api.h @@ -26,6 +26,8 @@ along with this program. If not, see . #include "engine/qcommon/q_shared.h" +#define MAX_FEATLABEL_CHARS 32 + #define CMD_BACKUP 64 #define CMD_MASK ( CMD_BACKUP - 1 ) // allow a lot of command backups for very fast systems @@ -87,6 +89,15 @@ enum class serverResponseProtocol_t : uint8_t IP6, }; +// "Trusted" as in we know it is correct and present, as opposed to the server's info string +// which is self-reported data whose fields may be missing, false or not of the right format +struct trustedServerInfo_t +{ + serverResponseProtocol_t responseProto; + char addr[ MAX_ADDR_CHARS ]; + char featuredLabel[ MAX_FEATLABEL_CHARS ]; +}; + using markMsgInput_t = std::pair< std::vector>, // points std::array // projection diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index f604d27f61..9918f5b3d3 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -434,8 +434,8 @@ namespace LAN { IPC::Reply >; using GetServerInfoMsg = IPC::SyncMessage< - IPC::Message, int, int, int>, - IPC::Reply + IPC::Message, int, int>, + IPC::Reply >; using GetServerPingMsg = IPC::SyncMessage< IPC::Message, int, int>, diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 816a7d6145..0cfb70029b 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -395,13 +395,10 @@ static int LAN_GetServerCount( int source ) * LAN_GetServerInfo * ==================== */ -static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) +static void LAN_GetServerInfo( int source, int n, trustedServerInfo_t &trustedInfo, std::string &info ) { - char info[ MAX_STRING_CHARS ]; serverInfo_t *server = nullptr; - info[ 0 ] = '\0'; - switch ( source ) { case AS_LOCAL: @@ -421,32 +418,17 @@ static void LAN_GetServerInfo( int source, int n, char *buf, int buflen ) break; } - if ( server && buf ) + if ( server ) { - buf[ 0 ] = '\0'; - Info_SetValueForKey( info, "hostname", server->hostName, false ); - Info_SetValueForKey( info, "serverload", va( "%i", server->load ), false ); - Info_SetValueForKey( info, "mapname", server->mapName, false ); - Info_SetValueForKey( info, "label", server->label, false ); - Info_SetValueForKey( info, "clients", va( "%i", server->clients ), false ); - Info_SetValueForKey( info, "bots", va( "%i", server->bots ), false ); - Info_SetValueForKey( info, "sv_maxclients", va( "%i", server->maxClients ), false ); - Info_SetValueForKey( info, "ping", va( "%i", server->ping ), false ); - Info_SetValueForKey( info, "minping", va( "%i", server->minPing ), false ); - Info_SetValueForKey( info, "maxping", va( "%i", server->maxPing ), false ); - Info_SetValueForKey( info, "game", server->game, false ); - Info_SetValueForKey( info, "nettype", Util::enum_str( server->responseProto ), false ); - Info_SetValueForKey( info, "addr", Net::AddressToString( server->adr, true ).c_str(), false ); - Info_SetValueForKey( info, "needpass", va( "%i", server->needpass ), false ); // NERVE - SMF - Info_SetValueForKey( info, "gamename", server->gameName, false ); // Arnout - Q_strncpyz( buf, info, buflen ); + trustedInfo.responseProto = server->responseProto; + Q_strncpyz( trustedInfo.addr, Net::AddressToString( server->adr, true ).c_str(), sizeof( trustedInfo.addr ) ); + Q_strncpyz( trustedInfo.featuredLabel, server->label, sizeof( trustedInfo.featuredLabel ) ); + info = server->infoString; } else { - if ( buf ) - { - buf[ 0 ] = '\0'; - } + trustedInfo = {}; + info.clear(); } } @@ -1419,11 +1401,8 @@ void CGameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& cha break; case CG_LAN_GETSERVERINFO: - IPC::HandleMsg(channel, std::move(reader), [this] (int source, int n, int len, std::string& info) { - std::unique_ptr buffer(new char[len]); - buffer[0] = '\0'; - LAN_GetServerInfo(source, n, buffer.get(), len); - info.assign(buffer.get()); + IPC::HandleMsg(channel, std::move(reader), [this] (int source, int n, trustedServerInfo_t& trustedInfo, std::string& info) { + LAN_GetServerInfo(source, n, trustedInfo, info); }); break; diff --git a/src/engine/client/cl_serverlist.cpp b/src/engine/client/cl_serverlist.cpp index 4c281efdb0..09f99d2e15 100644 --- a/src/engine/client/cl_serverlist.cpp +++ b/src/engine/client/cl_serverlist.cpp @@ -82,17 +82,10 @@ CL_InitServerInfo static void CL_InitServerInfo( serverInfo_t *server, netadr_t *address ) { server->adr = *address; - server->clients = 0; - server->hostName[ 0 ] = '\0'; - server->mapName[ 0 ] = '\0'; server->label[ 0 ] = '\0'; - server->maxClients = 0; - server->maxPing = 0; - server->minPing = 0; server->pingStatus = pingStatus_t::WAITING; server->pingAttempts = 0; server->ping = -1; - server->game[ 0 ] = '\0'; server->responseProto = serverResponseProtocol_t::UNKNOWN; } @@ -492,17 +485,7 @@ static void CL_SetServerInfo( { if ( info ) { - server->clients = atoi( Info_ValueForKey( info, "clients" ) ); - server->bots = atoi( Info_ValueForKey( info, "bots" ) ); - Q_strncpyz( server->hostName, Info_ValueForKey( info, "hostname" ), MAX_NAME_LENGTH ); - server->load = atoi( Info_ValueForKey( info, "serverload" ) ); - Q_strncpyz( server->mapName, Info_ValueForKey( info, "mapname" ), MAX_NAME_LENGTH ); - server->maxClients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); - Q_strncpyz( server->game, Info_ValueForKey( info, "game" ), MAX_NAME_LENGTH ); - server->minPing = atoi( Info_ValueForKey( info, "minping" ) ); - server->maxPing = atoi( Info_ValueForKey( info, "maxping" ) ); - server->needpass = atoi( Info_ValueForKey( info, "g_needpass" ) ); // NERVE - SMF - Q_strncpyz( server->gameName, Info_ValueForKey( info, "gamename" ), MAX_NAME_LENGTH ); // Arnout + server->infoString = info; } server->responseProto = proto; @@ -640,20 +623,11 @@ void CL_ServerInfoPacket( const netadr_t& from, msg_t *msg ) // add this to the list cls.numlocalservers = i + 1; cls.localServers[ i ].adr = from; - cls.localServers[ i ].clients = 0; - cls.localServers[ i ].hostName[ 0 ] = '\0'; - cls.localServers[ i ].load = -1; - cls.localServers[ i ].mapName[ 0 ] = '\0'; - cls.localServers[ i ].maxClients = 0; - cls.localServers[ i ].maxPing = 0; - cls.localServers[ i ].minPing = 0; cls.localServers[ i ].ping = -1; cls.localServers[ i ].pingStatus = pingStatus_t::WAITING; cls.localServers[ i ].pingAttempts = 0; - cls.localServers[ i ].game[ 0 ] = '\0'; cls.localServers[ i ].responseProto = serverResponseProtocol_t::UNKNOWN; - cls.localServers[ i ].needpass = 0; - cls.localServers[ i ].gameName[ 0 ] = '\0'; // Arnout + cls.localServers[ i ].infoString.clear(); Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING ); diff --git a/src/engine/client/client.h b/src/engine/client/client.h index e795380e60..2c70d0c4ea 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -250,27 +250,16 @@ enum class pingStatus_t TIMEOUT, }; -#define MAX_FEATLABEL_CHARS 32 struct serverInfo_t { netadr_t adr; - char hostName[ MAX_NAME_LENGTH ]; - int load; - char mapName[ MAX_NAME_LENGTH ]; - char game[ MAX_NAME_LENGTH ]; char label[ MAX_FEATLABEL_CHARS ]; // for featured servers, nullptr otherwise serverResponseProtocol_t responseProto; - int clients; - int bots; - int maxClients; - int minPing; - int maxPing; pingStatus_t pingStatus; int ping; int pingAttempts; bool visible; - int needpass; - char gameName[ MAX_NAME_LENGTH ]; // Arnout + std::string infoString; }; struct clientStatic_t diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index f824ebdee4..c524f503c5 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -627,11 +627,9 @@ int trap_LAN_GetServerCount( int source ) return count; } -void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ) +void trap_LAN_GetServerInfo( int source, int n, trustedServerInfo_t &trustedInfo, std::string &info ) { - std::string info; - VM::SendMsg(source, n, buflen, info); - Q_strncpyz(buf, info.c_str(), buflen); + VM::SendMsg(source, n, trustedInfo, info); } int trap_LAN_GetServerPing( int source, int n ) diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index 48c1b789d0..4e2781c3d7 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -124,7 +124,7 @@ void trap_SetColorGrading( int slot, qhandle_t hShader ); void trap_R_ScissorEnable( bool enable ); void trap_R_ScissorSet( int x, int y, int w, int h ); int trap_LAN_GetServerCount( int source ); -void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ); +void trap_LAN_GetServerInfo( int source, int n, trustedServerInfo_t &trustedInfo, std::string &info ); int trap_LAN_GetServerPing( int source, int n ); void trap_LAN_MarkServerVisible( int source, int n, bool visible ); int trap_LAN_ServerIsVisible( int source, int n ); From 059cb611112e8170ee10ef04b8522f2d3829b0d7 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 8 Feb 2025 20:46:21 +0300 Subject: [PATCH 19/66] Multiply with var_Color in generic shader before the u_AlphaThreshold check Fixes https://github.com/DaemonEngine/Daemon/issues/119. See https://github.com/DaemonEngine/Daemon/pull/1417 for details. --- src/engine/renderer/glsl_source/generic_fp.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/renderer/glsl_source/generic_fp.glsl b/src/engine/renderer/glsl_source/generic_fp.glsl index 2de327152a..020c701c78 100644 --- a/src/engine/renderer/glsl_source/generic_fp.glsl +++ b/src/engine/renderer/glsl_source/generic_fp.glsl @@ -57,6 +57,8 @@ void main() vec4 color = texture2D(u_ColorMap, var_TexCoords); + color *= var_Color; + if( abs(color.a + u_AlphaThreshold) <= 1.0 ) { discard; @@ -68,8 +70,6 @@ void main() float fadeDepth = 0.5 * var_FadeDepth.x / var_FadeDepth.y + 0.5; color.a *= smoothstep(gl_FragCoord.z, fadeDepth, depth); #endif - - color *= var_Color; SHADER_PROFILER_SET( color ) From 19e1249bb003cb1bcb1d9ebf56832c3ec9ae21e4 Mon Sep 17 00:00:00 2001 From: slipher Date: Sun, 9 Feb 2025 00:57:18 -0600 Subject: [PATCH 20/66] Add engine + ABI version to server info response --- src/engine/server/sv_main.cpp | 4 ++++ src/shared/client/cg_api.cpp | 1 + 2 files changed, 5 insertions(+) diff --git a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp index 4b2ee33739..e84e446475 100644 --- a/src/engine/server/sv_main.cpp +++ b/src/engine/server/sv_main.cpp @@ -599,6 +599,10 @@ static void SVC_Info( const netadr_t& from, const Cmd::Args& args ) } info_map["gamename"] = GAMENAME_STRING; // Arnout: to be able to filter out Quake servers + info_map["abi"] = IPC::SYSCALL_ABI_VERSION; + // Add the engine version. But is that really what we want? Probably the gamelogic version would + // be more interesting to players. Oh well, it's what's available for now. + info_map["daemonver"] = ENGINE_VERSION; Net::OutOfBandPrint( netsrc_t::NS_SERVER, from, "infoResponse\n%s", InfoMapToString( info_map ) ); } diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index c524f503c5..9eea1f66be 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -627,6 +627,7 @@ int trap_LAN_GetServerCount( int source ) return count; } +// See SVC_Info() for the keys that are supposed to be available in `info` void trap_LAN_GetServerInfo( int source, int n, trustedServerInfo_t &trustedInfo, std::string &info ) { VM::SendMsg(source, n, trustedInfo, info); From b10c9c2d9d8719d3bf4fb53c58efe7e798c2086c Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 26 Feb 2025 22:24:42 -0600 Subject: [PATCH 21/66] Add VM syscall for getting local time offset This is needed to get the local time since an NaCl VM can't read the time zone database. Returns an offset instead of just the local date, in the interests of not doing a trap call every frame. --- src/common/IPC/CommonSyscalls.h | 6 ++++++ src/engine/framework/CommonVMServices.cpp | 15 +++++++++++++++ src/shared/CommonProxies.cpp | 8 ++++++++ src/shared/CommonProxies.h | 1 + 4 files changed, 30 insertions(+) diff --git a/src/common/IPC/CommonSyscalls.h b/src/common/IPC/CommonSyscalls.h index 51b56bd84a..07747ece3d 100644 --- a/src/common/IPC/CommonSyscalls.h +++ b/src/common/IPC/CommonSyscalls.h @@ -154,6 +154,7 @@ namespace VM { enum EngineMiscMessages { CREATE_SHARED_MEMORY, CRASH_DUMP, + GET_LOCAL_TIME_OFFSET, }; // CreateSharedMemoryMsg @@ -165,6 +166,11 @@ namespace VM { using CrashDumpMsg = IPC::SyncMessage< IPC::Message, std::vector> >; + // GetLocalTimeOffsetMsg + using GetLocalTimeOffsetMsg = IPC::SyncMessage< + IPC::Message>, + IPC::Reply + >; enum VMMiscMessages { GET_NETCODE_TABLES, diff --git a/src/engine/framework/CommonVMServices.cpp b/src/engine/framework/CommonVMServices.cpp index 6f4f6bb9d9..5257a06401 100644 --- a/src/engine/framework/CommonVMServices.cpp +++ b/src/engine/framework/CommonVMServices.cpp @@ -59,6 +59,21 @@ namespace VM { Sys::NaclCrashDump(dump, vmName); }); break; + + case GET_LOCAL_TIME_OFFSET: + IPC::HandleMsg(channel, std::move(reader), [this](int& offset) { + time_t epochTime = time(nullptr); + struct tm localDate; +#ifdef _WIN32 + localtime_s(&localDate, &epochTime); + time_t localEpochTime = _mkgmtime(&localDate); +#else + localtime_r(&epochTime, &localDate); + time_t localEpochTime = timegm(&localDate); +#endif + offset = static_cast(difftime(localEpochTime, epochTime)); + }); + break; } } diff --git a/src/shared/CommonProxies.cpp b/src/shared/CommonProxies.cpp index 24b9b3fa58..a4f7c991b5 100644 --- a/src/shared/CommonProxies.cpp +++ b/src/shared/CommonProxies.cpp @@ -435,6 +435,14 @@ namespace VM { SendMsg(std::vector{data, data + size}); } + // Add this number of seconds to the UTC date/time to get the local date/time. + // The current daylight savings time adjustment is included in this. + int GetLocalTimeOffset() { + int offset; + SendMsg(offset); + return offset; + } + void InitializeProxies(int milliseconds) { baseTime = Sys::SteadyClock::now() - std::chrono::milliseconds(milliseconds); Cmd::InitializeProxy(); diff --git a/src/shared/CommonProxies.h b/src/shared/CommonProxies.h index 0c66d74cc8..7f96275033 100644 --- a/src/shared/CommonProxies.h +++ b/src/shared/CommonProxies.h @@ -43,6 +43,7 @@ namespace Cmd { namespace VM { void CrashDump(const uint8_t* data, size_t size); + int GetLocalTimeOffset(); void InitializeProxies(int milliseconds); void HandleCommonSyscall(int major, int minor, Util::Reader reader, IPC::Channel& channel); From cb73b0d2e086adfc66234380204ad32eea522873 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 26 Jan 2025 15:38:38 +0300 Subject: [PATCH 22/66] Add RSF_FORCE_LIGHTMAP Replaces RSF_NOLIGHTSCALE. If this flag is used when registering a shader, all `ST_COLORMAP` stages will be changed to `ST_DIFFUSEMAP`. This is intended for use with particles and trails, to make them use the lightGrid in the GLSL code. --- src/engine/renderer/tr_local.h | 2 ++ src/engine/renderer/tr_shader.cpp | 15 +++++++++++++++ src/engine/renderer/tr_types.h | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index df6d8ce7ea..f4441e5b2f 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1319,6 +1319,8 @@ enum class shaderProfilerRenderSubGroupsMode { int autoSpriteMode; + bool forceLightMap; + uint8_t numDeforms; deformStage_t deforms[ MAX_SHADER_DEFORMS ]; diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index eeac8658df..aa5c9d7395 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -5869,6 +5869,16 @@ static shader_t *FinishShader() numStages = MAX_SHADER_STAGES; GroupActiveStages(); + if ( shader.forceLightMap ) { + for( size_t stage = 0; stage < numStages; stage++ ) { + shaderStage_t* pStage = &stages[numStages]; + + if ( pStage->type == stageType_t::ST_COLORMAP ) { + pStage->type = stageType_t::ST_DIFFUSEMAP; + } + } + } + // set appropriate stage information for ( size_t stage = 0; stage < numStages; stage++ ) { @@ -6233,6 +6243,11 @@ shader_t *R_FindShader( const char *name, shaderType_t type, int flags ) shader.entitySpriteFaceViewDirection = true; } + if ( flags & RSF_FORCE_LIGHTMAP ) + { + shader.forceLightMap = true; + } + // attempt to define shader from an explicit parameter file shaderText = FindShaderInShaderText( strippedName ); diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 3746d33eed..42f9ed1221 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -90,7 +90,7 @@ enum RegisterShaderFlags_t { RSF_NOMIP = BIT( 2 ), RSF_FITSCREEN = BIT( 3 ), RSF_LIGHT_ATTENUATION = BIT( 4 ), - RSF_NOLIGHTSCALE = BIT( 5 ), // TODO(0.56): delete, does nothing + RSF_FORCE_LIGHTMAP = BIT( 5 ), // Used to make particles/trails work with the lightGrid in GLSL RSF_SPRITE = BIT( 6 ), }; From b5685db9343f90f981ac1a828d0f5abf905a8bf8 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Tue, 11 Mar 2025 10:04:07 +0300 Subject: [PATCH 23/66] Check for stage count with RSF_FORCE_LIGHTMAP Stops particle shaders with 2 stages from switching a pattern of `generic + lightgrid` to `lightgrid + lightmap` (relevant for `staratcs`). Also fixes an OOB. --- src/engine/renderer/tr_shader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index aa5c9d7395..fe5402307a 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -5869,9 +5869,9 @@ static shader_t *FinishShader() numStages = MAX_SHADER_STAGES; GroupActiveStages(); - if ( shader.forceLightMap ) { + if ( shader.forceLightMap && numStages == 1 ) { for( size_t stage = 0; stage < numStages; stage++ ) { - shaderStage_t* pStage = &stages[numStages]; + shaderStage_t* pStage = &stages[stage]; if ( pStage->type == stageType_t::ST_COLORMAP ) { pStage->type = stageType_t::ST_DIFFUSEMAP; From 1a4f393d87399b743053149617a7b102e5f19e52 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Tue, 11 Mar 2025 15:06:54 +0300 Subject: [PATCH 24/66] Remove useless loop --- src/engine/renderer/tr_shader.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index fe5402307a..8052e1ee7f 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -5870,12 +5870,10 @@ static shader_t *FinishShader() GroupActiveStages(); if ( shader.forceLightMap && numStages == 1 ) { - for( size_t stage = 0; stage < numStages; stage++ ) { - shaderStage_t* pStage = &stages[stage]; + shaderStage_t* pStage = &stages[0]; - if ( pStage->type == stageType_t::ST_COLORMAP ) { - pStage->type = stageType_t::ST_DIFFUSEMAP; - } + if ( pStage->type == stageType_t::ST_COLORMAP ) { + pStage->type = stageType_t::ST_DIFFUSEMAP; } } From ce90c49bd38506b252a634b202f4817e39464d95 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Wed, 12 Mar 2025 14:54:25 +0000 Subject: [PATCH 25/66] sync for-0.56.0/sync submodules --- libs/crunch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/crunch b/libs/crunch index af386c17ff..73e74fa7e2 160000 --- a/libs/crunch +++ b/libs/crunch @@ -1 +1 @@ -Subproject commit af386c17ff3321961d4b675fa40b4f986acd4231 +Subproject commit 73e74fa7e28093c4802a3034f78edd81d0d8544b From 3dda072acc88f12e86e96cf9741b54a99cb07772 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sun, 10 Nov 2024 00:56:45 +0300 Subject: [PATCH 26/66] Fix entity baseline overflow --- src/engine/client/cl_parse.cpp | 31 +++++++++++++++++++++---------- src/engine/client/client.h | 2 ++ src/engine/qcommon/qcommon.h | 3 ++- src/engine/server/sv_client.cpp | 10 ++++++++++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/engine/client/cl_parse.cpp b/src/engine/client/cl_parse.cpp index abb8b40a3c..f84051c4f3 100644 --- a/src/engine/client/cl_parse.cpp +++ b/src/engine/client/cl_parse.cpp @@ -403,11 +403,13 @@ void CL_ParseGamestate( msg_t *msg ) clc.connectPacketCount = 0; - // wipe local client state - CL_ClearState(); + if ( !cl.reading ) { + // wipe local client state + CL_ClearState(); - // a gamestate always marks a server command sequence - clc.serverCommandSequence = MSG_ReadLong( msg ); + // a gamestate always marks a server command sequence + clc.serverCommandSequence = MSG_ReadLong( msg ); + } // parse all the configstrings and baselines while (true) @@ -443,6 +445,13 @@ void CL_ParseGamestate( msg_t *msg ) entityState_t nullstate{}; es = &cl.entityBaselines[ newnum ]; MSG_ReadDeltaEntity( msg, &nullstate, es, newnum ); + + cl.reading = false; + } + else if ( cmd == svc_gamestatePartial ) + { + cl.reading = true; + break; } else { @@ -450,14 +459,16 @@ void CL_ParseGamestate( msg_t *msg ) } } - clc.clientNum = MSG_ReadLong( msg ); + if ( !cl.reading ) { + clc.clientNum = MSG_ReadLong( msg ); - // parse serverId and other cvars - CL_SystemInfoChanged(); + // parse serverId and other cvars + CL_SystemInfoChanged(); - // This used to call CL_StartHunkUsers, but now we enter the download state before loading the - // cgame - CL_InitDownloads(); + // This used to call CL_StartHunkUsers, but now we enter the download state before loading the + // cgame + CL_InitDownloads(); + } } //===================================================================== diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 2c70d0c4ea..5e2e41dd19 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -153,6 +153,8 @@ struct clientActive_t clSnapshot_t snapshots[ PACKET_BACKUP ]; entityState_t entityBaselines[ MAX_GENTITIES ]; // for delta compression when not in previous frame + + bool reading; // For gamestate that is split between different msg_t }; extern clientActive_t cl; diff --git a/src/engine/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index 128a4f03fa..ef54286e4a 100644 --- a/src/engine/qcommon/qcommon.h +++ b/src/engine/qcommon/qcommon.h @@ -248,12 +248,13 @@ enum svc_ops_e svc_bad, svc_nop, svc_gamestate, + svc_gamestatePartial, svc_configstring, // [short] [string] only in gamestate messages svc_baseline, // only in gamestate messages svc_serverCommand, // [string] to be executed by client game module svc_download, // [short] size [size bytes] svc_snapshot, - svc_EOF, + svc_EOF }; // diff --git a/src/engine/server/sv_client.cpp b/src/engine/server/sv_client.cpp index 7e718ccade..c380e8da7b 100644 --- a/src/engine/server/sv_client.cpp +++ b/src/engine/server/sv_client.cpp @@ -385,6 +385,16 @@ void SV_SendClientGameState( client_t *client ) MSG_WriteByte( &msg, svc_baseline ); MSG_WriteDeltaEntity( &msg, &nullstate, base, true ); + + if ( MAX_MSGLEN - msg.cursize < 128 ) { + // We have too many entities to put them all into one msg_t, so split it here + MSG_WriteByte( &msg, svc_gamestatePartial ); + SV_SendMessageToClient( &msg, client ); + + MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) ); + MSG_WriteLong( &msg, client->lastClientCommand ); + MSG_WriteByte( &msg, svc_gamestate ); + } } MSG_WriteByte( &msg, svc_EOF ); From 942670e186b37e765937650efcb986faae180230 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 28 Jun 2025 16:42:17 +0300 Subject: [PATCH 27/66] NUKE unused RDF_SKYBOXPORTAL --- src/engine/renderer/tr_types.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 533ae454fe..2b53212d68 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -73,9 +73,6 @@ using bool8_t = uint8_t; #define RDF_NOWORLDMODEL ( 1 << 0 ) // used for player configuration screen #define RDF_HYPERSPACE ( 1 << 1 ) // teleportation effect -// Rafael -#define RDF_SKYBOXPORTAL ( 1 << 2 ) - // XreaL BEGIN #define RDF_NOCUBEMAP ( 1 << 3 ) // RB: don't use cubemaps #define RDF_NOBLOOM ( 1 << 4 ) // RB: disable bloom. useful for HUD models From fc8b442760ba299171c1878a4c8863b0d8379abf Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 28 Jun 2025 16:42:24 +0300 Subject: [PATCH 28/66] NUKE unused RSF_LIGHT_ATTENUATION --- src/engine/renderer/tr_types.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 2b53212d68..785730410e 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -83,13 +83,11 @@ using bool8_t = uint8_t; #define GL_INDEX_TYPE GL_UNSIGNED_INT using glIndex_t = unsigned int; -// TODO(0.56): drop RSF_LIGHT_ATTENUATION enum RegisterShaderFlags_t { RSF_DEFAULT = BIT( 0 ), RSF_2D = BIT( 1 ), RSF_NOMIP = BIT( 2 ), RSF_FITSCREEN = BIT( 3 ), - RSF_LIGHT_ATTENUATION = BIT( 4 ), RSF_FORCE_LIGHTMAP = BIT( 5 ), // Used to make particles/trails work with the lightGrid in GLSL RSF_SPRITE = BIT( 6 ), }; From 33d476e576f5fb1c079be00a10646a092cc81cf3 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 28 Jun 2025 16:49:43 +0300 Subject: [PATCH 29/66] Update MAX_REF_ENTITIES --- src/engine/renderer/tr_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 785730410e..4868937ccf 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -49,7 +49,7 @@ using bool8_t = uint8_t; // XreaL BEGIN #define MAX_REF_LIGHTS 1024 -#define MAX_REF_ENTITIES 1023 // can't be increased without changing drawsurf bit packing +#define MAX_REF_ENTITIES 8191 // can't be increased without changing drawsurf bit packing #define MAX_BONES 256 #define MAX_WEIGHTS 4 // GPU vertex skinning limit, never change this without rewriting many GLSL shaders // XreaL END From 3182fd6cc1c4d3e54aaf47c8a130dc146988b3fb Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Wed, 23 Jul 2025 23:30:17 +0000 Subject: [PATCH 30/66] sync for-0.56.0/sync submodules --- libs/crunch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/crunch b/libs/crunch index 371d9f0cf7..73e74fa7e2 160000 --- a/libs/crunch +++ b/libs/crunch @@ -1 +1 @@ -Subproject commit 371d9f0cf74ce31c5d210897c2fb366b830558c0 +Subproject commit 73e74fa7e28093c4802a3034f78edd81d0d8544b From c0dedb3948f78ccb412ffb27026529575df42ed4 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Fri, 1 Aug 2025 09:49:55 +0000 Subject: [PATCH 31/66] sync for-0.56.0/sync submodules --- libs/crunch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/crunch b/libs/crunch index 73e74fa7e2..371d9f0cf7 160000 --- a/libs/crunch +++ b/libs/crunch @@ -1 +1 @@ -Subproject commit 73e74fa7e28093c4802a3034f78edd81d0d8544b +Subproject commit 371d9f0cf74ce31c5d210897c2fb366b830558c0 From 4041e179b643ba3b28db99758b16f69e6dcf2209 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Tue, 12 Aug 2025 13:57:43 +0300 Subject: [PATCH 32/66] NUKE trap_GetEntityToken Remove the remnants of a useless engine round-trip previously used by gamelogic. --- src/engine/server/sg_msgdef.h | 5 ----- src/engine/server/sv_sgame.cpp | 7 ------- src/shared/server/sg_api.cpp | 9 --------- src/shared/server/sg_api.h | 1 - 4 files changed, 22 deletions(-) diff --git a/src/engine/server/sg_msgdef.h b/src/engine/server/sg_msgdef.h index a5b45d8d15..6b3faa8624 100644 --- a/src/engine/server/sg_msgdef.h +++ b/src/engine/server/sg_msgdef.h @@ -40,7 +40,6 @@ enum gameImport_t G_GET_USERINFO, G_GET_SERVERINFO, G_GET_USERCMD, - G_GET_ENTITY_TOKEN, G_RSA_GENMSG, // ( const char *public_key, char *cleartext, char *encrypted ) G_GEN_FINGERPRINT, G_GET_PLAYER_PUBKEY, @@ -83,10 +82,6 @@ using GetUsercmdMsg = IPC::SyncMessage< IPC::Message, int>, IPC::Reply >; -using SgGetEntityTokenMsg = IPC::SyncMessage< - IPC::Message>, - IPC::Reply ->; using RSAGenMsgMsg = IPC::SyncMessage< IPC::Message, std::string>, IPC::Reply diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index e6daef925e..c2fd9b86a9 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -520,13 +520,6 @@ void GameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& chan }); break; - case G_GET_ENTITY_TOKEN: - IPC::HandleMsg(channel, std::move(reader), [this](bool& boolRes, std::string& res) { - res = COM_Parse(&sv.entityParsePoint); - boolRes = sv.entityParsePoint or res.size() > 0; - }); - break; - case G_RSA_GENMSG: IPC::HandleMsg(channel, std::move(reader), [this](std::string pubkey, int& res, std::string& cleartext, std::string& encrypted) { char cleartextBuffer[RSA_STRING_LENGTH]; diff --git a/src/shared/server/sg_api.cpp b/src/shared/server/sg_api.cpp index 27768fe553..550b40ba80 100644 --- a/src/shared/server/sg_api.cpp +++ b/src/shared/server/sg_api.cpp @@ -103,15 +103,6 @@ void trap_GetUsercmd(int clientNum, usercmd_t *cmd) VM::SendMsg(clientNum, *cmd); } -bool trap_GetEntityToken(char *buffer, int bufferSize) -{ - std::string text; - bool res; - VM::SendMsg(res, text); - Q_strncpyz(buffer, text.c_str(), bufferSize); - return res; -} - int trap_RSA_GenerateMessage(const char *public_key, char *cleartext, char *encrypted) { std::string cleartext2, encrypted2; diff --git a/src/shared/server/sg_api.h b/src/shared/server/sg_api.h index 9042f19b7c..80ef7cc46e 100644 --- a/src/shared/server/sg_api.h +++ b/src/shared/server/sg_api.h @@ -47,7 +47,6 @@ void trap_GetServerinfo( char *buffer, int bufferSize ); int trap_BotAllocateClient(); void trap_BotFreeClient( int clientNum ); void trap_GetUsercmd( int clientNum, usercmd_t *cmd ); -bool trap_GetEntityToken( char *buffer, int bufferSize ); int trap_BotGetServerCommand( int clientNum, char *message, int size ); int trap_RSA_GenerateMessage( const char *public_key, char *cleartext, char *encrypted ); void trap_GenFingerprint( const char *pubkey, int size, char *buffer, int bufsize ); From 7e02ae9764462393b02e3229d0d349c736294691 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Fri, 15 Aug 2025 14:07:26 +0300 Subject: [PATCH 33/66] NUKE server_t.entityParsePoint --- src/engine/server/server.h | 6 ------ src/engine/server/sv_sgame.cpp | 7 +------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/engine/server/server.h b/src/engine/server/server.h index c57237484f..db788010dd 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -75,12 +75,6 @@ struct server_t bool configstringsmodified[ MAX_CONFIGSTRINGS ]; svEntity_t svEntities[ MAX_GENTITIES ]; - // this is apparently just a proxy, this pointer - // is set to contain the strings that define entities - // which must be parsed by sgame for spawning map entities, - // notably. - const char *entityParsePoint; // used during game VM init - // the game virtual machine will update these on init and changes byte *gentities; // points to the sgame's array of gentity_t int gentitySize; // >= sizeof(sharedEntity_t) - game can have unlimited amount of private data diff --git a/src/engine/server/sv_sgame.cpp b/src/engine/server/sv_sgame.cpp index c2fd9b86a9..be4eebf2be 100644 --- a/src/engine/server/sv_sgame.cpp +++ b/src/engine/server/sv_sgame.cpp @@ -275,14 +275,9 @@ Called for both a full init and a restart */ static void SV_InitGameVM() { - int i; - - // start the entity parsing at the beginning - sv.entityParsePoint = CM_EntityString(); - // clear all gentity pointers that might still be set from // a previous level - for ( i = 0; i < sv_maxClients.Get(); i++ ) + for ( int i = 0; i < sv_maxClients.Get(); i++ ) { svs.clients[ i ].gentity = nullptr; } From 0ff14a012696e2f5920a3da1a0a49d2288e4ae71 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Fri, 15 Aug 2025 14:10:00 +0300 Subject: [PATCH 34/66] NUKE the remnants of R_GetEntityToken() --- src/engine/null/null_renderer.cpp | 5 ----- src/engine/renderer/tr_bsp.cpp | 23 ----------------------- src/engine/renderer/tr_init.cpp | 1 - src/engine/renderer/tr_local.h | 1 - src/engine/renderer/tr_public.h | 2 -- 5 files changed, 32 deletions(-) diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index 4e2c3b325e..39404e01c6 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -107,10 +107,6 @@ int R_LerpTag( orientation_t*, const refEntity_t*, const char*, int ) } void R_ModelBounds( qhandle_t, vec3_t, vec3_t ) { } void R_RemapShader( const char*, const char*, const char* ) { } -bool R_GetEntityToken( char*, int ) -{ - return true; -} bool R_inPVS( const vec3_t, const vec3_t ) { return false; @@ -240,7 +236,6 @@ refexport_t *GetRefAPI( int, refimport_t* ) re.ModelBounds = R_ModelBounds; re.RemapShader = R_RemapShader; - re.GetEntityToken = R_GetEntityToken; re.inPVS = R_inPVS; re.inPVVS = R_inPVVS; diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index 5a4079173d..71f41de77f 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -3956,29 +3956,6 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities ) } } -/* -================= -R_GetEntityToken -================= -*/ -bool R_GetEntityToken( char *buffer, int size ) -{ - const char *s; - - s = COM_Parse2( &s_worldData.entityParsePoint ); - Q_strncpyz( buffer, s, size ); - - if ( !s_worldData.entityParsePoint || !s[ 0 ] ) - { - s_worldData.entityParsePoint = s_worldData.entityString; - return false; - } - else - { - return true; - } -} - static std::string headerString; static const std::string gridPath = "reflectionCubemaps"; static const std::string gridExtension = ".cubemapGrid"; diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index f88c34244d..510d0b1b14 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1621,7 +1621,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p re.UnregisterFont = RE_UnregisterFont; re.RemapShader = R_RemapShader; - re.GetEntityToken = R_GetEntityToken; re.inPVS = R_inPVS; re.inPVVS = R_inPVVS; // Q3A END diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 2cd083437f..6607f0b198 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2948,7 +2948,6 @@ void GL_CompressedTexSubImage3D( GLenum target, GLint level, GLint xOffset, GLin qhandle_t RE_RegisterSkin( const char *name ); void RE_Shutdown( bool destroyWindow ); - bool R_GetEntityToken( char *buffer, int size ); void R_ProcessLightmap( byte *bytes, int width, int height, int bits ); // Arnout model_t *R_AllocModel(); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index e60dc65080..842b7fc978 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -228,8 +228,6 @@ struct refexport_t void ( *RemapShader )( const char *oldShader, const char *newShader, const char *offsetTime ); - bool( *GetEntityToken )( char *buffer, int size ); - bool( *inPVS )( const vec3_t p1, const vec3_t p2 ); bool( *inPVVS )( const vec3_t p1, const vec3_t p2 ); From 75471c00d48e95ffd764a86d977028581a163386 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Wed, 13 Aug 2025 18:37:17 +0300 Subject: [PATCH 35/66] NUKE glconfig_t, use WindowConfig instead Move the stuff actually used by cgame (window and display sizes and display aspect) to `WindowConfig`. --- src/engine/client/cg_msgdef.h | 4 ++-- src/engine/client/cl_cgame.cpp | 20 ++------------------ src/engine/renderer/tr_public.h | 10 ++-------- src/engine/renderer/tr_types.h | 21 ++------------------- 4 files changed, 8 insertions(+), 47 deletions(-) diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 9918f5b3d3..14978a68fc 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -510,7 +510,7 @@ using CGameStaticInitMsg = IPC::SyncMessage< IPC::Message, int> >; using CGameInitMsg = IPC::SyncMessage< - IPC::Message, int, int, glconfig_t, GameStateCSs> + IPC::Message, int, int, WindowConfig, GameStateCSs> >; using CGameShutdownMsg = IPC::SyncMessage< IPC::Message> @@ -540,7 +540,7 @@ using CGameFocusEventMsg = IPC::SyncMessage< //TODO Check all rocket calls using CGameRocketInitMsg = IPC::SyncMessage< - IPC::Message, glconfig_t> + IPC::Message, WindowConfig> >; using CGameRocketFrameMsg = IPC::SyncMessage< IPC::Message, cgClientState_t> diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 8075da1443..fac9c4a758 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -956,15 +956,7 @@ void CGameVM::CGameStaticInit() void CGameVM::CGameInit(int serverMessageNum, int clientNum) { - glconfig_t glConfig; - memset( &glConfig, 0, sizeof( glconfig_t ) ); - glConfig.displayAspect = cls.windowConfig.displayAspect; - glConfig.displayWidth = cls.windowConfig.displayWidth; - glConfig.displayHeight = cls.windowConfig.displayHeight; - glConfig.vidWidth = cls.windowConfig.vidWidth; - glConfig.vidHeight = cls.windowConfig.vidHeight; - - this->SendMsg(serverMessageNum, clientNum, glConfig, cl.gameState); + this->SendMsg(serverMessageNum, clientNum, cls.windowConfig, cl.gameState); NetcodeTable psTable; size_t psSize; this->SendMsg(psTable, psSize); @@ -1028,15 +1020,7 @@ void CGameVM::CGameTextInputEvent(int c) void CGameVM::CGameRocketInit() { - glconfig_t glConfig; - memset( &glConfig, 0, sizeof( glconfig_t ) ); - glConfig.displayAspect = cls.windowConfig.displayAspect; - glConfig.displayWidth = cls.windowConfig.displayWidth; - glConfig.displayHeight = cls.windowConfig.displayHeight; - glConfig.vidWidth = cls.windowConfig.vidWidth; - glConfig.vidHeight = cls.windowConfig.vidHeight; - - this->SendMsg( glConfig ); + this->SendMsg( cls.windowConfig ); } void CGameVM::CGameRocketFrame() diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 1e15d3d9ff..63a79c7f33 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -170,12 +170,6 @@ struct GLConfig bool motionBlur; }; -struct WindowConfig { - float displayAspect; - int displayWidth, displayHeight; // the entire monitor (the one indicated by displayIndex) - int vidWidth, vidHeight; // what the game is using -}; - // // these are the functions exported by the refresh module // @@ -192,8 +186,8 @@ struct refexport_t // if necessary. // // BeginRegistration makes any existing media pointers invalid - // and returns the current gl configuration, including screen width - // and height, which can be used by the client to intelligently + // and returns the current window configuration, including screen and display width + // and height, and aspect ratio, which can be used by the client to intelligently // size display elements. Returns false if the renderer couldn't // be initialized. bool( *BeginRegistration )( WindowConfig* windowCfg ); diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 6438b125a4..deedd1381a 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -273,30 +273,13 @@ enum class glHardwareType_t /** * Contains variables specific to the OpenGL configuration - * being run right now. These are constant once the OpenGL + * being run right now. These are constant once the OpenGL * subsystem is initialized. */ -struct glconfig_t -{ - char renderer_string[ MAX_STRING_CHARS ]; - char vendor_string[ MAX_STRING_CHARS ]; - char version_string[ MAX_STRING_CHARS ]; - - int maxTextureSize; // queried from GL - - int colorBits; - - glDriverType_t driverType; - glHardwareType_t hardwareType; - - textureCompression_t textureCompression; - - int displayIndex; +struct WindowConfig { float displayAspect; int displayWidth, displayHeight; // the entire monitor (the one indicated by displayIndex) int vidWidth, vidHeight; // what the game is using - - bool8_t smpActive; // dual processor }; #pragma pop_macro("bool") From 061ed952f9309901cb525efe8ba2da4564ac2517 Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 27 Aug 2025 03:11:18 -0500 Subject: [PATCH 36/66] Update dummygame for glconfig_t -> WindowConfig --- src/dummygame/cgame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dummygame/cgame.cpp b/src/dummygame/cgame.cpp index 275d226455..828d29d350 100644 --- a/src/dummygame/cgame.cpp +++ b/src/dummygame/cgame.cpp @@ -80,7 +80,7 @@ void VM::VMHandleSyscall(uint32_t id, Util::Reader reader) { break; case CG_ROCKET_VM_INIT: - IPC::HandleMsg(VM::rootChannel, std::move(reader), [] (const glconfig_t& gl) { + IPC::HandleMsg(VM::rootChannel, std::move(reader), [] (const WindowConfig& gl) { refdef.width = gl.vidWidth; refdef.height = gl.vidHeight; }); From 4823cdea269c8579bc05870caca5e4ab64191cd4 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Thu, 4 Sep 2025 17:32:46 +0000 Subject: [PATCH 37/66] sync for-0.56.0/sync submodules --- libs/breakpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/breakpad b/libs/breakpad index 5ee0dc12f6..fd6cc4ce9f 160000 --- a/libs/breakpad +++ b/libs/breakpad @@ -1 +1 @@ -Subproject commit 5ee0dc12f6403323494962b8d172b16b1ed99d37 +Subproject commit fd6cc4ce9f41047b13ca1e041726ef7dedb594bd From 66b2f11d95c88a2a0007614ef70457a0905b130c Mon Sep 17 00:00:00 2001 From: VReaperV Date: Wed, 13 Aug 2025 20:03:06 +0300 Subject: [PATCH 38/66] Fix looping sounds --- src/engine/audio/Audio.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/engine/audio/Audio.cpp b/src/engine/audio/Audio.cpp index 2147e349c0..753339dc77 100644 --- a/src/engine/audio/Audio.cpp +++ b/src/engine/audio/Audio.cpp @@ -197,9 +197,7 @@ namespace Audio { auto& loop = entityLoops[i]; if (loop.sound and not loop.addedThisFrame) { // The loop wasn't added this frame, that means it has to be removed. - loop.sound->FadeOutAndDie(); - loop = {false, nullptr, -1, -1}; - + loop.sound->SetSoundGain( 0 ); } else if (loop.oldSfx != loop.newSfx) { // The last sfx added in the frame is not the current one being played // To mimic the previous sound system's behavior we sart playing the new one. From 97c44663779f190e04b099c9e3145fda9536994c Mon Sep 17 00:00:00 2001 From: VReaperV Date: Wed, 13 Aug 2025 20:18:57 +0300 Subject: [PATCH 39/66] Get rid of some stupid javisms --- src/engine/audio/Audio.cpp | 8 +-- src/engine/audio/Emitter.cpp | 12 ++--- src/engine/audio/Sound.cpp | 95 ++++++++++-------------------------- src/engine/audio/Sound.h | 36 ++++---------- 4 files changed, 45 insertions(+), 106 deletions(-) diff --git a/src/engine/audio/Audio.cpp b/src/engine/audio/Audio.cpp index 753339dc77..15995ef4ad 100644 --- a/src/engine/audio/Audio.cpp +++ b/src/engine/audio/Audio.cpp @@ -194,10 +194,10 @@ namespace Audio { } for (int i = 0; i < MAX_GENTITIES; i++) { - auto& loop = entityLoops[i]; + entityLoop_t& loop = entityLoops[i]; if (loop.sound and not loop.addedThisFrame) { // The loop wasn't added this frame, that means it has to be removed. - loop.sound->SetSoundGain( 0 ); + loop.sound->soundGain = 0; } else if (loop.oldSfx != loop.newSfx) { // The last sfx added in the frame is not the current one being played // To mimic the previous sound system's behavior we sart playing the new one. @@ -341,7 +341,7 @@ namespace Audio { StopMusic(); music = std::make_shared(loopingSample, leadingSample); - music->SetVolumeModifier(musicVolume); + music->volumeModifier = &musicVolume; AddSound(GetLocalEmitter(), music, 1); } @@ -379,7 +379,7 @@ namespace Audio { } } - streams[streamNum]->SetGain(volume); + streams[streamNum]->soundGain = volume; AudioData audioData { rate, width, channels }; audioData.rawSamples.resize( width * numSamples * channels ); diff --git a/src/engine/audio/Emitter.cpp b/src/engine/audio/Emitter.cpp index e388545f87..d4b09a54e1 100644 --- a/src/engine/audio/Emitter.cpp +++ b/src/engine/audio/Emitter.cpp @@ -261,7 +261,7 @@ namespace Audio { Emitter::~Emitter() = default; void Emitter::SetupSound(Sound& sound) { - sound.GetSource().SetReferenceDistance(120.0f); + sound.source->SetReferenceDistance(120.0f); InternalSetupSound(sound); UpdateSound(sound); } @@ -278,7 +278,7 @@ namespace Audio { } void EntityEmitter::UpdateSound(Sound& sound) { - AL::Source& source = sound.GetSource(); + AL::Source& source = *sound.source; if (entityNum == listenerEntity) { MakeLocal(source); @@ -288,7 +288,7 @@ namespace Audio { } void EntityEmitter::InternalSetupSound(Sound& sound) { - AL::Source& source = sound.GetSource(); + AL::Source& source = *sound.source; Make3D(source, entities[entityNum].position, entities[entityNum].velocity); } @@ -306,13 +306,13 @@ namespace Audio { } void PositionEmitter::UpdateSound(Sound& sound) { - AL::Source& source = sound.GetSource(); + AL::Source& source = *sound.source; Make3D(source, position, origin); } void PositionEmitter::InternalSetupSound(Sound& sound) { - AL::Source& source = sound.GetSource(); + AL::Source& source = *sound.source; Make3D(source, position, origin); } @@ -334,7 +334,7 @@ namespace Audio { } void LocalEmitter::InternalSetupSound(Sound& sound) { - AL::Source& source = sound.GetSource(); + AL::Source& source = *sound.source; MakeLocal(source); } diff --git a/src/engine/audio/Sound.cpp b/src/engine/audio/Sound.cpp index a474d7479f..3cb392299d 100644 --- a/src/engine/audio/Sound.cpp +++ b/src/engine/audio/Sound.cpp @@ -85,18 +85,18 @@ namespace Audio { for (int i = 0; i < nSources; i++) { if (sources[i].active) { - auto sound = sources[i].usingSound; + std::shared_ptr sound = sources[i].usingSound; // Update and Emitter::UpdateSound can call Sound::Stop - if (not sound->IsStopped()) { + if ( sound->playing ) { sound->Update(); } - if (not sound->IsStopped()) { - sound->GetEmitter()->UpdateSound(*sound); + if ( sound->playing ) { + sound->emitter->UpdateSound(*sound); } - if (sound->IsStopped()) { + if ( !sound->playing ) { sources[i].active = false; sources[i].usingSound = nullptr; } @@ -126,7 +126,7 @@ namespace Audio { if (source) { // Make the source forget if it was a "static" or a "streaming" source. source->source.ResetBuffer(); - sound->SetEmitter(emitter); + sound->emitter = emitter; sound->AcquireSource(source->source); source->usingSound = sound; source->priority = priority; @@ -188,40 +188,6 @@ namespace Audio { playing = false; } - bool Sound::IsStopped() { - return not playing; - } - - void Sound::SetPositionalGain(float gain) { - positionalGain = gain; - } - - void Sound::SetSoundGain(float gain) { - soundGain = gain; - } - - float Sound::GetCurrentGain() { - return currentGain; - } - - void Sound::SetVolumeModifier(const Cvar::Range>& volumeMod) - { - this->volumeModifier = &volumeMod; - } - - float Sound::GetVolumeModifier() const - { - return volumeModifier->Get(); - } - - void Sound::SetEmitter(std::shared_ptr emitter) { - this->emitter = emitter; - } - - std::shared_ptr Sound::GetEmitter() { - return emitter; - } - void Sound::AcquireSource(AL::Source& source) { this->source = &source; @@ -231,19 +197,15 @@ namespace Audio { emitter->SetupSound(*this); } - AL::Source& Sound::GetSource() { - return *source; - } - // Set the gain before the source is started to avoid having a few milliseconds of very loud sound void Sound::FinishSetup() { - currentGain = positionalGain * soundGain * SliderToAmplitude(GetVolumeModifier()); + currentGain = positionalGain * soundGain * SliderToAmplitude(volumeModifier->Get()); source->SetGain(currentGain); } void Sound::Update() { // Fade the Gain update to avoid "ticking" sounds when there is a gain discontinuity - float targetGain = positionalGain * soundGain * SliderToAmplitude(GetVolumeModifier()); + float targetGain = positionalGain * soundGain * SliderToAmplitude(volumeModifier->Get()); //TODO make it framerate independent and fade out in about 1/8 seconds ? if (currentGain > targetGain) { @@ -267,15 +229,15 @@ namespace Audio { void OneShotSound::SetupSource(AL::Source& source) { source.SetBuffer(sample->GetBuffer()); - SetSoundGain(GetVolumeModifier()); + soundGain = volumeModifier->Get(); } void OneShotSound::InternalUpdate() { - if (GetSource().IsStopped()) { + if ( source->IsStopped() ) { Stop(); return; } - SetSoundGain(GetVolumeModifier()); + soundGain = volumeModifier->Get(); } // Implementation of LoopingSound @@ -289,7 +251,7 @@ namespace Audio { void LoopingSound::FadeOutAndDie() { fadingOut = true; - SetSoundGain(0.0f); + soundGain = 0.0f; } void LoopingSound::SetupSource(AL::Source& source) { @@ -298,23 +260,23 @@ namespace Audio { } else { SetupLoopingSound(source); } - SetSoundGain(GetVolumeModifier()); + soundGain = volumeModifier->Get(); } void LoopingSound::InternalUpdate() { - if (fadingOut and GetCurrentGain() == 0.0f) { + if (fadingOut and currentGain == 0.0f) { Stop(); } if (not fadingOut) { if (leadingSample) { - if (GetSource().IsStopped()) { - SetupLoopingSound(GetSource()); - GetSource().Play(); + if ( source->IsStopped() ) { + SetupLoopingSound( *source ); + source->Play(); leadingSample = nullptr; } } - SetSoundGain(GetVolumeModifier()); + soundGain = volumeModifier->Get(); } } @@ -335,32 +297,25 @@ namespace Audio { } void StreamingSound::InternalUpdate() { - AL::Source& source = GetSource(); - - while (source.GetNumProcessedBuffers() > 0) { - source.PopBuffer(); + while ( source->GetNumProcessedBuffers() > 0 ) { + source->PopBuffer(); } - if (source.GetNumQueuedBuffers() == 0) { + if ( source->GetNumQueuedBuffers() == 0 ) { Stop(); } } //TODO somehow try to catch back when data is coming faster than we consume (e.g. capture data) void StreamingSound::AppendBuffer(AL::Buffer buffer) { - if (IsStopped()) { + if ( !playing ) { return; } - AL::Source& source = GetSource(); - source.QueueBuffer(std::move(buffer)); + source->QueueBuffer(std::move(buffer)); - if (source.IsStopped()) { - source.Play(); + if ( source->IsStopped() ) { + source->Play(); } } - - void StreamingSound::SetGain(float gain) { - SetSoundGain(gain); - } } diff --git a/src/engine/audio/Sound.h b/src/engine/audio/Sound.h index fa2f3a1415..1bcc28ffef 100644 --- a/src/engine/audio/Sound.h +++ b/src/engine/audio/Sound.h @@ -54,29 +54,24 @@ namespace Audio { //TODO sound.mute class Sound { public: + float positionalGain; + float soundGain; + float currentGain; + + bool playing; + const Cvar::Range>* volumeModifier; + + AL::Source* source; + std::shared_ptr emitter; + Sound(); virtual ~Sound(); void Play(); // Stop the source and marks the sound for deletion. void Stop(); - bool IsStopped(); - - // The is attenuated because of its inherent porperties and because of its position. - // Each attenuation can be set separately. - void SetPositionalGain(float gain); - void SetSoundGain(float gain); - float GetCurrentGain(); - - // sfx vs. music - void SetVolumeModifier(const Cvar::Range>& volumeMod); - float GetVolumeModifier() const; - - void SetEmitter(std::shared_ptr emitter); - std::shared_ptr GetEmitter(); void AcquireSource(AL::Source& source); - AL::Source& GetSource(); // Used to setup a source for a specific kind of sound and to start the sound. virtual void SetupSource(AL::Source& source) = 0; @@ -85,16 +80,6 @@ namespace Audio { void Update(); // Called each frame, after emitters have been updated. virtual void InternalUpdate() = 0; - - private: - float positionalGain; - float soundGain; - float currentGain; - - bool playing; - std::shared_ptr emitter; - const Cvar::Range>* volumeModifier; - AL::Source* source; }; // A sound that is played once. @@ -139,7 +124,6 @@ namespace Audio { virtual void InternalUpdate() override; void AppendBuffer(AL::Buffer buffer); - void SetGain(float gain); }; } From c61dbf895673f0dd771b6872384ffecb78f6bf19 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Wed, 13 Aug 2025 23:33:35 +0300 Subject: [PATCH 40/66] Destroy dead sounds --- src/engine/audio/Audio.cpp | 24 ++++++++++++++++-------- src/engine/audio/Audio.h | 2 +- src/engine/client/cg_msgdef.h | 2 +- src/engine/client/cl_cgame.cpp | 4 ++-- src/engine/null/NullAudio.cpp | 2 +- src/shared/client/cg_api.cpp | 9 ++------- src/shared/client/cg_api.h | 4 ++-- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/engine/audio/Audio.cpp b/src/engine/audio/Audio.cpp index 15995ef4ad..145ecdd508 100644 --- a/src/engine/audio/Audio.cpp +++ b/src/engine/audio/Audio.cpp @@ -58,6 +58,7 @@ namespace Audio { // in a frame, it means it sould be destroyed. struct entityLoop_t { bool addedThisFrame; + bool persistent; std::shared_ptr sound; sfxHandle_t newSfx; sfxHandle_t oldSfx; @@ -148,7 +149,7 @@ namespace Audio { UpdateListenerGain(); for (auto &loop : entityLoops) { - loop = {false, nullptr, -1, -1}; + loop = {false, false, nullptr, -1, -1}; } return true; @@ -164,7 +165,7 @@ namespace Audio { if (loop.sound) { loop.sound->Stop(); } - loop = {false, nullptr, -1, -1}; + loop = {false, false, nullptr, -1, -1}; } StopMusic(); @@ -196,17 +197,23 @@ namespace Audio { for (int i = 0; i < MAX_GENTITIES; i++) { entityLoop_t& loop = entityLoops[i]; if (loop.sound and not loop.addedThisFrame) { - // The loop wasn't added this frame, that means it has to be removed. - loop.sound->soundGain = 0; + if ( loop.persistent ) { + loop.sound->soundGain = 0; + } else { + // The loop wasn't added this frame, that means it has to be removed. + loop.sound->FadeOutAndDie(); + loop = { false, false, nullptr, -1, -1 }; + } } else if (loop.oldSfx != loop.newSfx) { // The last sfx added in the frame is not the current one being played // To mimic the previous sound system's behavior we sart playing the new one. loop.sound->FadeOutAndDie(); int newSfx = loop.newSfx; - loop = {false, nullptr, -1, -1}; + bool persistent = loop.persistent; + loop = {false, false, nullptr, -1, -1}; - AddEntityLoopingSound(i, newSfx); + AddEntityLoopingSound(i, newSfx, persistent); } } @@ -221,7 +228,7 @@ namespace Audio { loop.addedThisFrame = false; // if we are the unique owner of a loop pointer, then it means it was stopped, free it. if (loop.sound.use_count() == 1) { - loop = {false, nullptr, -1, -1}; + loop = {false, false, nullptr, -1, -1}; } } @@ -286,7 +293,7 @@ namespace Audio { AddSound(GetLocalEmitter(), std::make_shared(Sample::FromHandle(sfx)), 1); } - void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx) { + void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx, bool persistent) { if (not initialized or not Sample::IsValidHandle(sfx) or not IsValidEntity(entityNum)) { return; } @@ -300,6 +307,7 @@ namespace Audio { AddSound(GetEmitterForEntity(entityNum), loop.sound, 1); } loop.addedThisFrame = true; + loop.persistent = persistent; // We remember what is the last sfx asked because cgame expects the sfx added last in the frame to be played loop.newSfx = sfx; diff --git a/src/engine/audio/Audio.h b/src/engine/audio/Audio.h index cbd30c989a..220c2422a0 100644 --- a/src/engine/audio/Audio.h +++ b/src/engine/audio/Audio.h @@ -50,7 +50,7 @@ namespace Audio { void StartSound(int entityNum, Vec3 origin, sfxHandle_t sfx); void StartLocalSound(int entityNum); - void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx); + void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx, bool persistent); void ClearAllLoopingSounds(); void ClearLoopingSoundsForEntity(int entityNum); diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 14978a68fc..a365fc1b8c 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -282,7 +282,7 @@ namespace Audio { using StartSoundMsg = IPC::Message, bool, Vec3, int, int>; using StartLocalSoundMsg = IPC::Message, int>; using ClearLoopingSoundsMsg = IPC::Message>; - using AddLoopingSoundMsg = IPC::Message, int, int>; + using AddLoopingSoundMsg = IPC::Message, int, int, bool>; using StopLoopingSoundMsg = IPC::Message, int>; using UpdateEntityPositionMsg = IPC::Message, int, Vec3>; using RespatializeMsg = IPC::Message, int, std::array>; diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index fac9c4a758..9010d5ef64 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1506,8 +1506,8 @@ void CGameVM::CmdBuffer::HandleCommandBufferSyscall(int major, int minor, Util:: break; case CG_S_ADDLOOPINGSOUND: - HandleMsg(std::move(reader), [this] (int entityNum, int sfx) { - Audio::AddEntityLoopingSound(entityNum, sfx); + HandleMsg(std::move(reader), [this] (int entityNum, int sfx, bool persistent) { + Audio::AddEntityLoopingSound(entityNum, sfx, persistent); }); break; diff --git a/src/engine/null/NullAudio.cpp b/src/engine/null/NullAudio.cpp index 3b96d95e52..cc213e8363 100644 --- a/src/engine/null/NullAudio.cpp +++ b/src/engine/null/NullAudio.cpp @@ -65,7 +65,7 @@ namespace Audio { } - void AddEntityLoopingSound(int, sfxHandle_t) { + void AddEntityLoopingSound(int, sfxHandle_t, bool) { } void ClearAllLoopingSounds() { diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index 9eea1f66be..995928b160 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -153,7 +153,7 @@ void trap_S_ClearLoopingSounds( bool ) cmdBuffer.SendMsg(); } -void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) +void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, bool persistent ) { if (origin) { trap_S_UpdateEntityPosition(entityNum, origin); @@ -161,12 +161,7 @@ void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t ve if (velocity) { trap_S_UpdateEntityVelocity(entityNum, velocity); } - cmdBuffer.SendMsg(entityNum, sfx); -} - -void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) -{ - trap_S_AddLoopingSound(entityNum, origin, velocity, sfx); + cmdBuffer.SendMsg( entityNum, sfx, persistent ); } void trap_S_StopLoopingSound( int entityNum ) diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index 4e2781c3d7..a8467c05d2 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -53,8 +53,8 @@ void trap_CM_BatchMarkFragments( void trap_S_StartSound( vec3_t origin, int entityNum, soundChannel_t entchannel, sfxHandle_t sfx ); void trap_S_StartLocalSound( sfxHandle_t sfx, soundChannel_t channelNum ); void trap_S_ClearLoopingSounds( bool killall ); -void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ); -void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ); +void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, + bool persistent = false ); void trap_S_StopLoopingSound( int entityNum ); void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ); void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[ 3 ], int inwater ); From 1b8efb9d31937f2d12df345f2554cde6224fb150 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Fri, 15 Aug 2025 10:52:06 +0300 Subject: [PATCH 41/66] Implement SVF_BROADCAST_ONCE --- src/engine/server/sg_api.h | 1 + src/engine/server/sv_snapshot.cpp | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/engine/server/sg_api.h b/src/engine/server/sg_api.h index 7ba16db755..db1d211ee8 100644 --- a/src/engine/server/sg_api.h +++ b/src/engine/server/sg_api.h @@ -44,6 +44,7 @@ along with this program. If not, see . #define SVF_SELF_PORTAL_EXCLUSIVE 0x00010000 #define SVF_RIGID_BODY 0x00020000 // ignored by the engine #define SVF_CLIENTS_IN_RANGE 0x00040000 // clients within range +#define SVF_BROADCAST_ONCE 0x00040000 // broadcasted to newly connecting clients, and once to connected clients when spawned #define MAX_ENT_CLUSTERS 16 diff --git a/src/engine/server/sv_snapshot.cpp b/src/engine/server/sv_snapshot.cpp index 4bb29b85d5..f9a29fccf8 100644 --- a/src/engine/server/sv_snapshot.cpp +++ b/src/engine/server/sv_snapshot.cpp @@ -341,7 +341,7 @@ static void SV_AddEntToSnapshot( svEntity_t *svEnt, sharedEntity_t *gEnt, SV_AddEntitiesVisibleFromPoint =============== */ -static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, +static void SV_AddEntitiesVisibleFromPoint( client_t* client, vec3_t origin, clientSnapshot_t *frame, // snapshotEntityNumbers_t *eNums, bool portal, clientSnapshot_t *oldframe, bool localClient ) { // snapshotEntityNumbers_t *eNums, bool portal ) { snapshotEntityNumbers_t *eNums /*, bool portal, bool localClient */ ) @@ -379,7 +379,7 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra if ( playerEnt->r.svFlags & SVF_SELF_PORTAL ) { - SV_AddEntitiesVisibleFromPoint( playerEnt->s.origin2, frame, eNums ); + SV_AddEntitiesVisibleFromPoint( client, playerEnt->s.origin2, frame, eNums ); } for ( e = 0; e < sv.num_entities; e++ ) @@ -462,6 +462,11 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra continue; } + if ( ( ent->r.svFlags & SVF_BROADCAST_ONCE ) && !client->reliableAcknowledge ) { + SV_AddEntToSnapshot( svEnt, ent, eNums ); + continue; + } + // send entity if the client is in range if ( (ent->r.svFlags & SVF_CLIENTS_IN_RANGE) && Distance( ent->s.origin, playerEnt->s.origin ) <= ent->r.clientRadius ) @@ -637,7 +642,7 @@ static void SV_AddEntitiesVisibleFromPoint( vec3_t origin, clientSnapshot_t *fra } // SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums, true, oldframe, localClient ); - SV_AddEntitiesVisibleFromPoint( ent->s.origin2, frame, eNums /*, true, localClient */ ); + SV_AddEntitiesVisibleFromPoint( client, ent->s.origin2, frame, eNums /*, true, localClient */ ); } continue; @@ -720,7 +725,7 @@ static void SV_BuildClientSnapshot( client_t *client ) // add all the entities directly visible to the eye, which // may include portal entities that merge other viewpoints - SV_AddEntitiesVisibleFromPoint( org, frame, &entityNumbers /*, false, client->netchan.remoteAddress.type == NA_LOOPBACK */ ); + SV_AddEntitiesVisibleFromPoint( client, org, frame, &entityNumbers /*, false, client->netchan.remoteAddress.type == NA_LOOPBACK */ ); // if there were portals visible, there may be out of order entities // in the list which will need to be resorted for the delta compression From 162d8cf0a78e9aadb78d9929ecd5e10a0e72e240 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Fri, 15 Aug 2025 12:26:11 +0300 Subject: [PATCH 42/66] Allow multiple sounds per entity --- src/engine/audio/Audio.cpp | 122 +++++++++++++++++++++++--------- src/engine/audio/AudioPrivate.h | 2 + src/engine/audio/Emitter.cpp | 58 +++++++++------ 3 files changed, 127 insertions(+), 55 deletions(-) diff --git a/src/engine/audio/Audio.cpp b/src/engine/audio/Audio.cpp index 145ecdd508..42b6dccb73 100644 --- a/src/engine/audio/Audio.cpp +++ b/src/engine/audio/Audio.cpp @@ -63,7 +63,58 @@ namespace Audio { sfxHandle_t newSfx; sfxHandle_t oldSfx; }; - static entityLoop_t entityLoops[MAX_GENTITIES]; + + struct EntityMultiLoop { + entityLoop_t loops[MAX_ENTITY_SOUNDS]; + + entityLoop_t& FindSlot( const sfxHandle_t sfx ) { + uint32_t bestSlot = 0; + float minGain = FLT_MAX; + + for ( entityLoop_t& loop : loops ) { + if ( sfx == loop.oldSfx ) { + return loop; + } + + if ( !loop.sound ) { + return loop; + } + + if ( loop.sound->currentGain < minGain ) { + bestSlot = &loop - loops; + minGain = loop.sound->currentGain; + } + } + + return loops[bestSlot]; + } + + void StopAll() { + for ( entityLoop_t& loop : loops ) { + if ( loop.sound ) { + loop.sound->Stop(); + } + + loop = { false, false, nullptr, -1, -1 }; + } + } + + void ResetAll() { + for ( entityLoop_t& loop : loops ) { + loop = { false, false, nullptr, -1, -1 }; + } + } + + void ClearLoopingSounds() { + for ( entityLoop_t& loop : loops ) { + if ( loop.sound ) { + loop.addedThisFrame = false; + } + } + } + }; + + static EntityMultiLoop entityLoops[MAX_GENTITIES]; static std::shared_ptr streams[N_STREAMS]; @@ -148,8 +199,8 @@ namespace Audio { UpdateListenerGain(); - for (auto &loop : entityLoops) { - loop = {false, false, nullptr, -1, -1}; + for ( EntityMultiLoop& loop : entityLoops ) { + loop.ResetAll(); } return true; @@ -161,11 +212,8 @@ namespace Audio { } // Shuts down the wrapper - for (auto &loop : entityLoops) { - if (loop.sound) { - loop.sound->Stop(); - } - loop = {false, false, nullptr, -1, -1}; + for ( EntityMultiLoop& loop : entityLoops ) { + loop.StopAll(); } StopMusic(); @@ -194,26 +242,29 @@ namespace Audio { return; } - for (int i = 0; i < MAX_GENTITIES; i++) { - entityLoop_t& loop = entityLoops[i]; - if (loop.sound and not loop.addedThisFrame) { - if ( loop.persistent ) { - loop.sound->soundGain = 0; - } else { - // The loop wasn't added this frame, that means it has to be removed. + for ( uint32_t i = 0; i < MAX_GENTITIES; i++ ) { + EntityMultiLoop& multiLoop = entityLoops[i]; + + for ( entityLoop_t& loop : multiLoop.loops ) { + if ( loop.sound and not loop.addedThisFrame ) { + if ( loop.persistent ) { + loop.sound->soundGain = 0; + } else { + // The loop wasn't added this frame, that means it has to be removed. + loop.sound->FadeOutAndDie(); + loop = { false, false, nullptr, -1, -1 }; + } + } else if ( loop.oldSfx != loop.newSfx ) { + // The last sfx added in the frame is not the current one being played + // To mimic the previous sound system's behavior we sart playing the new one. loop.sound->FadeOutAndDie(); - loop = { false, false, nullptr, -1, -1 }; - } - } else if (loop.oldSfx != loop.newSfx) { - // The last sfx added in the frame is not the current one being played - // To mimic the previous sound system's behavior we sart playing the new one. - loop.sound->FadeOutAndDie(); - int newSfx = loop.newSfx; - bool persistent = loop.persistent; - loop = {false, false, nullptr, -1, -1}; + int newSfx = loop.newSfx; + bool persistent = loop.persistent; + loop = { false, false, nullptr, -1, -1 }; - AddEntityLoopingSound(i, newSfx, persistent); + AddEntityLoopingSound( i, newSfx, persistent ); + } } } @@ -224,15 +275,17 @@ namespace Audio { UpdateEmitters(); UpdateSounds(); - for (auto &loop : entityLoops) { - loop.addedThisFrame = false; - // if we are the unique owner of a loop pointer, then it means it was stopped, free it. - if (loop.sound.use_count() == 1) { - loop = {false, false, nullptr, -1, -1}; + for ( EntityMultiLoop& multiLoop : entityLoops ) { + for ( entityLoop_t& loop : multiLoop.loops ) { + loop.addedThisFrame = false; + // if we are the unique owner of a loop pointer, then it means it was stopped, free it. + if ( loop.sound.use_count() == 1 ) { + loop = { false, false, nullptr, -1, -1 }; + } } } - for (auto &stream : streams) { + for ( std::shared_ptr &stream : streams ) { if (stream and stream.use_count() == 1) { stream = nullptr; } @@ -298,7 +351,7 @@ namespace Audio { return; } - entityLoop_t& loop = entityLoops[entityNum]; + entityLoop_t& loop = entityLoops[entityNum].FindSlot( sfx ); // If we have no sound we can play the loop directly if (not loop.sound) { @@ -306,6 +359,7 @@ namespace Audio { loop.oldSfx = sfx; AddSound(GetEmitterForEntity(entityNum), loop.sound, 1); } + loop.addedThisFrame = true; loop.persistent = persistent; @@ -328,9 +382,7 @@ namespace Audio { return; } - if (entityLoops[entityNum].sound) { - entityLoops[entityNum].addedThisFrame = false; - } + entityLoops[entityNum].ClearLoopingSounds(); } void StartMusic(Str::StringRef leadingSound, Str::StringRef loopSound) { diff --git a/src/engine/audio/AudioPrivate.h b/src/engine/audio/AudioPrivate.h index 0bbde3377b..2b7b2b98de 100644 --- a/src/engine/audio/AudioPrivate.h +++ b/src/engine/audio/AudioPrivate.h @@ -63,6 +63,8 @@ namespace Audio { // There is only a small number of reverb slots because by default we can create only 4 AuxEffects CONSTEXPR int N_REVERB_SLOTS = 3; + constexpr uint32_t MAX_ENTITY_SOUNDS = 4; + // Tweaks the value given by the audio slider float SliderToAmplitude(float slider); diff --git a/src/engine/audio/Emitter.cpp b/src/engine/audio/Emitter.cpp index d4b09a54e1..673ae174fc 100644 --- a/src/engine/audio/Emitter.cpp +++ b/src/engine/audio/Emitter.cpp @@ -41,8 +41,30 @@ namespace Audio { static entityData_t entities[MAX_GENTITIES]; static int listenerEntity = -1; - // Keep entity Emitters in an array because there is at most one per entity. - static std::shared_ptr entityEmitters[MAX_GENTITIES]; + struct EntityMultiEmitter { + std::shared_ptr emitters[MAX_ENTITY_SOUNDS]; + + std::shared_ptr& FindSlot( const int entityNum ) { + for ( std::shared_ptr& emitter : emitters ) { + if ( !emitter ) { + emitter = std::make_shared( entityNum ); + return emitter; + } + } + + return emitters[0]; + } + + void Shutdown() { + for ( std::shared_ptr& emitter : emitters ) { + if ( emitter ) { + emitter = nullptr; + } + } + } + }; + + static EntityMultiEmitter entityEmitters[MAX_GENTITIES]; // Position Emitters can be reused so we keep the list of all of them // this is not very efficient but we cannot have more position emitters @@ -100,15 +122,13 @@ namespace Audio { localEmitter = nullptr; - for (auto &slot : reverbSlots) { + for ( ReverbSlot& slot : reverbSlots ) { delete slot.effect; slot.effect = nullptr; } - for (auto &emitter : entityEmitters) { - if ( emitter ) { - emitter = nullptr; - } + for ( EntityMultiEmitter& emitter : entityEmitters ) { + emitter.Shutdown(); } posEmitters.clear(); @@ -124,16 +144,18 @@ namespace Audio { // Both PositionEmitters and EntityEmitters are ref-counted. // If we hold the only reference to them then no sound is still using // the Emitter that can be destroyed. - for (auto &emitter : entityEmitters) { - if (not emitter) { - continue; - } + for ( EntityMultiEmitter& multiEmitter : entityEmitters ) { + for ( std::shared_ptr& emitter : multiEmitter.emitters ) { + if ( not emitter ) { + continue; + } - emitter->Update(); + emitter->Update(); - // No sound is using this emitter, destroy it - if (emitter.use_count() == 1) { - emitter = nullptr; + // No sound is using this emitter, destroy it + if ( emitter.use_count() == 1 ) { + emitter = nullptr; + } } } @@ -165,11 +187,7 @@ namespace Audio { } std::shared_ptr GetEmitterForEntity(int entityNum) { - if (not entityEmitters[entityNum]) { - entityEmitters[entityNum] = std::make_shared(entityNum); - } - - return entityEmitters[entityNum]; + return entityEmitters[entityNum].FindSlot( entityNum ); } std::shared_ptr GetEmitterForPosition(Vec3 position) { From 74e26bba8bc10d2c1c6284fb031049560ae5aa2c Mon Sep 17 00:00:00 2001 From: VReaperV Date: Fri, 15 Aug 2025 17:00:39 +0300 Subject: [PATCH 43/66] Implement some sound priorities Use the sound's volume and distance to determine which sounds to replace. Player/bot sounds get a higher priority within `a_clientSoundPriorityMaxDistance` distance, with the multiplier `a_clientSoundPriorityMultiplier`. --- src/engine/audio/Audio.cpp | 22 ++++++--- src/engine/audio/Audio.h | 2 +- src/engine/audio/AudioPrivate.h | 15 +++++++ src/engine/audio/Emitter.cpp | 17 +++---- src/engine/audio/Emitter.h | 10 ++++- src/engine/audio/Sound.cpp | 79 +++++++++++++++++++++++---------- src/engine/client/cg_msgdef.h | 2 +- src/engine/client/cl_cgame.cpp | 4 +- src/engine/null/NullAudio.cpp | 2 +- src/shared/client/cg_api.cpp | 4 +- src/shared/client/cg_api.h | 2 +- 11 files changed, 111 insertions(+), 48 deletions(-) diff --git a/src/engine/audio/Audio.cpp b/src/engine/audio/Audio.cpp index 42b6dccb73..527abbd455 100644 --- a/src/engine/audio/Audio.cpp +++ b/src/engine/audio/Audio.cpp @@ -120,6 +120,8 @@ namespace Audio { static bool initialized = false; + int playerClientNum; + static AL::Device* device; static AL::Context* context; @@ -292,11 +294,13 @@ namespace Audio { } } - void BeginRegistration() { + void BeginRegistration( const int playerNum ) { if (not initialized) { return; } + playerClientNum = playerNum; + BeginSampleRegistration(); } @@ -317,6 +321,10 @@ namespace Audio { EndSampleRegistration(); } + static int GetSoundPriorityForEntity( const int entityNum ) { + return entityNum < MAX_CLIENTS ? CLIENT : ANY; + } + void StartSound(int entityNum, Vec3 origin, sfxHandle_t sfx) { if (not initialized or not Sample::IsValidHandle(sfx)) { return; @@ -335,7 +343,7 @@ namespace Audio { return; } - AddSound(emitter, std::make_shared(Sample::FromHandle(sfx)), 1); + AddSound( emitter, std::make_shared( Sample::FromHandle( sfx ) ), GetSoundPriorityForEntity( entityNum ) ); } void StartLocalSound(sfxHandle_t sfx) { @@ -343,7 +351,7 @@ namespace Audio { return; } - AddSound(GetLocalEmitter(), std::make_shared(Sample::FromHandle(sfx)), 1); + AddSound( GetLocalEmitter(), std::make_shared( Sample::FromHandle( sfx ) ), ANY ); } void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx, bool persistent) { @@ -357,7 +365,7 @@ namespace Audio { if (not loop.sound) { loop.sound = std::make_shared(Sample::FromHandle(sfx)); loop.oldSfx = sfx; - AddSound(GetEmitterForEntity(entityNum), loop.sound, 1); + AddSound( GetEmitterForEntity( entityNum ), loop.sound, GetSoundPriorityForEntity( entityNum ) ); } loop.addedThisFrame = true; @@ -402,7 +410,7 @@ namespace Audio { StopMusic(); music = std::make_shared(loopingSample, leadingSample); music->volumeModifier = &musicVolume; - AddSound(GetLocalEmitter(), music, 1); + AddSound( GetLocalEmitter(), music, ANY ); } void StopMusic() { @@ -433,9 +441,9 @@ namespace Audio { if (not streams[streamNum]) { streams[streamNum] = std::make_shared(); if (IsValidEntity(entityNum)) { - AddSound(GetEmitterForEntity(entityNum), streams[streamNum], 1); + AddSound( GetEmitterForEntity( entityNum ), streams[streamNum], GetSoundPriorityForEntity( entityNum ) ); } else { - AddSound(GetLocalEmitter(), streams[streamNum], 1); + AddSound( GetLocalEmitter(), streams[streamNum], ANY ); } } diff --git a/src/engine/audio/Audio.h b/src/engine/audio/Audio.h index 220c2422a0..cce810af9b 100644 --- a/src/engine/audio/Audio.h +++ b/src/engine/audio/Audio.h @@ -43,7 +43,7 @@ namespace Audio { void Shutdown(); void Update(); - void BeginRegistration(); + void BeginRegistration( const int playerNum ); sfxHandle_t RegisterSFX(Str::StringRef filename); void EndRegistration(); diff --git a/src/engine/audio/AudioPrivate.h b/src/engine/audio/AudioPrivate.h index 2b7b2b98de..6ccc1665a4 100644 --- a/src/engine/audio/AudioPrivate.h +++ b/src/engine/audio/AudioPrivate.h @@ -65,6 +65,21 @@ namespace Audio { constexpr uint32_t MAX_ENTITY_SOUNDS = 4; + extern int playerClientNum; + + struct entityData_t { + Vec3 position; + Vec3 velocity; + float occlusion; + }; + + extern entityData_t entities[MAX_GENTITIES]; + + enum EmitterPriority { + ANY, + CLIENT + }; + // Tweaks the value given by the audio slider float SliderToAmplitude(float slider); diff --git a/src/engine/audio/Emitter.cpp b/src/engine/audio/Emitter.cpp index 673ae174fc..6c3302d2ff 100644 --- a/src/engine/audio/Emitter.cpp +++ b/src/engine/audio/Emitter.cpp @@ -31,14 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AudioPrivate.h" namespace Audio { - - // Structures to keep the state of entities we were given - struct entityData_t { - Vec3 position; - Vec3 velocity; - float occlusion; - }; - static entityData_t entities[MAX_GENTITIES]; + entityData_t entities[MAX_GENTITIES]; static int listenerEntity = -1; struct EntityMultiEmitter { @@ -311,6 +304,10 @@ namespace Audio { Make3D(source, entities[entityNum].position, entities[entityNum].velocity); } + Vec3 EntityEmitter::GetPosition() const { + return entities[entityNum].position; + } + // Implementation of PositionEmitter PositionEmitter::PositionEmitter(Vec3 position){ @@ -357,6 +354,10 @@ namespace Audio { MakeLocal(source); } + Vec3 LocalEmitter::GetPosition() const { + return Vec3 {}; + } + class TestReverbCmd : public Cmd::StaticCmd { public: TestReverbCmd(): StaticCmd("testReverb", Cmd::AUDIO, "Tests a reverb preset.") { diff --git a/src/engine/audio/Emitter.h b/src/engine/audio/Emitter.h index ab0a9d6c8e..a4ee1b37cb 100644 --- a/src/engine/audio/Emitter.h +++ b/src/engine/audio/Emitter.h @@ -64,11 +64,13 @@ namespace Audio { void SetupSound(Sound& sound); // Called each frame before any UpdateSound is called, used to factor computations - void virtual Update() = 0; + virtual void Update() = 0; // Update the Sound's source's spatialization virtual void UpdateSound(Sound& sound) = 0; // Setup a source for the spatialization of this Emitter virtual void InternalSetupSound(Sound& sound) = 0; + + virtual Vec3 GetPosition() const = 0; }; // An Emitter that will follow an entity @@ -81,6 +83,8 @@ namespace Audio { virtual void UpdateSound(Sound& sound) override; virtual void InternalSetupSound(Sound& sound) override; + Vec3 GetPosition() const override; + private: int entityNum; }; @@ -95,7 +99,7 @@ namespace Audio { virtual void UpdateSound(Sound& sound) override; virtual void InternalSetupSound(Sound& sound) override; - Vec3 GetPosition() const; + Vec3 GetPosition() const override; private: Vec3 position; @@ -110,6 +114,8 @@ namespace Audio { void virtual Update() override; virtual void UpdateSound(Sound& sound) override; virtual void InternalSetupSound(Sound& sound) override; + + Vec3 GetPosition() const override; }; } diff --git a/src/engine/audio/Sound.cpp b/src/engine/audio/Sound.cpp index 3cb392299d..1451e3039f 100644 --- a/src/engine/audio/Sound.cpp +++ b/src/engine/audio/Sound.cpp @@ -49,8 +49,6 @@ namespace Audio { static sourceRecord_t* sources = nullptr; static CONSTEXPR int nSources = 128; //TODO see what's the limit for OpenAL soft - sourceRecord_t* GetSource(int priority); - static bool initialized = false; void InitSounds() { @@ -116,34 +114,40 @@ namespace Audio { } } - void AddSound(std::shared_ptr emitter, std::shared_ptr sound, int priority) { - if (not initialized) { - return; - } + static Cvar::Range> a_clientSoundPriorityMaxDistance( "a_clientSoundPriorityMaxDistance", + "Sounds emitted by players/bots within this distance (in qu) will have higher priority than other sounds" + " (multiplier: a_clientSoundPriorityMultiplier)", Cvar::NONE, 32 * 32, 0, BIT( 16 ) ); - sourceRecord_t* source = GetSource(priority); + static Cvar::Range> a_clientSoundPriorityMultiplier( "a_clientSoundPriorityMultiplier", + "Sounds emitted by players/bots within a_clientSoundPriorityMaxDistance" + " will use this value as their priority multiplier", + Cvar::NONE, 2.0f, 0.0f, 1024.0f ); - if (source) { - // Make the source forget if it was a "static" or a "streaming" source. - source->source.ResetBuffer(); - sound->emitter = emitter; - sound->AcquireSource(source->source); - source->usingSound = sound; - source->priority = priority; - source->active = true; + static float GetAdjustedVolumeForPosition( const Vec3& origin, const Vec3& src, const bool isClient ) { + vec3_t v0 { origin.Data()[0], origin.Data()[1], origin.Data()[2] }; + vec3_t v1 { src.Data()[0], src.Data()[1], src.Data()[2] }; - sound->FinishSetup(); - sound->Play(); + float totalPriority = VectorDistanceSquared( v0, v1 ); + + const float distanceThreshold = a_clientSoundPriorityMaxDistance.Get(); + if ( isClient && totalPriority < distanceThreshold * distanceThreshold ) { + totalPriority *= 1.0f / a_clientSoundPriorityMultiplier.Get(); } + + return 1.0f / totalPriority; } // Finds a inactive or low-priority source to play a new sound. - sourceRecord_t* GetSource(int priority) { - //TODO make a better heuristic? (take into account the distance / the volume /... ?) + static sourceRecord_t* GetSource( const Vec3& position, int priority, const float currentGain ) { int best = -1; - int bestPriority = priority; - // Gets the minimum sound by comparing activity first then priority + const Vec3& playerPos = entities[playerClientNum].position; + + // Sound volume is inversely proportional to distance to the source + const float adjustedVolume = Q_rsqrt_fast( currentGain ) + * GetAdjustedVolumeForPosition( playerPos, position, priority == CLIENT ); + + // Gets the minimum sound by comparing activity first, then the adjusted volume for (int i = 0; i < nSources; i++) { sourceRecord_t& source = sources[i]; @@ -151,9 +155,14 @@ namespace Audio { return &source; } - if (source.priority < bestPriority || (best < 0 && source.priority <= priority)) { + const Vec3& sourcePos = source.usingSound->emitter->GetPosition(); + + // Sound volume is inversely proportional to distance to the source + const float adjustedSourceVolume = Q_rsqrt_fast( source.usingSound->currentGain ) + * GetAdjustedVolumeForPosition( playerPos, sourcePos, source.priority == CLIENT ); + + if ( adjustedVolume > adjustedSourceVolume ) { best = i; - bestPriority = source.priority; continue; } } @@ -171,6 +180,30 @@ namespace Audio { } } + void AddSound( std::shared_ptr emitter, std::shared_ptr sound, int priority ) { + if ( not initialized ) { + return; + } + + const Vec3& position = emitter->GetPosition(); + const float currentGain = sound->positionalGain * sound->soundGain + * SliderToAmplitude( sound->volumeModifier->Get() ); + sourceRecord_t* source = GetSource( position, priority, currentGain ); + + if ( source ) { + // Make the source forget if it was a "static" or a "streaming" source. + source->source.ResetBuffer(); + sound->emitter = emitter; + sound->AcquireSource( source->source ); + source->usingSound = sound; + source->priority = priority; + source->active = true; + + sound->FinishSetup(); + sound->Play(); + } + } + // Implementation of Sound Sound::Sound() : positionalGain(1.0f), soundGain(1.0f), currentGain(1.0f), diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index a365fc1b8c..38b78dbc78 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -291,7 +291,7 @@ namespace Audio { using UpdateEntityVelocityMsg = IPC::Message, int, Vec3>; using UpdateEntityPositionVelocityMsg = IPC::Message, int, Vec3, Vec3>; using SetReverbMsg = IPC::Message, int, std::string, float>; - using BeginRegistrationMsg = IPC::Message>; + using BeginRegistrationMsg = IPC::Message, int>; using EndRegistrationMsg = IPC::Message>; } diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 9010d5ef64..f23d49f671 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1561,8 +1561,8 @@ void CGameVM::CmdBuffer::HandleCommandBufferSyscall(int major, int minor, Util:: break; case CG_S_BEGINREGISTRATION: - HandleMsg(std::move(reader), [this] { - Audio::BeginRegistration(); + HandleMsg(std::move(reader), [this] ( const int playerNum ) { + Audio::BeginRegistration( playerNum ); }); break; diff --git a/src/engine/null/NullAudio.cpp b/src/engine/null/NullAudio.cpp index cc213e8363..6e4a5e77a5 100644 --- a/src/engine/null/NullAudio.cpp +++ b/src/engine/null/NullAudio.cpp @@ -47,7 +47,7 @@ namespace Audio { } - void BeginRegistration() { + void BeginRegistration( const int ) { } sfxHandle_t RegisterSFX(Str::StringRef) { diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index 995928b160..dc9bb6cce8 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -218,9 +218,9 @@ void trap_S_SetReverb( int slotNum, const char* name, float ratio ) cmdBuffer.SendMsg(slotNum, name, ratio); } -void trap_S_BeginRegistration() +void trap_S_BeginRegistration( const int playerNum ) { - cmdBuffer.SendMsg(); + cmdBuffer.SendMsg( playerNum ); } void trap_S_EndRegistration() diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index a8467c05d2..b748cf11d6 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -138,7 +138,7 @@ void trap_R_SetAltShaderTokens( const char * ); void trap_S_UpdateEntityVelocity( int entityNum, const vec3_t velocity ); void trap_S_UpdateEntityPositionVelocity( int entityNum, const vec3_t position, const vec3_t velocity ); void trap_S_SetReverb( int slotNum, const char* presetName, float ratio ); -void trap_S_BeginRegistration(); +void trap_S_BeginRegistration( const int playerNum ); void trap_S_EndRegistration(); #endif From 907090049e916e047883d01f22ca2d4ecddc7283 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sun, 28 Sep 2025 03:01:55 +0000 Subject: [PATCH 44/66] sync for-0.56.0/sync submodules --- libs/breakpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/breakpad b/libs/breakpad index fd6cc4ce9f..ad5451e89c 160000 --- a/libs/breakpad +++ b/libs/breakpad @@ -1 +1 @@ -Subproject commit fd6cc4ce9f41047b13ca1e041726ef7dedb594bd +Subproject commit ad5451e89cf451a90f598ab911f59a1458f1ebda From af4d2c88a5b7e120959080e1066a7440607cf965 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Sat, 8 Nov 2025 23:08:47 +0000 Subject: [PATCH 45/66] sync for-0.56.0/sync submodules --- libs/crunch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/crunch b/libs/crunch index 371d9f0cf7..e242bb2a7a 160000 --- a/libs/crunch +++ b/libs/crunch @@ -1 +1 @@ -Subproject commit 371d9f0cf74ce31c5d210897c2fb366b830558c0 +Subproject commit e242bb2a7ae7efc44d144fd5d621b35baddeab25 From e3b6aabdc356a191e486f3639663c724b7c8e094 Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 17 Oct 2025 16:32:39 -0500 Subject: [PATCH 46/66] Refactor SetLightDeluxeMode arguments Take pointer to stage instead of pointer to shader plus stage type. --- src/engine/renderer/Material.cpp | 12 ++++++------ src/engine/renderer/Material.h | 2 +- src/engine/renderer/ShadeCommon.h | 10 +++++----- src/engine/renderer/tr_shade.cpp | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index c901c63852..f2c8c24e90 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -1159,7 +1159,7 @@ void ProcessMaterialLightMapping( Material* material, shaderStage_t* pStage, Mat lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( surface, pStage->shader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( surface, pStage, lightMode, deluxeMode ); bool enableDeluxeMapping = ( deluxeMode == deluxeMode_t::MAP ); bool enableGridLighting = ( lightMode == lightMode_t::GRID ); @@ -1242,7 +1242,7 @@ void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage, MaterialS lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( surface, pStage->shader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( surface, pStage, lightMode, deluxeMode ); material->hasHeightMapInNormalMap = pStage->hasHeightMapInNormalMap; material->enableReliefMapping = pStage->enableReliefMapping; @@ -1390,7 +1390,7 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta uint32_t& previousMaterialID, bool skipStageSync ) { lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( surface, shader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( surface, pStage, lightMode, deluxeMode ); const bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP && surface->bspSurface && pStage->shaderBinder == BindShaderGeneric3D; const bool vertexLit = lightMode == lightMode_t::VERTEX && pStage->shaderBinder == BindShaderLightMapping; @@ -1479,7 +1479,7 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta pStage->initialized = true; AddStage( surface, pStage, stage, mayUseVertexOverbright, vertexLit, fullbright ); - AddStageTextures( surface, shader, pStage, stage, &materials[previousMaterialID] ); + AddStageTextures( surface, pStage, stage, &materials[previousMaterialID] ); surface->materialIDs[stage] = previousMaterialID; surface->materialPackIDs[stage] = materialPack; @@ -1539,7 +1539,7 @@ void MaterialSystem::GLSLRestart() { } } -void MaterialSystem::AddStageTextures( MaterialSurface* surface, shader_t* shader, shaderStage_t* pStage, const uint32_t stage, Material* material ) { +void MaterialSystem::AddStageTextures( MaterialSurface* surface, shaderStage_t* pStage, const uint32_t stage, Material* material ) { TextureData textureData; int bundleNum = 0; @@ -1570,7 +1570,7 @@ void MaterialSystem::AddStageTextures( MaterialSurface* surface, shader_t* shade // Add lightmap and deluxemap for this surface to the material as well lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( surface, shader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( surface, pStage, lightMode, deluxeMode ); // u_Map, u_DeluxeMap image_t* lightmap = SetLightMap( surface, lightMode ); diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index e9eb42eb1a..219cacc1c0 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -374,7 +374,7 @@ class MaterialSystem { return texData.size(); } - void AddStageTextures( MaterialSurface* surface, shader_t* shader, shaderStage_t* pStage, const uint32_t stage, Material* material ); + void AddStageTextures( MaterialSurface* surface, shaderStage_t* pStage, const uint32_t stage, Material* material ); void AddStage( MaterialSurface* surface, shaderStage_t* pStage, uint32_t stage, const bool mayUseVertexOverbright, const bool vertexLit, const bool fullbright ); void ProcessStage( MaterialSurface* surface, shaderStage_t* pStage, shader_t* shader, uint32_t* packIDs, uint32_t& stage, diff --git a/src/engine/renderer/ShadeCommon.h b/src/engine/renderer/ShadeCommon.h index 7d8f107439..50388194db 100644 --- a/src/engine/renderer/ShadeCommon.h +++ b/src/engine/renderer/ShadeCommon.h @@ -114,18 +114,18 @@ template bool isExplicitelyVertexLitSurface( Obj* obj ) return lastStage != stages && stages[0].rgbGen == colorGen_t::CGEN_VERTEX; } -template void SetLightDeluxeMode( Obj* obj, shader_t* shader, - stageType_t stageType, +template void SetLightDeluxeMode( + const Obj *obj, const shaderStage_t *stage, lightMode_t& lightMode, deluxeMode_t& deluxeMode ) { lightMode = lightMode_t::FULLBRIGHT; deluxeMode = deluxeMode_t::NONE; - if ( hasExplicitelyDisabledLightMap( shader ) && !isExplicitelyVertexLitSurface( shader ) ) + if ( hasExplicitelyDisabledLightMap( stage->shader ) && !isExplicitelyVertexLitSurface( stage->shader ) ) { // Use fullbright on “surfaceparm nolightmap” materials. } - else if ( stageType == stageType_t::ST_COLLAPSE_COLORMAP ) + else if ( stage->type == stageType_t::ST_COLLAPSE_COLORMAP ) { /* Use fullbright for collapsed stages without lightmaps, for example: @@ -137,7 +137,7 @@ template void SetLightDeluxeMode( Obj* obj, shader_t* shader, This is doable for some complex multi-stage materials. */ } - else if( stageType == stageType_t::ST_LIQUIDMAP ) + else if( stage->type == stageType_t::ST_LIQUIDMAP ) { lightMode = tr.modelLight; deluxeMode = tr.modelDeluxe; diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 19c481d928..bc261a58a3 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -795,7 +795,7 @@ void ProcessShaderGeneric3D( const shaderStage_t* pStage ) { void ProcessShaderLightMapping( const shaderStage_t* pStage ) { lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( &tess, tess.surfaceShader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( &tess, pStage, lightMode, deluxeMode ); bool enableDeluxeMapping = ( deluxeMode == deluxeMode_t::MAP ); bool enableGridLighting = ( lightMode == lightMode_t::GRID ); @@ -845,7 +845,7 @@ void ProcessShaderHeatHaze( const shaderStage_t* pStage ) { void ProcessShaderLiquid( const shaderStage_t* pStage ) { lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( &tess, tess.surfaceShader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( &tess, pStage, lightMode, deluxeMode ); gl_liquidShader->SetHeightMapInNormalMap( pStage->hasHeightMapInNormalMap ); @@ -1000,7 +1000,7 @@ void Render_lightMapping( shaderStage_t *pStage ) lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( &tess, tess.surfaceShader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( &tess, pStage, lightMode, deluxeMode ); // u_Map, u_DeluxeMap image_t *lightmap = SetLightMap( &tess, lightMode ); @@ -1507,7 +1507,7 @@ void Render_liquid( shaderStage_t *pStage ) lightMode_t lightMode; deluxeMode_t deluxeMode; - SetLightDeluxeMode( &tess, tess.surfaceShader, pStage->type, lightMode, deluxeMode ); + SetLightDeluxeMode( &tess, pStage, lightMode, deluxeMode ); // choose right shader program ProcessShaderLiquid( pStage ); From 394a1c57fe52418c76756acc9c9785b19a86d73d Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 17 Oct 2025 09:21:11 -0500 Subject: [PATCH 47/66] Enable realtime lights for vertex-lit surfaces Use the lightMapping GLSL shader instead of `generic` to render BSP surfaces that are vertex-lit due to an explicit `rgbGen vertex`. This makes them use the same code path as BSP surfaces where vertex lighting is automatically selected due to the absence of a lightmap. So now it is possible to render realtime lights on explicitly vertex-lit surfaces, though they are still not as bright as they should be due to https://github.com/DaemonEngine/Daemon/issues/1415. In the following commit, this will let us remove some ugly code used for applying the overbright factor to the `generic` shader. --- src/engine/renderer/Material.cpp | 3 ++- src/engine/renderer/ShadeCommon.h | 7 ++++++- src/engine/renderer/tr_bsp.cpp | 2 +- src/engine/renderer/tr_local.h | 4 ++++ src/engine/renderer/tr_shader.cpp | 9 +++++++++ 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index f2c8c24e90..59f02e9731 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -680,7 +680,8 @@ void MaterialSystem::GenerateWorldCommandBuffer( std::vector& s surfaceCommand.drawCommand.baseInstance |= surface.texDataDynamic[stage] ? ( surface.texDataIDs[stage] + texData.size() ) << TEX_BUNDLE_BITS : surface.texDataIDs[stage] << TEX_BUNDLE_BITS; - surfaceCommand.drawCommand.baseInstance |= ( HasLightMap( &surface ) ? GetLightMapNum( &surface ) : 255 ) << LIGHTMAP_BITS; + surfaceCommand.drawCommand.baseInstance |= + ( !pStage->forceVertexLighting && HasLightMap( &surface ) ? GetLightMapNum( &surface ) : 255 ) << LIGHTMAP_BITS; surfaceCommands[cmdID] = surfaceCommand; material->drawCommandCount++; diff --git a/src/engine/renderer/ShadeCommon.h b/src/engine/renderer/ShadeCommon.h index 50388194db..da4cac0fcd 100644 --- a/src/engine/renderer/ShadeCommon.h +++ b/src/engine/renderer/ShadeCommon.h @@ -121,7 +121,12 @@ template void SetLightDeluxeMode( lightMode = lightMode_t::FULLBRIGHT; deluxeMode = deluxeMode_t::NONE; - if ( hasExplicitelyDisabledLightMap( stage->shader ) && !isExplicitelyVertexLitSurface( stage->shader ) ) + if ( stage->forceVertexLighting ) + { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + else if ( hasExplicitelyDisabledLightMap( stage->shader ) && !isExplicitelyVertexLitSurface( stage->shader ) ) { // Use fullbright on “surfaceparm nolightmap” materials. } diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index 120ddbe28d..3f025727f5 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -871,7 +871,7 @@ static shader_t* ShaderForShaderNum( int shaderNum ) { dshader_t* dsh = &s_worldData.shaders[shaderNum]; - shader_t* shader = R_FindShader( dsh->shader, RSF_3D ); + shader_t* shader = R_FindShader( dsh->shader, RSF_3D | RSF_BSP ); // If the shader had errors, just use default shader if ( shader->defaultShader ) { diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index ea4553b9b2..e1ad634ddc 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -964,6 +964,8 @@ enum // TODO(0.56): move to the public RegisterShaderFlags_t interface #define RSF_3D ( BIT( 30 ) ) +#define RSF_BSP ( BIT ( 29 ) ) + using stageRenderer_t = void(*)(shaderStage_t *); using stageShaderBuildMarker_t = void(*)(const shaderStage_t*); using surfaceDataUpdater_t = void(*)(uint32_t*, shaderStage_t*, bool, bool, bool); @@ -1033,6 +1035,8 @@ enum bool highQuality; bool forceHighQuality; + bool forceVertexLighting; + bool hasDepthFade; // for soft particles float depthFadeValue; diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index a110943f8d..ba69ed6df9 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -5202,6 +5202,14 @@ static void FinishStages() lightStageFound = true; break; + case stageType_t::ST_COLORMAP: + if ( stage->rgbGen == colorGen_t::CGEN_VERTEX && shader.registerFlags & RSF_BSP ) + { + // vertex colors used as lighting detected. Enable overbright and realtime lights + stage->type = stageType_t::ST_DIFFUSEMAP; + stage->forceVertexLighting = true; // use vertex lighting even if there is a lightmap + } + default: break; } @@ -6453,6 +6461,7 @@ class ListShadersCmd : public Cmd::StaticCmd shader->registerFlags & RSF_FORCE_LIGHTMAP ? 'L' : '_', shader->registerFlags & RSF_SPRITE ? 'S' : '_', shader->registerFlags & RSF_3D ? '3' : '_', + shader->registerFlags & RSF_BSP ? 'B' : '_', }; if ( !shaderSortName.count( (shaderSort_t) shader->sort ) ) From fb4162b8f3963c26a426d0e9eb5a14b8589e0b16 Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 17 Oct 2025 12:36:51 -0500 Subject: [PATCH 48/66] NUKE vertex overbright code for `generic` shader This is unused following the previous commit which make shaders that need overbright with `rgbGen vertex` run on the `lightMapping` shader instead of `generic`. Note: IS_LIGHT_STYLE was misnamed. It actually meant vertex overbright --- src/engine/renderer/Material.cpp | 48 +++++++++------------ src/engine/renderer/Material.h | 22 +++++----- src/engine/renderer/gl_shader.h | 30 +++---------- src/engine/renderer/glsl_source/common.glsl | 29 ++----------- src/engine/renderer/tr_local.h | 9 ++-- src/engine/renderer/tr_shade.cpp | 5 +-- 6 files changed, 45 insertions(+), 98 deletions(-) diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index 59f02e9731..8cd370a6fd 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -134,14 +134,14 @@ All of these functions must write stage material data regardless of whether pSta because stages here are combined into as few as possible, and the stage chosen for storage might not have all of those enabled */ -void UpdateSurfaceDataNONE( uint32_t*, shaderStage_t*, bool, bool, bool ) { +void UpdateSurfaceDataNONE( uint32_t*, shaderStage_t*, bool, bool ) { ASSERT_UNREACHABLE(); } -void UpdateSurfaceDataNOP( uint32_t*, shaderStage_t*, bool, bool, bool ) { +void UpdateSurfaceDataNOP( uint32_t*, shaderStage_t*, bool, bool ) { } -void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, bool mayUseVertexOverbright, bool, bool ) { +void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, bool, bool ) { // shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -154,7 +154,7 @@ void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, boo alphaGen_t alphaGen = SetAlphaGen( pStage ); const bool styleLightMap = pStage->type == stageType_t::ST_STYLELIGHTMAP || pStage->type == stageType_t::ST_STYLECOLORMAP; - gl_genericShaderMaterial->SetUniform_ColorModulateColorGen_Uint( rgbGen, alphaGen, mayUseVertexOverbright, styleLightMap ); + gl_genericShaderMaterial->SetUniform_ColorModulateColorGen_Uint( rgbGen, alphaGen, styleLightMap ); Tess_ComputeColor( pStage ); gl_genericShaderMaterial->SetUniform_Color_Uint( tess.svars.color ); @@ -164,7 +164,7 @@ void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, boo gl_genericShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, bool, bool vertexLit, bool fullbright ) { +void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, bool vertexLit, bool fullbright ) { shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -181,7 +181,7 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, } // u_ColorModulate - gl_lightMappingShaderMaterial->SetUniform_ColorModulateColorGen_Uint( rgbGen, alphaGen, false, !fullbright ); + gl_lightMappingShaderMaterial->SetUniform_ColorModulateColorGen_Uint( rgbGen, alphaGen, !fullbright ); // u_Color gl_lightMappingShaderMaterial->SetUniform_Color_Uint( tess.svars.color ); @@ -210,7 +210,7 @@ void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, gl_lightMappingShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataReflection( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { +void UpdateSurfaceDataReflection( uint32_t* materials, shaderStage_t* pStage, bool, bool ) { shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -247,7 +247,7 @@ void UpdateSurfaceDataReflection( uint32_t* materials, shaderStage_t* pStage, bo gl_reflectionShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { +void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, bool ) { // shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -258,7 +258,7 @@ void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, gl_skyboxShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { +void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, bool ) { // shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -271,7 +271,7 @@ void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, gl_screenShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { +void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, bool, bool ) { // shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -288,7 +288,7 @@ void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, bool gl_heatHazeShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataLiquid( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { +void UpdateSurfaceDataLiquid( uint32_t* materials, shaderStage_t* pStage, bool, bool ) { // shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -334,7 +334,7 @@ void UpdateSurfaceDataLiquid( uint32_t* materials, shaderStage_t* pStage, bool, gl_liquidShaderMaterial->WriteUniformsToBuffer( materials ); } -void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ) { +void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, bool ) { // shader_t* shader = pStage->shader; materials += pStage->bufferOffset; @@ -436,14 +436,13 @@ void MaterialSystem::GenerateMaterialsBuffer( std::vector& stage uint32_t variants = 0; for ( int i = 0; i < ShaderStageVariant::ALL && variants < pStage->variantOffset; i++ ) { if ( pStage->variantOffsets[i] != -1 ) { - const bool mayUseVertexOverbright = i & ShaderStageVariant::VERTEX_OVERBRIGHT; const bool vertexLit = i & ShaderStageVariant::VERTEX_LIT; const bool fullbright = i & ShaderStageVariant::FULLBRIGHT; const uint32_t variantOffset = pStage->variantOffsets[i] * pStage->paddedSize; pStage->bufferOffset += variantOffset; - pStage->surfaceDataUpdater( materialsData, pStage, mayUseVertexOverbright, vertexLit, fullbright ); + pStage->surfaceDataUpdater( materialsData, pStage, vertexLit, fullbright ); pStage->bufferOffset -= variantOffset; variants++; @@ -774,14 +773,10 @@ static std::string GetStageInfo( const shaderStage_t* pStage, const uint32_t dyn stageShaderNames.at( pStage->shaderBinder ), pStage->materialOffset, pStage->bufferOffset ); static const char* stageVariants[] = { - "base variant ", - "vertex overbright ", - "vertex-lit ", - "vertex overbright vertex-lit ", - "fullbright ", - "vertex overbright fullbright ", - "vertex-lit fullbright ", - "vertex overbright vertex-lit fullbright" + "base variant ", + "vertex-lit ", + "fullbright ", + "vertex-lit fullbright", }; static_assert( ARRAY_LEN( stageVariants ) == ShaderStageVariant::ALL, "update stage variant text descriptions" ); @@ -1272,9 +1267,8 @@ void ProcessMaterialFog( Material* material, shaderStage_t* pStage, MaterialSurf } void MaterialSystem::AddStage( MaterialSurface* surface, shaderStage_t* pStage, uint32_t stage, - const bool mayUseVertexOverbright, const bool vertexLit, const bool fullbright ) { - const int variant = ( mayUseVertexOverbright ? ShaderStageVariant::VERTEX_OVERBRIGHT : 0 ) - | ( vertexLit ? ShaderStageVariant::VERTEX_LIT : 0 ) + const bool vertexLit, const bool fullbright ) { + const int variant = ( vertexLit ? ShaderStageVariant::VERTEX_LIT : 0 ) | ( fullbright ? ShaderStageVariant::FULLBRIGHT : 0 ); if ( pStage->variantOffsets[variant] == -1 ) { @@ -1392,8 +1386,6 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta lightMode_t lightMode; deluxeMode_t deluxeMode; SetLightDeluxeMode( surface, pStage, lightMode, deluxeMode ); - const bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP - && surface->bspSurface && pStage->shaderBinder == BindShaderGeneric3D; const bool vertexLit = lightMode == lightMode_t::VERTEX && pStage->shaderBinder == BindShaderLightMapping; const bool fullbright = lightMode == lightMode_t::FULLBRIGHT && pStage->shaderBinder == BindShaderLightMapping; @@ -1479,7 +1471,7 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta pStage->useMaterialSystem = true; pStage->initialized = true; - AddStage( surface, pStage, stage, mayUseVertexOverbright, vertexLit, fullbright ); + AddStage( surface, pStage, stage, vertexLit, fullbright ); AddStageTextures( surface, pStage, stage, &materials[previousMaterialID] ); surface->materialIDs[stage] = previousMaterialID; diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index 219cacc1c0..3997c4d6d7 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -376,7 +376,7 @@ class MaterialSystem { void AddStageTextures( MaterialSurface* surface, shaderStage_t* pStage, const uint32_t stage, Material* material ); void AddStage( MaterialSurface* surface, shaderStage_t* pStage, uint32_t stage, - const bool mayUseVertexOverbright, const bool vertexLit, const bool fullbright ); + const bool vertexLit, const bool fullbright ); void ProcessStage( MaterialSurface* surface, shaderStage_t* pStage, shader_t* shader, uint32_t* packIDs, uint32_t& stage, uint32_t& previousMaterialID, bool skipStageSync = false ); void GenerateMaterial( MaterialSurface* surface, int globalFog ); @@ -451,16 +451,16 @@ extern GLSSBO debugSSBO; // Global extern MaterialSystem materialSystem; -void UpdateSurfaceDataNONE( uint32_t*, shaderStage_t*, bool, bool, bool ); -void UpdateSurfaceDataNOP( uint32_t*, shaderStage_t*, bool, bool, bool ); -void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, bool mayUseVertexOverbright, bool, bool ); -void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, bool, bool vertexLit, bool fullbright ); -void UpdateSurfaceDataReflection( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); -void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); -void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); -void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); -void UpdateSurfaceDataLiquid( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); -void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, bool, bool ); +void UpdateSurfaceDataNONE( uint32_t*, shaderStage_t*, bool, bool ); +void UpdateSurfaceDataNOP( uint32_t*, shaderStage_t*, bool, bool ); +void UpdateSurfaceDataGeneric3D( uint32_t* materials, shaderStage_t* pStage, bool, bool ); +void UpdateSurfaceDataLightMapping( uint32_t* materials, shaderStage_t* pStage, bool vertexLit, bool fullbright ); +void UpdateSurfaceDataReflection( uint32_t* materials, shaderStage_t* pStage, bool, bool ); +void UpdateSurfaceDataSkybox( uint32_t* materials, shaderStage_t* pStage, bool, bool ); +void UpdateSurfaceDataScreen( uint32_t* materials, shaderStage_t* pStage, bool, bool ); +void UpdateSurfaceDataHeatHaze( uint32_t* materials, shaderStage_t* pStage, bool, bool ); +void UpdateSurfaceDataLiquid( uint32_t* materials, shaderStage_t* pStage, bool, bool ); +void UpdateSurfaceDataFog( uint32_t* materials, shaderStage_t* pStage, bool, bool ); void BindShaderNONE( Material* ); void BindShaderNOP( Material* ); diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 2fe9ae8878..dcf2678820 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -2737,13 +2737,11 @@ struct colorModulation_t { float colorGen = 0.0f; float alphaGen = 0.0f; float lightFactor = 1.0f; - bool useVertexLightFactor = false; }; static colorModulation_t ColorModulateColorGen( const colorGen_t colorGen, const alphaGen_t alphaGen, - const bool vertexOverbright, const bool useMapLightFactor ) { colorModulation_t colorModulation = {}; @@ -2751,17 +2749,7 @@ static colorModulation_t ColorModulateColorGen( switch ( colorGen ) { case colorGen_t::CGEN_VERTEX: - if ( vertexOverbright ) - { - // vertexOverbright is only needed for non-lightmapped cases. When there is a - // lightmap, this is done by multiplying with the overbright-scaled white image - colorModulation.useVertexLightFactor = true; - colorModulation.lightFactor = tr.mapLightFactor; - } - else - { - colorModulation.colorGen = 1.0f; - } + colorModulation.colorGen = 1.0f; break; case colorGen_t::CGEN_ONE_MINUS_VERTEX: @@ -2774,7 +2762,6 @@ static colorModulation_t ColorModulateColorGen( if ( useMapLightFactor ) { - DAEMON_ASSERT_EQ( vertexOverbright, false ); colorModulation.lightFactor = tr.mapLightFactor; } @@ -2807,7 +2794,6 @@ class u_ColorModulateColorGen_Float : void SetUniform_ColorModulateColorGen_Float( const colorGen_t colorGen, const alphaGen_t alphaGen, - const bool vertexOverbright = false, const bool useMapLightFactor = false ) { GLIMP_LOGCOMMENT( "--- u_ColorModulate::SetUniform_ColorModulateColorGen_Float( " @@ -2815,12 +2801,11 @@ class u_ColorModulateColorGen_Float : _shader->_name.c_str(), Util::enum_str( colorGen ), Util::enum_str( alphaGen ) ); colorModulation_t colorModulation = ColorModulateColorGen( - colorGen, alphaGen, vertexOverbright, useMapLightFactor ); + colorGen, alphaGen, useMapLightFactor ); vec4_t colorModulate_Float; colorModulate_Float[ 0 ] = colorModulation.colorGen; colorModulate_Float[ 1 ] = colorModulation.lightFactor; - colorModulate_Float[ 1 ] *= colorModulation.useVertexLightFactor ? -1.0f : 1.0f; colorModulate_Float[ 2 ] = {}; colorModulate_Float[ 3 ] = colorModulation.alphaGen; @@ -2838,7 +2823,6 @@ class u_ColorModulateColorGen_Uint : void SetUniform_ColorModulateColorGen_Uint( const colorGen_t colorGen, const alphaGen_t alphaGen, - const bool vertexOverbright = false, const bool useMapLightFactor = false ) { GLIMP_LOGCOMMENT( "--- u_ColorModulate::SetUniform_ColorModulateColorGen_Uint( " @@ -2846,7 +2830,7 @@ class u_ColorModulateColorGen_Uint : _shader->_name.c_str(), Util::enum_str( colorGen ), Util::enum_str( alphaGen ) ); colorModulation_t colorModulation = ColorModulateColorGen( - colorGen, alphaGen, vertexOverbright, useMapLightFactor ); + colorGen, alphaGen, useMapLightFactor ); enum class ColorModulate_Bit { COLOR_ONE = 0, @@ -2854,7 +2838,6 @@ class u_ColorModulateColorGen_Uint : ALPHA_ONE = 2, ALPHA_MINUS_ONE = 3, // <-- Insert new bits there. - IS_LIGHT_STYLE = 27, LIGHTFACTOR_BIT0 = 28, LIGHTFACTOR_BIT1 = 29, LIGHTFACTOR_BIT2 = 30, @@ -2872,8 +2855,6 @@ class u_ColorModulateColorGen_Uint : << Util::ordinal( ColorModulate_Bit::ALPHA_ONE ); colorModulate_Uint |= ( colorModulation.alphaGen == -1.0f ) << Util::ordinal( ColorModulate_Bit::ALPHA_MINUS_ONE ); - colorModulate_Uint |= colorModulation.useVertexLightFactor - << Util::ordinal( ColorModulate_Bit::IS_LIGHT_STYLE ); colorModulate_Uint |= uint32_t( colorModulation.lightFactor ) << Util::ordinal( ColorModulate_Bit::LIGHTFACTOR_BIT0 ); @@ -2885,16 +2866,15 @@ template void SetUniform_ColorModulateColorGen( Shader* shader, const colorGen_t colorGen, const alphaGen_t alphaGen, - const bool vertexOverbright = false, const bool useMapLightFactor = false ) { if( glConfig.gpuShader4Available ) { - shader->SetUniform_ColorModulateColorGen_Uint( colorGen, alphaGen, vertexOverbright, useMapLightFactor ); + shader->SetUniform_ColorModulateColorGen_Uint( colorGen, alphaGen, useMapLightFactor ); } else { - shader->SetUniform_ColorModulateColorGen_Float( colorGen, alphaGen, vertexOverbright, useMapLightFactor ); + shader->SetUniform_ColorModulateColorGen_Float( colorGen, alphaGen, useMapLightFactor ); } } diff --git a/src/engine/renderer/glsl_source/common.glsl b/src/engine/renderer/glsl_source/common.glsl index e90fd5474b..141f632261 100644 --- a/src/engine/renderer/glsl_source/common.glsl +++ b/src/engine/renderer/glsl_source/common.glsl @@ -68,15 +68,13 @@ colorMod << 0: color * 1 colorMod << 1: color * ( -1 ) colorMod << 2: alpha * 1 colorMod << 3: alpha * ( -1 ) -colorMod << 4-26: available for future usage -colorMod << 27: color += lightFactor +colorMod << 4-27: available for future usage colorMod << 28-31: lightFactor colorMod float format: colorMod[ 0 ]: color * f -colorMod[ 1 ] absolute value: lightFactor -colorMod[ 1 ] minus sign: color += lightFactor +colorMod[ 1 ]: lightFactor colorMod[ 3 ]: alpha * f */ vec4 ColorModulateToColor( const in colorModulatePack colorMod ) @@ -97,30 +95,12 @@ vec4 ColorModulateToColor( const in colorModulatePack colorMod ) return vec4( rgb, rgb, rgb, alpha ); } -struct ModBits_t -{ - bool useVertexLightFactor; -}; - -ModBits_t ColorModulateToBits( const in colorModulatePack colorMod ) -{ - ModBits_t modBits; - -#if defined(HAVE_EXT_gpu_shader4) - modBits.useVertexLightFactor = bool( ( colorMod >> 27u ) & 1u ); -#else - modBits.useVertexLightFactor = colorMod.g < 0; -#endif - - return modBits; -} - float ColorModulateToLightFactor( const in colorModulatePack colorMod ) { #if defined(HAVE_EXT_gpu_shader4) return float( colorMod >> 28u ); #else - return abs( colorMod.g ); + return colorMod.g; #endif } @@ -151,11 +131,8 @@ void ColorModulateColor_lightFactor( inout vec4 color ) { vec4 colorModulation = ColorModulateToColor( colorMod ); - ModBits_t modBits = ColorModulateToBits( colorMod ); float lightFactor = ColorModulateToLightFactor( colorMod ); - colorModulation.rgb += vec3( modBits.useVertexLightFactor ? lightFactor : 0 ); - vec4 unpackedColor = UnpackColor( packedColor ); unpackedColor.rgb *= lightFactor; diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index e1ad634ddc..a0d618d383 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -968,15 +968,14 @@ enum using stageRenderer_t = void(*)(shaderStage_t *); using stageShaderBuildMarker_t = void(*)(const shaderStage_t*); - using surfaceDataUpdater_t = void(*)(uint32_t*, shaderStage_t*, bool, bool, bool); + using surfaceDataUpdater_t = void(*)(uint32_t*, shaderStage_t*, bool, bool); using stageShaderBinder_t = void(*)(Material*); using stageMaterialProcessor_t = void(*)(Material*, shaderStage_t*, MaterialSurface*); enum ShaderStageVariant { - VERTEX_OVERBRIGHT = 1, - VERTEX_LIT = BIT( 1 ), - FULLBRIGHT = BIT( 2 ), - ALL = BIT( 3 ) + VERTEX_LIT = BIT( 0 ), + FULLBRIGHT = BIT( 1 ), + ALL = BIT( 2 ) }; struct shaderStage_t diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index bc261a58a3..b26fa27aa1 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -904,9 +904,8 @@ void Render_generic3D( shaderStage_t *pStage ) colorGen_t rgbGen = SetRgbGen( pStage ); alphaGen_t alphaGen = SetAlphaGen( pStage ); - bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP && tess.bspSurface; const bool styleLightMap = pStage->type == stageType_t::ST_STYLELIGHTMAP || pStage->type == stageType_t::ST_STYLECOLORMAP; - SetUniform_ColorModulateColorGen( gl_genericShader, rgbGen, alphaGen, mayUseVertexOverbright, styleLightMap ); + SetUniform_ColorModulateColorGen( gl_genericShader, rgbGen, alphaGen, styleLightMap ); // u_Color SetUniform_Color( gl_genericShader, tess.svars.color ); @@ -1083,7 +1082,7 @@ void Render_lightMapping( shaderStage_t *pStage ) gl_lightMappingShader->SetUniform_Time( backEnd.refdef.floatTime - backEnd.currentEntity->e.shaderTime ); // u_ColorModulate - SetUniform_ColorModulateColorGen( gl_lightMappingShader, rgbGen, alphaGen, false, lightMode != lightMode_t::FULLBRIGHT ); + SetUniform_ColorModulateColorGen( gl_lightMappingShader, rgbGen, alphaGen, lightMode != lightMode_t::FULLBRIGHT ); // u_Color SetUniform_Color( gl_lightMappingShader, tess.svars.color ); From f6980737e020706590488d51060c2eeb19259b78 Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 18 Feb 2026 02:26:58 -0600 Subject: [PATCH 49/66] Remove unimplemented refEntity_t::lightingOrigin --- src/engine/renderer/tr_types.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index deedd1381a..827219b0d6 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -63,10 +63,6 @@ using bool8_t = uint8_t; #define RF_DEPTHHACK 0x000008 // for view weapon Z crunching #define RF_NOSHADOW 0x000010 // don't add stencil shadows -#define RF_LIGHTING_ORIGIN 0x000020 // use refEntity->lightingOrigin instead of refEntity->origin -// for lighting. This allows entities to sink into the floor -// with their origin going solid, and allows all parts of a -// player to get the same lighting #define RF_SWAPCULL 0x000040 // swap CT_FRONT_SIDED and CT_BACK_SIDED // refdef flags @@ -175,8 +171,6 @@ struct refEntity_t qhandle_t hModel; // opaque type outside refresh // most recent data - vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN) - vec3_t axis[ 3 ]; // rotation vectors bool8_t nonNormalizedAxes; // axis are not normalized, i.e. they have scale vec3_t origin; From 0182eb153171ebb4839a0919c968e44cadfd3d7b Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 18 Feb 2026 03:50:40 -0600 Subject: [PATCH 50/66] Remove unused REF_xxx_DLIGHT flags --- src/engine/qcommon/q_shared.h | 7 ------- src/engine/renderer/tr_scene.cpp | 8 +------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/engine/qcommon/q_shared.h b/src/engine/qcommon/q_shared.h index 0ea400d3b2..7b33e27f36 100644 --- a/src/engine/qcommon/q_shared.h +++ b/src/engine/qcommon/q_shared.h @@ -1892,13 +1892,6 @@ inline vec_t VectorNormalize2( const vec3_t v, vec3_t out ) using GameStateCSs = std::array; -// TODO(0.56): NUKE all -#define REF_FORCE_DLIGHT ( 1 << 31 ) // RF, passed in through overdraw parameter, force this dlight under all conditions -#define REF_JUNIOR_DLIGHT ( 1 << 30 ) // (SA) this dlight does not light surfaces. it only affects dynamic light grid -#define REF_DIRECTED_DLIGHT ( 1 << 29 ) // ydnar: global directional light, origin should be interpreted as a normal vector -#define REF_RESTRICT_DLIGHT ( 1 << 1 ) // dlight is restricted to following entities -#define REF_INVERSE_DLIGHT ( 1 << 0 ) // inverse dlight for dynamic shadows - // bit field limits #define MAX_STATS 16 #define MAX_PERSISTANT 16 diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index abb52ca765..f9152cd67f 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -302,7 +302,7 @@ RE_AddDynamicLightToScene ydnar: modified dlight system to support separate radius and intensity ===================== */ -void RE_AddDynamicLightToScene( const vec3_t org, float radius, float r, float g, float b, int flags ) +void RE_AddDynamicLightToScene( const vec3_t org, float radius, float r, float g, float b, int /*flags*/) { if ( !glConfig.realtimeLighting || !r_drawDynamicLights.Get() ) { @@ -324,12 +324,6 @@ void RE_AddDynamicLightToScene( const vec3_t org, float radius, float r, float g return; } - if ( flags & REF_INVERSE_DLIGHT ) - { - Log::Warn( "REF_INVERSE_DLIGHT not implemtented" ); - return; - } - refLight_t *light = &backEndData[ tr.smpFrame ]->lights[ r_numLights++ ]; light->rlType = refLightType_t::RL_OMNI; From aa4819db8837011218e827e9e68b89a64676a107 Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 18 Feb 2026 03:51:58 -0600 Subject: [PATCH 51/66] Remove unused RF_MINLIGHT --- src/engine/renderer/tr_types.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 827219b0d6..72d84a2c9f 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -57,7 +57,6 @@ using bool8_t = uint8_t; #define MAX_ENTITIES MAX_REF_ENTITIES // RB: for compatibility // renderfx flags -#define RF_MINLIGHT 0x000001 // always have some light (viewmodel, some items) #define RF_THIRD_PERSON 0x000002 // don't draw through eyes, only mirrors (player bodies, chat sprites) #define RF_FIRST_PERSON 0x000004 // only draw through eyes (view weapon, damage blood blob) #define RF_DEPTHHACK 0x000008 // for view weapon Z crunching From 4f60849d83e0295e95587353187ff078995e603f Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 18 Feb 2026 04:00:51 -0600 Subject: [PATCH 52/66] Remove glDriverType_t enum This was already removed from the ABI so it was just unused. --- src/engine/renderer/GLUtils.h | 1 - src/engine/renderer/tr_types.h | 9 --------- src/engine/sys/sdl_glimp.cpp | 2 -- 3 files changed, 12 deletions(-) diff --git a/src/engine/renderer/GLUtils.h b/src/engine/renderer/GLUtils.h index 9ea2aff90d..e7a3a635ed 100644 --- a/src/engine/renderer/GLUtils.h +++ b/src/engine/renderer/GLUtils.h @@ -45,7 +45,6 @@ struct GLConfig int colorBits; - glDriverType_t driverType; glHardwareType_t hardwareType; textureCompression_t textureCompression; diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 72d84a2c9f..968a3622c1 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -244,15 +244,6 @@ enum class textureCompression_t TC_EXT_COMP_S3TC }; -// TODO(0.56): remove. -enum class glDriverType_t -{ - GLDRV_UNKNOWN = -1, - GLDRV_ICD, - GLDRV_STANDALONE, - GLDRV_OPENGL3, -}; - // Keep the list in sdl_glimp.c:reportHardwareType in sync with this enum class glHardwareType_t { diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index f3e17e7bb3..28adcf324b 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -2683,8 +2683,6 @@ of OpenGL */ bool GLimp_Init() { - glConfig.driverType = glDriverType_t::GLDRV_OPENGL3; - r_sdlDriver = Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); r_allowResize = Cvar_Get( "r_allowResize", "0", CVAR_LATCH ); r_displayIndex = Cvar_Get( "r_displayIndex", "0", 0 ); From 755f89400ddd004c7ef4456934ca610ef8f6c194 Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 18 Feb 2026 04:14:03 -0600 Subject: [PATCH 53/66] Clean up RegisterShaderFlags_t ABI interface --- src/engine/renderer/tr_local.h | 6 ------ src/engine/renderer/tr_shader.cpp | 3 --- src/engine/renderer/tr_types.h | 10 ++++++++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 200a5d5477..8463a4e28d 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -962,12 +962,6 @@ enum struct Material; struct MaterialSurface; - // [implicit only] enable lightmapping, front-side culling, disable (non-BSP) vertex colors, disable blending - // TODO(0.56): move to the public RegisterShaderFlags_t interface -#define RSF_3D ( BIT( 30 ) ) - -#define RSF_BSP ( BIT ( 29 ) ) - using stageRenderer_t = void(*)(shaderStage_t *); using stageShaderBuildMarker_t = void(*)(const shaderStage_t*); using surfaceDataUpdater_t = void(*)(uint32_t*, shaderStage_t*, bool, bool); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 1091310518..db5ab9d8cb 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -6255,9 +6255,6 @@ shader_t *R_FindShader( const char *name, int flags ) return tr.defaultShader; } - // TODO(0.56): RSF_DEFAULT should be 0! - flags &= ~RSF_DEFAULT; - COM_StripExtension3( name, strippedName, sizeof( strippedName ) ); hash = generateHashValue( strippedName, FILE_HASH_SIZE ); diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 968a3622c1..eb0b068c56 100644 --- a/src/engine/renderer/tr_types.h +++ b/src/engine/renderer/tr_types.h @@ -82,10 +82,13 @@ using glIndex_t = unsigned int; // shader was auto-generated from an image. enum RegisterShaderFlags_t { // nothing - RSF_DEFAULT = BIT( 0 ), + RSF_DEFAULT = 0, // [implicit only] alter filter and wrap type - RSF_2D = BIT( 1 ), + RSF_2D = BIT( 0 ), + + // [implicit only] enable lightmapping, front-side culling, disable (non-BSP) vertex colors, disable blending + RSF_3D = BIT( 1 ), // load images without mipmaps RSF_NOMIP = BIT( 2 ), @@ -98,6 +101,9 @@ enum RegisterShaderFlags_t { // when the shader is used on an entity sprite, face view direction instead of viewer RSF_SPRITE = BIT( 6 ), + + // Probably not useful for cgame. Signals that vertex colors are light values + RSF_BSP = BIT ( 30 ), }; struct polyVert_t From e4110620ac20760c4f8b1d31d9c4ad681cab3900 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Mon, 23 Feb 2026 23:07:46 +0300 Subject: [PATCH 54/66] Make SVF_BROADCAST_ONCE have a unique SVF_* value --- src/engine/server/sg_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/server/sg_api.h b/src/engine/server/sg_api.h index db1d211ee8..f13f07ef44 100644 --- a/src/engine/server/sg_api.h +++ b/src/engine/server/sg_api.h @@ -44,7 +44,7 @@ along with this program. If not, see . #define SVF_SELF_PORTAL_EXCLUSIVE 0x00010000 #define SVF_RIGID_BODY 0x00020000 // ignored by the engine #define SVF_CLIENTS_IN_RANGE 0x00040000 // clients within range -#define SVF_BROADCAST_ONCE 0x00040000 // broadcasted to newly connecting clients, and once to connected clients when spawned +#define SVF_BROADCAST_ONCE 0x00080000 // broadcasted to newly connecting clients, and once to connected clients when spawned #define MAX_ENT_CLUSTERS 16 From 3fc9984347ec1bec58d76b892dcf8574e910e141 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Wed, 25 Feb 2026 20:03:47 +0100 Subject: [PATCH 55/66] cameraEffects: do the tone mapping operation before the color conversion --- src/engine/renderer/glsl_source/cameraEffects_fp.glsl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl index e2a1dc8e58..8b243fdb44 100644 --- a/src/engine/renderer/glsl_source/cameraEffects_fp.glsl +++ b/src/engine/renderer/glsl_source/cameraEffects_fp.glsl @@ -84,11 +84,6 @@ void main() vec4 color = texture2D(u_CurrentMap, st); color *= u_GlobalLightFactor; - if ( u_SRGB ) - { - convertToSRGB( color.rgb ); - } - color.rgb *= u_Exposure; #if defined(r_highPrecisionRendering) && defined(HAVE_ARB_texture_float) @@ -99,6 +94,11 @@ void main() color.rgb = clamp( color.rgb, vec3( 0.0f ), vec3( 1.0f ) ); + if ( u_SRGB ) + { + convertToSRGB( color.rgb ); + } + #if defined(r_colorGrading) // apply color grading vec3 colCoord = color.rgb * 15.0 / 16.0 + 0.5 / 16.0; From 237eb7b772fdbdb8debc87a460f7b37d34ad289d Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Fri, 27 Feb 2026 07:17:16 +0100 Subject: [PATCH 56/66] tr_init: set r_toneMappingContrast to 1.4 --- src/engine/renderer/tr_init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 366a08912b..f9380a0c7d 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -192,7 +192,7 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul "r_toneMappingExposure", "Exposure (brightness adjustment)", Cvar::NONE, 1.0f ); Cvar::Range> r_toneMappingContrast( "r_toneMappingContrast", "Makes dark areas light up faster", - Cvar::NONE, 1.6f, 1.0f, 10.0f ); + Cvar::NONE, 1.4f, 1.0f, 10.0f ); Cvar::Range> r_toneMappingHighlightsCompressionSpeed( "r_toneMappingHighlightsCompressionSpeed", "Highlights saturation", Cvar::NONE, 0.977f, 0.0f, 10.0f ); From 017bd2661c0aa3fb8af016debb2a97864fdeebdc Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 27 Feb 2026 03:42:34 -0600 Subject: [PATCH 57/66] Rename r_toneMappingExposure -> r_exposure --- src/engine/renderer/tr_backend.cpp | 4 ++-- src/engine/renderer/tr_init.cpp | 5 ++--- src/engine/renderer/tr_local.h | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 9f0c1537a3..d8604cc632 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1682,7 +1682,7 @@ void RB_CameraPostFX() { gl_cameraEffectsShader->SetUniform_InverseGamma( 1.0 / r_gamma->value ); gl_cameraEffectsShader->SetUniform_SRGB( tr.worldLinearizeTexture ); - gl_cameraEffectsShader->SetUniform_Exposure( r_toneMappingExposure.Get() ); + gl_cameraEffectsShader->SetUniform_Exposure( r_exposure.Get() ); const bool tonemap = r_toneMapping.Get() && r_highPrecisionRendering.Get() && glConfig.textureFloatAvailable; if ( tonemap ) { @@ -2841,7 +2841,7 @@ static void SetFrameUniforms() { globalUBOProxy->SetUniform_ColorModulate( tr.viewParms.gradingWeights ); globalUBOProxy->SetUniform_InverseGamma( 1.0f / r_gamma->value ); - globalUBOProxy->SetUniform_Exposure( r_toneMappingExposure.Get() ); + globalUBOProxy->SetUniform_Exposure( r_exposure.Get() ); const bool tonemap = r_toneMapping.Get() && r_highPrecisionRendering.Get() && glConfig.textureFloatAvailable; if ( tonemap ) { diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index f9380a0c7d..bd36037c59 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -187,9 +187,8 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Cvar r_toneMapping( "r_toneMapping", "Use HDR->LDR tonemapping", Cvar::NONE, true ); - // TODO(0.56): rename because it can be used without tone mapping now - Cvar::Cvar r_toneMappingExposure( - "r_toneMappingExposure", "Exposure (brightness adjustment)", Cvar::NONE, 1.0f ); + Cvar::Cvar r_exposure( + "r_exposure", "Exposure (brightness adjustment)", Cvar::NONE, 1.0f ); Cvar::Range> r_toneMappingContrast( "r_toneMappingContrast", "Makes dark areas light up faster", Cvar::NONE, 1.4f, 1.0f, 10.0f ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 8463a4e28d..34e900b11d 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2670,7 +2670,7 @@ enum extern cvar_t *r_gamma; extern Cvar::Cvar r_toneMapping; - extern Cvar::Cvar r_toneMappingExposure; + extern Cvar::Cvar r_exposure; extern Cvar::Range> r_toneMappingContrast; extern Cvar::Range> r_toneMappingHighlightsCompressionSpeed; extern Cvar::Range> r_toneMappingHDRMax; From a74c8b47b939b66a761c818e027884404bcc9c4d Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Fri, 27 Feb 2026 13:24:06 +0100 Subject: [PATCH 58/66] tr_shader: rework the non-delayed texture loading, fix loading legacy diffuse stage --- src/engine/renderer/tr_shader.cpp | 168 ++++++++++++++---------------- 1 file changed, 80 insertions(+), 88 deletions(-) diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index db5ab9d8cb..bffc8d2f72 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -1632,28 +1632,43 @@ static void DelayAnimationTexture( const char* texturePath, const size_t animati delayedAnimationTextures[ animationIndex ].active = true; } +enum class mapLoadingMode_t { + DELAYED, + IMMEDIATE, + IMMEDIATE_COLORMAP, +}; + +static void LoadMapOrDelay( shaderStage_t *stage, char* buffer, const stageType_t stageType, + const int bundleIndex, const mapLoadingMode_t mode=mapLoadingMode_t::DELAYED ) +{ + switch ( mode ) + { + case mapLoadingMode_t::DELAYED: + DelayStageTexture( buffer, stageType, bundleIndex ); + break; + case mapLoadingMode_t::IMMEDIATE: + LoadMap( stage, buffer, stageType, bundleIndex ); + break; + case mapLoadingMode_t::IMMEDIATE_COLORMAP: + LoadMap( stage, buffer, stageType, TB_COLORMAP ); + break; + } +} + /* =================== ParseDifuseMap and others =================== */ -static void ParseDiffuseMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_DIFFUSEMAP ) +static void ParseDiffuseMap( shaderStage_t *stage, const char **text, + const mapLoadingMode_t mode=mapLoadingMode_t::DELAYED ) { char buffer[ 1024 ] = ""; if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { - stageType_t stageType = stageType_t::ST_DIFFUSEMAP; - - if ( bundleIndex == TB_DIFFUSEMAP ) - { - DelayStageTexture( buffer, stageType, bundleIndex ); - } - else - { - LoadMap( stage, buffer, stageType, bundleIndex ); - } + LoadMapOrDelay( stage, buffer, stageType_t::ST_DIFFUSEMAP, TB_DIFFUSEMAP, mode ); } } @@ -1664,10 +1679,11 @@ static void ParseLegacyDiffuseStage( shaderStage_t *stage, const char **text ) stage->rgbGen = colorGen_t::CGEN_IDENTITY; stage->stateBits = GLS_DEFAULT; - ParseDiffuseMap( stage, text, TB_COLORMAP ); + ParseDiffuseMap( stage, text, mapLoadingMode_t::IMMEDIATE_COLORMAP ); } -static void ParseNormalMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_NORMALMAP ) +static void ParseNormalMap( shaderStage_t *stage, const char **text, + const mapLoadingMode_t mode=mapLoadingMode_t::DELAYED ) { char buffer[ 1024 ] = ""; @@ -1682,16 +1698,7 @@ static void ParseNormalMap( shaderStage_t *stage, const char **text, const int b if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { - stageType_t stageType = stageType_t::ST_NORMALMAP; - - if ( bundleIndex == TB_NORMALMAP ) - { - DelayStageTexture( buffer, stageType, bundleIndex ); - } - else - { - LoadMap( stage, buffer, stageType, bundleIndex ); - } + LoadMapOrDelay( stage, buffer, stageType_t::ST_NORMALMAP, TB_NORMALMAP, mode ); } } @@ -1702,10 +1709,11 @@ static void ParseLegacyNormalStage( shaderStage_t *stage, const char **text ) stage->rgbGen = colorGen_t::CGEN_IDENTITY; stage->stateBits = GLS_DEFAULT; - ParseNormalMap( stage, text, TB_COLORMAP ); + ParseNormalMap( stage, text, mapLoadingMode_t::IMMEDIATE_COLORMAP ); } -static void ParseNormalMapDetectHeightMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_NORMALMAP ) +static void ParseNormalMapDetectHeightMap( shaderStage_t *stage, const char **text, + const mapLoadingMode_t mode ) { /* Always call this function on assets known to never use RGTC format or the engine running on hardware with driver not implementing the @@ -1723,16 +1731,16 @@ static void ParseNormalMapDetectHeightMap( shaderStage_t *stage, const char **te const char* initialText = *text; - ParseNormalMap( stage, text, bundleIndex ); + ParseNormalMap( stage, text, mode ); /* Tell renderer to enable relief mapping since an heightmap is found, also tell renderer to not abuse normalmap alpha channel because it's an heightmap. See https://github.com/DaemonEngine/Daemon/issues/183#issuecomment-473691252 */ - if ( stage->bundle[ bundleIndex ].image[ 0 ] - && stage->bundle[ bundleIndex ].image[ 0 ]->bits & IF_NORMALMAP - && stage->bundle[ bundleIndex ].image[ 0 ]->bits & IF_ALPHA ) + if ( stage->bundle[ TB_NORMALMAP ].image[ 0 ] + && stage->bundle[ TB_NORMALMAP ].image[ 0 ]->bits & IF_NORMALMAP + && stage->bundle[ TB_NORMALMAP ].image[ 0 ]->bits & IF_ALPHA ) { Log::defaultLogger.DoDebugCode([&] { char buffer[ 1024 ]; @@ -1750,43 +1758,29 @@ static void ParseNormalMapDetectHeightMap( shaderStage_t *stage, const char **te // There is no ParseLegacyNormalStageDetectHeightMap. -static void ParseHeightMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_HEIGHTMAP ) +static void ParseHeightMap( shaderStage_t* /* stage */, const char **text, + const mapLoadingMode_t mode=mapLoadingMode_t::DELAYED ) { + Q_UNUSED(mode); + char buffer[ 1024 ] = ""; if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { - stageType_t stageType = stageType_t::ST_HEIGHTMAP; - - if ( bundleIndex == TB_HEIGHTMAP ) - { - DelayStageTexture( buffer, stageType, bundleIndex ); - } - else - { - LoadMap( stage, buffer, stageType, bundleIndex ); - } + DelayStageTexture( buffer, stageType_t::ST_HEIGHTMAP, TB_HEIGHTMAP ); } } // There is no ParseLegacyHeightStage. -static void ParseSpecularMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_SPECULARMAP ) +static void ParseSpecularMap( shaderStage_t *stage, const char **text, + const mapLoadingMode_t mode=mapLoadingMode_t::DELAYED ) { char buffer[ 1024 ] = ""; if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { - stageType_t stageType = stageType_t::ST_SPECULARMAP; - - if ( bundleIndex == TB_SPECULARMAP ) - { - DelayStageTexture( buffer, stageType, bundleIndex ); - } - else - { - LoadMap( stage, buffer, stageType, bundleIndex ); - } + LoadMapOrDelay( stage, buffer, stageType_t::ST_SPECULARMAP, TB_SPECULARMAP, mode ); } } @@ -1797,10 +1791,10 @@ static void ParseLegacySpecularStage( shaderStage_t *stage, const char **text ) stage->rgbGen = colorGen_t::CGEN_IDENTITY; stage->stateBits = GLS_DEFAULT; - ParseSpecularMap( stage, text, TB_COLORMAP ); + ParseSpecularMap( stage, text, mapLoadingMode_t::IMMEDIATE_COLORMAP ); } -static void ParsePhysicalMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_PHYSICALMAP ) +static void ParsePhysicalMap( shaderStage_t *stage, const char **text ) { char buffer[ 1024 ] = ""; @@ -1810,37 +1804,19 @@ static void ParsePhysicalMap( shaderStage_t *stage, const char **text, const int if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { - stageType_t stageType = stageType_t::ST_PHYSICALMAP; - - if ( bundleIndex == TB_PHYSICALMAP ) - { - DelayStageTexture( buffer, stageType, bundleIndex ); - } - else - { - LoadMap( stage, buffer, stageType, bundleIndex ); - } + DelayStageTexture( buffer, stageType_t::ST_PHYSICALMAP, TB_PHYSICALMAP ); } } // There is no ParseLegacyPhysicalStage. -static void ParseGlowMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_GLOWMAP ) +static void ParseGlowMap( shaderStage_t *stage, const char **text, const mapLoadingMode_t mode=mapLoadingMode_t::DELAYED ) { char buffer[ 1024 ] = ""; if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { - stageType_t stageType = stageType_t::ST_GLOWMAP; - - if ( bundleIndex == TB_GLOWMAP ) - { - DelayStageTexture( buffer, stageType, bundleIndex ); - } - else - { - LoadMap( stage, buffer, stageType, bundleIndex ); - } + LoadMapOrDelay( stage, buffer, stageType_t::ST_GLOWMAP, TB_GLOWMAP, mode ); } } @@ -1851,10 +1827,11 @@ static void ParseLegacyGlowStage( shaderStage_t *stage, const char **text ) stage->rgbGen = colorGen_t::CGEN_IDENTITY; stage->stateBits = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE; // blend add - ParseGlowMap( stage, text, TB_COLORMAP ); + ParseGlowMap( stage, text, mapLoadingMode_t::IMMEDIATE_COLORMAP ); } -static void ParseReflectionMap( shaderStage_t *stage, const char **text, const int bundleIndex = TB_REFLECTIONMAP ) +static void ParseReflectionMap( shaderStage_t *stage, const char **text, + const mapLoadingMode_t mode=mapLoadingMode_t::IMMEDIATE ) { char buffer[ 1024 ] = ""; @@ -1864,7 +1841,7 @@ static void ParseReflectionMap( shaderStage_t *stage, const char **text, const i if ( ParseMap( text, buffer, sizeof( buffer ) ) ) { stage->isCubeMap = true; - LoadMap( stage, buffer, stageType_t::ST_REFLECTIONMAP, bundleIndex ); + LoadMapOrDelay( stage, buffer, stageType_t::ST_REFLECTIONMAP, TB_REFLECTIONMAP, mode ); } } @@ -1876,7 +1853,7 @@ static void ParseReflectionStage( shaderStage_t *stage, const char **text ) stage->rgbGen = colorGen_t::CGEN_IDENTITY; stage->stateBits = GLS_DEFAULT; - ParseReflectionMap( stage, text, TB_COLORMAP ); + ParseReflectionMap( stage, text, mapLoadingMode_t::IMMEDIATE_COLORMAP ); } static void ParseReflectionStageBlended( shaderStage_t *stage, const char **text ) @@ -1886,7 +1863,7 @@ static void ParseReflectionStageBlended( shaderStage_t *stage, const char **text stage->rgbGen = colorGen_t::CGEN_IDENTITY; stage->stateBits = GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE; - ParseReflectionMap( stage, text, TB_COLORMAP ); + ParseReflectionMap( stage, text, mapLoadingMode_t::IMMEDIATE_COLORMAP ); } static bool HasNormalFormat( shaderStage_t *stage ) @@ -1941,19 +1918,34 @@ struct extraMapParser_t { const char *suffix; const char *description; - void ( *parser ) ( shaderStage_t*, const char**, int ); - int bundleIndex; + const mapLoadingMode_t mode; + void ( *parser ) ( shaderStage_t*, const char**, mapLoadingMode_t ); }; static const extraMapParser_t dpExtraMapParsers[] = { - { "_norm", "DarkPlaces normal map", ParseNormalMapDetectHeightMap, TB_NORMALMAP, }, - { "_bump", "DarkPlaces height map", ParseHeightMap, TB_HEIGHTMAP, }, - { "_gloss", "DarkPlaces specular map", ParseSpecularMap, TB_SPECULARMAP, }, - { "_glow", "DarkPlaces glow map", ParseGlowMap, TB_GLOWMAP, }, + { "_norm", + "DarkPlaces normal map", + mapLoadingMode_t::IMMEDIATE, + ParseNormalMapDetectHeightMap, }, + { "_bump", + "DarkPlaces height map", + mapLoadingMode_t::DELAYED, + ParseHeightMap, }, + { "_gloss", + "DarkPlaces specular map", + mapLoadingMode_t::DELAYED, + ParseSpecularMap, }, + { "_glow", + "DarkPlaces glow map", + mapLoadingMode_t::DELAYED, + ParseGlowMap, }, // DarkPlaces implemented _luma for Tenebrae compatibility, the // probability of finding this suffix with Xonotic maps is very low. - { "_luma", "Tenebrae glow map", ParseGlowMap, TB_GLOWMAP, }, + { "_luma", + "Tenebrae glow map", + mapLoadingMode_t::DELAYED, + ParseGlowMap, }, }; /* @@ -2069,9 +2061,9 @@ void LoadExtraMaps( shaderStage_t *stage, const char *colorMapName ) Log::Debug( "found extra %s '%s'", parser.description, extraMapName.c_str() ); const char *name = extraMapName.c_str(); - parser.parser( stage, &name, parser.bundleIndex ); + parser.parser( stage, &name, parser.mode ); - if ( parser.bundleIndex == TB_NORMALMAP ) + if ( parser.parser == &ParseNormalMapDetectHeightMap ) { // Xonotic uses +X +Y +Z (OpenGL) SetNormalFormat( stage, glNormalFormat ); From ef2ae9ea870089753086a822d587ef8be9ca2e20 Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 16 Feb 2026 13:45:26 -0600 Subject: [PATCH 59/66] NUKE LightForPoint function and trap call --- src/engine/RefAPI.h | 2 - src/engine/client/cg_msgdef.h | 5 -- src/engine/client/cl_cgame.cpp | 6 --- src/engine/null/null_renderer.cpp | 5 -- src/engine/renderer/tr_init.cpp | 1 - src/engine/renderer/tr_light.cpp | 81 ------------------------------- src/engine/renderer/tr_local.h | 1 - src/shared/client/cg_api.cpp | 12 ----- src/shared/client/cg_api.h | 1 - 9 files changed, 114 deletions(-) diff --git a/src/engine/RefAPI.h b/src/engine/RefAPI.h index 04ff33c77f..79b7b2be8f 100644 --- a/src/engine/RefAPI.h +++ b/src/engine/RefAPI.h @@ -114,8 +114,6 @@ struct refexport_t { void ( *ClearScene )( ); void ( *AddRefEntityToScene )( const refEntity_t* re ); - int ( *LightForPoint )( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); - void ( *AddPolyToScene )( qhandle_t hShader, int numVerts, const polyVert_t* verts ); void ( *AddPolysToScene )( qhandle_t hShader, int numVerts, const polyVert_t* verts, int numPolys ); diff --git a/src/engine/client/cg_msgdef.h b/src/engine/client/cg_msgdef.h index 3a9338136e..6821a9595b 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -182,7 +182,6 @@ enum cgameImport_t CG_R_LERPTAG, CG_R_REMAP_SHADER, CG_R_BATCHINPVS, - CG_R_LIGHTFORPOINT, CG_R_REGISTERANIMATION, CG_R_BUILDSKELETON, CG_R_BONEINDEX, @@ -332,10 +331,6 @@ namespace Render { std::vector>>, IPC::Reply> >; - using LightForPointMsg = IPC::SyncMessage< - IPC::Message, std::array>, - IPC::Reply, std::array, std::array, int> - >; using RegisterAnimationMsg = IPC::SyncMessage< IPC::Message, std::string>, IPC::Reply diff --git a/src/engine/client/cl_cgame.cpp b/src/engine/client/cl_cgame.cpp index 01e42217bd..abb50789aa 100644 --- a/src/engine/client/cl_cgame.cpp +++ b/src/engine/client/cl_cgame.cpp @@ -1243,12 +1243,6 @@ void CGameVM::QVMSyscall(int syscallNum, Util::Reader& reader, IPC::Channel& cha }); break; - case CG_R_LIGHTFORPOINT: - IPC::HandleMsg(channel, std::move(reader), [this] (std::array point, std::array& ambient, std::array& directed, std::array& dir, int& res) { - res = re.LightForPoint(point.data(), ambient.data(), directed.data(), dir.data()); - }); - break; - case CG_R_REGISTERANIMATION: IPC::HandleMsg(channel, std::move(reader), [this] (const std::string& name, int& handle) { handle = re.RegisterAnimation(name.c_str()); diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index 3a0f741d82..c81158aef7 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -79,10 +79,6 @@ void RE_SetWorldVisData( const byte * ) { } void RE_EndRegistration() { } void RE_ClearScene() { } void RE_AddRefEntityToScene( const refEntity_t * ) { } -int R_LightForPoint( vec3_t, vec3_t, vec3_t, vec3_t ) -{ - return 0; -} void RE_AddPolyToScene( qhandle_t, int, const polyVert_t* ) { } void RE_AddPolysToScene( qhandle_t, int, const polyVert_t*, int ) { } void RE_AddLightToScene( const vec3_t, float, float, float, float, int ) { } @@ -207,7 +203,6 @@ refexport_t *GetRefAPI( int, refimport_t* ) re.ClearScene = RE_ClearScene; re.AddRefEntityToScene = RE_AddRefEntityToScene; - re.LightForPoint = R_LightForPoint; re.AddPolyToScene = RE_AddPolyToScene; // Ridah diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index bd36037c59..2885749bcd 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1660,7 +1660,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p re.AddPolyToScene = RE_AddPolyToSceneET; re.AddPolysToScene = RE_AddPolysToScene; - re.LightForPoint = R_LightForPoint; re.AddLightToScene = RE_AddDynamicLightToScene; diff --git a/src/engine/renderer/tr_light.cpp b/src/engine/renderer/tr_light.cpp index 37130f697f..f347419af0 100644 --- a/src/engine/renderer/tr_light.cpp +++ b/src/engine/renderer/tr_light.cpp @@ -95,84 +95,3 @@ float R_InterpolateLightGrid( world_t *w, int from[3], int to[3], return totalFactor; } - -/* -================= -R_LightForPoint -================= -*/ -int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) -{ - int i; - int from[ 3 ], to[ 3 ]; - float frac[ 3 ][ 2 ]; - float *factors[ 3 ] = { frac[ 0 ], frac[ 1 ], frac[ 2 ] }; - float totalFactor; - - // bk010103 - this segfaults with -nolight maps - if ( tr.world->lightGridData1 == nullptr || - tr.world->lightGridData2 == nullptr ) - { - return false; - } - - for ( i = 0; i < 3; i++ ) - { - float v; - - v = point[ i ] - tr.world->lightGridOrigin[ i ]; - v *= tr.world->lightGridInverseSize[ i ]; - from[ i ] = floor( v ); - frac[ i ][ 0 ] = v - from[ i ]; - - if ( from[ i ] < 0 ) - { - from[ i ] = 0; - frac[ i ][ 0 ] = 0.0f; - } - else if ( from[ i ] >= tr.world->lightGridBounds[ i ] - 1 ) - { - from[ i ] = tr.world->lightGridBounds[ i ] - 2; - frac[ i ][ 0 ] = 1.0f; - } - - to[ i ] = from[ i ] + 1; - frac[ i ][ 1 ] = 1.0f - frac[ i ][ 0 ]; - } - - totalFactor = R_InterpolateLightGrid( tr.world, from, to, factors, - ambientLight, directedLight, - lightDir ); - - if ( totalFactor > 0 && totalFactor < 0.99 ) - { - totalFactor = 1.0f / totalFactor; - - VectorScale( lightDir, totalFactor, lightDir ); - VectorScale( ambientLight, totalFactor, ambientLight ); - VectorScale( directedLight, totalFactor, directedLight ); - } - - // compute z-component of direction - lightDir[ 2 ] = 1.0f - fabsf( lightDir[ 0 ] ) - fabsf( lightDir[ 1 ] ); - if( lightDir[ 2 ] < 0.0f ) { - float X = lightDir[ 0 ]; - float Y = lightDir[ 1 ]; - lightDir[ 0 ] = copysignf( 1.0f - fabsf( Y ), X ); - lightDir[ 1 ] = copysignf( 1.0f - fabsf( X ), Y ); - } - - VectorNormalize( lightDir ); - - if ( ambientLight[ 0 ] < r_forceAmbient.Get() && - ambientLight[ 1 ] < r_forceAmbient.Get() && - ambientLight[ 2 ] < r_forceAmbient.Get() ) - { - ambientLight[ 0 ] = r_forceAmbient.Get(); - ambientLight[ 1 ] = r_forceAmbient.Get(); - ambientLight[ 2 ] = r_forceAmbient.Get(); - } - - return true; -} - diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 34e900b11d..c5570f8704 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -3266,7 +3266,6 @@ void GLimp_LogComment_( std::string comment ); float R_InterpolateLightGrid( world_t *w, int from[3], int to[3], float *factors[3], vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); - int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); /* ============================================================ diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index dc9bb6cce8..961583ab6a 100644 --- a/src/shared/client/cg_api.cpp +++ b/src/shared/client/cg_api.cpp @@ -414,18 +414,6 @@ std::vector trap_R_BatchInPVS( return inPVS; } -int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) -{ - int result; - std::array mypoint, myambient, mydirected, mydir; - VectorCopy(point, mypoint); - VM::SendMsg(mypoint, myambient, mydirected, mydir, result); - VectorCopy(myambient, ambientLight); - VectorCopy(mydirected, directedLight); - VectorCopy(mydir, lightDir); - return result; -} - qhandle_t trap_R_RegisterAnimation( const char *name ) { int handle; diff --git a/src/shared/client/cg_api.h b/src/shared/client/cg_api.h index 071d1fb1a6..518a76d3ea 100644 --- a/src/shared/client/cg_api.h +++ b/src/shared/client/cg_api.h @@ -106,7 +106,6 @@ std::vector trap_R_BatchInPVS( const vec3_t origin, const std::vector>& posEntities ); -int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); qhandle_t trap_R_RegisterAnimation( const char *name ); int trap_R_BuildSkeleton( refSkeleton_t *skel, qhandle_t anim, int startFrame, int endFrame, float frac, bool clearOrigin ); int trap_R_BlendSkeleton( refSkeleton_t *skel, const refSkeleton_t *blend, float frac ); From b6dc4ae49c3e928c916cfa422e0fd4d20030f4d3 Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 16 Feb 2026 18:08:22 -0600 Subject: [PATCH 60/66] Rewrite light grid direction interpolation Redesign the scheme for storing light grid direction and directedness vs. ambientness information in the pixels of a 3D image. Note for context: the light grid does not store the separate directed and ambient colors; it just averages them. Before: Light dir is always stored as a normal vector. There is an "ambient part" byte which is supposed to indicate what fraction of the light is ambient and what fraction directed. After: Light dir is scaled according to how much ambient light there is. Amount of light which is ambient is determined by how long the direction vector is. Some issues with the old code which are fixed: - Wrong averaging of the directed and ambient colors. Previously directed and ambient colors were equally weighted, but ambient should have more weight since there is no dot product term which can decrease it. - Bad interpolation behavior. Example 1: if neighboring grid cells had nearly opposing directions, the resulting direction vector would be garbage. With the new code, this results in a small vector which causes most light to be automatically moved into directed instead of ambient. Example 2: if one cell has a large directed component and its neighbor has none, the directions are equally weighted despite the second one being meaningless. With the new code, directions are weighted according to how much directed light there is. - Excessive brightness when deluxe mapping is disabled, because it behaved in that case as if the normal vector were always perfectly aligned with the light direction. --- .../renderer/glsl_source/computeLight_fp.glsl | 16 ++-- .../renderer/glsl_source/lightMapping_fp.glsl | 19 +++-- src/engine/renderer/tr_backend.cpp | 15 ++-- src/engine/renderer/tr_bsp.cpp | 76 +++++++++---------- src/engine/renderer/tr_light.cpp | 27 +++---- src/engine/renderer/tr_local.h | 10 ++- 6 files changed, 85 insertions(+), 78 deletions(-) diff --git a/src/engine/renderer/glsl_source/computeLight_fp.glsl b/src/engine/renderer/glsl_source/computeLight_fp.glsl index f3c23bf9e9..d3508a9828 100644 --- a/src/engine/renderer/glsl_source/computeLight_fp.glsl +++ b/src/engine/renderer/glsl_source/computeLight_fp.glsl @@ -50,13 +50,19 @@ vec4 EnvironmentalSpecularFactor( vec3 viewDir, vec3 normal ) // lighting helper functions #if defined(USE_GRID_LIGHTING) || defined(USE_GRID_DELUXE_MAPPING) - void ReadLightGrid( in vec4 texel, in float lightFactor, out vec3 ambientColor, out vec3 lightColor ) { - float ambientScale = 2.0 * texel.a; - float directedScale = 2.0 - ambientScale; - ambientColor = ambientScale * texel.rgb; - lightColor = directedScale * texel.rgb; + void ReadLightGrid( in vec4 texel1, in vec4 texel2, in float lightFactor, out vec3 lightDir, out vec3 ambientColor, out vec3 lightColor ) { + vec3 totalColor = /*LIGHTGRID_MAX_LIGHT*/ 1.25 * texel1.rgb; + float total1Norm = totalColor.r + totalColor.g + totalColor.b; + vec3 scaledLightDir = 2.0 * (texel2.xyz - (128.0 / 255.0)); + float directed1Norm = 3.0 * length(scaledLightDir); + float directedFraction = clamp((0.25 * directed1Norm) / total1Norm, 0.0, 1.0); + float directedScale = 4.0 * directedFraction; + float ambientScale = 1.0 - directedFraction; + ambientColor = ambientScale * totalColor; + lightColor = directedScale * totalColor; ambientColor *= lightFactor; lightColor *= lightFactor; + lightDir = normalize(scaledLightDir); } #endif diff --git a/src/engine/renderer/glsl_source/lightMapping_fp.glsl b/src/engine/renderer/glsl_source/lightMapping_fp.glsl index da72f901e2..484098150c 100644 --- a/src/engine/renderer/glsl_source/lightMapping_fp.glsl +++ b/src/engine/renderer/glsl_source/lightMapping_fp.glsl @@ -130,19 +130,10 @@ void main() vec4 color; color.a = diffuse.a; - #if defined(USE_GRID_LIGHTING) || defined(USE_GRID_DELUXE_MAPPING) - // Compute light grid position. - vec3 lightGridPos = (var_Position - u_LightGridOrigin) * u_LightGridScale; - #endif - #if defined(USE_DELUXE_MAPPING) // Compute light direction in world space from deluxe map. vec4 deluxe = texture2D(u_DeluxeMap, var_TexLight); vec3 lightDir = normalize(2.0 * deluxe.xyz - 1.0); - #elif defined(USE_GRID_DELUXE_MAPPING) - // Compute light direction in world space from light grid. - vec4 texel = texture3D(u_LightGrid2, lightGridPos); - vec3 lightDir = normalize(texel.xyz - (128.0 / 255.0)); #endif float lightFactor = ColorModulateToLightFactor( u_ColorModulateColorGen ); @@ -156,8 +147,16 @@ void main() color.rgb = vec3(0.0); #else // Compute light color from lightgrid. + vec3 lightGridPos = (var_Position - u_LightGridOrigin) * u_LightGridScale; + vec4 texel1 = texture3D(u_LightGrid1, lightGridPos); + #if defined(USE_GRID_DELUXE_MAPPING) + vec4 texel2 = texture3D(u_LightGrid2, lightGridPos); + #else + vec4 texel2 = vec4(128.0 / 255.0); // zero direction vector + #endif + vec3 lightDir; vec3 ambientColor, lightColor; - ReadLightGrid(texture3D(u_LightGrid1, lightGridPos), lightFactor, ambientColor, lightColor); + ReadLightGrid(texel1, texel2, lightFactor, lightDir, ambientColor, lightColor); color.rgb = ambientColor * r_AmbientScale * diffuse.rgb; #endif diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index d8604cc632..6d80b8fa40 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -2223,14 +2223,19 @@ static void RB_RenderDebugUtils() int gridIndex = x + tr.world->lightGridBounds[ 0 ] * ( y + tr.world->lightGridBounds[ 1 ] * z ); const bspGridPoint1_t *gp1 = tr.world->lightGridData1 + gridIndex; const bspGridPoint2_t *gp2 = tr.world->lightGridData2 + gridIndex; - Color::Color generalColor = Color::Adapt( gp1->color ); - float ambientScale = 2.0f * unorm8ToFloat( gp1->ambientPart ); - float directedScale = 2.0f - ambientScale; - Color::Color ambientColor = generalColor * ambientScale; - Color::Color directedColor = generalColor * directedScale; lightDir[ 0 ] = snorm8ToFloat( gp2->direction[ 0 ] - 128 ); lightDir[ 1 ] = snorm8ToFloat( gp2->direction[ 1 ] - 128 ); lightDir[ 2 ] = snorm8ToFloat( gp2->direction[ 2 ] - 128 ); + Color::Color totalColor = Color::Adapt( gp1->color ); + totalColor *= LIGHTGRID_MAX_LIGHT; + float total1Norm = totalColor.Red() + totalColor.Green() + totalColor.Blue(); + float directed1Norm = 3.0f * VectorLength( lightDir ); + float directedFraction = ( 0.25 * directed1Norm ) / total1Norm; + float directedScale = 4.0 * directedFraction; + float ambientScale = 1.0 - directedFraction; + Color::Color ambientColor = totalColor * ambientScale; + Color::Color directedColor = totalColor * directedScale; + VectorNormalize( lightDir ); VectorNegate( lightDir, lightDir ); diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index 3655ea0fb2..76d4f3a028 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -3438,14 +3438,13 @@ static void R_SetConstantColorLightGrid( const byte color[3] ) bspGridPoint1_t *gridPoint1 = (bspGridPoint1_t *) ri.Hunk_Alloc( sizeof( bspGridPoint1_t ) + sizeof( bspGridPoint2_t ), ha_pref::h_low ); bspGridPoint2_t *gridPoint2 = (bspGridPoint2_t *) (gridPoint1 + w->numLightGridPoints); - // default some white light from above - gridPoint1->color[ 0 ] = color[0]; - gridPoint1->color[ 1 ] = color[1]; - gridPoint1->color[ 2 ] = color[2]; - gridPoint1->ambientPart = 128; + // directed part comes from above; ambient color and directed color are both `color` + VectorCopy( color, gridPoint1->color ); + gridPoint1->unused = 255; gridPoint2->direction[ 0 ] = 128 + floatToSnorm8( 0.0f ); gridPoint2->direction[ 1 ] = 128 + floatToSnorm8( 0.0f ); - gridPoint2->direction[ 2 ] = 128 + floatToSnorm8( 1.0f ); + gridPoint2->direction[ 2 ] = 128 + floatToSnorm8( + ( color[ 0 ] + color[ 1 ] + color[ 2 ] ) / ( 3.0f * 255 ) ); gridPoint2->isSet = 255; w->lightGridData1 = gridPoint1; @@ -3496,7 +3495,6 @@ void R_LoadLightGrid( lump_t *l ) float weights[ 3 ] = { 0.25f, 0.5f, 0.25f }; float *factors[ 3 ] = { weights, weights, weights }; vec3_t ambientColor, directedColor, direction; - float scale; if ( tr.ambientLightSet ) { const byte color[3]{ floatToUnorm8( tr.ambientLight[0] ), floatToUnorm8( tr.ambientLight[1] ), @@ -3637,19 +3635,28 @@ void R_LoadLightGrid( lump_t *l ) direction[ 1 ] = sinf( lng ) * sinf( lat ); direction[ 2 ] = cosf( lat ); - // Pack data into an bspGridPoint - gridPoint1->color[ 0 ] = floatToUnorm8( 0.5f * (ambientColor[ 0 ] + directedColor[ 0 ]) ); - gridPoint1->color[ 1 ] = floatToUnorm8( 0.5f * (ambientColor[ 1 ] + directedColor[ 1 ]) ); - gridPoint1->color[ 2 ] = floatToUnorm8( 0.5f * (ambientColor[ 2 ] + directedColor[ 2 ]) ); - - float ambientLength = VectorLength(ambientColor); - float directedLength = VectorLength(directedColor); - float length = ambientLength + directedLength; - gridPoint1->ambientPart = floatToUnorm8( ambientLength / length ); - - gridPoint2->direction[0] = 128 + floatToSnorm8( direction[ 0 ] ); - gridPoint2->direction[1] = 128 + floatToSnorm8( direction[ 1 ] ); - gridPoint2->direction[2] = 128 + floatToSnorm8( direction[ 2 ] ); + // Separate ambient and directed colors are not implemented, so this is the total average light + // (averaged over all direction vectors): ambient + 0.25 * directed. See TraceGrid in light.c in + // q3map2 for more information about this equation. Though if to take + // half-Lambert lighting's cosine modification into account, the 1/4 factor should be replaced + // by 1/3. The result is scaled down to fit in [0, 1]. + gridPoint1->color[ 0 ] = floatToUnorm8( ( ambientColor[ 0 ] + 0.25f * directedColor[ 0 ] ) / LIGHTGRID_MAX_LIGHT ); + gridPoint1->color[ 1 ] = floatToUnorm8( ( ambientColor[ 1 ] + 0.25f * directedColor[ 1 ] ) / LIGHTGRID_MAX_LIGHT ); + gridPoint1->color[ 2 ] = floatToUnorm8( ( ambientColor[ 2 ] + 0.25f * directedColor[ 2 ] ) / LIGHTGRID_MAX_LIGHT ); + gridPoint1->unused = 255; + + // The length of the direction vector is used to determine how much directed light there is. + // When adjacent grid points have opposing directions that (partially) cancel each other upon + // interpolation, the GLSL will see a smaller direction vector and put more light into the + // ambient part. "How much light" is determined using the 1-norm (Maybe it should be + // luma-aware?) since that is preserved under interpolation. + // TODO: send the directed contribution to zero if it is worse than random? If you had perfectly + // ambient white light with a total of sum of A, you'd get a directed color of 0.25*A and an ambient color + // of 0.1875*A. So if the directed to ambient ratio is lower than that, the direction is surely garbage. + float dirScale = ( directedColor[ 0 ] + directedColor[ 1 ] + directedColor[ 2 ] ) / 3.0f; + gridPoint2->direction[0] = 128 + floatToSnorm8( dirScale * direction[ 0 ] ); + gridPoint2->direction[1] = 128 + floatToSnorm8( dirScale * direction[ 1 ] ); + gridPoint2->direction[2] = 128 + floatToSnorm8( dirScale * direction[ 2 ] ); gridPoint2->isSet = 255; } @@ -3678,27 +3685,18 @@ void R_LoadLightGrid( lump_t *l ) continue; } - scale = R_InterpolateLightGrid( w, from, to, factors, - ambientColor, directedColor, - direction ); - if( scale > 0.0f ) { - scale = 1.0f / scale; - - VectorScale( ambientColor, scale, ambientColor ); - VectorScale( directedColor, scale, directedColor ); - VectorScale( direction, scale, direction ); + vec3_t interpolatedColor, interpolatedDir; + R_InterpolateLightGrid( w, from, to, factors, interpolatedColor, interpolatedDir ); + gridPoint1->color[0] = floatToUnorm8( interpolatedColor[ 0 ] ); + gridPoint1->color[1] = floatToUnorm8( interpolatedColor[ 1 ] ); + gridPoint1->color[2] = floatToUnorm8( interpolatedColor[ 2 ] ); + gridPoint1->unused = 255; - gridPoint1->color[0] = floatToUnorm8(0.5f * (ambientColor[0] + directedColor[0])); - gridPoint1->color[1] = floatToUnorm8(0.5f * (ambientColor[1] + directedColor[1])); - gridPoint1->color[2] = floatToUnorm8(0.5f * (ambientColor[2] + directedColor[2])); - gridPoint1->ambientPart = floatToUnorm8(VectorLength(ambientColor) / (VectorLength(ambientColor) + VectorLength(directedColor))); - - gridPoint2->direction[0] = 128 + floatToSnorm8(direction[0]); - gridPoint2->direction[1] = 128 + floatToSnorm8(direction[1]); - gridPoint2->direction[2] = 128 + floatToSnorm8(direction[2]); - gridPoint2->isSet = 255; - } + gridPoint2->direction[0] = 128 + floatToSnorm8( interpolatedDir[ 0 ] ); + gridPoint2->direction[1] = 128 + floatToSnorm8( interpolatedDir[ 1 ] ); + gridPoint2->direction[2] = 128 + floatToSnorm8( interpolatedDir[ 2 ] ); + gridPoint2->isSet = 255; } } } diff --git a/src/engine/renderer/tr_light.cpp b/src/engine/renderer/tr_light.cpp index f347419af0..5c870dc0f1 100644 --- a/src/engine/renderer/tr_light.cpp +++ b/src/engine/renderer/tr_light.cpp @@ -31,9 +31,9 @@ LIGHT SAMPLING ============================================================================= */ -float R_InterpolateLightGrid( world_t *w, int from[3], int to[3], - float *factors[3], vec3_t ambientLight, - vec3_t directedLight, vec3_t lightDir ) { +void R_InterpolateLightGrid( world_t *w, int from[3], int to[3], float *factors[3], + vec3_t lightColor, vec3_t lightDir ) +{ float totalFactor = 0.0f, factor; float *xFactor, *yFactor, *zFactor; int gridStep[ 3 ]; @@ -41,8 +41,7 @@ float R_InterpolateLightGrid( world_t *w, int from[3], int to[3], bspGridPoint1_t *gp1; bspGridPoint2_t *gp2; - VectorClear( ambientLight ); - VectorClear( directedLight ); + VectorClear( lightColor ); VectorClear( lightDir ); gridStep[ 0 ] = 1; @@ -80,18 +79,16 @@ float R_InterpolateLightGrid( world_t *w, int from[3], int to[3], lightDir[ 1 ] += factor * snorm8ToFloat( gp2->direction[ 1 ] - 128 ); lightDir[ 2 ] += factor * snorm8ToFloat( gp2->direction[ 2 ] - 128 ); - float ambientScale = 2.0f * unorm8ToFloat( gp1->ambientPart ); - float directedScale = 2.0f - ambientScale; - - ambientLight[ 0 ] += factor * ambientScale * unorm8ToFloat( gp1->color[ 0 ] ); - ambientLight[ 1 ] += factor * ambientScale * unorm8ToFloat( gp1->color[ 1 ] ); - ambientLight[ 2 ] += factor * ambientScale * unorm8ToFloat( gp1->color[ 2 ] ); - directedLight[ 0 ] += factor * directedScale * unorm8ToFloat( gp1->color[ 0 ] ); - directedLight[ 1 ] += factor * directedScale * unorm8ToFloat( gp1->color[ 1 ] ); - directedLight[ 2 ] += factor * directedScale * unorm8ToFloat( gp1->color[ 2 ] ); + lightColor[ 0 ] += factor * unorm8ToFloat( gp1->color[ 0 ] ); + lightColor[ 1 ] += factor * unorm8ToFloat( gp1->color[ 1 ] ); + lightColor[ 2 ] += factor * unorm8ToFloat( gp1->color[ 2 ] ); } } } - return totalFactor; + if ( totalFactor > 0.0f ) + { + VectorScale( lightDir, 1.0f / totalFactor, lightDir ); + VectorScale( lightColor, 1.0f / totalFactor, lightColor ); + } } diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index c5570f8704..41097edacf 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1684,13 +1684,16 @@ enum bspSurface_t *firstSurface; }; +// max combined ambient+directed contribution to one color channel +#define LIGHTGRID_MAX_LIGHT 1.25f + // The ambient and directional colors are packed into four bytes, the color[3] is the // average of the ambient and directional colors and the ambientPart factor is the // proportion of ambient light in the total light struct bspGridPoint1_t { byte color[3]; - byte ambientPart; + byte unused; }; struct bspGridPoint2_t { @@ -3263,9 +3266,8 @@ void GLimp_LogComment_( std::string comment ); ============================================================ */ - float R_InterpolateLightGrid( world_t *w, int from[3], int to[3], - float *factors[3], vec3_t ambientLight, - vec3_t directedLight, vec3_t lightDir ); + void R_InterpolateLightGrid( world_t *w, int from[3], int to[3], float *factors[3], + vec3_t lightColor, vec3_t lightDir ); /* ============================================================ From 0e1b0096fa328cb4dfde809de1fef113f7386bea Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 2 Mar 2026 19:24:50 -0600 Subject: [PATCH 61/66] Make models brighter with deluxe mapping off The previous commit fixed excessive brightness with grid lighting when deluxe mapping is disabled by using the average expected brightness (over all directions) instead of the maximum, but it went too far and made things dim. Boost the light a bit since light directions are positively correlated with normals in practice. --- src/engine/renderer/gl_shader.cpp | 2 ++ .../renderer/glsl_source/computeLight_fp.glsl | 6 +++--- src/engine/renderer/tr_backend.cpp | 6 +++--- src/engine/renderer/tr_bsp.cpp | 12 +++++------- src/engine/renderer/tr_init.cpp | 15 +++++++++++++++ src/engine/renderer/tr_local.h | 4 +--- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index f23055feb4..bd143ca82e 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -687,6 +687,8 @@ static std::string GenEngineConstants() { AddDefine( str, "r_tileStep", glState.tileStep[0], glState.tileStep[1] ); + AddDefine( str, "LIGHTGRID_AVERAGE_COSINE", tr.lightGridAverageCosine ); + if ( glConfig.realtimeLighting ) { AddDefine( str, "r_realtimeLighting", 1 ); diff --git a/src/engine/renderer/glsl_source/computeLight_fp.glsl b/src/engine/renderer/glsl_source/computeLight_fp.glsl index d3508a9828..34c59389f0 100644 --- a/src/engine/renderer/glsl_source/computeLight_fp.glsl +++ b/src/engine/renderer/glsl_source/computeLight_fp.glsl @@ -51,12 +51,12 @@ vec4 EnvironmentalSpecularFactor( vec3 viewDir, vec3 normal ) #if defined(USE_GRID_LIGHTING) || defined(USE_GRID_DELUXE_MAPPING) void ReadLightGrid( in vec4 texel1, in vec4 texel2, in float lightFactor, out vec3 lightDir, out vec3 ambientColor, out vec3 lightColor ) { - vec3 totalColor = /*LIGHTGRID_MAX_LIGHT*/ 1.25 * texel1.rgb; + vec3 totalColor = (1.0 + LIGHTGRID_AVERAGE_COSINE) * texel1.rgb; float total1Norm = totalColor.r + totalColor.g + totalColor.b; vec3 scaledLightDir = 2.0 * (texel2.xyz - (128.0 / 255.0)); float directed1Norm = 3.0 * length(scaledLightDir); - float directedFraction = clamp((0.25 * directed1Norm) / total1Norm, 0.0, 1.0); - float directedScale = 4.0 * directedFraction; + float directedFraction = clamp((LIGHTGRID_AVERAGE_COSINE * directed1Norm) / total1Norm, 0.0, 1.0); + float directedScale = directedFraction / LIGHTGRID_AVERAGE_COSINE; float ambientScale = 1.0 - directedFraction; ambientColor = ambientScale * totalColor; lightColor = directedScale * totalColor; diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 6d80b8fa40..8cec6eaad8 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -2227,11 +2227,11 @@ static void RB_RenderDebugUtils() lightDir[ 1 ] = snorm8ToFloat( gp2->direction[ 1 ] - 128 ); lightDir[ 2 ] = snorm8ToFloat( gp2->direction[ 2 ] - 128 ); Color::Color totalColor = Color::Adapt( gp1->color ); - totalColor *= LIGHTGRID_MAX_LIGHT; + totalColor *= 1.0f + tr.lightGridAverageCosine; float total1Norm = totalColor.Red() + totalColor.Green() + totalColor.Blue(); float directed1Norm = 3.0f * VectorLength( lightDir ); - float directedFraction = ( 0.25 * directed1Norm ) / total1Norm; - float directedScale = 4.0 * directedFraction; + float directedFraction = ( tr.lightGridAverageCosine * directed1Norm ) / total1Norm; + float directedScale = directedFraction / tr.lightGridAverageCosine; float ambientScale = 1.0 - directedFraction; Color::Color ambientColor = totalColor * ambientScale; Color::Color directedColor = totalColor * directedScale; diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index 76d4f3a028..29cb4bb626 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -3636,13 +3636,11 @@ void R_LoadLightGrid( lump_t *l ) direction[ 2 ] = cosf( lat ); // Separate ambient and directed colors are not implemented, so this is the total average light - // (averaged over all direction vectors): ambient + 0.25 * directed. See TraceGrid in light.c in - // q3map2 for more information about this equation. Though if to take - // half-Lambert lighting's cosine modification into account, the 1/4 factor should be replaced - // by 1/3. The result is scaled down to fit in [0, 1]. - gridPoint1->color[ 0 ] = floatToUnorm8( ( ambientColor[ 0 ] + 0.25f * directedColor[ 0 ] ) / LIGHTGRID_MAX_LIGHT ); - gridPoint1->color[ 1 ] = floatToUnorm8( ( ambientColor[ 1 ] + 0.25f * directedColor[ 1 ] ) / LIGHTGRID_MAX_LIGHT ); - gridPoint1->color[ 2 ] = floatToUnorm8( ( ambientColor[ 2 ] + 0.25f * directedColor[ 2 ] ) / LIGHTGRID_MAX_LIGHT ); + // (averaged over all direction vectors). The result is scaled down to fit in [0, 1]. + float colorScale = 1.0f / ( 1.0f + tr.lightGridAverageCosine ); + gridPoint1->color[ 0 ] = floatToUnorm8( ( ambientColor[ 0 ] + tr.lightGridAverageCosine * directedColor[ 0 ] ) * colorScale ); + gridPoint1->color[ 1 ] = floatToUnorm8( ( ambientColor[ 1 ] + tr.lightGridAverageCosine * directedColor[ 1 ] ) * colorScale ); + gridPoint1->color[ 2 ] = floatToUnorm8( ( ambientColor[ 2 ] + tr.lightGridAverageCosine * directedColor[ 2 ] ) * colorScale ); gridPoint1->unused = 255; // The length of the direction vector is used to determine how much directed light there is. diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 2885749bcd..8d496d1b47 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1350,6 +1350,21 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p } } + if ( glConfig.deluxeMapping ) + { + // Average value of max(0, dot(random vector, light dir)) over the unit sphere, used to + // compare directed lighting's average contribution with ambient. See TraceGrid in light.c in + // q3map2 for more information about this calculation. Though if we took half-Lambert lighting's + // cosine modification into account it would be 1/3 instead of 1/4. + tr.lightGridAverageCosine = 0.25f; + } + else + { + // Boost it when deluxe is disabled because otherwise it's too dark. Normals tend to line up + // with the light direction better than chance. + tr.lightGridAverageCosine = 0.4f; + } + R_NoiseInit(); R_Register(); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 41097edacf..68328fde7d 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1684,9 +1684,6 @@ enum bspSurface_t *firstSurface; }; -// max combined ambient+directed contribution to one color channel -#define LIGHTGRID_MAX_LIGHT 1.25f - // The ambient and directional colors are packed into four bytes, the color[3] is the // average of the ambient and directional colors and the ambientPart factor is the // proportion of ambient light in the total light @@ -2501,6 +2498,7 @@ enum vec3_t ambientLight; bool ambientLightSet = false; + float lightGridAverageCosine; image_t *lightGrid1Image; image_t *lightGrid2Image; From 1af2e404995a726e0c3493b32e69efcad4230365 Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 25 Feb 2026 18:07:38 -0600 Subject: [PATCH 62/66] Remove SVF_ flags that do nothing --- src/engine/server/sg_api.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/engine/server/sg_api.h b/src/engine/server/sg_api.h index f13f07ef44..12315d0120 100644 --- a/src/engine/server/sg_api.h +++ b/src/engine/server/sg_api.h @@ -28,13 +28,8 @@ along with this program. If not, see . #define SVF_NOCLIENT 0x00000001 #define SVF_CLIENTMASK 0x00000002 #define SVF_VISDUMMY 0x00000004 -#define SVF_BOT 0x00000008 -#define SVF_POW 0x00000010 // ignored by the engine #define SVF_BROADCAST 0x00000020 #define SVF_PORTAL 0x00000040 -#define SVF_BLANK 0x00000080 // ignored by the engine -#define SVF_NOFOOTSTEPS 0x00000100 // ignored by the engine -#define SVF_CAPSULE 0x00000200 #define SVF_VISDUMMY_MULTIPLE 0x00000400 #define SVF_SINGLECLIENT 0x00000800 #define SVF_NOSERVERINFO 0x00001000 // only meaningful for entities numbered in [0..MAX_CLIENTS) @@ -42,7 +37,6 @@ along with this program. If not, see . #define SVF_IGNOREBMODELEXTENTS 0x00004000 #define SVF_SELF_PORTAL 0x00008000 #define SVF_SELF_PORTAL_EXCLUSIVE 0x00010000 -#define SVF_RIGID_BODY 0x00020000 // ignored by the engine #define SVF_CLIENTS_IN_RANGE 0x00040000 // clients within range #define SVF_BROADCAST_ONCE 0x00080000 // broadcasted to newly connecting clients, and once to connected clients when spawned @@ -53,7 +47,7 @@ struct entityShared_t bool linked; // false if not in any good cluster int linkcount; - int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc. + int svFlags; // SVF_*, flags for controlling which entities are sent to which clients int singleClient; // only send to this client when SVF_SINGLECLIENT is set int hiMask, loMask; // if SVF_CLIENTMASK is set, then only send to the // clients specified by the following 64-bit bitmask: From 45d6e95781ef4e62aa9a3fd6e483d6c84ebcae36 Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 27 Feb 2026 04:28:58 -0600 Subject: [PATCH 63/66] Reorder and comment SVF_* flags --- src/engine/server/sg_api.h | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/engine/server/sg_api.h b/src/engine/server/sg_api.h index 12315d0120..f2dbf04566 100644 --- a/src/engine/server/sg_api.h +++ b/src/engine/server/sg_api.h @@ -25,20 +25,27 @@ along with this program. If not, see . #include "engine/qcommon/q_shared.h" -#define SVF_NOCLIENT 0x00000001 -#define SVF_CLIENTMASK 0x00000002 -#define SVF_VISDUMMY 0x00000004 -#define SVF_BROADCAST 0x00000020 -#define SVF_PORTAL 0x00000040 -#define SVF_VISDUMMY_MULTIPLE 0x00000400 -#define SVF_SINGLECLIENT 0x00000800 -#define SVF_NOSERVERINFO 0x00001000 // only meaningful for entities numbered in [0..MAX_CLIENTS) -#define SVF_NOTSINGLECLIENT 0x00002000 -#define SVF_IGNOREBMODELEXTENTS 0x00004000 -#define SVF_SELF_PORTAL 0x00008000 -#define SVF_SELF_PORTAL_EXCLUSIVE 0x00010000 -#define SVF_CLIENTS_IN_RANGE 0x00040000 // clients within range -#define SVF_BROADCAST_ONCE 0x00080000 // broadcasted to newly connecting clients, and once to connected clients when spawned +// flags for masking which clients can see the entity +#define SVF_CLIENTMASK BIT( 0 ) +#define SVF_SINGLECLIENT BIT( 1 ) +#define SVF_NOCLIENT BIT( 2 ) +#define SVF_NOTSINGLECLIENT BIT( 3 ) + +// flags for modifying visibility +#define SVF_BROADCAST BIT( 4 ) // visible from anywhere +#define SVF_BROADCAST_ONCE BIT( 5 ) // broadcasted to newly connecting clients, and once to connected clients when spawned +#define SVF_CLIENTS_IN_RANGE BIT( 6 ) +#define SVF_IGNOREBMODELEXTENTS BIT( 7 ) + +#define SVF_PORTAL BIT( 8 ) // if you see the portal, you also see what can be seen through its camera +#define SVF_NOSERVERINFO BIT( 9 ) // only meaningful for entities numbered in [0..MAX_CLIENTS) + +// ??? +#define SVF_VISDUMMY BIT( 10 ) +#define SVF_VISDUMMY_MULTIPLE BIT( 11 ) +#define SVF_SELF_PORTAL BIT( 12 ) +#define SVF_SELF_PORTAL_EXCLUSIVE BIT( 13 ) + #define MAX_ENT_CLUSTERS 16 From 4a92b2961a9ec733ba9699d8cf78b02d42a64a56 Mon Sep 17 00:00:00 2001 From: DolceTriade Date: Sun, 22 Feb 2026 03:57:27 -0800 Subject: [PATCH 64/66] glsl_restart: Stop segfaulting Using git bisect, e497a0867d6a2f4170756b379123b04fc6d5124e introduces a window where globalUBOProxy can be null after glsl_restart. Therefore, also return early, if glboalUBOProxy is null. It will be instantiated later. Further, only initialize world shaders *AFTER* all shader storage has been initialized. --- src/engine/renderer/tr_backend.cpp | 2 +- src/engine/renderer/tr_shade.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 8cec6eaad8..f1921b96c6 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -2835,7 +2835,7 @@ static void RB_RenderPostProcess() static void SetFrameUniforms() { // This can happen with glsl_restart/vid_restart in R_SyncRenderThread() - if ( !stagingBuffer.Active() ) { + if ( !stagingBuffer.Active() || globalUBOProxy == nullptr ) { return; } diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index b2c95800e5..abdabc8ecf 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -256,11 +256,6 @@ static void GLSL_InitGPUShadersOrError() gl_depthReductionShader->MarkProgramForBuilding(); } - if ( tr.world ) // this only happens with /glsl_restart - { - GLSL_InitWorldShaders(); - } - if ( glConfig.realtimeLighting ) { gl_shaderManager.LoadShader( gl_depthtile1Shader ); @@ -384,6 +379,12 @@ static void GLSL_InitGPUShadersOrError() gl_shaderManager.PostProcessGlobalUniforms(); gl_shaderManager.InitShaders(); + // Init world shaders last so that everyhthing is already initialized. + if ( tr.world ) // this only happens with /glsl_restart + { + GLSL_InitWorldShaders(); + } + if ( r_lazyShaders.Get() == 0 ) { gl_shaderManager.BuildAll( false ); From 11ec5c11b273cfc6d2038318345fab45637693ce Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Mon, 9 Mar 2026 12:26:57 +0100 Subject: [PATCH 65/66] whitespace --- src/engine/renderer/tr_shade.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index abdabc8ecf..b40416751c 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -198,7 +198,7 @@ static void EnableAvailableFeatures() glConfig.usingGeometryCache = glConfig.usingMaterialSystem && glConfig.geometryCacheAvailable; } -// For shaders that require map data for compile-time values +// For shaders that require map data for compile-time values void GLSL_InitWorldShaders() { // make sure the render thread is stopped R_SyncRenderThread(); @@ -326,7 +326,7 @@ static void GLSL_InitGPUShadersOrError() gl_contrastShader->MarkProgramForBuilding(); } - + // portal process effect gl_shaderManager.LoadShader( gl_portalShader ); @@ -1448,7 +1448,7 @@ void Render_heatHaze( shaderStage_t *pStage ) // bind u_NormalMap gl_heatHazeShader->SetUniform_NormalMapBindless( - GL_BindToTMU( 0, pStage->bundle[TB_NORMALMAP].image[0] ) + GL_BindToTMU( 0, pStage->bundle[TB_NORMALMAP].image[0] ) ); if ( pStage->enableNormalMapping ) @@ -1464,7 +1464,7 @@ void Render_heatHaze( shaderStage_t *pStage ) // bind u_CurrentMap gl_heatHazeShader->SetUniform_CurrentMapBindless( - GL_BindToTMU( 1, tr.currentRenderImage[backEnd.currentMainFBO] ) + GL_BindToTMU( 1, tr.currentRenderImage[backEnd.currentMainFBO] ) ); gl_heatHazeShader->SetRequiredVertexPointers(); @@ -1474,7 +1474,7 @@ void Render_heatHaze( shaderStage_t *pStage ) // copy to foreground image R_BindFBO( tr.mainFBO[ backEnd.currentMainFBO ] ); gl_heatHazeShader->SetUniform_CurrentMapBindless( - GL_BindToTMU( 1, tr.currentRenderImage[1 - backEnd.currentMainFBO] ) + GL_BindToTMU( 1, tr.currentRenderImage[1 - backEnd.currentMainFBO] ) ); gl_heatHazeShader->SetUniform_DeformMagnitude( 0.0f ); Tess_DrawElements(); From 2bf3f00a981d50a9c8f15877ff9db488075e68c6 Mon Sep 17 00:00:00 2001 From: Thomas Debesse Date: Wed, 19 Mar 2025 15:00:06 +0100 Subject: [PATCH 66/66] gl_shader: catch shader source processing exceptions and print raw source --- src/engine/renderer/gl_shader.cpp | 139 ++++++++++++++++-------------- 1 file changed, 76 insertions(+), 63 deletions(-) diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index bd143ca82e..1acd69611a 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -1733,90 +1733,103 @@ void GLShaderManager::PrintShaderSource( Str::StringRef programName, GLuint obje std::string delim( "\n" ); std::string src( dump ); - ri.Hunk_FreeTempMemory( dump ); + try + { + int lineNumber = 0; + size_t pos = 0; - int lineNumber = 0; - size_t pos = 0; + int infoLogID = -1; + if ( infoLog.size() > 0 ) { + infoLogID = 0; + } - int infoLogID = -1; - if ( infoLog.size() > 0 ) { - infoLogID = 0; - } + while ( ( pos = src.find( delim ) ) != std::string::npos ) { + std::string line = src.substr( 0, pos ); + if ( Str::IsPrefix( "#line ", line ) ) + { + size_t lineNumEnd = line.find( ' ', 6 ); + Str::ParseInt( lineNumber, line.substr( 6, lineNumEnd - 6 ) ); + } - while ( ( pos = src.find( delim ) ) != std::string::npos ) { - std::string line = src.substr( 0, pos ); - if ( Str::IsPrefix( "#line ", line ) ) - { - size_t lineNumEnd = line.find( ' ', 6 ); - Str::ParseInt( lineNumber, line.substr( 6, lineNumEnd - 6 ) ); - } + std::string number = std::to_string( lineNumber ); - std::string number = std::to_string( lineNumber ); + static const int numberWidth = 4; + int p = numberWidth - number.length(); + p = p < 0 ? 0 : p; + number.insert( number.begin(), p, ' ' ); - static const int numberWidth = 4; - int p = numberWidth - number.length(); - p = p < 0 ? 0 : p; - number.insert( number.begin(), p, ' ' ); + buffer.append( number ); + buffer.append( ": " ); + buffer.append( line ); + buffer.append( delim ); - buffer.append( number ); - buffer.append( ": " ); - buffer.append( line ); - buffer.append( delim ); + while ( infoLogID != -1 && infoLog[infoLogID].line == lineNumber ) { + if ( ( int( line.length() ) > infoLog[infoLogID].character ) && ( infoLog[infoLogID].character != -1 ) ) { + buffer.append( numberWidth + 2, '-' ); + const size_t position = line.find_first_not_of( "\t" ); - while ( infoLogID != -1 && infoLog[infoLogID].line == lineNumber ) { - if ( ( int( line.length() ) > infoLog[infoLogID].character ) && ( infoLog[infoLogID].character != -1 ) ) { - buffer.append( numberWidth + 2, '-' ); - const size_t position = line.find_first_not_of( "\t" ); + if ( position != std::string::npos ) { + buffer.append( position, '\t' ); + buffer.append( infoLog[infoLogID].character - position, '-' ); + } else { + buffer.append( infoLog[infoLogID].character, '-' ); + } + buffer.append( "^" ); + buffer.append( line.length() - infoLog[infoLogID].character - 1, '-' ); - if ( position != std::string::npos ) { - buffer.append( position, '\t' ); - buffer.append( infoLog[infoLogID].character - position, '-' ); - } else { - buffer.append( infoLog[infoLogID].character, '-' ); - } - buffer.append( "^" ); - buffer.append( line.length() - infoLog[infoLogID].character - 1, '-' ); + } else if ( ( line.length() > 0 ) && ( infoLog[infoLogID].token.length() > 0 ) ) { + size_t position = line.find_first_not_of( "\t" ); + size_t prevPosition = 0; - } else if ( ( line.length() > 0 ) && ( infoLog[infoLogID].token.length() > 0 ) ) { - size_t position = line.find_first_not_of( "\t" ); - size_t prevPosition = 0; + buffer.append( numberWidth + 2, '-' ); + if ( position != std::string::npos ) { + buffer.append( position, '\t' ); + } else { + position = 0; + } - buffer.append( numberWidth + 2, '-' ); - if ( position != std::string::npos ) { - buffer.append( position, '\t' ); + while ( ( position = line.find( infoLog[infoLogID].token, position ) ) && ( position != std::string::npos ) ) { + buffer.append( position - prevPosition - 1, '-' ); + buffer.append( "^" ); + prevPosition = position; + position++; + } + buffer.append( line.length() - position - 1, '-' ); } else { - position = 0; + buffer.append( numberWidth + 2 + line.length(), '^' ); } - while ( ( position = line.find( infoLog[infoLogID].token, position ) ) && ( position != std::string::npos ) ) { - buffer.append( position - prevPosition - 1, '-' ); - buffer.append( "^" ); - prevPosition = position; - position++; + buffer.append( delim ); + buffer.append( infoLog[infoLogID].error ); + buffer.append( delim ); + buffer.append( delim ); + + infoLogID++; + + if ( infoLogID >= int( infoLog.size() ) ) { + infoLogID = -1; } - buffer.append( line.length() - position - 1, '-' ); - } else { - buffer.append( numberWidth + 2 + line.length(), '^' ); } - buffer.append( delim ); - buffer.append( infoLog[infoLogID].error ); - buffer.append( delim ); - buffer.append( delim ); - - infoLogID++; + src.erase( 0, pos + delim.length() ); - if ( infoLogID >= int( infoLog.size() ) ) { - infoLogID = -1; - } + lineNumber++; } - src.erase( 0, pos + delim.length() ); - - lineNumber++; + Log::Warn( "Source for shader program %s:\n%s", programName, buffer ); + } + catch (std::exception& err) + { + Log::Warn( "Exception occurred when processing the source for shader program %s (%s): %s", programName, typeid(err).name(), err.what() ); + Log::Warn( "Raw source for shader program %s:\n%s", programName, dump ); + } + catch (...) + { + Log::Warn( "Unknown exception occurred when processing the source for shader program %s.", programName ); + Log::Warn( "Raw source for shader program %s:\n%s", programName, dump ); } - Log::Warn("Source for shader program %s:\n%s", programName, buffer.c_str()); + ri.Hunk_FreeTempMemory( dump ); } std::vector GLShaderManager::ParseInfoLog( const std::string& infoLog ) const {