BlurryVisionOverlay.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. using Robust.Client.Graphics;
  2. using Robust.Client.Player;
  3. using Content.Shared.CCVar;
  4. using Robust.Shared.Enums;
  5. using Robust.Shared.Prototypes;
  6. using Content.Shared.Eye.Blinding.Components;
  7. using Robust.Shared.Configuration;
  8. namespace Content.Client.Eye.Blinding
  9. {
  10. public sealed class BlurryVisionOverlay : Overlay
  11. {
  12. [Dependency] private readonly IEntityManager _entityManager = default!;
  13. [Dependency] private readonly IPlayerManager _playerManager = default!;
  14. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  15. [Dependency] private readonly IConfigurationManager _configManager = default!;
  16. public override bool RequestScreenTexture => true;
  17. public override OverlaySpace Space => OverlaySpace.WorldSpace;
  18. private readonly ShaderInstance _cataractsShader;
  19. private readonly ShaderInstance _circleMaskShader;
  20. private float _magnitude;
  21. private float _correctionPower = 2.0f;
  22. private const float Distortion_Pow = 2.0f; // Exponent for the distortion effect
  23. private const float Cloudiness_Pow = 1.0f; // Exponent for the cloudiness effect
  24. private const float NoMotion_Radius = 30.0f; // Base radius for the nomotion variant at its full strength
  25. private const float NoMotion_Pow = 0.2f; // Exponent for the nomotion variant's gradient
  26. private const float NoMotion_Max = 8.0f; // Max value for the nomotion variant's gradient
  27. private const float NoMotion_Mult = 0.75f; // Multiplier for the nomotion variant
  28. public BlurryVisionOverlay()
  29. {
  30. IoCManager.InjectDependencies(this);
  31. _cataractsShader = _prototypeManager.Index<ShaderPrototype>("Cataracts").InstanceUnique();
  32. _circleMaskShader = _prototypeManager.Index<ShaderPrototype>("CircleMask").InstanceUnique();
  33. _circleMaskShader.SetParameter("CircleMinDist", 0.0f);
  34. _circleMaskShader.SetParameter("CirclePow", NoMotion_Pow);
  35. _circleMaskShader.SetParameter("CircleMax", NoMotion_Max);
  36. _circleMaskShader.SetParameter("CircleMult", NoMotion_Mult);
  37. }
  38. protected override bool BeforeDraw(in OverlayDrawArgs args)
  39. {
  40. if (!_entityManager.TryGetComponent(_playerManager.LocalSession?.AttachedEntity, out EyeComponent? eyeComp))
  41. return false;
  42. if (args.Viewport.Eye != eyeComp.Eye)
  43. return false;
  44. var playerEntity = _playerManager.LocalSession?.AttachedEntity;
  45. if (playerEntity == null)
  46. return false;
  47. if (!_entityManager.TryGetComponent<BlurryVisionComponent>(playerEntity, out var blurComp))
  48. return false;
  49. if (blurComp.Magnitude <= 0)
  50. return false;
  51. if (_entityManager.TryGetComponent<BlindableComponent>(playerEntity, out var blindComp)
  52. && blindComp.IsBlind)
  53. return false;
  54. _magnitude = blurComp.Magnitude;
  55. _correctionPower = blurComp.CorrectionPower;
  56. return true;
  57. }
  58. protected override void Draw(in OverlayDrawArgs args)
  59. {
  60. if (ScreenTexture == null)
  61. return;
  62. var playerEntity = _playerManager.LocalSession?.AttachedEntity;
  63. var worldHandle = args.WorldHandle;
  64. var viewport = args.WorldBounds;
  65. var strength = (float) Math.Pow(Math.Min(_magnitude / BlurryVisionComponent.MaxMagnitude, 1.0f), _correctionPower);
  66. var zoom = 1.0f;
  67. if (_entityManager.TryGetComponent<EyeComponent>(playerEntity, out var eyeComponent))
  68. {
  69. zoom = eyeComponent.Zoom.X;
  70. }
  71. // While the cataracts shader is designed to be tame enough to keep motion sickness at bay, the general waviness means that those who are particularly sensitive to motion sickness will probably hurl.
  72. // So the reasonable alternative here is to replace it with a static effect! Specifically, one that replicates the blindness effect seen across most SS13 servers.
  73. if (_configManager.GetCVar(CCVars.ReducedMotion))
  74. {
  75. _circleMaskShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
  76. _circleMaskShader.SetParameter("Zoom", zoom);
  77. _circleMaskShader.SetParameter("CircleRadius", NoMotion_Radius / strength);
  78. worldHandle.UseShader(_circleMaskShader);
  79. worldHandle.DrawRect(viewport, Color.White);
  80. worldHandle.UseShader(null);
  81. return;
  82. }
  83. _cataractsShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
  84. _cataractsShader.SetParameter("LIGHT_TEXTURE", args.Viewport.LightRenderTarget.Texture); // this is a little hacky but we spent way longer than we'd like to admit trying to do this a cleaner way to no avail
  85. _cataractsShader.SetParameter("Zoom", zoom);
  86. _cataractsShader.SetParameter("DistortionScalar", (float) Math.Pow(strength, Distortion_Pow));
  87. _cataractsShader.SetParameter("CloudinessScalar", (float) Math.Pow(strength, Cloudiness_Pow));
  88. worldHandle.UseShader(_cataractsShader);
  89. worldHandle.DrawRect(viewport, Color.White);
  90. worldHandle.UseShader(null);
  91. }
  92. }
  93. }