diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs
index 3bd85af225..cb05916ee0 100644
--- a/Content.Client/Entry/EntryPoint.cs
+++ b/Content.Client/Entry/EntryPoint.cs
@@ -12,6 +12,7 @@ using Content.Client.IoC;
using Content.Client.Launcher;
using Content.Client.Lobby;
using Content.Client.MainMenu;
+using Content.Client.Overlays;
using Content.Client.Parallax.Managers;
using Content.Client.Players.PlayTimeTracking;
using Content.Client.Radiation.Overlays;
@@ -159,6 +160,7 @@ namespace Content.Client.Entry
_parallaxManager.LoadDefaultParallax();
+ _overlayManager.AddOverlay(new CP14BasePostProcessOverlay()); // CP14-PostProcess
_overlayManager.AddOverlay(new SingularityOverlay());
_overlayManager.AddOverlay(new RadiationPulseOverlay());
_chatManager.Initialize();
diff --git a/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml b/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml
index 597073e510..c6604f1b45 100644
--- a/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml
+++ b/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml
@@ -16,11 +16,12 @@
-
-
-
-
-
+
+
+
diff --git a/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml.cs b/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml.cs
index 97860323dc..3342c7c1c1 100644
--- a/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml.cs
+++ b/Content.Client/_CP14/Options/CP14OptionsMenuMainTab.xaml.cs
@@ -13,6 +13,7 @@ public sealed partial class CP14OptionsMenuMainTab : Control
RobustXamlLoader.Load(this);
Control.AddOptionCheckBox(CP14ConfigVars.WaveShaderEnabled, WaveShaderEnabled);
+ Control.AddOptionCheckBox(CP14ConfigVars.PostProcess, PostProcessCheckBox);
Control.Initialize();
}
diff --git a/Content.Client/_CP14/Overlays/BasePostProcessOverlay.cs b/Content.Client/_CP14/Overlays/BasePostProcessOverlay.cs
new file mode 100644
index 0000000000..4fe8434a35
--- /dev/null
+++ b/Content.Client/_CP14/Overlays/BasePostProcessOverlay.cs
@@ -0,0 +1,77 @@
+using Content.Shared._CP14.Configuration;
+using System.Numerics;
+using Robust.Client.Graphics;
+using Robust.Client.Player;
+using Robust.Shared.Configuration;
+using Robust.Shared.Enums;
+using Robust.Shared.Graphics;
+using Robust.Shared.Physics;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Overlays;
+
+// This overlay serves as the foundational post processing overlay.
+// Ideally, for performance reasons, post processing designed to be present at all times, such as additive light blending or tonemapping, should be done as part of a single shader pass.
+public sealed class CP14BasePostProcessOverlay : Overlay
+{
+ [Dependency] private readonly IConfigurationManager _configManager = default!;
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly ILightManager _lightManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+
+ public override bool RequestScreenTexture => true;
+ public override OverlaySpace Space => OverlaySpace.WorldSpace;
+ private readonly ShaderInstance _basePostProcessShader;
+
+ public CP14BasePostProcessOverlay()
+ {
+ IoCManager.InjectDependencies(this);
+ _basePostProcessShader = _prototypeManager.Index("BasePostProcess").InstanceUnique();
+ }
+
+ protected override bool BeforeDraw(in OverlayDrawArgs args)
+ {
+ if (!_configManager.GetCVar(CP14ConfigVars.PostProcess))
+ return false;
+
+ if (!_entityManager.TryGetComponent(_playerManager.LocalSession?.AttachedEntity, out EyeComponent? eyeComp))
+ return false;
+
+ if (args.Viewport.Eye != eyeComp.Eye)
+ return false;
+
+ if (!_lightManager.Enabled || !eyeComp.Eye.DrawLight)
+ return false;
+
+ var playerEntity = _playerManager.LocalSession?.AttachedEntity;
+
+ if (playerEntity == null)
+ return false;
+
+ return true;
+ }
+
+ protected override void Draw(in OverlayDrawArgs args)
+ {
+ if (ScreenTexture == null)
+ return;
+
+ if (args.Viewport.Eye == null)
+ return;
+
+ var playerEntity = _playerManager.LocalSession?.AttachedEntity;
+
+ var worldHandle = args.WorldHandle;
+ var viewport = args.WorldBounds;
+
+ _basePostProcessShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
+ _basePostProcessShader.SetParameter("LIGHT_TEXTURE", args.Viewport.LightRenderTarget.Texture);
+
+ _basePostProcessShader.SetParameter("Zoom", args.Viewport.Eye.Zoom.X);
+
+ worldHandle.UseShader(_basePostProcessShader);
+ worldHandle.DrawRect(viewport, Color.White);
+ worldHandle.UseShader(null);
+ }
+}
\ No newline at end of file
diff --git a/Content.Shared/_CP14/Configuration/CP14ConfigVars.cs b/Content.Shared/_CP14/Configuration/CP14ConfigVars.cs
index 08be32ea3b..ec1206c68c 100644
--- a/Content.Shared/_CP14/Configuration/CP14ConfigVars.cs
+++ b/Content.Shared/_CP14/Configuration/CP14ConfigVars.cs
@@ -8,4 +8,12 @@ public sealed class CP14ConfigVars : CVars
{
public static readonly CVarDef
WaveShaderEnabled = CVarDef.Create("cp14_rendering.wave_shader_enabled", true, CVar.CLIENT | CVar.ARCHIVE);
+
+ ///
+ /// Toggle for non-gameplay-affecting or otherwise status indicative post-process effects, such additive lighting.
+ /// In the future, this could probably be turned into an enum that allows only disabling more expensive post-process shaders.
+ /// However, for now (mid-July of 2024), this only applies specifically to a particularly cheap shader: additive lighting.
+ ///
+ public static readonly CVarDef
+ PostProcess = CVarDef.Create("cp14_graphics.post_process", true, CVar.CLIENTONLY | CVar.ARCHIVE);
}
diff --git a/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl
index 15361673cc..e0fbdb6096 100644
--- a/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl
+++ b/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl
@@ -5,4 +5,12 @@ cp14-ui-options-tab-main = CP14
## Graphics
cp14-ui-options-main-graphics-label = Graphics
-cp14-ui-options-main-graphics-wave-shader = Wave shader:
+
+cp14-ui-options-main-graphics-wave-shader = Wave shader
+
+cp14-ui-options-postprocess = Cosmetic Post-processing
+cp14-ui-options-postprocess-tooltip =
+ When enabled, cosmetic post-processing effects such as
+ additive lighting will be present. This does not control
+ post-process effects that affect the game or otherwise
+ carry some form of gameplay-related meaning.
diff --git a/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl b/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl
index 8f288f570b..42d32f2236 100644
--- a/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl
+++ b/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl
@@ -5,4 +5,12 @@ cp14-ui-options-tab-main = CP14
## Graphics
cp14-ui-options-main-graphics-label = Графика
-cp14-ui-options-main-graphics-wave-shader = Шейдер покачивания (Wave shader):
+
+cp14-ui-options-main-graphics-wave-shader = Шейдер покачивания
+
+cp14-ui-options-postprocess = Косметическая постобработка
+cp14-ui-options-postprocess-tooltip =
+ Если эта функция включена, то будут присутствовать косметические эффекты постобработки,
+ такие как аддитивное освещение. Это не управляет эффеками постобработки, которые
+ влияют на игру или иным образом не контролирует эффекты постобработки, которые
+ влияют на игру или имеют какое-то значение для игрового процесса.
diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml
index 6e0bbd55b4..1f537c6e6c 100644
--- a/Resources/Prototypes/Shaders/shaders.yml
+++ b/Resources/Prototypes/Shaders/shaders.yml
@@ -108,4 +108,4 @@
- type: shader
id: Hologram
kind: source
- path: "/Textures/Shaders/hologram.swsl"
\ No newline at end of file
+ path: "/Textures/Shaders/hologram.swsl"
diff --git a/Resources/Prototypes/_CP14/Entities/Structures/Furniture/lamppost.yml b/Resources/Prototypes/_CP14/Entities/Structures/Furniture/lamppost.yml
index 1238bb25ec..f3fa5a37cc 100644
--- a/Resources/Prototypes/_CP14/Entities/Structures/Furniture/lamppost.yml
+++ b/Resources/Prototypes/_CP14/Entities/Structures/Furniture/lamppost.yml
@@ -69,7 +69,7 @@
drawdepth: Mobs
offset: 0,0.9
- type: PointLight
- energy: 5
+ energy: 2.5
radius: 8
- type: entity
diff --git a/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount.yml b/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount.yml
index b7e517b9bf..18cd2e13b2 100644
--- a/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount.yml
+++ b/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount.yml
@@ -90,7 +90,7 @@
shader: unshaded
- type: PointLight
color: "#e67c34"
- energy: 5
+ energy: 2
radius: 8
- type: AmbientSound
enabled: true
diff --git a/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount_lamp.yml b/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount_lamp.yml
index 104826fe69..16e70e455a 100644
--- a/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount_lamp.yml
+++ b/Resources/Prototypes/_CP14/Entities/Structures/Furniture/wallmount_lamp.yml
@@ -20,7 +20,7 @@
map: [ "light" ]
visible: false
- type: PointLight
- energy: 2
+ energy: 1
radius: 8
color: "#b2ceeb"
enabled: false
diff --git a/Resources/Prototypes/_CP14/Shaders/shaders.yml b/Resources/Prototypes/_CP14/Shaders/shaders.yml
index 718e1c926d..468675576d 100644
--- a/Resources/Prototypes/_CP14/Shaders/shaders.yml
+++ b/Resources/Prototypes/_CP14/Shaders/shaders.yml
@@ -1,4 +1,21 @@
- type: shader
id: Wave
kind: source
- path: "/Textures/_CP14/Shaders/wave.swsl"
\ No newline at end of file
+ path: "/Textures/_CP14/Shaders/wave.swsl"
+
+# Base post-processing
+- type: shader
+ id: BasePostProcess
+ kind: source
+ path: "/Textures/_CP14/Shaders/base_postprocess.swsl"
+ params:
+ CircleRadius: 420.0
+ CircleMinDist: 0.0
+ CirclePow: 1.0
+ CircleMax: 4.0
+ CircleMult: 0.25
+ FalloffClampMin: 0.075
+ FalloffClampMax: 1.0
+ FalloffStrength: 0.75
+ FalloffPow: 3.0
+ HDR: 1.5
diff --git a/Resources/Textures/_CP14/Shaders/base_postprocess.swsl b/Resources/Textures/_CP14/Shaders/base_postprocess.swsl
new file mode 100644
index 0000000000..43b1275bb4
--- /dev/null
+++ b/Resources/Textures/_CP14/Shaders/base_postprocess.swsl
@@ -0,0 +1,34 @@
+//Boilerplate
+uniform sampler2D SCREEN_TEXTURE;
+uniform sampler2D LIGHT_TEXTURE;
+
+uniform highp float Zoom;
+
+//Variables for controlling the falloff of the additive lighting effect.
+uniform highp float CircleRadius; //= 420.0;
+uniform highp float CircleMinDist; //= 0.0;
+uniform highp float CirclePow; //= 1.0;
+uniform highp float CircleMax; //= 4.0;
+uniform highp float CircleMult; //= 0.25;
+uniform highp float FalloffClampMin; //= 0.075;
+uniform highp float FalloffClampMax; //= 1.0;
+uniform highp float FalloffStrength; //= 0.75;
+uniform highp float FalloffPow; //= 3.0;
+uniform highp float HDR; //= 1.5;
+
+void fragment() {
+ COLOR = zTextureSpec(SCREEN_TEXTURE, Pos);
+ highp vec2 aspect = vec2(1.0/SCREEN_PIXEL_SIZE.x, 1.0/SCREEN_PIXEL_SIZE.y);
+ highp float actualZoom = Zoom;
+
+ highp float circle = clamp(zCircleGradient(aspect, FRAGCOORD.xy, CircleMax, CircleRadius / actualZoom, CircleMinDist / actualZoom, CirclePow) * CircleMult, FalloffClampMin, FalloffClampMax);
+
+ highp vec3 lightsampleraw = texture2D(LIGHT_TEXTURE, Pos).rgb;
+ lightsampleraw = smoothstep(0.0, HDR, lightsampleraw);
+ highp float graylight = max(zGrayscale(lightsampleraw) - max((1.0 - circle) * FalloffStrength, 0.0), 0.0);
+ graylight = pow(graylight, FalloffPow);
+
+ highp vec3 lightsample = lightsampleraw * vec3(graylight);
+
+ COLOR.rgb = COLOR.rgb + lightsample;
+}
\ No newline at end of file