diff --git a/Content.Client/_DV/Options/UI/Tabs/DeltaTab.xaml b/Content.Client/_DV/Options/UI/Tabs/DeltaTab.xaml
index c77c45ea7f..87f1230030 100644
--- a/Content.Client/_DV/Options/UI/Tabs/DeltaTab.xaml
+++ b/Content.Client/_DV/Options/UI/Tabs/DeltaTab.xaml
@@ -14,6 +14,7 @@
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
+
OverlaySpace.WorldSpace;
+ private readonly ShaderInstance _glimmerShader;
+ private readonly ProtoId _shaderProto = "HighGlimmer";
+
+ private float _visualGlimmerLevel = 0f;
+ public int ActualGlimmerLevel = 0;
+
+ public GlimmerOverlay()
+ {
+ IoCManager.InjectDependencies(this);
+ _glimmerShader = _prototype.Index(_shaderProto).Instance().Duplicate();
+ }
+
+ protected override bool BeforeDraw(in OverlayDrawArgs args)
+ {
+ if (_player.LocalEntity == null)
+ {
+ return false;
+ }
+
+ return base.BeforeDraw(in args);
+ }
+
+ protected override void Draw(in OverlayDrawArgs args)
+ {
+ var lastFrameTime = (float) _timing.FrameTime.TotalSeconds;
+
+ // lerp glimmer level to avoid jumps
+ _visualGlimmerLevel = !MathHelper.CloseTo(_visualGlimmerLevel, ActualGlimmerLevel, 0.001f)
+ ? float.Lerp(_visualGlimmerLevel, ActualGlimmerLevel, 0.1f * lastFrameTime)
+ : ActualGlimmerLevel;
+
+ // clamp glimmer to 0-1, map to exponential ease-out
+ var progress = Math.Clamp((_visualGlimmerLevel - 700f) / 300f,0,1);
+ var size = 1f - MathF.Pow(2f, -8f * progress);
+
+ _glimmerShader.SetParameter("size",size);
+
+ var worldHandle = args.WorldHandle;
+ var viewport = args.WorldBounds;
+ worldHandle.UseShader(_glimmerShader);
+ worldHandle.DrawRect(viewport, Color.White);
+ worldHandle.UseShader(null);
+ }
+
+ // used to avoid lerp jump if overlay was removed weirdly prior
+ public void Reset()
+ {
+ _visualGlimmerLevel = ActualGlimmerLevel;
+ }
+
+}
diff --git a/Content.Client/_DV/Overlays/GlimmerOverlaySystem.cs b/Content.Client/_DV/Overlays/GlimmerOverlaySystem.cs
new file mode 100644
index 0000000000..fd27be58fc
--- /dev/null
+++ b/Content.Client/_DV/Overlays/GlimmerOverlaySystem.cs
@@ -0,0 +1,64 @@
+using Content.Shared._DV.CCVars;
+using Content.Shared.Psionics.Glimmer;
+using Robust.Client.Graphics;
+using Robust.Shared.Configuration;
+
+namespace Content.Client._DV.Overlays;
+
+public sealed partial class GlimmerOverlaySystem : EntitySystem
+{
+ [Dependency] private readonly IOverlayManager _overlayMan = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+ private GlimmerOverlay _overlay = default!;
+
+ private bool _cvarDisabled;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ _overlay = new GlimmerOverlay();
+ SubscribeNetworkEvent(OnGlimmerChanged);
+ _cfg.OnValueChanged(DCCVars.DisableGlimmerShader, OnDisableGlimmerShaderChanged);
+ }
+
+ private void OnGlimmerChanged(GlimmerChangedEvent eventArgs)
+ {
+ if(_cvarDisabled)
+ return;
+
+ if(eventArgs.Glimmer > 700)
+ {
+ _overlay.ActualGlimmerLevel = eventArgs.Glimmer;
+ if (!_overlayMan.HasOverlay())
+ {
+ _overlay.Reset();
+ _overlayMan.AddOverlay(_overlay);
+ }
+ }
+ else
+ {
+ if (_overlayMan.HasOverlay())
+ {
+ _overlayMan.RemoveOverlay(_overlay);
+ }
+ }
+ }
+
+ public override void Shutdown()
+ {
+ base.Shutdown();
+ _overlayMan.RemoveOverlay();
+ }
+
+ private void OnDisableGlimmerShaderChanged(bool enabled)
+ {
+ _cvarDisabled = enabled;
+ if (enabled)
+ _overlayMan.RemoveOverlay(_overlay);
+ else if (_overlay.ActualGlimmerLevel > 700)
+ _overlayMan.AddOverlay(_overlay);
+ }
+
+}
diff --git a/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs b/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs
index 561b2202f9..56e4a4e5d6 100644
--- a/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs
+++ b/Content.Shared/Nyanotrasen/Psionics/Glimmer/GlimmerSystem.cs
@@ -15,7 +15,15 @@ namespace Content.Shared.Psionics.Glimmer
public int Glimmer
{
get { return _glimmer; }
- set { _glimmer = _enabled ? Math.Clamp(value, 0, 1000) : 0; }
+ set
+ {
+ var newGlimmer = _enabled ? Math.Clamp(value, 0, 1000) : 0;
+ if (_glimmer == newGlimmer)
+ return;
+
+ _glimmer = newGlimmer;
+ RaiseNetworkEvent(new GlimmerChangedEvent(_glimmer));
+ }
}
private bool _enabled;
public override void Initialize()
@@ -62,4 +70,15 @@ namespace Content.Shared.Psionics.Glimmer
Dangerous,
Critical,
}
+
+ [Serializable, NetSerializable]
+ public sealed class GlimmerChangedEvent : EntityEventArgs
+ {
+ public int Glimmer { get; }
+
+ public GlimmerChangedEvent(int glimmer)
+ {
+ Glimmer = glimmer;
+ }
+ }
}
diff --git a/Content.Shared/_DV/CCVars/DCCVars.cs b/Content.Shared/_DV/CCVars/DCCVars.cs
index db1c90b502..2cbfb5c0f7 100644
--- a/Content.Shared/_DV/CCVars/DCCVars.cs
+++ b/Content.Shared/_DV/CCVars/DCCVars.cs
@@ -94,6 +94,12 @@ public sealed partial class DCCVars
public static readonly CVarDef NoVisionFilters =
CVarDef.Create("accessibility.no_vision_filters", true, CVar.CLIENTONLY | CVar.ARCHIVE);
+ ///
+ /// Disables the fullscreen shader at 700+ glimmer.
+ ///
+ public static readonly CVarDef DisableGlimmerShader =
+ CVarDef.Create("accessibility.disable_glimmer_shader", false, CVar.CLIENTONLY | CVar.ARCHIVE);
+
///
/// Whether the Shipyard is enabled.
///
diff --git a/Content.Shared/_DV/Overlays/GlimmerOverlayComponent.cs b/Content.Shared/_DV/Overlays/GlimmerOverlayComponent.cs
new file mode 100644
index 0000000000..1338c8ef9d
--- /dev/null
+++ b/Content.Shared/_DV/Overlays/GlimmerOverlayComponent.cs
@@ -0,0 +1,6 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._DV.Overlays;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class GlimmerOverlayComponent : Component;
diff --git a/Resources/Locale/en-US/_DV/escape-menu/options-menu.ftl b/Resources/Locale/en-US/_DV/escape-menu/options-menu.ftl
index 68bb35fa5f..71e4d1c8a3 100644
--- a/Resources/Locale/en-US/_DV/escape-menu/options-menu.ftl
+++ b/Resources/Locale/en-US/_DV/escape-menu/options-menu.ftl
@@ -2,6 +2,7 @@ ui-options-tab-deltav = DeltaV
ui-options-general-forknotice = Note: These settings are fork-specific and might not apply on other servers.
ui-options-no-filters = Disable species vision filters
+ui-options-disable-glimmer-effect = Disable high glimmer shader effect
## DeltaV NanoChat keybinds
ui-options-header-nano-chat = NanoChat
diff --git a/Resources/Prototypes/_DV/Shaders/highglimmer.yml b/Resources/Prototypes/_DV/Shaders/highglimmer.yml
new file mode 100644
index 0000000000..f5eb048782
--- /dev/null
+++ b/Resources/Prototypes/_DV/Shaders/highglimmer.yml
@@ -0,0 +1,4 @@
+- type: shader
+ id: HighGlimmer
+ kind: source
+ path: "/Textures/_DV/Shaders/highglimmer.swsl"
diff --git a/Resources/Textures/_DV/Shaders/highglimmer.swsl b/Resources/Textures/_DV/Shaders/highglimmer.swsl
new file mode 100644
index 0000000000..bf4b129578
--- /dev/null
+++ b/Resources/Textures/_DV/Shaders/highglimmer.swsl
@@ -0,0 +1,49 @@
+// Shader by Xor, taken and modified from https://www.shadertoy.com/view/3fKSzc.
+// Licensed under CC BY-NC-SA 3.0: https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
+
+const highp float TimeScale = 0.2;
+
+uniform highp float size = 1;
+
+void fragment() {
+ vec2 iResolution = vec2(1.0);
+ vec2 I = UV * iResolution;
+
+ //Raymarch depth
+ float z = 0.0;
+ //Step distance
+ float d = 0.0;
+ //Raymarch iterator
+ float i = 0.0;
+ //Animation time
+ float t = TIME * TimeScale;
+
+ vec4 O = vec4(0.0);
+
+ //Clear fragColor and raymarch (some amount of) steps
+ while (i++ < 25) {
+ // sample point (from ray direction)
+ vec3 p = z * normalize(vec3(I + I, 0.0) - iResolution.xyx) + 0.1;
+
+ // polar coordinates
+ p = vec3(atan(p.y, p.x) * 2.0, p.z / (3.0*(3.0-size)), length(p.xy) - 4.5 - z * (0.5 * 2.8-size));
+
+ // apply turbulence
+ d = 0.0;
+ float j = 0.0;
+ while (++j < 9.0)
+ p += sin(p.yzx * j - t + 0.2 * i) / j;
+
+ // distance to cylinder and waves
+ d = 0.2 * length(vec4(p.z, 0.1 * cos(p * 3.0) - 0.1));
+ z += d;
+
+ // coloring and brightness
+ O += (1.0 + cos(i * 0.7 + vec4(6.0, 1.0, 2.0, 0.0))) / d / i;
+ }
+
+ // tanh tonemap
+ O = tanh(O * O / 900.0);
+
+ COLOR = O;
+}