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 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/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; }); diff --git a/src/engine/RefAPI.h b/src/engine/RefAPI.h index d1129e01ef..79b7b2be8f 100644 --- a/src/engine/RefAPI.h +++ b/src/engine/RefAPI.h @@ -45,12 +45,6 @@ Maryland 20850 USA. extern Cvar::Modified> r_fullscreen; -struct WindowConfig { - float displayAspect; - int displayWidth, displayHeight; // the entire monitor (the one indicated by displayIndex) - int vidWidth, vidHeight; // what the game is using -}; - // font support struct glyphInfo_t { @@ -120,13 +114,10 @@ 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 ); - 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 r, float g, float b, int flags ); void ( *AddAdditiveLightToScene )( const vec3_t org, float intensity, float r, float g, float b ); @@ -153,8 +144,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 ); diff --git a/src/engine/audio/Audio.cpp b/src/engine/audio/Audio.cpp index 2147e349c0..527abbd455 100644 --- a/src/engine/audio/Audio.cpp +++ b/src/engine/audio/Audio.cpp @@ -58,16 +58,70 @@ 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; }; - 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]; static bool initialized = false; + int playerClientNum; + static AL::Device* device; static AL::Context* context; @@ -147,8 +201,8 @@ namespace Audio { UpdateListenerGain(); - for (auto &loop : entityLoops) { - loop = {false, nullptr, -1, -1}; + for ( EntityMultiLoop& loop : entityLoops ) { + loop.ResetAll(); } return true; @@ -160,11 +214,8 @@ namespace Audio { } // Shuts down the wrapper - for (auto &loop : entityLoops) { - if (loop.sound) { - loop.sound->Stop(); - } - loop = {false, nullptr, -1, -1}; + for ( EntityMultiLoop& loop : entityLoops ) { + loop.StopAll(); } StopMusic(); @@ -193,22 +244,29 @@ namespace Audio { return; } - for (int i = 0; i < MAX_GENTITIES; i++) { - 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}; - - } 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}; - - AddEntityLoopingSound(i, newSfx); + 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(); + + int newSfx = loop.newSfx; + bool persistent = loop.persistent; + loop = { false, false, nullptr, -1, -1 }; + + AddEntityLoopingSound( i, newSfx, persistent ); + } } } @@ -219,26 +277,30 @@ 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, 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; } } } - void BeginRegistration() { + void BeginRegistration( const int playerNum ) { if (not initialized) { return; } + playerClientNum = playerNum; + BeginSampleRegistration(); } @@ -259,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; @@ -277,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) { @@ -285,23 +351,25 @@ 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) { + void AddEntityLoopingSound(int entityNum, sfxHandle_t sfx, bool persistent) { if (not initialized or not Sample::IsValidHandle(sfx) or not IsValidEntity(entityNum)) { 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) { 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; + 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; @@ -322,9 +390,7 @@ namespace Audio { return; } - if (entityLoops[entityNum].sound) { - entityLoops[entityNum].addedThisFrame = false; - } + entityLoops[entityNum].ClearLoopingSounds(); } void StartMusic(Str::StringRef leadingSound, Str::StringRef loopSound) { @@ -343,8 +409,8 @@ namespace Audio { StopMusic(); music = std::make_shared(loopingSample, leadingSample); - music->SetVolumeModifier(musicVolume); - AddSound(GetLocalEmitter(), music, 1); + music->volumeModifier = &musicVolume; + AddSound( GetLocalEmitter(), music, ANY ); } void StopMusic() { @@ -375,13 +441,13 @@ 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 ); } } - 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/Audio.h b/src/engine/audio/Audio.h index cbd30c989a..cce810af9b 100644 --- a/src/engine/audio/Audio.h +++ b/src/engine/audio/Audio.h @@ -43,14 +43,14 @@ namespace Audio { void Shutdown(); void Update(); - void BeginRegistration(); + void BeginRegistration( const int playerNum ); sfxHandle_t RegisterSFX(Str::StringRef filename); void EndRegistration(); 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/audio/AudioPrivate.h b/src/engine/audio/AudioPrivate.h index 0bbde3377b..6ccc1665a4 100644 --- a/src/engine/audio/AudioPrivate.h +++ b/src/engine/audio/AudioPrivate.h @@ -63,6 +63,23 @@ 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; + + 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 e388545f87..6c3302d2ff 100644 --- a/src/engine/audio/Emitter.cpp +++ b/src/engine/audio/Emitter.cpp @@ -31,18 +31,33 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AudioPrivate.h" namespace Audio { + entityData_t entities[MAX_GENTITIES]; + static int listenerEntity = -1; + + 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]; + } - // Structures to keep the state of entities we were given - struct entityData_t { - Vec3 position; - Vec3 velocity; - float occlusion; + void Shutdown() { + for ( std::shared_ptr& emitter : emitters ) { + if ( emitter ) { + emitter = nullptr; + } + } + } }; - 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]; + 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 +115,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 +137,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 +180,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) { @@ -261,7 +272,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 +289,7 @@ namespace Audio { } void EntityEmitter::UpdateSound(Sound& sound) { - AL::Source& source = sound.GetSource(); + AL::Source& source = *sound.source; if (entityNum == listenerEntity) { MakeLocal(source); @@ -288,11 +299,15 @@ 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); } + Vec3 EntityEmitter::GetPosition() const { + return entities[entityNum].position; + } + // Implementation of PositionEmitter PositionEmitter::PositionEmitter(Vec3 position){ @@ -306,13 +321,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,11 +349,15 @@ namespace Audio { } void LocalEmitter::InternalSetupSound(Sound& sound) { - AL::Source& source = sound.GetSource(); + AL::Source& source = *sound.source; 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 a474d7479f..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() { @@ -85,18 +83,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; } @@ -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->SetEmitter(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), @@ -188,40 +221,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 +230,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 +262,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 +284,7 @@ namespace Audio { void LoopingSound::FadeOutAndDie() { fadingOut = true; - SetSoundGain(0.0f); + soundGain = 0.0f; } void LoopingSound::SetupSource(AL::Source& source) { @@ -298,23 +293,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 +330,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); }; } diff --git a/src/engine/client/cg_api.h b/src/engine/client/cg_api.h index ff034d5fa1..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 @@ -80,6 +82,22 @@ 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, +}; + +// "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 87178ae8bc..6821a9595b 100644 --- a/src/engine/client/cg_msgdef.h +++ b/src/engine/client/cg_msgdef.h @@ -127,16 +127,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, @@ -162,7 +159,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, @@ -173,7 +169,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, @@ -186,9 +181,7 @@ 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, CG_R_BUILDSKELETON, CG_R_BONEINDEX, @@ -239,11 +232,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, @@ -271,17 +260,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> >; @@ -302,7 +281,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>; @@ -311,7 +290,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>; } @@ -321,11 +300,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< @@ -350,10 +324,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, @@ -361,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 @@ -410,8 +376,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 AddAdditiveLightToSceneMsg = IPC::Message, std::array, float, float, float, float>; + 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>; @@ -464,8 +429,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>, @@ -540,7 +505,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> @@ -570,7 +535,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 e9ece77b44..abb50789aa 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->netType), 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(); } } @@ -974,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); @@ -1046,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() @@ -1107,17 +1073,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, @@ -1190,30 +1145,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); @@ -1248,12 +1185,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)); @@ -1297,12 +1228,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, @@ -1318,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()); @@ -1482,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; @@ -1584,8 +1500,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; @@ -1639,8 +1555,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; @@ -1689,14 +1605,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 shader, int flags) { - re.AddLightToScene(point.data(), radius, intensity, r, g, b, shader, 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, int flags) { + re.AddLightToScene(point.data(), radius, r, g, b, flags); }); break; diff --git a/src/engine/client/cl_parse.cpp b/src/engine/client/cl_parse.cpp index bc47793be0..cf91714f19 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/cl_serverlist.cpp b/src/engine/client/cl_serverlist.cpp index 0daf49cb4a..09f99d2e15 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 ]; }; @@ -81,18 +82,11 @@ 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->netType = netadrtype_t::NA_BOT; + server->responseProto = serverResponseProtocol_t::UNKNOWN; } /* @@ -485,29 +479,23 @@ 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 ) { - 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->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->infoString = info; } + 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 +503,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 +511,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 +523,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 +570,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; } @@ -638,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 ].netType = from.type; - cls.localServers[ i ].needpass = 0; - cls.localServers[ i ].gameName[ 0 ] = '\0'; // Arnout + cls.localServers[ i ].responseProto = serverResponseProtocol_t::UNKNOWN; + cls.localServers[ i ].infoString.clear(); Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING ); @@ -851,7 +827,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 +981,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 1bb4fae16f..834a857e56 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -155,6 +155,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; @@ -252,27 +254,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 - netadrtype_t netType; - int clients; - int bots; - int maxClients; - int minPing; - int maxPing; + serverResponseProtocol_t responseProto; 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/engine/framework/CommonVMServices.cpp b/src/engine/framework/CommonVMServices.cpp index 262a2aa642..0bfbf5194c 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/engine/null/NullAudio.cpp b/src/engine/null/NullAudio.cpp index 3b96d95e52..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) { @@ -65,7 +65,7 @@ namespace Audio { } - void AddEntityLoopingSound(int, sfxHandle_t) { + void AddEntityLoopingSound(int, sfxHandle_t, bool) { } void ClearAllLoopingSounds() { diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index ff4fd99d16..c81158aef7 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -79,14 +79,9 @@ 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, float, qhandle_t, int ) { } -void RE_AddLightToSceneQ3A( const vec3_t, float, float, float, float ) { } +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* ) { } @@ -107,10 +102,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; @@ -212,14 +203,12 @@ refexport_t *GetRefAPI( int, refimport_t* ) re.ClearScene = RE_ClearScene; re.AddRefEntityToScene = RE_AddRefEntityToScene; - re.LightForPoint = R_LightForPoint; re.AddPolyToScene = RE_AddPolyToScene; // Ridah re.AddPolysToScene = RE_AddPolysToScene; // done. re.AddLightToScene = RE_AddLightToScene; - re.AddAdditiveLightToScene = RE_AddLightToSceneQ3A; re.RenderScene = RE_RenderScene; @@ -239,7 +228,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/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/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/q_shared.h b/src/engine/qcommon/q_shared.h index 0e7bb81cc7..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 @@ -1940,7 +1933,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/qcommon/qcommon.h b/src/engine/qcommon/qcommon.h index cad6ad230a..c3d56f5157 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 ); //============================================================================ @@ -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 }; // @@ -323,8 +324,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/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/Material.cpp b/src/engine/renderer/Material.cpp index 0909b96ada..4cbbafa879 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, GLShader::MATERIAL ); } -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, GLShader::MATERIAL ); } -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, GLShader::MATERIAL ); } -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, GLShader::MATERIAL ); } -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, GLShader::MATERIAL ); } -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, GLShader::MATERIAL ); } -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; @@ -428,14 +428,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++; @@ -672,7 +671,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++; @@ -764,14 +764,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" ); @@ -1116,7 +1112,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 ); @@ -1199,7 +1195,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; @@ -1219,9 +1215,8 @@ void ProcessMaterialLiquid( Material* material, shaderStage_t* pStage, MaterialS } 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 ) { @@ -1338,9 +1333,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 ); - const bool mayUseVertexOverbright = pStage->type == stageType_t::ST_COLORMAP - && surface->bspSurface && pStage->shaderBinder == BindShaderGeneric3D; + SetLightDeluxeMode( surface, pStage, lightMode, deluxeMode ); const bool vertexLit = lightMode == lightMode_t::VERTEX && pStage->shaderBinder == BindShaderLightMapping; const bool fullbright = lightMode == lightMode_t::FULLBRIGHT && pStage->shaderBinder == BindShaderLightMapping; @@ -1426,8 +1419,8 @@ void MaterialSystem::ProcessStage( MaterialSurface* surface, shaderStage_t* pSta pStage->useMaterialSystem = true; pStage->initialized = true; - AddStage( surface, pStage, stage, mayUseVertexOverbright, vertexLit, fullbright ); - AddStageTextures( surface, shader, pStage, stage, &materials[previousMaterialID] ); + AddStage( surface, pStage, stage, vertexLit, fullbright ); + AddStageTextures( surface, pStage, stage, &materials[previousMaterialID] ); surface->materialIDs[stage] = previousMaterialID; surface->materialPackIDs[stage] = materialPack; @@ -1480,7 +1473,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; @@ -1511,7 +1504,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 0147ac030b..edb3b5f2b6 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -373,9 +373,9 @@ 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 ); + 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 ); @@ -450,15 +450,15 @@ 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 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 BindShaderNONE( Material* ); void BindShaderNOP( Material* ); diff --git a/src/engine/renderer/ShadeCommon.h b/src/engine/renderer/ShadeCommon.h index 7d8f107439..da4cac0fcd 100644 --- a/src/engine/renderer/ShadeCommon.h +++ b/src/engine/renderer/ShadeCommon.h @@ -114,18 +114,23 @@ 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 ( stage->forceVertexLighting ) + { + lightMode = lightMode_t::VERTEX; + deluxeMode = deluxeMode_t::NONE; + } + else 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 +142,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/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index f23055feb4..1acd69611a 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 ); @@ -1731,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 { diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 4130987b3c..781438e1b5 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -2535,13 +2535,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 = {}; @@ -2549,17 +2547,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: @@ -2572,7 +2560,6 @@ static colorModulation_t ColorModulateColorGen( if ( useMapLightFactor ) { - DAEMON_ASSERT_EQ( vertexOverbright, false ); colorModulation.lightFactor = tr.mapLightFactor; } @@ -2605,7 +2592,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( " @@ -2613,12 +2599,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; @@ -2636,7 +2621,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( " @@ -2644,7 +2628,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, @@ -2652,7 +2636,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, @@ -2670,8 +2653,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 ); @@ -2683,16 +2664,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/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; 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/glsl_source/computeLight_fp.glsl b/src/engine/renderer/glsl_source/computeLight_fp.glsl index f3c23bf9e9..34c59389f0 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 = (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((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; ambientColor *= lightFactor; lightColor *= lightFactor; + lightDir = normalize(scaledLightDir); } #endif diff --git a/src/engine/renderer/glsl_source/generic_fp.glsl b/src/engine/renderer/glsl_source/generic_fp.glsl index 67e7dabefa..77f0e0ea57 100644 --- a/src/engine/renderer/glsl_source/generic_fp.glsl +++ b/src/engine/renderer/glsl_source/generic_fp.glsl @@ -59,6 +59,8 @@ void main() vec4 color = texture2D(u_ColorMap, var_TexCoords); + color *= var_Color; + if( abs(color.a + u_AlphaThreshold) <= 1.0 ) { discard; @@ -77,8 +79,6 @@ void main() // fade curve will be different depending on the distance to the viewer and znear/zfar color.a *= smoothstep(gl_FragCoord.z, fadeDepth, depth); #endif - - color *= var_Color; SHADER_PROFILER_SET( color ) 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 e37d094bc1..f1921b96c6 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 ) { @@ -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 *= 1.0f + tr.lightGridAverageCosine; + float total1Norm = totalColor.Red() + totalColor.Green() + totalColor.Blue(); + float directed1Norm = 3.0f * VectorLength( lightDir ); + 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; + VectorNormalize( lightDir ); VectorNegate( lightDir, lightDir ); @@ -2830,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; } @@ -2841,7 +2846,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 ) { @@ -3405,18 +3410,18 @@ const RenderCommand *GradientPicCommand::ExecuteSelf( ) const RB_SetupLights ============= */ -const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const +const RenderCommand *SetupLightsCommand::ExecuteSelf() const { - int numLights; GLenum bufferTarget = glConfig.uniformBufferObjectAvailable ? GL_UNIFORM_BUFFER : GL_PIXEL_UNPACK_BUFFER; GLIMP_LOGCOMMENT( "--- SetupLightsCommand::ExecuteSelf ---" ); - 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 ); @@ -3425,20 +3430,19 @@ const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const VectorCopy( light->origin, buffer[i].center ); buffer[i].radius = light->radius; - VectorScale( light->color, 4.0f * light->scale, buffer[i].color ); + VectorCopy( light->color, buffer[i].color ); + buffer[i].type = Util::ordinal( light->rlType ); switch( light->rlType ) { - case refLightType_t::RL_PROJ: - VectorCopy( light->projTarget, - buffer[i].direction ); - buffer[i].angle = cosf( atan2f( VectorLength( light->projUp), VectorLength( light->projTarget ) ) ); - break; - case refLightType_t::RL_DIRECTIONAL: - VectorCopy( light->projTarget, - buffer[i].direction ); - break; - default: - break; + case refLightType_t::RL_PROJ: + VectorCopy( light->projTarget, buffer[i].direction ); + buffer[i].angle = cosf( atan2f( VectorLength( light->projUp), VectorLength( light->projTarget ) ) ); + break; + case refLightType_t::RL_DIRECTIONAL: + VectorCopy( light->projTarget, buffer[i].direction ); + break; + default: + break; } } diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index f302c9e581..29cb4bb626 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 ) { @@ -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,26 @@ 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). 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. + // 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 +3683,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; } } } @@ -4017,29 +4013,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 eb916d36c3..8d496d1b47 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -187,12 +187,11 @@ 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.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 ); @@ -229,7 +228,6 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul Cvar::Range> r_forceAmbient( "r_forceAmbient", "Minimal light amount in lightGrid; -1 to use map value", Cvar::CHEAT, -1.0f, -1.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 +1191,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 ); @@ -1353,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(); @@ -1663,10 +1675,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p re.AddPolyToScene = RE_AddPolyToSceneET; re.AddPolysToScene = RE_AddPolysToScene; - re.LightForPoint = R_LightForPoint; - re.AddLightToScene = RE_AddDynamicLightToSceneET; - re.AddAdditiveLightToScene = RE_AddDynamicLightToSceneQ3A; + re.AddLightToScene = RE_AddDynamicLightToScene; re.RenderScene = RE_RenderScene; @@ -1687,7 +1697,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_light.cpp b/src/engine/renderer/tr_light.cpp index 37130f697f..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,99 +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; -} - -/* -================= -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() ) + if ( totalFactor > 0.0f ) { - ambientLight[ 0 ] = r_forceAmbient.Get(); - ambientLight[ 1 ] = r_forceAmbient.Get(); - ambientLight[ 2 ] = r_forceAmbient.Get(); + VectorScale( lightDir, 1.0f / totalFactor, lightDir ); + VectorScale( lightColor, 1.0f / totalFactor, lightColor ); } - - return true; } - diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index e3faea0632..68328fde7d 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -417,9 +417,7 @@ enum class ssaoMode { refLightType_t rlType; vec3_t origin; - vec3_t color; // range from 0.0 to 1.0, should be color normalized - - float scale; // r_lightScale if not set + vec3_t color; // should be color normalized // omni-directional light specific float radius; @@ -964,21 +962,16 @@ 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 ) ) - 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 ) }; using floatProcessor_t = float(*)(float); @@ -1045,6 +1038,8 @@ enum bool highQuality; bool forceHighQuality; + bool forceVertexLighting; + bool hasDepthFade; // for soft particles float depthFadeValue; @@ -1182,6 +1177,8 @@ enum int autoSpriteMode; bool autoSpriteWarned = false; + bool forceLightMap; + bool shaderRemapWarned; uint8_t numDeforms; @@ -1693,7 +1690,7 @@ enum struct bspGridPoint1_t { byte color[3]; - byte ambientPart; + byte unused; }; struct bspGridPoint2_t { @@ -2501,6 +2498,7 @@ enum vec3_t ambientLight; bool ambientLightSet = false; + float lightGridAverageCosine; image_t *lightGrid1Image; image_t *lightGrid2Image; @@ -2637,7 +2635,6 @@ enum 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::Cvar r_realtimeLighting; @@ -2674,7 +2671,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; @@ -2968,7 +2965,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(); @@ -3268,10 +3264,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 ); - int R_LightForPoint( vec3_t point, 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 ); /* ============================================================ @@ -3335,11 +3329,10 @@ void GLimp_LogComment_( std::string comment ); 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 r, float g, float b, int flags ); + void R_AddFogBrushSurfaces(); - 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_RenderScene( const refdef_t *fd ); qhandle_t RE_RegisterVisTest(); diff --git a/src/engine/renderer/tr_mesh.cpp b/src/engine/renderer/tr_mesh.cpp index e4e5975f91..be3eafda5d 100644 --- a/src/engine/renderer/tr_mesh.cpp +++ b/src/engine/renderer/tr_mesh.cpp @@ -255,21 +255,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_scene.cpp b/src/engine/renderer/tr_scene.cpp index 981f1872be..f9152cd67f 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -302,10 +302,8 @@ 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 r, float g, float b, int /*flags*/) { - refLight_t *light; - if ( !glConfig.realtimeLighting || !r_drawDynamicLights.Get() ) { return; @@ -316,23 +314,17 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit return; } - if ( flags & REF_INVERSE_DLIGHT ) - { - Log::Warn( "REF_INVERSE_DLIGHT not implemtented" ); - return; - } - if ( r_numLights >= MAX_REF_LIGHTS ) { return; } - if ( intensity <= 0 || radius <= 0 ) + if ( radius <= 0 ) { return; } - light = &backEndData[ tr.smpFrame ]->lights[ r_numLights++ ]; + refLight_t *light = &backEndData[ tr.smpFrame ]->lights[ r_numLights++ ]; light->rlType = refLightType_t::RL_OMNI; VectorCopy( org, light->origin ); @@ -348,13 +340,6 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit { convertFromSRGB( light->color ); } - - light->scale = intensity; -} - -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 ); } 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 c7a0e55b18..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(); @@ -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 ); @@ -331,7 +326,7 @@ static void GLSL_InitGPUShadersOrError() gl_contrastShader->MarkProgramForBuilding(); } - + // portal process effect gl_shaderManager.LoadShader( gl_portalShader ); @@ -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 ); @@ -794,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 ); @@ -844,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 ); @@ -899,9 +900,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 ); @@ -999,7 +999,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 ); @@ -1072,7 +1072,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 ); @@ -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(); @@ -1499,7 +1499,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 ); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index ff10f06b6c..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 ); @@ -5446,6 +5438,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; } @@ -6022,6 +6022,14 @@ static shader_t *FinishShader() numStages = MAX_SHADER_STAGES; GroupActiveStages(); + if ( shader.forceLightMap && numStages == 1 ) { + shaderStage_t* pStage = &stages[0]; + + 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++ ) { @@ -6239,9 +6247,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 ); @@ -6323,6 +6328,11 @@ shader_t *R_FindShader( const char *name, 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 ); @@ -6672,8 +6682,10 @@ class ListShadersCmd : public Cmd::StaticCmd shader->registerFlags & RSF_2D ? '2' : '_', shader->registerFlags & RSF_NOMIP ? 'N' : '_', shader->registerFlags & RSF_FITSCREEN ? 'F' : '_', + 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 ) ) diff --git a/src/engine/renderer/tr_types.h b/src/engine/renderer/tr_types.h index 9052d7ddfd..eb0b068c56 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 @@ -57,36 +57,20 @@ 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 #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_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 -#define RDF_NOSHADOWS ( 1 << 1 ) // force renderer to use faster lighting only path -#define RDF_HYPERSPACE ( 1 << 2 ) // 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_HYPERSPACE ( 1 << 1 ) // teleportation effect // 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 @@ -96,13 +80,15 @@ using glIndex_t = unsigned int; // "[implicit only]" means the flag only has effect if there is no shader text and the // shader was auto-generated from an image. -// TODO(0.56): drop RSF_LIGHT_ATTENUATION, RSF_NOLIGHTSCALE 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 ), @@ -110,14 +96,14 @@ enum RegisterShaderFlags_t { // mip images to the screen size when they are larger than the screen RSF_FITSCREEN = BIT( 3 ), - // nothing - RSF_LIGHT_ATTENUATION = BIT( 4 ), - - // nothing - RSF_NOLIGHTSCALE = BIT( 5 ), + // used to make particles/trails work with the lightGrid in GLSL + RSF_FORCE_LIGHTMAP = BIT( 5 ), // 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 @@ -190,8 +176,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; @@ -266,15 +250,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 { @@ -288,30 +263,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") diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 25a25a4925..514c9f822b 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -75,19 +75,13 @@ 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 - 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; @@ -389,7 +383,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/sg_api.h b/src/engine/server/sg_api.h index 7ba16db755..f2dbf04566 100644 --- a/src/engine/server/sg_api.h +++ b/src/engine/server/sg_api.h @@ -25,25 +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_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) -#define SVF_NOTSINGLECLIENT 0x00002000 -#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 +// 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 @@ -52,7 +54,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: diff --git a/src/engine/server/sg_msgdef.h b/src/engine/server/sg_msgdef.h index 73b2239a37..6b3faa8624 100644 --- a/src/engine/server/sg_msgdef.h +++ b/src/engine/server/sg_msgdef.h @@ -40,11 +40,11 @@ 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, G_GET_TIME_STRING, + G_GET_PINGS, BOT_ALLOCATE_CLIENT, BOT_FREE_CLIENT, @@ -82,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 @@ -102,6 +98,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_ccmds.cpp b/src/engine/server/sv_ccmds.cpp index ec5fcfcad9..5f066e1fd1 100644 --- a/src/engine/server/sv_ccmds.cpp +++ b/src/engine/server/sv_ccmds.cpp @@ -328,7 +328,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_client.cpp b/src/engine/server/sv_client.cpp index b7441f423e..3b6f336754 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 ); diff --git a/src/engine/server/sv_main.cpp b/src/engine/server/sv_main.cpp index 14fdeec358..293acb8c8f 100644 --- a/src/engine/server/sv_main.cpp +++ b/src/engine/server/sv_main.cpp @@ -494,7 +494,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 ); } } @@ -596,6 +596,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 ) ); } @@ -1208,10 +1212,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 257370beed..be4eebf2be 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.Get() || 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.Get()) * 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; } @@ -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; } @@ -520,13 +515,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]; @@ -564,6 +552,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.Get(); + 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/engine/server/sv_snapshot.cpp b/src/engine/server/sv_snapshot.cpp index 6408ace628..a68baad5e1 100644 --- a/src/engine/server/sv_snapshot.cpp +++ b/src/engine/server/sv_snapshot.cpp @@ -343,7 +343,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 */ ) @@ -381,7 +381,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++ ) @@ -464,6 +464,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 ) @@ -639,7 +644,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; @@ -692,7 +697,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 @@ -722,7 +727,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 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 ); diff --git a/src/shared/CommonProxies.cpp b/src/shared/CommonProxies.cpp index 26dba204f6..24be8c403b 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); Cvar::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); diff --git a/src/shared/client/cg_api.cpp b/src/shared/client/cg_api.cpp index 269b2fa976..961583ab6a 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); @@ -187,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); @@ -195,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 ) @@ -257,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() @@ -291,16 +252,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); @@ -390,18 +341,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); -} - -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); + VectorCopy( origin, myorg ); + cmdBuffer.SendMsg(myorg, radius, r * intensity, g * intensity, b * intensity, flags); } void trap_R_RenderScene( const refdef_t *fd ) @@ -459,16 +403,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 ) @@ -480,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; @@ -688,11 +610,10 @@ int trap_LAN_GetServerCount( int source ) return count; } -void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ) +// 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 ) { - 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 de0d2f3f47..518a76d3ea 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, @@ -54,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 ); @@ -69,8 +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_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); +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(); @@ -101,17 +99,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 ); int trap_R_BlendSkeleton( refSkeleton_t *skel, const refSkeleton_t *blend, float frac ); @@ -119,7 +113,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, @@ -130,7 +123,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 ); @@ -144,7 +137,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 diff --git a/src/shared/server/sg_api.cpp b/src/shared/server/sg_api.cpp index faf17a9af0..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; @@ -144,6 +135,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..80ef7cc46e 100644 --- a/src/shared/server/sg_api.h +++ b/src/shared/server/sg_api.h @@ -47,11 +47,11 @@ 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 ); 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