diff --git a/src/common/rendering/hwrenderer/data/hw_meshbuilder.h b/src/common/rendering/hwrenderer/data/hw_meshbuilder.h index c111caf3e..d66453506 100644 --- a/src/common/rendering/hwrenderer/data/hw_meshbuilder.h +++ b/src/common/rendering/hwrenderer/data/hw_meshbuilder.h @@ -80,6 +80,7 @@ public: void SetTextureMatrix(const VSMatrix& matrix) override { mTextureMatrix = matrix; } int UploadLights(const FDynLightData& lightdata) override { return -1; } int UploadBones(const TArray& bones) override { return -1; } + int UploadFogballs(const TArray& balls) override { return -1; } // Draw commands void Draw(int dt, int index, int count, bool apply = true) override; diff --git a/src/common/rendering/hwrenderer/data/hw_renderstate.h b/src/common/rendering/hwrenderer/data/hw_renderstate.h index bd217d104..af4a8826a 100644 --- a/src/common/rendering/hwrenderer/data/hw_renderstate.h +++ b/src/common/rendering/hwrenderer/data/hw_renderstate.h @@ -224,6 +224,14 @@ struct StreamData float padding3; }; +struct Fogball +{ + FVector3 Position; + float Radius; + FVector3 Color; + float Fog; +}; + class FRenderState { protected: @@ -236,6 +244,7 @@ protected: int mLightIndex; int mBoneIndexBase; + int mFogballIndex; int mSpecialEffect; int mTextureMode; int mTextureClamp; @@ -290,6 +299,7 @@ public: mSpecialEffect = EFF_NONE; mLightIndex = -1; mBoneIndexBase = -1; + mFogballIndex = -1; mStreamData.uInterpolationFactor = 0; mRenderStyle = DefaultRenderStyle(); mMaterial.Reset(); @@ -578,6 +588,11 @@ public: mBoneIndexBase = index; } + void SetFogballIndex(int index) + { + mFogballIndex = index; + } + void SetRenderStyle(FRenderStyle rs) { mRenderStyle = rs; @@ -750,6 +765,7 @@ public: virtual void SetTextureMatrix(const VSMatrix& matrix) = 0; virtual int UploadLights(const FDynLightData& lightdata) = 0; virtual int UploadBones(const TArray& bones) = 0; + virtual int UploadFogballs(const TArray& balls) = 0; // Draw commands virtual void ClearScreen() = 0; diff --git a/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp b/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp index d2f5fafd4..960894f84 100644 --- a/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp +++ b/src/common/rendering/vulkan/buffers/vk_rsbuffers.cpp @@ -93,6 +93,17 @@ VkRSBuffers::VkRSBuffers(VulkanRenderDevice* fb) .Create(fb->GetDevice()); Bonebuffer.Data = Bonebuffer.SSO->Map(0, Bonebuffer.SSO->size); + + Fogballbuffer.UBO = BufferBuilder() + .Usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .Size(Fogballbuffer.Count * sizeof(Fogball)) + .DebugName("Fogballbuffer.UBO") + .Create(fb->GetDevice()); + + Fogballbuffer.Data = Fogballbuffer.UBO->Map(0, Fogballbuffer.UBO->size); } VkRSBuffers::~VkRSBuffers() @@ -113,6 +124,10 @@ VkRSBuffers::~VkRSBuffers() if (Bonebuffer.SSO) Bonebuffer.SSO->Unmap(); Bonebuffer.SSO.reset(); + + if (Fogballbuffer.UBO) + Fogballbuffer.UBO->Unmap(); + Fogballbuffer.UBO.reset(); } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/common/rendering/vulkan/buffers/vk_rsbuffers.h b/src/common/rendering/vulkan/buffers/vk_rsbuffers.h index df06cac0c..a25f8bb2e 100644 --- a/src/common/rendering/vulkan/buffers/vk_rsbuffers.h +++ b/src/common/rendering/vulkan/buffers/vk_rsbuffers.h @@ -51,6 +51,14 @@ public: void* Data = nullptr; } Bonebuffer; + struct + { + int UploadIndex = 0; + int Count = 1000; + std::unique_ptr UBO; + void* Data = nullptr; + } Fogballbuffer; + std::unique_ptr MatrixBuffer; std::unique_ptr StreamBuffer; }; diff --git a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp index d71411aac..1c168f3b0 100644 --- a/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp +++ b/src/common/rendering/vulkan/descriptorsets/vk_descriptorset.cpp @@ -66,6 +66,7 @@ void VkDescriptorSetManager::Init() .AddBuffer(rsbufferset.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, rsbuffers->StreamBuffer->UBO(), 0, sizeof(StreamUBO)) .AddBuffer(rsbufferset.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, rsbuffers->Lightbuffer.UBO.get(), 0, sizeof(LightBufferUBO)) .AddBuffer(rsbufferset.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, rsbuffers->Bonebuffer.SSO.get()) + .AddBuffer(rsbufferset.get(), 5, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, rsbuffers->Fogballbuffer.UBO.get(), 0, sizeof(Fogball)) .Execute(fb->GetDevice()); RSBufferSet = std::move(rsbufferset); @@ -258,6 +259,7 @@ void VkDescriptorSetManager::CreateRSBufferSetLayout() .AddBinding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) .AddBinding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) .AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT) + .AddBinding(5, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) .DebugName("VkDescriptorSetManager.RSBufferSetLayout") .Create(fb->GetDevice()); } @@ -284,7 +286,7 @@ void VkDescriptorSetManager::CreateFixedSetLayout() void VkDescriptorSetManager::CreateRSBufferPool() { RSBufferDescriptorPool = DescriptorPoolBuilder() - .AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 4) + .AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 5) .AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1) .MaxSets(1) .DebugName("VkDescriptorSetManager.RSBufferDescriptorPool") diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 685e92c3d..595b99b9a 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -134,6 +134,7 @@ std::unique_ptr VkShaderManager::LoadVertShader(FString shadername definesBlock << defines; definesBlock << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n"; definesBlock << "#define MAX_LIGHT_DATA " << std::to_string(MAX_LIGHT_DATA).c_str() << "\n"; + definesBlock << "#define MAX_FOGBALL_DATA " << std::to_string(MAX_FOGBALL_DATA).c_str() << "\n"; #ifdef NPOT_EMULATION definesBlock << "#define NPOT_EMULATION\n"; #endif @@ -171,6 +172,7 @@ std::unique_ptr VkShaderManager::LoadFragShader(FString shadername definesBlock << defines; definesBlock << "\n#define MAX_STREAM_DATA " << std::to_string(MAX_STREAM_DATA).c_str() << "\n"; definesBlock << "#define MAX_LIGHT_DATA " << std::to_string(MAX_LIGHT_DATA).c_str() << "\n"; + definesBlock << "#define MAX_FOGBALL_DATA " << std::to_string(MAX_FOGBALL_DATA).c_str() << "\n"; #ifdef NPOT_EMULATION definesBlock << "#define NPOT_EMULATION\n"; #endif diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index 8ee090ba0..f5e9ff1d7 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -40,12 +40,14 @@ struct LightBufferUBO FVector4 lights[MAX_LIGHT_DATA]; }; +#define MAX_FOGBALL_DATA ((int)(65536 / sizeof(Fogball))) + struct PushConstants { int uDataIndex; // streamdata index int uLightIndex; // dynamic lights int uBoneIndexBase; // bone animation - int padding; + int uFogballIndex; // fog balls }; class VkShaderKey diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index 20502a39d..34c816543 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -283,6 +283,7 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.ShaderKey.FogRadial = (fogset < -1 || fogset > 1); pipelineKey.ShaderKey.SWLightRadial = (gl_fogmode == 2); pipelineKey.ShaderKey.SWLightBanded = false; // gl_bandedswlight; + pipelineKey.ShaderKey.FogBalls = mFogballIndex >= 0; float lightlevel = mStreamData.uLightLevel; if (lightlevel < 0.0) @@ -420,6 +421,7 @@ void VkRenderState::ApplyPushConstants() mPushConstants.uDataIndex = mRSBuffers->StreamBuffer->DataIndex(); mPushConstants.uLightIndex = mLightIndex >= 0 ? (mLightIndex % MAX_LIGHT_DATA) : -1; mPushConstants.uBoneIndexBase = mBoneIndexBase; + mPushConstants.uFogballIndex = mFogballIndex >= 0 ? (mFogballIndex % MAX_FOGBALL_DATA) : -1; mCommandBuffer->pushConstants(fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.NumTextureLayers), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &mPushConstants); } @@ -500,19 +502,21 @@ void VkRenderState::ApplyBufferSets() uint32_t matrixOffset = mRSBuffers->MatrixBuffer->Offset(); uint32_t streamDataOffset = mRSBuffers->StreamBuffer->Offset(); uint32_t lightsOffset = mLightIndex >= 0 ? (uint32_t)(mLightIndex / MAX_LIGHT_DATA) * sizeof(LightBufferUBO) : mLastLightsOffset; - if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || streamDataOffset != mLastStreamDataOffset || lightsOffset != mLastLightsOffset) + uint32_t fogballsOffset = mFogballIndex >= 0 ? (uint32_t)(mFogballIndex / MAX_FOGBALL_DATA) * sizeof(Fogball) : mLastFogballsOffset; + if (mViewpointOffset != mLastViewpointOffset || matrixOffset != mLastMatricesOffset || streamDataOffset != mLastStreamDataOffset || lightsOffset != mLastLightsOffset || fogballsOffset != mLastFogballsOffset) { auto descriptors = fb->GetDescriptorSetManager(); VulkanPipelineLayout* layout = fb->GetRenderPassManager()->GetPipelineLayout(mPipelineKey.NumTextureLayers); - uint32_t offsets[4] = { mViewpointOffset, matrixOffset, streamDataOffset, lightsOffset }; + uint32_t offsets[5] = { mViewpointOffset, matrixOffset, streamDataOffset, lightsOffset, fogballsOffset }; mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptors->GetFixedDescriptorSet()); - mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetRSBufferDescriptorSet(), 4, offsets); + mCommandBuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetRSBufferDescriptorSet(), 5, offsets); mLastViewpointOffset = mViewpointOffset; mLastMatricesOffset = matrixOffset; mLastStreamDataOffset = streamDataOffset; mLastLightsOffset = lightsOffset; + mLastFogballsOffset = fogballsOffset; } } @@ -635,6 +639,35 @@ int VkRenderState::UploadBones(const TArray& bones) } } +int VkRenderState::UploadFogballs(const TArray& balls) +{ + int totalsize = balls.Size() + 1; + if (balls.Size() == 0) + { + return -1; + } + + // Make sure the fogball list doesn't cross a page boundary + if (mRSBuffers->Fogballbuffer.UploadIndex % MAX_FOGBALL_DATA + totalsize > MAX_FOGBALL_DATA) + mRSBuffers->Fogballbuffer.UploadIndex = (mRSBuffers->Fogballbuffer.UploadIndex / MAX_FOGBALL_DATA + 1) * MAX_FOGBALL_DATA; + + int thisindex = mRSBuffers->Fogballbuffer.UploadIndex; + mRSBuffers->Fogballbuffer.UploadIndex += totalsize; + + if (thisindex + totalsize <= mRSBuffers->Fogballbuffer.Count) + { + Fogball sizeinfo; // First entry is actually not a fogball. It is the size of the array. + sizeinfo.Position.X = (float)balls.Size(); + memcpy((Fogball*)mRSBuffers->Fogballbuffer.Data + thisindex, &sizeinfo, sizeof(Fogball)); + memcpy((Fogball*)mRSBuffers->Fogballbuffer.Data + thisindex + 1, balls.Data(), balls.Size() * sizeof(Fogball)); + return thisindex; + } + else + { + return -1; + } +} + std::pair VkRenderState::AllocVertices(unsigned int count) { unsigned int index = mRSBuffers->Flatbuffer.CurIndex; diff --git a/src/common/rendering/vulkan/vk_renderstate.h b/src/common/rendering/vulkan/vk_renderstate.h index 1ae2896ee..cf1be5ddd 100644 --- a/src/common/rendering/vulkan/vk_renderstate.h +++ b/src/common/rendering/vulkan/vk_renderstate.h @@ -48,6 +48,7 @@ public: void SetTextureMatrix(const VSMatrix& matrix) override; int UploadLights(const FDynLightData& lightdata) override; int UploadBones(const TArray& bones) override; + int UploadFogballs(const TArray& balls) override; // Vertices std::pair AllocVertices(unsigned int count) override; @@ -114,6 +115,7 @@ protected: uint32_t mLastMatricesOffset = 0xffffffff; uint32_t mLastStreamDataOffset = 0xffffffff; uint32_t mLastLightsOffset = 0; + uint32_t mLastFogballsOffset = 0; uint32_t mViewpointOffset = 0; int mLastVertexOffsets[2] = { 0, 0 }; diff --git a/src/namedef_custom.h b/src/namedef_custom.h index 6f5e281a0..22971f014 100644 --- a/src/namedef_custom.h +++ b/src/namedef_custom.h @@ -866,3 +866,4 @@ xx(skew_middle) xx(skew_top) xx(Corona) +xx(Fogball) diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 6163e16fd..f63411635 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -125,6 +125,7 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni for (int i = 0; i < GLDL_TYPES; i++) drawlists[i].Reset(); hudsprites.Clear(); Coronas.Clear(); + Fogballs.Clear(); VisibleSurfaces.Clear(); vpIndex = 0; @@ -813,7 +814,11 @@ void HWDrawInfo::DrawScene(int drawmode, FRenderState& state) state.SetDepthMask(true); if (!gl_no_skyclear) drawctx->portalState.RenderFirstSkyPortal(recursion, this, state); + int fogballIndex = state.UploadFogballs(Fogballs); + + state.SetFogballIndex(fogballIndex); RenderScene(state); + state.SetFogballIndex(-1); if (applySSAO && state.GetPassType() == GBUFFER_PASS) { @@ -826,7 +831,10 @@ void HWDrawInfo::DrawScene(int drawmode, FRenderState& state) recursion++; drawctx->portalState.EndFrame(this, state); recursion--; + + state.SetFogballIndex(fogballIndex); RenderTranslucent(state); + state.SetFogballIndex(-1); } diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.h b/src/rendering/hwrenderer/scene/hw_drawinfo.h index 5466ffca7..bd81bf9a2 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.h +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.h @@ -9,6 +9,7 @@ #include "v_video.h" #include "hw_weapon.h" #include "hw_drawlist.h" +#include "hw_renderstate.h" EXTERN_CVAR(Bool, lm_always_update); EXTERN_CVAR(Int, lm_max_updates); @@ -33,6 +34,7 @@ struct particle_t; struct FDynLightData; struct HUDSprite; class ACorona; +class AFogball; class Clipper; class HWPortal; class HWScenePortalBase; @@ -151,6 +153,7 @@ struct HWDrawInfo TArray Decals[2]; // the second slot is for mirrors which get rendered in a separate pass. TArray hudsprites; // These may just be stored by value. TArray Coronas; + TArray Fogballs; TArray VisibleSurfaces; uint64_t LastFrameTime = 0; diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 11b1b4de9..564835afa 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -33,6 +33,7 @@ #include "r_sky.h" #include "r_utility.h" #include "a_pickups.h" +#include "a_fogball.h" #include "d_player.h" #include "g_levellocals.h" #include "events.h" @@ -748,12 +749,25 @@ void HWSprite::Process(HWDrawInfo *di, FRenderState& state, AActor* thing, secto // [ZZ] allow CustomSprite-style direct picnum specification bool isPicnumOverride = thing->picnum.isValid(); + bool isFogball = thing->IsKindOf(NAME_Fogball); + // Don't waste time projecting sprites that are definitely not visible. - if ((thing->sprite == 0 && !isPicnumOverride) || !thing->IsVisibleToPlayer() || ((thing->renderflags & RF_MASKROTATION) && !thing->IsInsideVisibleAngles())) + if ((thing->sprite == 0 && !isPicnumOverride && !isFogball) || !thing->IsVisibleToPlayer() || ((thing->renderflags & RF_MASKROTATION) && !thing->IsInsideVisibleAngles())) { return; } + if (isFogball) + { + Fogball fogball; + fogball.Position = FVector3(thing->Pos()); + fogball.Radius = (float)thing->renderradius; + fogball.Color = FVector3(1.0f, 0.8f, 0.5f); + fogball.Fog = 0.5f; + di->Fogballs.Push(fogball); + return; + } + if (thing->IsKindOf(NAME_Corona)) { di->Coronas.Push(thing); diff --git a/wadsrc/static/shaders/scene/fogball.glsl b/wadsrc/static/shaders/scene/fogball.glsl index de5cc8677..7031adf43 100644 --- a/wadsrc/static/shaders/scene/fogball.glsl +++ b/wadsrc/static/shaders/scene/fogball.glsl @@ -46,13 +46,17 @@ vec4 ProcessFogBalls(vec4 light) float dbuffer = distance(pixelpos.xyz, uCameraPos.xyz); vec3 rayDirection = normalize(pixelpos.xyz - uCameraPos.xyz); - vec3 sphereCenter = vec3(715, 89, 743); - float sphereRadius = 400; + int first = uFogballIndex + 1; + int last = uFogballIndex + int(fogballs[uFogballIndex].position.x); + for (int i = first; i <= last; i++) + { + vec3 sphereCenter = fogballs[i].position.xzy; + float sphereRadius = fogballs[i].radius; - float fogintensity = 0.5; - vec3 fogcolor = vec3(1.0, 0.8, 0.5) * fogintensity; - float density = FogSphereDensity(rayOrigin, rayDirection, sphereCenter, sphereRadius, dbuffer); - light.rgb = mix(light.rgb, fogcolor * density, density); + vec3 fogcolor = fogballs[i].color * fogballs[i].fog; + float density = FogSphereDensity(rayOrigin, rayDirection, sphereCenter, sphereRadius, dbuffer); + light.rgb = mix(light.rgb, fogcolor * density, density); + } return light; } diff --git a/wadsrc/static/shaders/scene/layout_shared.glsl b/wadsrc/static/shaders/scene/layout_shared.glsl index 741fb6247..0382725d1 100644 --- a/wadsrc/static/shaders/scene/layout_shared.glsl +++ b/wadsrc/static/shaders/scene/layout_shared.glsl @@ -9,7 +9,7 @@ layout(push_constant) uniform PushConstants int uDataIndex; // streamdata index int uLightIndex; // dynamic lights int uBoneIndexBase; // bone animation - int padding; + int uFogballIndex; // fog balls }; // material types diff --git a/wadsrc/static/shaders/scene/lightmode.glsl b/wadsrc/static/shaders/scene/lightmode.glsl index 1fc82c017..495de69f3 100644 --- a/wadsrc/static/shaders/scene/lightmode.glsl +++ b/wadsrc/static/shaders/scene/lightmode.glsl @@ -88,7 +88,7 @@ vec4 getLightColor(Material material) #endif - #if !defined(FOGBALLS) + #if defined(FOGBALLS) frag = ProcessFogBalls(frag); #endif