diff --git a/src/actor.h b/src/actor.h index aafb5cec97..2059b83095 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1171,6 +1171,7 @@ public: uint8_t smokecounter; uint8_t FloatBobPhase; + double FloatBobStrength; uint8_t FriendPlayer; // [RH] Player # + 1 this friendly monster works for (so 0 is no player, 1 is player 0, etc) PalEntry BloodColor; uint32_t BloodTranslation; diff --git a/src/g_statusbar/shared_sbar.cpp b/src/g_statusbar/shared_sbar.cpp index 2710c5156d..30bc5f1df1 100644 --- a/src/g_statusbar/shared_sbar.cpp +++ b/src/g_statusbar/shared_sbar.cpp @@ -1079,7 +1079,7 @@ bool DBaseStatusBar::MustDrawLog(EHudState state) { IFVIRTUAL(DBaseStatusBar, MustDrawLog) { - VMValue params[] = { (DObject*)this }; + VMValue params[] = { (DObject*)this, int(state) }; int rv; VMReturn ret(&rv); VMCall(func, params, countof(params), &ret, 1); diff --git a/src/gl/dynlights/gl_shadowmap.cpp b/src/gl/dynlights/gl_shadowmap.cpp index 609e09e641..0f493b7517 100644 --- a/src/gl/dynlights/gl_shadowmap.cpp +++ b/src/gl/dynlights/gl_shadowmap.cpp @@ -33,6 +33,7 @@ #include "gl/shaders/gl_shadowmapshader.h" #include "r_state.h" #include "g_levellocals.h" +#include "stats.h" /* The 1D shadow maps are stored in a 1024x1024 texture as float depth values (R32F). @@ -67,11 +68,48 @@ as on the CPU, except everything uses indexes as pointers are not allowed in GLSL. */ +namespace +{ + cycle_t UpdateCycles; + int LightsProcessed; + int LightsShadowmapped; +} + +ADD_STAT(shadowmap) +{ + FString out; + out.Format("upload=%04.2f ms lights=%d shadowmapped=%d", UpdateCycles.TimeMS(), LightsProcessed, LightsShadowmapped); + return out; +} + +CUSTOM_CVAR(Int, gl_shadowmap_quality, 128, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + switch (self) + { + case 32: + case 64: + case 128: + case 256: + case 512: + case 1024: + break; + default: + self = 128; + break; + } +} + void FShadowMap::Update() { + UpdateCycles.Reset(); + LightsProcessed = 0; + LightsShadowmapped = 0; + if (!IsEnabled()) return; + UpdateCycles.Clock(); + UploadAABBTree(); UploadLights(); @@ -81,11 +119,12 @@ void FShadowMap::Update() GLRenderer->mBuffers->BindShadowMapFB(); GLRenderer->mShadowMapShader->Bind(); + GLRenderer->mShadowMapShader->ShadowmapQuality.Set(gl_shadowmap_quality); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, mLightList); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, mNodesBuffer); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, mLinesBuffer); - glViewport(0, 0, 1024, 1024); + glViewport(0, 0, gl_shadowmap_quality, 1024); GLRenderer->RenderScreenQuad(); const auto &viewport = GLRenderer->mScreenViewport; @@ -98,6 +137,8 @@ void FShadowMap::Update() GLRenderer->mBuffers->BindShadowMapTexture(16); FGLDebug::PopGroup(); + + UpdateCycles.Unclock(); } bool FShadowMap::ShadowTest(ADynamicLight *light, const DVector3 &pos) @@ -133,8 +174,11 @@ void FShadowMap::UploadLights() TThinkerIterator it(STAT_DLIGHT); while (auto light = it.Next()) { + LightsProcessed++; if (light->shadowmapped) { + LightsShadowmapped++; + mLightToShadowmap[light] = lightindex >> 2; mLights[lightindex] = light->X(); diff --git a/src/gl/renderer/gl_renderbuffers.cpp b/src/gl/renderer/gl_renderbuffers.cpp index 74dc36e729..d60045f3e3 100644 --- a/src/gl/renderer/gl_renderbuffers.cpp +++ b/src/gl/renderer/gl_renderbuffers.cpp @@ -81,6 +81,7 @@ FGLRenderBuffers::~FGLRenderBuffers() ClearBloom(); ClearExposureLevels(); ClearAmbientOcclusion(); + ClearShadowMap(); } void FGLRenderBuffers::ClearScene() @@ -759,18 +760,27 @@ void FGLRenderBuffers::BindShadowMapTexture(int texunit) glBindTexture(GL_TEXTURE_2D, mShadowMapTexture); } +void FGLRenderBuffers::ClearShadowMap() +{ + DeleteFrameBuffer(mShadowMapFB); + DeleteTexture(mShadowMapTexture); + mCurrentShadowMapSize = 0; +} + void FGLRenderBuffers::CreateShadowMap() { - if (mShadowMapTexture != 0) + if (mShadowMapTexture != 0 && gl_shadowmap_quality == mCurrentShadowMapSize) return; + ClearShadowMap(); + GLint activeTex, textureBinding, frameBufferBinding; glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTex); glActiveTexture(GL_TEXTURE0); glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &frameBufferBinding); - mShadowMapTexture = Create2DTexture("ShadowMap", GL_R32F, 1024, 1024); + mShadowMapTexture = Create2DTexture("ShadowMap", GL_R32F, gl_shadowmap_quality, 1024); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -781,6 +791,8 @@ void FGLRenderBuffers::CreateShadowMap() glBindTexture(GL_TEXTURE_2D, textureBinding); glActiveTexture(activeTex); glBindFramebuffer(GL_FRAMEBUFFER, frameBufferBinding); + + mCurrentShadowMapSize = gl_shadowmap_quality; } //========================================================================== diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index 41202b499f..1c8ea1690e 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -89,6 +89,7 @@ private: void ClearBloom(); void ClearExposureLevels(); void ClearAmbientOcclusion(); + void ClearShadowMap(); void CreateScene(int width, int height, int samples, bool needsSceneTextures); void CreatePipeline(int width, int height); void CreateBloom(int width, int height); @@ -142,6 +143,7 @@ private: // Shadow map texture GLuint mShadowMapTexture = 0; GLuint mShadowMapFB = 0; + int mCurrentShadowMapSize = 0; static bool FailedCreate; static bool BuffersActive; diff --git a/src/gl/shaders/gl_shadowmapshader.cpp b/src/gl/shaders/gl_shadowmapshader.cpp index 674d0a04f2..8b81d386ae 100644 --- a/src/gl/shaders/gl_shadowmapshader.cpp +++ b/src/gl/shaders/gl_shadowmapshader.cpp @@ -40,6 +40,7 @@ void FShadowMapShader::Bind() mShader.SetFragDataLocation(0, "FragColor"); mShader.Link("shaders/glsl/shadowmap"); mShader.SetAttribLocation(0, "PositionInProjection"); + ShadowmapQuality.Init(mShader, "ShadowmapQuality"); } mShader.Bind(); } diff --git a/src/gl/shaders/gl_shadowmapshader.h b/src/gl/shaders/gl_shadowmapshader.h index 7d01f9974a..309dccb525 100644 --- a/src/gl/shaders/gl_shadowmapshader.h +++ b/src/gl/shaders/gl_shadowmapshader.h @@ -8,6 +8,8 @@ class FShadowMapShader public: void Bind(); + FBufferedUniform1f ShadowmapQuality; + private: FShaderProgram mShader; }; diff --git a/src/gl/system/gl_cvars.h b/src/gl/system/gl_cvars.h index b7122b01c3..51ab642de7 100644 --- a/src/gl/system/gl_cvars.h +++ b/src/gl/system/gl_cvars.h @@ -27,6 +27,7 @@ EXTERN_CVAR (Bool, gl_lights_checkside); EXTERN_CVAR (Bool, gl_light_sprites); EXTERN_CVAR (Bool, gl_light_particles); EXTERN_CVAR (Bool, gl_light_shadowmap); +EXTERN_CVAR (Int, gl_shadowmap_quality); EXTERN_CVAR(Int, gl_fogmode) EXTERN_CVAR(Int, gl_lightmode) diff --git a/src/gl/system/gl_debug.cpp b/src/gl/system/gl_debug.cpp index 22bbf597b0..1fca45f0ca 100644 --- a/src/gl/system/gl_debug.cpp +++ b/src/gl/system/gl_debug.cpp @@ -29,8 +29,10 @@ #include "gl/system/gl_system.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_debug.h" +#include "stats.h" #include #include +#include #ifndef _MSC_VER #include @@ -46,6 +48,20 @@ CUSTOM_CVAR(Int, gl_debug_level, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOIN CVAR(Bool, gl_debug_breakpoint, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +namespace +{ + bool gpuStatActive = false; + bool keepGpuStatActive = false; + std::vector> timeElapsedQueries; + FString gpuStatOutput; +} + +ADD_STAT(gpu) +{ + keepGpuStatActive = true; + return gpuStatOutput; +} + //----------------------------------------------------------------------------- // // Updates OpenGL debugging state @@ -54,6 +70,22 @@ CVAR(Bool, gl_debug_breakpoint, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); void FGLDebug::Update() { + gpuStatOutput = ""; + for (auto &query : timeElapsedQueries) + { + GLuint timeElapsed = 0; + glGetQueryObjectuiv(query.second, GL_QUERY_RESULT, &timeElapsed); + glDeleteQueries(1, &query.second); + + FString out; + out.Format("%s=%04.2f ms\n", query.first.GetChars(), timeElapsed / 1000000.0f); + gpuStatOutput += out; + } + timeElapsedQueries.clear(); + + gpuStatActive = keepGpuStatActive; + keepGpuStatActive = false; + if (!HasDebugApi()) return; @@ -98,6 +130,14 @@ void FGLDebug::PushGroup(const FString &name) { glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, (GLsizei)name.Len(), name.GetChars()); } + + if (gpuStatActive) + { + GLuint queryHandle = 0; + glGenQueries(1, &queryHandle); + glBeginQuery(GL_TIME_ELAPSED, queryHandle); + timeElapsedQueries.push_back({ name, queryHandle }); + } } void FGLDebug::PopGroup() @@ -106,6 +146,11 @@ void FGLDebug::PopGroup() { glPopDebugGroup(); } + + if (gpuStatActive) + { + glEndQuery(GL_TIME_ELAPSED); + } } //----------------------------------------------------------------------------- diff --git a/src/namedef.h b/src/namedef.h index a22a5de5f0..c2c23f497a 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -503,6 +503,7 @@ xx(Scale) xx(ScaleX) xx(ScaleY) xx(Floatbobphase) +xx(Floatbobstrength) xx(Target) xx(Master) xx(Tracer) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 13af2837c4..dc4229c5c7 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -282,6 +282,7 @@ DEFINE_FIELD(AActor, Floorclip) DEFINE_FIELD(AActor, DamageType) DEFINE_FIELD(AActor, DamageTypeReceived) DEFINE_FIELD(AActor, FloatBobPhase) +DEFINE_FIELD(AActor, FloatBobStrength) DEFINE_FIELD(AActor, RipperLevel) DEFINE_FIELD(AActor, RipLevelMin) DEFINE_FIELD(AActor, RipLevelMax) @@ -443,6 +444,7 @@ void AActor::Serialize(FSerializer &arc) ("inventory", Inventory) A("inventoryid", InventoryID) A("floatbobphase", FloatBobPhase) + A("floatbobstrength", FloatBobStrength) A("translation", Translation) A("bloodcolor", BloodColor) A("bloodtranslation", BloodTranslation) @@ -7991,7 +7993,7 @@ double AActor::GetBobOffset(double ticfrac) const { return 0; } - return BobSin(FloatBobPhase + level.maptime + ticfrac); + return BobSin(FloatBobPhase + level.maptime + ticfrac) * FloatBobStrength; } DEFINE_ACTION_FUNCTION(AActor, GetBobOffset) diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 170fa11483..d10f505173 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -653,6 +653,15 @@ DEFINE_PROPERTY(floatbobphase, I, Actor) defaults->FloatBobPhase = id; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(floatbobstrength, F, Actor) +{ + PROP_DOUBLE_PARM(id, 0); + defaults->FloatBobStrength = id; +} + //========================================================================== // //========================================================================== diff --git a/src/stats.cpp b/src/stats.cpp index d0d5d2f022..d4c1d37dfa 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -89,8 +89,10 @@ void FStat::ToggleStat () void FStat::PrintStat () { + int textScale = active_con_scale(); + int fontheight = ConFont->GetHeight() + 1; - int y = SCREENHEIGHT; + int y = SCREENHEIGHT / textScale; int count = 0; for (FStat *stat = FirstStat; stat != NULL; stat = stat->m_Next) @@ -107,7 +109,10 @@ void FStat::PrintStat () // Count number of linefeeds but ignore terminating ones. if (stattext[i] == '\n') y -= fontheight; } - screen->DrawText(ConFont, CR_GREEN, 5, y, stattext, TAG_DONE); + screen->DrawText(ConFont, CR_GREEN, 5 / textScale, y, stattext, + DTA_VirtualWidth, screen->GetWidth() / textScale, + DTA_VirtualHeight, screen->GetHeight() / textScale, + DTA_KeepRatio, true, TAG_DONE); count++; } } diff --git a/wadsrc/static/shaders/glsl/shadowmap.fp b/wadsrc/static/shaders/glsl/shadowmap.fp index 194da954ef..47696aa74d 100644 --- a/wadsrc/static/shaders/glsl/shadowmap.fp +++ b/wadsrc/static/shaders/glsl/shadowmap.fp @@ -2,6 +2,11 @@ in vec2 TexCoord; out vec4 FragColor; +// This constant must match the same constant in gl_shadowmap.h +// #define ShadowmapQuality 1024 +//#define ShadowmapQuality 128 +uniform float ShadowmapQuality; + struct GPUNode { vec2 aabb_min; @@ -140,12 +145,12 @@ void main() if (radius > 0.0) { vec2 pixelpos; - switch (int(gl_FragCoord.x) / 256) + switch (int(gl_FragCoord.x) / int(ShadowmapQuality/4.0)) { - case 0: pixelpos = vec2((gl_FragCoord.x - 128.0) / 128.0, 1.0); break; - case 1: pixelpos = vec2(1.0, (gl_FragCoord.x - 384.0) / 128.0); break; - case 2: pixelpos = vec2(-(gl_FragCoord.x - 640.0) / 128.0, -1.0); break; - case 3: pixelpos = vec2(-1.0, -(gl_FragCoord.x - 896.0) / 128.0); break; + case 0: pixelpos = vec2((gl_FragCoord.x - float(ShadowmapQuality/8.0)) / float(ShadowmapQuality/8.0), 1.0); break; + case 1: pixelpos = vec2(1.0, (gl_FragCoord.x - float(ShadowmapQuality/4.0 + ShadowmapQuality/8.0)) / float(ShadowmapQuality/8.0)); break; + case 2: pixelpos = vec2(-(gl_FragCoord.x - float(ShadowmapQuality/2.0 + ShadowmapQuality/8.0)) / float(ShadowmapQuality/8.0), -1.0); break; + case 3: pixelpos = vec2(-1.0, -(gl_FragCoord.x - float(ShadowmapQuality*3.0/4.0 + ShadowmapQuality/8.0)) / float(ShadowmapQuality/8.0)); break; } pixelpos = lightpos + pixelpos * radius; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 49d2944650..3195f18cf0 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -131,6 +131,7 @@ class Actor : Thinker native native name DamageType; native name DamageTypeReceived; native uint8 FloatBobPhase; + native double FloatBobStrength; native int RipperLevel; native int RipLevelMin; native int RipLevelMax; @@ -325,6 +326,7 @@ class Actor : Thinker native BounceCount -1; FloatSpeed 4; FloatBobPhase -1; // randomly initialize by default + FloatBobStrength 1.0; Gravity 1; Friction 1; DamageFactor 1.0; // damage multiplier as target of damage.