From 7662b17d493a89c368350ea31743cc653fb78ed6 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Wed, 2 Oct 2024 17:35:50 +1000 Subject: [PATCH 01/10] Add another lookup overload --- .../Systems/EntityLookupSystem.ComponentQueries.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Robust.Shared/GameObjects/Systems/EntityLookupSystem.ComponentQueries.cs b/Robust.Shared/GameObjects/Systems/EntityLookupSystem.ComponentQueries.cs index 02280cecfde..ddcab6d49b1 100644 --- a/Robust.Shared/GameObjects/Systems/EntityLookupSystem.ComponentQueries.cs +++ b/Robust.Shared/GameObjects/Systems/EntityLookupSystem.ComponentQueries.cs @@ -496,6 +496,16 @@ public void GetEntitiesIntersecting(Type type, MapId mapId, Box2 worldAABB, Hash GetEntitiesIntersecting(type, mapId, shape, transform, intersecting, flags); } + public void GetEntitiesIntersecting(MapId mapId, Box2Rotated worldBounds, HashSet> entities, LookupFlags flags = DefaultFlags) where T : IComponent + { + if (mapId == MapId.Nullspace) return; + + var shape = new Polygon(worldBounds); + var shapeTransform = Physics.Transform.Empty; + + GetEntitiesIntersecting(mapId, shape, shapeTransform, entities, flags); + } + public void GetEntitiesIntersecting(MapId mapId, Box2 worldAABB, HashSet> entities, LookupFlags flags = DefaultFlags) where T : IComponent { if (mapId == MapId.Nullspace) return; From 60169325e91105a74f624918e56cd21d346c8fdb Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Wed, 2 Oct 2024 17:38:40 +1000 Subject: [PATCH 02/10] Fix RenderInRenderTarget See the linked issue for what happens. --- Robust.Client/Graphics/Clyde/Clyde.HLR.cs | 13 +++++++++++++ Robust.Client/Graphics/Clyde/Clyde.Rendering.cs | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs index ea9271562a3..0af9afa08d7 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs @@ -423,6 +423,11 @@ private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearCol var oldTransform = _currentMatrixModel; var oldScissor = _currentScissorState; + var oldMatrixProj = _currentMatrixProj; + var oldMatrixView = _currentMatrixView; + var oldBoundTarget = _currentBoundRenderTarget; + var oldRenderTarget = _currentRenderTarget; + var oldShader = _queuedShaderInstance; // Have to flush the render queue so that all commands finish rendering to the previous framebuffer. FlushRenderQueue(); @@ -452,6 +457,14 @@ private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearCol SetScissorFull(oldScissor); _currentMatrixModel = oldTransform; + + DebugTools.Assert(_currentMatrixModel.Equals(oldTransform)); + DebugTools.Assert(_currentScissorState.Equals(oldScissor)); + DebugTools.Assert(_currentMatrixProj.Equals(oldMatrixProj)); + DebugTools.Assert(oldMatrixView.Equals(_currentMatrixView)); + DebugTools.Assert(oldRenderTarget.Equals(_currentRenderTarget)); + DebugTools.Assert(oldBoundTarget.Equals(_currentBoundRenderTarget)); + DebugTools.Assert(oldShader.Equals(_queuedShaderInstance)); } private void RenderViewport(Viewport viewport) diff --git a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs index af19a2c1a2e..160c9aea270 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs @@ -859,13 +859,13 @@ private void BreakBatch() private FullStoredRendererState PushRenderStateFull() { - return new FullStoredRendererState(_currentMatrixProj, _currentMatrixView, _currentRenderTarget); + return new FullStoredRendererState(_currentMatrixProj, _currentMatrixView, _currentBoundRenderTarget); } private void PopRenderStateFull(in FullStoredRendererState state) { SetProjViewFull(state.ProjMatrix, state.ViewMatrix); - BindRenderTargetFull(state.RenderTarget); + BindRenderTargetImmediate(state.RenderTarget); var (width, height) = state.RenderTarget.Size; GL.Viewport(0, 0, width, height); From a6a6e17a2925285f7bb304af8280379bbdc36a32 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Thu, 3 Oct 2024 13:51:24 +1000 Subject: [PATCH 03/10] Also this one --- Robust.Client/Graphics/Clyde/Clyde.HLR.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs index 0af9afa08d7..fcb88d60af3 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs @@ -452,6 +452,7 @@ private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearCol FenceRenderTarget(rt); + _currentRenderTarget = oldRenderTarget; PopRenderStateFull(state); _updateUniformConstants(_currentRenderTarget.Size); From 41aa38389c780c82a0826b0bc0ca64cb6d6af281 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Sun, 6 Oct 2024 14:28:21 +1100 Subject: [PATCH 04/10] stuff --- Robust.Client/Graphics/Clyde/Clyde.HLR.cs | 1 - .../Graphics/Clyde/Clyde.LightRendering.cs | 65 +++++++++++-------- .../Graphics/Clyde/Clyde.RenderTargets.cs | 23 ++++++- .../Graphics/Clyde/Clyde.Rendering.cs | 11 ++-- Robust.Client/Graphics/Clyde/ClydeHeadless.cs | 10 +++ Robust.Client/Graphics/IClyde.cs | 4 ++ Robust.Client/Graphics/IRenderTarget.cs | 39 +++++++++++ Robust.Shared/Enums/OverlaySpaces.cs | 7 +- 8 files changed, 126 insertions(+), 34 deletions(-) diff --git a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs index fcb88d60af3..0af9afa08d7 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs @@ -452,7 +452,6 @@ private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearCol FenceRenderTarget(rt); - _currentRenderTarget = oldRenderTarget; PopRenderStateFull(state); _updateUniformConstants(_currentRenderTarget.Size); diff --git a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs index 80008a627f3..2c6ad239364 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs @@ -16,6 +16,7 @@ using TKStencilOp = OpenToolkit.Graphics.OpenGL4.StencilOp; using Robust.Shared.Physics; using Robust.Client.ComponentTrees; +using Robust.Shared.Enums; using Robust.Shared.Graphics; using static Robust.Shared.GameObjects.OccluderComponent; using Robust.Shared.Utility; @@ -402,12 +403,32 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w CheckGlError(); BindRenderTargetImmediate(RtToLoaded(viewport.LightRenderTarget)); + DebugTools.Assert(_currentBoundRenderTarget.TextureHandle.Equals(viewport.LightRenderTarget.Texture.TextureId)); CheckGlError(); GLClearColor(_entityManager.GetComponentOrNull(mapUid)?.AmbientLightColor ?? MapLightComponent.DefaultColor); GL.ClearStencil(0xFF); GL.StencilMask(0xFF); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit); CheckGlError(); + var oldTarget = _currentRenderTarget; + var oldProj = _currentMatrixProj; + var oldShader = _queuedShaderInstance; + var oldModel = _currentMatrixModel; + var oldScissor = _currentScissorState; + var oldScissoring = _isScissoring; + _lightingReady = true; + + RenderOverlays(viewport, OverlaySpace.BeforeLighting, worldAABB, worldBounds); + + GL.Viewport(0, 0, lightW, lightH); + BindVertexArray(_occlusionVao.Handle); + DebugTools.Assert(oldScissoring.Equals(_isScissoring)); + DebugTools.Assert(oldScissor.Equals(_currentScissorState)); + DebugTools.Assert(oldModel.Equals(_currentMatrixModel)); + DebugTools.Assert(oldShader.Equals(_queuedShaderInstance)); + DebugTools.Assert(oldProj.Equals(_currentMatrixProj)); + DebugTools.Assert(oldTarget.Equals(_currentRenderTarget)); + DebugTools.Assert(_currentBoundRenderTarget.TextureHandle.Equals(viewport.LightRenderTarget.Texture.TextureId)); ApplyLightingFovToBuffer(viewport, eye); @@ -515,7 +536,7 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w CheckGlError(); if (_cfg.GetCVar(CVars.LightBlur)) - BlurLights(viewport, eye); + BlurLights(viewport, viewport.LightRenderTarget, eye); using (_prof.Group("BlurOntoWalls")) { @@ -532,8 +553,6 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w CheckGlError(); Array.Clear(_lightsToRenderList, 0, count); - - _lightingReady = true; } private static bool LightQuery(ref ( @@ -643,10 +662,14 @@ public int Compare( return (state.count, expandedBounds); } - private void BlurLights(Viewport viewport, IEye eye) + public void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, float multiplier = 14f) { + if (target is not RenderTexture rTexture || viewport is not Viewport rViewport) + return; + using var _ = DebugGroup(nameof(BlurLights)); + var state = PushRenderStateFull(); GL.Disable(EnableCap.Blend); CheckGlError(); CalcScreenMatrices(viewport.Size, out var proj, out var view); @@ -655,7 +678,7 @@ private void BlurLights(Viewport viewport, IEye eye) var shader = _loadedShaders[_lightBlurShaderHandle].Program; shader.Use(); - SetupGlobalUniformsImmediate(shader, viewport.LightRenderTarget.Texture); + SetupGlobalUniformsImmediate(shader, rTexture.Texture); var size = viewport.LightRenderTarget.Size; shader.SetUniformMaybe("size", (Vector2)size); @@ -667,14 +690,13 @@ private void BlurLights(Viewport viewport, IEye eye) // Initially we're pulling from the light render target. // So we set it out of the loop so // _wallBleedIntermediateRenderTarget2 gets bound at the end of the loop body. - SetTexture(TextureUnit.Texture0, viewport.LightRenderTarget.Texture); + SetTexture(TextureUnit.Texture0, rTexture.Texture); // Have to scale the blurring radius based on viewport size and camera zoom. - const float refCameraHeight = 14; var facBase = _cfg.GetCVar(CVars.LightBlurFactor); var cameraSize = eye.Zoom.Y * viewport.Size.Y * (1 / viewport.RenderScale.Y) / EyeManager.PixelsPerMeter; // 7e-3f is just a magic factor that makes it look ok. - var factor = facBase * (refCameraHeight / cameraSize); + var factor = facBase * (multiplier / cameraSize); // Multi-iteration gaussian blur. for (var i = 3; i > 0; i--) @@ -683,23 +705,24 @@ private void BlurLights(Viewport viewport, IEye eye) // Set factor. shader.SetUniformMaybe("radius", scale); - BindRenderTargetFull(viewport.LightBlurTarget); + BindRenderTargetImmediate(RtToLoaded(rViewport.LightBlurTarget)); // Blur horizontally to _wallBleedIntermediateRenderTarget1. shader.SetUniformMaybe("direction", Vector2.UnitX); _drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader); - SetTexture(TextureUnit.Texture0, viewport.LightBlurTarget.Texture); + SetTexture(TextureUnit.Texture0, rViewport.LightBlurTarget.Texture); - BindRenderTargetFull(viewport.LightRenderTarget); + BindRenderTargetImmediate(RtToLoaded(rTexture)); // Blur vertically to _wallBleedIntermediateRenderTarget2. shader.SetUniformMaybe("direction", Vector2.UnitY); _drawQuad(Vector2.Zero, viewport.Size, Matrix3x2.Identity, shader); - SetTexture(TextureUnit.Texture0, viewport.LightRenderTarget.Texture); + SetTexture(TextureUnit.Texture0, rTexture.Texture); } + PopRenderStateFull(state); GL.Enable(EnableCap.Blend); CheckGlError(); // We didn't trample over the old _currentMatrices so just roll it back. @@ -1135,10 +1158,6 @@ private void RegenLightRts(Viewport viewport) var lightMapSize = GetLightMapSize(viewport.Size); var lightMapSizeQuart = GetLightMapSize(viewport.Size, true); - var lightMapColorFormat = _hasGLFloatFramebuffers - ? RenderTargetColorFormat.R11FG11FB10F - : RenderTargetColorFormat.Rgba8; - var lightMapSampleParameters = new TextureSampleParameters { Filter = true }; viewport.LightRenderTarget?.Dispose(); viewport.WallMaskRenderTarget?.Dispose(); @@ -1148,22 +1167,16 @@ private void RegenLightRts(Viewport viewport) viewport.WallMaskRenderTarget = CreateRenderTarget(viewport.Size, RenderTargetColorFormat.R8, name: $"{viewport.Name}-{nameof(viewport.WallMaskRenderTarget)}"); - viewport.LightRenderTarget = CreateRenderTarget(lightMapSize, - new RenderTargetFormatParameters(lightMapColorFormat, hasDepthStencil: true), - lightMapSampleParameters, + viewport.LightRenderTarget = (RenderTexture) CreateLightRenderTarget(lightMapSize, $"{viewport.Name}-{nameof(viewport.LightRenderTarget)}"); - viewport.LightBlurTarget = CreateRenderTarget(lightMapSize, - new RenderTargetFormatParameters(lightMapColorFormat), - lightMapSampleParameters, + viewport.LightBlurTarget = (RenderTexture) CreateLightRenderTarget(lightMapSize, $"{viewport.Name}-{nameof(viewport.LightBlurTarget)}"); - viewport.WallBleedIntermediateRenderTarget1 = CreateRenderTarget(lightMapSizeQuart, lightMapColorFormat, - lightMapSampleParameters, + viewport.WallBleedIntermediateRenderTarget1 = (RenderTexture) CreateLightRenderTarget(lightMapSizeQuart, $"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget1)}"); - viewport.WallBleedIntermediateRenderTarget2 = CreateRenderTarget(lightMapSizeQuart, lightMapColorFormat, - lightMapSampleParameters, + viewport.WallBleedIntermediateRenderTarget2 = (RenderTexture) CreateLightRenderTarget(lightMapSizeQuart, $"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget2)}"); } diff --git a/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs b/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs index a07f1cfc7ed..eb2289533f1 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs @@ -30,6 +30,19 @@ private readonly ConcurrentQueue _renderTargetDisposeQueue // It, like _mainWindowRenderTarget, is initialized in Clyde's constructor private LoadedRenderTarget _currentBoundRenderTarget; + public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name) + { + var lightMapColorFormat = _hasGLFloatFramebuffers + ? RTCF.R11FG11FB10F + : RTCF.Rgba8; + var lightMapSampleParameters = new TextureSampleParameters { Filter = true }; + + return CreateRenderTarget(size, + new RenderTargetFormatParameters(lightMapColorFormat, hasDepthStencil: true), + lightMapSampleParameters, + name: name); + } + IRenderTexture IClyde.CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format, TextureSampleParameters? sampleParameters, string? name) { @@ -251,9 +264,15 @@ private void BindRenderTargetFull(RenderTargetBase rt) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private LoadedRenderTarget RtToLoaded(RenderTargetBase rt) + private LoadedRenderTarget RtToLoaded(IRenderTarget rt) { - return _renderTargets[rt.Handle]; + switch (rt) + { + case RenderTargetBase based: + return _renderTargets[based.Handle]; + default: + throw new NotImplementedException(); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs index 160c9aea270..e04b711ce5f 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs @@ -859,15 +859,16 @@ private void BreakBatch() private FullStoredRendererState PushRenderStateFull() { - return new FullStoredRendererState(_currentMatrixProj, _currentMatrixView, _currentBoundRenderTarget); + return new FullStoredRendererState(_currentMatrixProj, _currentMatrixView, _currentBoundRenderTarget, _currentRenderTarget); } private void PopRenderStateFull(in FullStoredRendererState state) { SetProjViewFull(state.ProjMatrix, state.ViewMatrix); - BindRenderTargetImmediate(state.RenderTarget); + BindRenderTargetImmediate(state.BoundRenderTarget); - var (width, height) = state.RenderTarget.Size; + _currentRenderTarget = state.RenderTarget; + var (width, height) = state.BoundRenderTarget.Size; GL.Viewport(0, 0, width, height); CheckGlError(); } @@ -1061,13 +1062,15 @@ private readonly struct FullStoredRendererState { public readonly Matrix3x2 ProjMatrix; public readonly Matrix3x2 ViewMatrix; + public readonly LoadedRenderTarget BoundRenderTarget; public readonly LoadedRenderTarget RenderTarget; public FullStoredRendererState(in Matrix3x2 projMatrix, in Matrix3x2 viewMatrix, - LoadedRenderTarget renderTarget) + LoadedRenderTarget boundRenderTarget, LoadedRenderTarget renderTarget) { ProjMatrix = projMatrix; ViewMatrix = viewMatrix; + BoundRenderTarget = boundRenderTarget; RenderTarget = renderTarget; } } diff --git a/Robust.Client/Graphics/Clyde/ClydeHeadless.cs b/Robust.Client/Graphics/Clyde/ClydeHeadless.cs index 5754702641c..14117581ad5 100644 --- a/Robust.Client/Graphics/Clyde/ClydeHeadless.cs +++ b/Robust.Client/Graphics/Clyde/ClydeHeadless.cs @@ -188,6 +188,16 @@ public OwnedTexture CreateBlankTexture( return new DummyTexture(size); } + public void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, float multiplier = 14) + { + // NOOP + } + + public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null) + { + return CreateRenderTarget(size, new RenderTargetFormatParameters(), null, name: name); + } + public IRenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format, TextureSampleParameters? sampleParameters = null, string? name = null) { diff --git a/Robust.Client/Graphics/IClyde.cs b/Robust.Client/Graphics/IClyde.cs index 348e705e943..7f0629eac4c 100644 --- a/Robust.Client/Graphics/IClyde.cs +++ b/Robust.Client/Graphics/IClyde.cs @@ -71,6 +71,10 @@ OwnedTexture CreateBlankTexture( in TextureLoadParameters? loadParams = null) where T : unmanaged, IPixel; + void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, float multiplier = 14f); + + IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null); + IRenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format, TextureSampleParameters? sampleParameters = null, string? name = null); diff --git a/Robust.Client/Graphics/IRenderTarget.cs b/Robust.Client/Graphics/IRenderTarget.cs index 61b27762967..dc8cc53c5dd 100644 --- a/Robust.Client/Graphics/IRenderTarget.cs +++ b/Robust.Client/Graphics/IRenderTarget.cs @@ -1,4 +1,6 @@ using System; +using System.Numerics; +using Robust.Shared.Graphics; using Robust.Shared.Maths; using SixLabors.ImageSharp.PixelFormats; @@ -15,5 +17,42 @@ public interface IRenderTarget : IDisposable Vector2i Size { get; } void CopyPixelsToMemory(CopyPixelsDelegate callback, UIBox2i? subRegion = null) where T : unmanaged, IPixel; + + public Vector2 LocalToWorld(IEye eye, Vector2 point, Vector2 scale) + { + var newPoint = point; + + // (inlined version of UiProjMatrix^-1) + newPoint -= Size / 2f; + newPoint *= new Vector2(1, -1) / EyeManager.PixelsPerMeter; + + // view matrix + eye.GetViewMatrixInv(out var viewMatrixInv, scale); + newPoint = Vector2.Transform(newPoint, viewMatrixInv); + + return newPoint; + } + + public Vector2 WorldToLocal(Vector2 point, IEye eye, Vector2 scale) + { + var newPoint = point; + + eye.GetViewMatrix(out var viewMatrix, scale); + newPoint = Vector2.Transform(newPoint, viewMatrix); + + // (inlined version of UiProjMatrix) + newPoint *= new Vector2(1, -1) * EyeManager.PixelsPerMeter; + newPoint += Size / 2f; + + return newPoint; + } + + public Matrix3x2 GetWorldToLocalMatrix(IEye eye, Vector2 scale) + { + eye.GetViewMatrix(out var viewMatrix, scale * new Vector2(EyeManager.PixelsPerMeter, -EyeManager.PixelsPerMeter)); + viewMatrix.M31 += Size.X / 2f; + viewMatrix.M32 += Size.Y / 2f; + return viewMatrix; + } } } diff --git a/Robust.Shared/Enums/OverlaySpaces.cs b/Robust.Shared/Enums/OverlaySpaces.cs index deefdc64c71..28be50a7673 100644 --- a/Robust.Shared/Enums/OverlaySpaces.cs +++ b/Robust.Shared/Enums/OverlaySpaces.cs @@ -54,6 +54,11 @@ public enum OverlaySpace : ushort /// /// Overlay will be rendered below grids, entities, and everything else. In world space. /// - WorldSpaceBelowWorld = 1 << 8 + WorldSpaceBelowWorld = 1 << 8, + + /// + /// Called after GLClear but before FOV applied to the lighting buffer. + /// + BeforeLighting = 1 << 9, } } From fccbc0d975c96f5aecd6dea79173bafceb0df246 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Sun, 6 Oct 2024 18:17:05 +1100 Subject: [PATCH 05/10] Fix stencilling --- .../Graphics/Clyde/Clyde.LightRendering.cs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs index 2c6ad239364..3227fb6151b 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs @@ -410,18 +410,20 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w GL.StencilMask(0xFF); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit); CheckGlError(); + var oldTarget = _currentRenderTarget; var oldProj = _currentMatrixProj; var oldShader = _queuedShaderInstance; var oldModel = _currentMatrixModel; var oldScissor = _currentScissorState; var oldScissoring = _isScissoring; - _lightingReady = true; RenderOverlays(viewport, OverlaySpace.BeforeLighting, worldAABB, worldBounds); - GL.Viewport(0, 0, lightW, lightH); - BindVertexArray(_occlusionVao.Handle); + // Batching doesn't restore stencil state so we do it here. + // Yes I spent 8 hours across 2 days just to track down this as the problem. + GL.Enable(EnableCap.StencilTest); + _isStencilling = true; DebugTools.Assert(oldScissoring.Equals(_isScissoring)); DebugTools.Assert(oldScissor.Equals(_currentScissorState)); DebugTools.Assert(oldModel.Equals(_currentMatrixModel)); @@ -552,6 +554,7 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w GL.Viewport(0, 0, viewport.Size.X, viewport.Size.Y); CheckGlError(); + _lightingReady = true; Array.Clear(_lightsToRenderList, 0, count); } @@ -1163,6 +1166,10 @@ private void RegenLightRts(Viewport viewport) viewport.WallMaskRenderTarget?.Dispose(); viewport.WallBleedIntermediateRenderTarget1?.Dispose(); viewport.WallBleedIntermediateRenderTarget2?.Dispose(); + var lightMapColorFormat = _hasGLFloatFramebuffers + ? RenderTargetColorFormat.R11FG11FB10F + : RenderTargetColorFormat.Rgba8; + var lightMapSampleParameters = new TextureSampleParameters { Filter = true }; viewport.WallMaskRenderTarget = CreateRenderTarget(viewport.Size, RenderTargetColorFormat.R8, name: $"{viewport.Name}-{nameof(viewport.WallMaskRenderTarget)}"); @@ -1170,13 +1177,19 @@ private void RegenLightRts(Viewport viewport) viewport.LightRenderTarget = (RenderTexture) CreateLightRenderTarget(lightMapSize, $"{viewport.Name}-{nameof(viewport.LightRenderTarget)}"); - viewport.LightBlurTarget = (RenderTexture) CreateLightRenderTarget(lightMapSize, + viewport.LightBlurTarget = CreateRenderTarget(lightMapSize, + new RenderTargetFormatParameters(lightMapColorFormat), + lightMapSampleParameters, $"{viewport.Name}-{nameof(viewport.LightBlurTarget)}"); - viewport.WallBleedIntermediateRenderTarget1 = (RenderTexture) CreateLightRenderTarget(lightMapSizeQuart, + viewport.WallBleedIntermediateRenderTarget1 = CreateRenderTarget(lightMapSizeQuart, + new RenderTargetFormatParameters(lightMapColorFormat), + lightMapSampleParameters, $"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget1)}"); - viewport.WallBleedIntermediateRenderTarget2 = (RenderTexture) CreateLightRenderTarget(lightMapSizeQuart, + viewport.WallBleedIntermediateRenderTarget2 = CreateRenderTarget(lightMapSizeQuart, + new RenderTargetFormatParameters(lightMapColorFormat), + lightMapSampleParameters, $"{viewport.Name}-{nameof(viewport.WallBleedIntermediateRenderTarget2)}"); } From 3d3422c074f9f4b1a471352f60507175e7c670b6 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Fri, 11 Oct 2024 21:41:39 +1100 Subject: [PATCH 06/10] fixes --- Robust.Client/Graphics/Clyde/Clyde.HLR.cs | 4 +++- .../Graphics/Clyde/Clyde.LightRendering.cs | 11 ++++++++++- .../Graphics/Clyde/Clyde.RenderTargets.cs | 10 +++++++--- Robust.Client/Graphics/Clyde/Clyde.Rendering.cs | 16 ++++++++++++---- Robust.Client/Graphics/Clyde/Clyde.cs | 2 ++ Robust.Client/Graphics/Clyde/ClydeHeadless.cs | 4 ++-- Robust.Client/Graphics/IClyde.cs | 12 +++++++++--- Robust.Client/Graphics/Lighting/ILightManager.cs | 5 +++++ Robust.Client/Graphics/Lighting/LightManager.cs | 3 +++ 9 files changed, 53 insertions(+), 14 deletions(-) diff --git a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs index 0af9afa08d7..6fd6c4ff9ca 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.HLR.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.HLR.cs @@ -429,10 +429,12 @@ private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearCol var oldRenderTarget = _currentRenderTarget; var oldShader = _queuedShaderInstance; + // Need to get state before flushing render queue in case they modify the original state. + var state = PushRenderStateFull(); + // Have to flush the render queue so that all commands finish rendering to the previous framebuffer. FlushRenderQueue(); - var state = PushRenderStateFull(); { BindRenderTargetFull(RtToLoaded(rt)); diff --git a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs index 3227fb6151b..13146ae2f59 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs @@ -18,6 +18,7 @@ using Robust.Client.ComponentTrees; using Robust.Shared.Enums; using Robust.Shared.Graphics; +using Robust.Shared.Prototypes; using static Robust.Shared.GameObjects.OccluderComponent; using Robust.Shared.Utility; using TextureWrapMode = Robust.Shared.Graphics.TextureWrapMode; @@ -417,12 +418,20 @@ private void DrawLightsAndFov(Viewport viewport, Box2Rotated worldBounds, Box2 w var oldModel = _currentMatrixModel; var oldScissor = _currentScissorState; var oldScissoring = _isScissoring; + var state = PushRenderStateFull(); RenderOverlays(viewport, OverlaySpace.BeforeLighting, worldAABB, worldBounds); + if (_lightManager.BlurFactor != 0f && viewport.Eye != null) + BlurLights(viewport, viewport.LightRenderTarget, viewport.Eye, _lightManager.BlurFactor); + // Batching doesn't restore stencil state so we do it here. // Yes I spent 8 hours across 2 days just to track down this as the problem. GL.Enable(EnableCap.StencilTest); + GL.ClearStencil(0xFF); + GL.StencilMask(0xFF); + GL.Clear(ClearBufferMask.StencilBufferBit); + PopRenderStateFull(state); _isStencilling = true; DebugTools.Assert(oldScissoring.Equals(_isScissoring)); DebugTools.Assert(oldScissor.Equals(_currentScissorState)); @@ -683,7 +692,7 @@ public void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, SetupGlobalUniformsImmediate(shader, rTexture.Texture); - var size = viewport.LightRenderTarget.Size; + var size = target.Size; shader.SetUniformMaybe("size", (Vector2)size); shader.SetUniformTextureMaybe(UniIMainTexture, TextureUnit.Texture0); diff --git a/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs b/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs index eb2289533f1..5ea57a1aeac 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.RenderTargets.cs @@ -30,7 +30,8 @@ private readonly ConcurrentQueue _renderTargetDisposeQueue // It, like _mainWindowRenderTarget, is initialized in Clyde's constructor private LoadedRenderTarget _currentBoundRenderTarget; - public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name) + + public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true) { var lightMapColorFormat = _hasGLFloatFramebuffers ? RTCF.R11FG11FB10F @@ -38,7 +39,7 @@ public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name) var lightMapSampleParameters = new TextureSampleParameters { Filter = true }; return CreateRenderTarget(size, - new RenderTargetFormatParameters(lightMapColorFormat, hasDepthStencil: true), + new RenderTargetFormatParameters(lightMapColorFormat, hasDepthStencil: depthStencil), lightMapSampleParameters, name: name); } @@ -217,7 +218,8 @@ private RenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParame Size = size, TextureHandle = textureObject.TextureId, MemoryPressure = pressure, - ColorFormat = format.ColorFormat + ColorFormat = format.ColorFormat, + SampleParameters = sampleParameters, }; //GC.AddMemoryPressure(pressure); @@ -321,6 +323,8 @@ private sealed class LoadedRenderTarget // Renderbuffer handle public GLHandle DepthStencilHandle; public long MemoryPressure; + + public TextureSampleParameters? SampleParameters; } private abstract class RenderTargetBase : IRenderTarget diff --git a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs index e04b711ce5f..3da618f01f1 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.Rendering.cs @@ -859,7 +859,7 @@ private void BreakBatch() private FullStoredRendererState PushRenderStateFull() { - return new FullStoredRendererState(_currentMatrixProj, _currentMatrixView, _currentBoundRenderTarget, _currentRenderTarget); + return new FullStoredRendererState(_currentMatrixProj, _currentMatrixView, _currentBoundRenderTarget, _currentRenderTarget, _queuedShaderInstance); } private void PopRenderStateFull(in FullStoredRendererState state) @@ -867,6 +867,7 @@ private void PopRenderStateFull(in FullStoredRendererState state) SetProjViewFull(state.ProjMatrix, state.ViewMatrix); BindRenderTargetImmediate(state.BoundRenderTarget); + _queuedShaderInstance = state.QueuedShaderInstance; _currentRenderTarget = state.RenderTarget; var (width, height) = state.BoundRenderTarget.Size; GL.Viewport(0, 0, width, height); @@ -1064,14 +1065,21 @@ private readonly struct FullStoredRendererState public readonly Matrix3x2 ViewMatrix; public readonly LoadedRenderTarget BoundRenderTarget; public readonly LoadedRenderTarget RenderTarget; - - public FullStoredRendererState(in Matrix3x2 projMatrix, in Matrix3x2 viewMatrix, - LoadedRenderTarget boundRenderTarget, LoadedRenderTarget renderTarget) + public readonly ClydeShaderInstance QueuedShaderInstance; + + public FullStoredRendererState( + in Matrix3x2 projMatrix, + in Matrix3x2 viewMatrix, + LoadedRenderTarget boundRenderTarget, + LoadedRenderTarget renderTarget, + ClydeShaderInstance queuedShaderInstance + ) { ProjMatrix = projMatrix; ViewMatrix = viewMatrix; BoundRenderTarget = boundRenderTarget; RenderTarget = renderTarget; + QueuedShaderInstance = queuedShaderInstance; } } } diff --git a/Robust.Client/Graphics/Clyde/Clyde.cs b/Robust.Client/Graphics/Clyde/Clyde.cs index 736116e5abc..85ceb609726 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.cs @@ -21,6 +21,7 @@ using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Profiling; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; using TextureWrapMode = Robust.Shared.Graphics.TextureWrapMode; @@ -36,6 +37,7 @@ internal sealed partial class Clyde : IClydeInternal, IPostInjectInit, IEntityEv [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IOverlayManager _overlayManager = default!; + [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly IResourceManager _resManager = default!; [Dependency] private readonly IUserInterfaceManagerInternal _userInterfaceManager = default!; diff --git a/Robust.Client/Graphics/Clyde/ClydeHeadless.cs b/Robust.Client/Graphics/Clyde/ClydeHeadless.cs index 14117581ad5..b0c6e76d419 100644 --- a/Robust.Client/Graphics/Clyde/ClydeHeadless.cs +++ b/Robust.Client/Graphics/Clyde/ClydeHeadless.cs @@ -193,9 +193,9 @@ public void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, // NOOP } - public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null) + public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true) { - return CreateRenderTarget(size, new RenderTargetFormatParameters(), null, name: name); + return CreateRenderTarget(size, new RenderTargetFormatParameters(RenderTargetColorFormat.R8, hasDepthStencil: depthStencil), null, name: name); } public IRenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format, diff --git a/Robust.Client/Graphics/IClyde.cs b/Robust.Client/Graphics/IClyde.cs index 7f0629eac4c..726af1f0583 100644 --- a/Robust.Client/Graphics/IClyde.cs +++ b/Robust.Client/Graphics/IClyde.cs @@ -71,9 +71,15 @@ OwnedTexture CreateBlankTexture( in TextureLoadParameters? loadParams = null) where T : unmanaged, IPixel; - void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, float multiplier = 14f); - - IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null); + void BlurRenderTarget( + IClydeViewport viewport, + DrawingHandleWorld worldHandle, + Box2Rotated bounds, + IRenderTarget target, + IEye eye, + float multiplier = 14f); + + IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true); IRenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format, TextureSampleParameters? sampleParameters = null, string? name = null); diff --git a/Robust.Client/Graphics/Lighting/ILightManager.cs b/Robust.Client/Graphics/Lighting/ILightManager.cs index 3204c4689cd..7e6e07f4a05 100644 --- a/Robust.Client/Graphics/Lighting/ILightManager.cs +++ b/Robust.Client/Graphics/Lighting/ILightManager.cs @@ -24,5 +24,10 @@ public interface ILightManager /// This is useful to prevent players messing with lighting setup when they shouldn't. /// bool LockConsoleAccess { get; set; } + + /// + /// How much to blur the lighting render target by after BeforeLighting overlays have run. + /// + float BlurFactor { get; set; } } } diff --git a/Robust.Client/Graphics/Lighting/LightManager.cs b/Robust.Client/Graphics/Lighting/LightManager.cs index 19bb4c4986b..5399cd54a09 100644 --- a/Robust.Client/Graphics/Lighting/LightManager.cs +++ b/Robust.Client/Graphics/Lighting/LightManager.cs @@ -9,6 +9,9 @@ public sealed class LightManager : ILightManager public bool DrawHardFov { get; set; } = true; public bool DrawLighting { get; set; } = true; public bool LockConsoleAccess { get; set; } = false; + public Color AmbientLightColor { get; set; } = Color.FromSrgb(Color.Black); + + public float BlurFactor { get; set; } = 14f * 5f; } } From 692840bbf0623150d2ed14b251a8c06617d9a7ac Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Fri, 11 Oct 2024 21:41:50 +1100 Subject: [PATCH 07/10] mix blend --- Resources/EnginePrototypes/Shaders/stockshaders.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/EnginePrototypes/Shaders/stockshaders.yml b/Resources/EnginePrototypes/Shaders/stockshaders.yml index 63e2dcf6890..13f0d6361fe 100644 --- a/Resources/EnginePrototypes/Shaders/stockshaders.yml +++ b/Resources/EnginePrototypes/Shaders/stockshaders.yml @@ -4,6 +4,12 @@ kind: canvas light_mode: unshaded +# Simple mix blend +- type: shader + id: Mix + kind: canvas + blend_mode: Mix + - type: shader id: shaded kind: canvas From d5a5673495a25ced502b1cd932fb4f18b479723d Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Sun, 13 Oct 2024 14:41:05 +1100 Subject: [PATCH 08/10] fix --- Robust.Client/Graphics/IClyde.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Robust.Client/Graphics/IClyde.cs b/Robust.Client/Graphics/IClyde.cs index 726af1f0583..55d4fd1b227 100644 --- a/Robust.Client/Graphics/IClyde.cs +++ b/Robust.Client/Graphics/IClyde.cs @@ -71,14 +71,6 @@ OwnedTexture CreateBlankTexture( in TextureLoadParameters? loadParams = null) where T : unmanaged, IPixel; - void BlurRenderTarget( - IClydeViewport viewport, - DrawingHandleWorld worldHandle, - Box2Rotated bounds, - IRenderTarget target, - IEye eye, - float multiplier = 14f); - IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true); IRenderTexture CreateRenderTarget(Vector2i size, RenderTargetFormatParameters format, From fbe438ea5a2fbbbfa65e9d145ad9117e4003ced0 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Mon, 14 Oct 2024 15:10:35 +1100 Subject: [PATCH 09/10] blur fixes --- Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs | 2 +- Robust.Client/Graphics/Clyde/ClydeHeadless.cs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs index 13146ae2f59..bf8f1eb8dd7 100644 --- a/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs +++ b/Robust.Client/Graphics/Clyde/Clyde.LightRendering.cs @@ -674,7 +674,7 @@ public int Compare( return (state.count, expandedBounds); } - public void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, float multiplier = 14f) + private void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, float multiplier = 14f) { if (target is not RenderTexture rTexture || viewport is not Viewport rViewport) return; diff --git a/Robust.Client/Graphics/Clyde/ClydeHeadless.cs b/Robust.Client/Graphics/Clyde/ClydeHeadless.cs index b0c6e76d419..f56a6b1d161 100644 --- a/Robust.Client/Graphics/Clyde/ClydeHeadless.cs +++ b/Robust.Client/Graphics/Clyde/ClydeHeadless.cs @@ -188,11 +188,6 @@ public OwnedTexture CreateBlankTexture( return new DummyTexture(size); } - public void BlurLights(IClydeViewport viewport, IRenderTarget target, IEye eye, float multiplier = 14) - { - // NOOP - } - public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true) { return CreateRenderTarget(size, new RenderTargetFormatParameters(RenderTargetColorFormat.R8, hasDepthStencil: depthStencil), null, name: name); From aeb50893daefc830334e23bb554e790d41f5806e Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Tue, 15 Oct 2024 20:25:51 +1100 Subject: [PATCH 10/10] Tile flag --- Robust.Shared/Map/Tile.cs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Robust.Shared/Map/Tile.cs b/Robust.Shared/Map/Tile.cs index 23c6ad9f389..35304d7225e 100644 --- a/Robust.Shared/Map/Tile.cs +++ b/Robust.Shared/Map/Tile.cs @@ -1,5 +1,6 @@ using System; using JetBrains.Annotations; +using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Robust.Shared.Map; @@ -20,6 +21,11 @@ namespace Robust.Shared.Map; /// public readonly TileRenderFlag Flags; + /// + /// Tile-flags for content usage. + /// + public readonly ushort ContentFlag; + /// /// Variant of this tile to render. /// @@ -41,11 +47,13 @@ namespace Robust.Shared.Map; /// Internal type ID. /// Flags used by toolbox's rendering. /// The visual variant this tile is using. - public Tile(int typeId, TileRenderFlag flags = 0, byte variant = 0) + /// + public Tile(int typeId, TileRenderFlag flags = 0, byte variant = 0, ushort contentFlag = 0) { TypeId = typeId; Flags = flags; Variant = variant; + ContentFlag = contentFlag; } /// @@ -93,7 +101,7 @@ public bool TryFormat( /// public bool Equals(Tile other) { - return TypeId == other.TypeId && Flags == other.Flags && Variant == other.Variant; + return TypeId == other.TypeId && Flags == other.Flags && Variant == other.Variant && ContentFlag == other.ContentFlag; } /// @@ -112,8 +120,22 @@ public override int GetHashCode() return (TypeId.GetHashCode() * 397) ^ Flags.GetHashCode() ^ Variant.GetHashCode(); } } + + [Pure] + public Tile WithContentFlag(ushort tileContentFlag) + { + return new Tile(typeId: TypeId, flags: Flags, variant: Variant, contentFlag: tileContentFlag); + } + + [Pure] + public Tile WithVariant(byte variant) + { + return new Tile(TypeId, Flags, variant, ContentFlag); + } } +public sealed class TileFlagLayer {} + public enum TileRenderFlag : byte {