From a001864faefcbdf090813598e12d19c30b2b0178 Mon Sep 17 00:00:00 2001 From: modern-nm <87994977+modern-nm@users.noreply.github.com> Date: Sun, 10 Dec 2023 20:16:42 +0300 Subject: [PATCH] =?UTF-8?q?done:=20=D0=9F=D0=BE=D1=87=D0=B8=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=8D=D1=84=D1=84=D0=B5=D0=BA=D1=82=20=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B5=D0=BF=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE?= =?UTF-8?q?=D1=82=20EMP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Overlays/Shaders/StaticOverlay.cs | 92 +++++++++++++++++++ .../Silicon/Systems/SeeingStaticSystem.cs | 57 ++++++++++++ Content.Server/Bed/BedSystem.cs | 3 +- .../Electrocution/ElectrocutionSystem.cs | 5 +- Content.Server/Emp/EmpSystem.cs | 19 +++- .../Systems/BatteryElectrocuteChargeSystem.cs | 38 ++++++++ .../Electrocution/ElectrocutionEvents.cs | 4 +- .../Entities/Mobs/Player/ipc.yml | 5 + .../Entities/Mobs/Player/silicon_base.yml | 8 ++ .../SimpleStation14/Shaders/shaders.yml | 14 +++ .../SimpleStation14/status_effects.yml | 2 + .../SimpleStation14/Shaders/color_tint.swsl | 56 +++++++++++ .../SimpleStation14/Shaders/ethereal.swsl | 75 +++++++++++++++ .../Shaders/seeing_static.swsl | 43 +++++++++ 14 files changed, 416 insertions(+), 5 deletions(-) create mode 100644 Content.Client/SimpleStation14/Overlays/Shaders/StaticOverlay.cs create mode 100644 Content.Client/SimpleStation14/Silicon/Systems/SeeingStaticSystem.cs create mode 100644 Content.Server/SimpleStation14/Power/Systems/BatteryElectrocuteChargeSystem.cs create mode 100644 Resources/Prototypes/SimpleStation14/Shaders/shaders.yml create mode 100644 Resources/Prototypes/SimpleStation14/status_effects.yml create mode 100644 Resources/Textures/SimpleStation14/Shaders/color_tint.swsl create mode 100644 Resources/Textures/SimpleStation14/Shaders/ethereal.swsl create mode 100644 Resources/Textures/SimpleStation14/Shaders/seeing_static.swsl diff --git a/Content.Client/SimpleStation14/Overlays/Shaders/StaticOverlay.cs b/Content.Client/SimpleStation14/Overlays/Shaders/StaticOverlay.cs new file mode 100644 index 00000000000..151d3ef8a92 --- /dev/null +++ b/Content.Client/SimpleStation14/Overlays/Shaders/StaticOverlay.cs @@ -0,0 +1,92 @@ +using Content.Shared.SimpleStation14.Silicon.Components; +using Content.Shared.SimpleStation14.Silicon.Systems; +using Content.Shared.StatusEffect; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Enums; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Client.SimpleStation14.Overlays.Shaders; + +public sealed class StaticOverlay : Overlay +{ + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + + public override OverlaySpace Space => OverlaySpace.WorldSpace; + public override bool RequestScreenTexture => true; + private readonly ShaderInstance _staticShader; + + private (TimeSpan, TimeSpan)? _time; + private float? _fullTimeLeft; + private float? _curTimeLeft; + + public float MixAmount = 0; + + public StaticOverlay() + { + IoCManager.InjectDependencies(this); + _staticShader = _prototypeManager.Index("SeeingStatic").InstanceUnique(); + } + + protected override void FrameUpdate(FrameEventArgs args) + { + var playerEntity = _playerManager.LocalPlayer?.ControlledEntity; + + if (playerEntity == null) + return; + + if (!_entityManager.TryGetComponent(playerEntity, out var staticComp) + || !_entityManager.TryGetComponent(playerEntity, out var statusComp)) + return; + + var status = _entityManager.EntitySysManager.GetEntitySystem(); + + if (playerEntity == null || statusComp == null) + return; + + if (!status.TryGetTime(playerEntity.Value, SeeingStaticSystem.StaticKey, out var timeTemp, statusComp)) + return; + + if (_time != timeTemp) // Resets the shader if the times change. This should factor in wheather it's a reset, or a increase, but I have a lot of cough syrup in me, so TODO. + { + _time = timeTemp; + _fullTimeLeft = null; + _curTimeLeft = null; + } + + _fullTimeLeft ??= (float) (timeTemp.Value.Item2 - timeTemp.Value.Item1).TotalSeconds; + _curTimeLeft ??= _fullTimeLeft; + + _curTimeLeft -= args.DeltaSeconds; + + MixAmount = Math.Clamp(_curTimeLeft.Value / _fullTimeLeft.Value * staticComp.Multiplier, 0, 1); + } + + protected override bool BeforeDraw(in OverlayDrawArgs args) + { + if (!_entityManager.TryGetComponent(_playerManager.LocalPlayer?.ControlledEntity, out EyeComponent? eyeComp)) + return false; + + if (args.Viewport.Eye != eyeComp.Eye) + return false; + + return MixAmount > 0; + } + + protected override void Draw(in OverlayDrawArgs args) + { + if (ScreenTexture == null) + return; + + var handle = args.WorldHandle; + _staticShader.SetParameter("SCREEN_TEXTURE", ScreenTexture); + _staticShader.SetParameter("mixAmount", MixAmount); + handle.UseShader(_staticShader); + handle.DrawRect(args.WorldBounds, Color.White); + handle.UseShader(null); + } +} diff --git a/Content.Client/SimpleStation14/Silicon/Systems/SeeingStaticSystem.cs b/Content.Client/SimpleStation14/Silicon/Systems/SeeingStaticSystem.cs new file mode 100644 index 00000000000..d842ebb2b9d --- /dev/null +++ b/Content.Client/SimpleStation14/Silicon/Systems/SeeingStaticSystem.cs @@ -0,0 +1,57 @@ +using Content.Client.SimpleStation14.Overlays.Shaders; +using Content.Shared.SimpleStation14.Silicon.Components; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Player; + +namespace Content.Client.SimpleStation14.Silicon.Systems; + +/// +/// System to handle the SeeingStatic overlay. +/// +public sealed class SeeingStaticSystem : EntitySystem +{ + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IOverlayManager _overlayMan = default!; + + private StaticOverlay _overlay = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnShutdown); + + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); + + _overlay = new(); + } + + private void OnPlayerAttached(EntityUid uid, SeeingStaticComponent component, LocalPlayerAttachedEvent args) + { + _overlayMan.AddOverlay(_overlay); + } + + private void OnPlayerDetached(EntityUid uid, SeeingStaticComponent component, LocalPlayerDetachedEvent args) + { + _overlay.MixAmount = 0; + _overlayMan.RemoveOverlay(_overlay); + } + + private void OnInit(EntityUid uid, SeeingStaticComponent component, ComponentInit args) + { + if (_player.LocalPlayer?.ControlledEntity == uid) + _overlayMan.AddOverlay(_overlay); + } + + private void OnShutdown(EntityUid uid, SeeingStaticComponent component, ComponentShutdown args) + { + if (_player.LocalPlayer?.ControlledEntity == uid) + { + _overlay.MixAmount = 0; + _overlayMan.RemoveOverlay(_overlay); + } + } +} diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs index e7d1e3be3c3..35192ae3530 100644 --- a/Content.Server/Bed/BedSystem.cs +++ b/Content.Server/Bed/BedSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Emag.Systems; using Content.Shared.Mobs.Systems; using Robust.Shared.Timing; +using Content.Shared.SimpleStation14.Silicon.Components; // Parkstation-IPCs // I shouldn't have to modify this. namespace Content.Server.Bed { @@ -70,7 +71,7 @@ public override void Update(float frameTime) foreach (var healedEntity in strapComponent.BuckledEntities) { - if (_mobStateSystem.IsDead(healedEntity)) + if (_mobStateSystem.IsDead(healedEntity) || HasComp(healedEntity)) // Parkstation-IPCs // I shouldn't have to modify this. continue; var damage = bedComponent.Damage; diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index c3ae2460744..aecb4b2c23a 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -63,6 +63,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem private const string DamageType = "Shock"; // Yes, this is absurdly small for a reason. + public const float ElectrifiedDamagePerWatt = 0.0015f; // Parkstation-IPC // This information is allowed to be public, and was needed in BatteryElectrocuteChargeSystem.cs private const float ElectrifiedScalePerWatt = 1E-6f; private const float RecursiveDamageMultiplier = 0.75f; @@ -312,7 +313,7 @@ public override bool TryDoElectrocution( || !DoCommonElectrocution(uid, sourceUid, shockDamage, time, refresh, siemensCoefficient, statusEffects)) return false; - RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true); + RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient, shockDamage), true); // Parkstation-IPC return true; } @@ -362,7 +363,7 @@ private bool TryDoElectrocutionPowered( electrocutionComponent.Electrocuting = uid; electrocutionComponent.Source = sourceUid; - RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient), true); + RaiseLocalEvent(uid, new ElectrocutedEvent(uid, sourceUid, siemensCoefficient, shockDamage), true); // Parkstation-IPC return true; } diff --git a/Content.Server/Emp/EmpSystem.cs b/Content.Server/Emp/EmpSystem.cs index 02a18284e8b..386d8a4c405 100644 --- a/Content.Server/Emp/EmpSystem.cs +++ b/Content.Server/Emp/EmpSystem.cs @@ -36,11 +36,28 @@ public override void Initialize() /// The duration of the EMP effects. public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration) { + /* foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range)) { TryEmpEffects(uid, energyConsumption, duration); } Spawn(EmpPulseEffectPrototype, coordinates); + */ + foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range)) + { + var ev = new EmpPulseEvent(energyConsumption, false, false, TimeSpan.FromSeconds(duration)); // Parkstation-IPCs + RaiseLocalEvent(uid, ref ev); + if (ev.Affected) + { + Spawn(EmpDisabledEffectPrototype, Transform(uid).Coordinates); + } + if (ev.Disabled) + { + var disabled = EnsureComp(uid); + disabled.DisabledUntil = Timing.CurTime + TimeSpan.FromSeconds(duration); + } + } + Spawn(EmpPulseEffectPrototype, coordinates); } /// @@ -142,7 +159,7 @@ public sealed partial class EmpAttemptEvent : CancellableEntityEventArgs } [ByRefEvent] -public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration); +public record struct EmpPulseEvent(float EnergyConsumption, bool Affected, bool Disabled, TimeSpan Duration); // Parkstation-IPCs [ByRefEvent] public record struct EmpDisabledRemoved(); diff --git a/Content.Server/SimpleStation14/Power/Systems/BatteryElectrocuteChargeSystem.cs b/Content.Server/SimpleStation14/Power/Systems/BatteryElectrocuteChargeSystem.cs new file mode 100644 index 00000000000..86238aab6c9 --- /dev/null +++ b/Content.Server/SimpleStation14/Power/Systems/BatteryElectrocuteChargeSystem.cs @@ -0,0 +1,38 @@ +using Content.Server.Electrocution; +using Content.Server.Popups; +using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Shared.Electrocution; +using Robust.Shared.Random; +using Robust.Shared.Timing; + +namespace Content.Server.SimpleStation14.Power.Systems; + +public sealed class BatteryElectrocuteChargeSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly BatterySystem _battery = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnElectrocuted); + } + + private void OnElectrocuted(EntityUid uid, BatteryComponent battery, ElectrocutedEvent args) + { + if (args.ShockDamage == null || args.ShockDamage <= 0) + return; + + var damagePerWatt = ElectrocutionSystem.ElectrifiedDamagePerWatt * 2; + + var damage = args.ShockDamage.Value * args.SiemensCoefficient; + var charge = Math.Min(damage / damagePerWatt, battery.MaxCharge * 0.25f) * _random.NextFloat(0.75f, 1.25f); + + _battery.SetCharge(uid, battery.CurrentCharge + charge); + + _popup.PopupEntity(Loc.GetString("battery-electrocute-charge"), uid, uid); + } +} diff --git a/Content.Shared/Electrocution/ElectrocutionEvents.cs b/Content.Shared/Electrocution/ElectrocutionEvents.cs index fe5753c7fb3..8f87f7149b4 100644 --- a/Content.Shared/Electrocution/ElectrocutionEvents.cs +++ b/Content.Shared/Electrocution/ElectrocutionEvents.cs @@ -24,12 +24,14 @@ public sealed class ElectrocutedEvent : EntityEventArgs public readonly EntityUid TargetUid; public readonly EntityUid? SourceUid; public readonly float SiemensCoefficient; + public readonly float? ShockDamage = null; // Parkstation-IPC - public ElectrocutedEvent(EntityUid targetUid, EntityUid? sourceUid, float siemensCoefficient) + public ElectrocutedEvent(EntityUid targetUid, EntityUid? sourceUid, float siemensCoefficient, float shockDamage) // Parkstation-IPC { TargetUid = targetUid; SourceUid = sourceUid; SiemensCoefficient = siemensCoefficient; + ShockDamage = shockDamage; // Parkstation-IPC } } } diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/ipc.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/ipc.yml index 4899c44f569..95b45fff053 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/ipc.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/ipc.yml @@ -45,6 +45,9 @@ - type: Battery maxCharge: 150000 startingCharge: 150000 + #- type: RandomBatteryCharge + # batteryMaxMinMax: 0.85, 1.15 + # batteryChargeMinMax: 0.40, 0.90 - type: Silicon entityType: enum.SiliconType.Player batteryPowered: true @@ -58,6 +61,7 @@ 2: 0.80 1: 0.45 0: 0.00 + #- type: Carriable - type: BatteryDrinker - type: EncryptionKeyHolder keySlots: 3 @@ -69,6 +73,7 @@ - type: Wires boardName: "IPC" layoutId: IPC + #- type: CharacterInformation - type: SSDIndicator - type: entity diff --git a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon_base.yml b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon_base.yml index 3ec8f35e958..5547668a5d1 100644 --- a/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon_base.yml +++ b/Resources/Prototypes/SimpleStation14/Entities/Mobs/Player/silicon_base.yml @@ -19,6 +19,13 @@ - type: Clickable - type: Damageable damageContainer: Inorganic # Note that for dumb reasons, this essentially makes them a wall. + - type: PassiveDamage # Slight passive regen. Костыль. + allowedStates: + - Critical + damageCap: 20 + damage: + groups: + Brute: 0.01 # - type: Bloodstream # This is left commented out because it's not necessary for a robot, but you may want it. # bloodReagent: MotorOil # bloodlossDamage: @@ -171,6 +178,7 @@ - map: ["pocket1"] - map: ["pocket2"] - map: ["enum.HumanoidVisualLayers.Tail"] + #- map: ["enum.HumanoidVisualLayers.Wings"] - map: ["clownedon"] # Dynamically generated sprite: "Effects/creampie.rsi" state: "creampie_human" diff --git a/Resources/Prototypes/SimpleStation14/Shaders/shaders.yml b/Resources/Prototypes/SimpleStation14/Shaders/shaders.yml new file mode 100644 index 00000000000..ee9c1b2f6aa --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/Shaders/shaders.yml @@ -0,0 +1,14 @@ +- type: shader + id: ColorTint + kind: source + path: "/Textures/SimpleStation14/Shaders/color_tint.swsl" + +- type: shader + id: Ethereal + kind: source + path: "/Textures/SimpleStation14/Shaders/ethereal.swsl" + +- type: shader + id: SeeingStatic + kind: source + path: "/Textures/SimpleStation14/Shaders/seeing_static.swsl" diff --git a/Resources/Prototypes/SimpleStation14/status_effects.yml b/Resources/Prototypes/SimpleStation14/status_effects.yml new file mode 100644 index 00000000000..de4048f912a --- /dev/null +++ b/Resources/Prototypes/SimpleStation14/status_effects.yml @@ -0,0 +1,2 @@ +- type: statusEffect + id: SeeingStatic diff --git a/Resources/Textures/SimpleStation14/Shaders/color_tint.swsl b/Resources/Textures/SimpleStation14/Shaders/color_tint.swsl new file mode 100644 index 00000000000..f95011cefab --- /dev/null +++ b/Resources/Textures/SimpleStation14/Shaders/color_tint.swsl @@ -0,0 +1,56 @@ +light_mode unshaded; + +uniform sampler2D SCREEN_TEXTURE; +uniform lowp vec3 tint_color; // RGB color between 0 and 1 +uniform lowp float tint_amount; // Number between 0 and 1 + +// Function to convert RGB to HSV. +highp vec3 rgb2hsv(highp vec3 c) +{ + highp vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + highp vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + highp vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + highp float d = q.x - min(q.w, q.y); + /* float e = 1.0e-10; */ + highp float e = 0.0000000001; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +// Function to convert HSV to RGB. +highp vec3 hsv2rgb(highp vec3 c) +{ + highp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +void fragment() { + highp vec4 color = zTextureSpec(SCREEN_TEXTURE, FRAGCOORD.xy * SCREEN_PIXEL_SIZE); + + // Convert color to HSV. + highp vec3 hsvTint = rgb2hsv(tint_color); + highp vec3 hsvColor = rgb2hsv(color.rgb); + + // Set the original hue to the tint hue as long as it's not greyscale. + if (hsvTint.y > 0.05 && hsvTint.z != 0.0) + { + hsvColor.x = hsvTint.x; + } + // Modify saturation based on tint color saturation, + // Halving it if it's higher and capping it at the original. + hsvColor.y = (hsvColor.y < hsvTint.y) ? + mix(hsvColor.y, hsvTint.y, 0.75) : mix(hsvColor.y, hsvTint.y, 0.35); + + // Modify value based on tint color value, but only if it's darker. + hsvColor.z = (mix(hsvColor.z, hsvTint.z, 0.85) <= hsvColor.z) ? + mix(hsvColor.z, hsvTint.z, 0.85) : hsvColor.z; + + // Convert back to RGB. + highp vec3 rgbColorMod = hsv2rgb(hsvColor); + + // Mix the final RGB product with the original color to the intensity of the tint. + color.rgb = mix(color.rgb, rgbColorMod, tint_amount); + + COLOR = color; +} diff --git a/Resources/Textures/SimpleStation14/Shaders/ethereal.swsl b/Resources/Textures/SimpleStation14/Shaders/ethereal.swsl new file mode 100644 index 00000000000..45dcb9b6ac9 --- /dev/null +++ b/Resources/Textures/SimpleStation14/Shaders/ethereal.swsl @@ -0,0 +1,75 @@ +light_mode unshaded; + +uniform sampler2D SCREEN_TEXTURE; + +// Function to convert RGB to HSV. +highp vec3 rgb2hsv(highp vec3 c) +{ + highp vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + highp vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + highp vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + highp float d = q.x - min(q.w, q.y); + /* float e = 1.0e-10; */ + highp float e = 0.0000000001; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +// Function to convert HSV to RGB. +highp vec3 hsv2rgb(highp vec3 c) +{ + highp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +// Random number function with potential negative values. +highp float rand(highp vec2 n) { + highp float r = 2.0 * (0.5 + 0.5 * fract (sin (dot (n.xy, vec2(12.9898, 78.233)))* 43758.5453)) - 1.0; + return r * (r < 0.0 ? 0.8 : 1.3); +} + +void fragment() { + highp vec4 color = zTextureSpec(SCREEN_TEXTURE, FRAGCOORD.xy * SCREEN_PIXEL_SIZE); + + // Increase the contrast of the image if the luminance is low enough. + highp float luminance = dot(color.rgb, vec3(0.2126, 0.7152, 0.0722)); + if (luminance < 0.06) { + color.rgb *= 0.5; + } + + // Convert to HSV. + highp vec3 hsvColor = rgb2hsv(color.rgb); + + // Apply a breathing effect to the value of the image. + hsvColor.z *= mix(0.35, 0.7, (sin(TIME) * 0.65)); + + // Increase the saturation of the color, incorperating a random value, as long as the value is above 0.1. + if (hsvColor.z > 0.065) { + hsvColor.y *= (rand(FRAGCOORD.xy * (TIME * 0.15)) * 1.5) + 1.0; + } + + // Convert back to RGB. + color.rgb = hsv2rgb(hsvColor); + + + + // get distortion magnitude. hand crafted from a random jumble of trig functions + highp float w = sin(TIME + (FRAGCOORD.x + FRAGCOORD.y + 2.0*sin(TIME*0.3) * sin(TIME*0.3 + FRAGCOORD.x - FRAGCOORD.y)) ); + + // visualize distortion via: + // COLOR = vec4(w,w,w,1.0); + + w *= (3.0 + 1 * 2.0); + + highp vec4 background = zTextureSpec(SCREEN_TEXTURE, ( FRAGCOORD.xy + vec2(w) ) * SCREEN_PIXEL_SIZE ); + highp vec3 hsvBg = rgb2hsv(background.rgb); + hsvBg.x *= -1; + background.rgb = hsv2rgb(hsvBg); + + color.xyz = mix(background.xyz, color.xyz, 0.75); + + + + COLOR = color; +} diff --git a/Resources/Textures/SimpleStation14/Shaders/seeing_static.swsl b/Resources/Textures/SimpleStation14/Shaders/seeing_static.swsl new file mode 100644 index 00000000000..765cb94f712 --- /dev/null +++ b/Resources/Textures/SimpleStation14/Shaders/seeing_static.swsl @@ -0,0 +1,43 @@ +// Credited to PelicanPolice on Shadertoy +// Free for any purpose, commercial or otherwise. +// But do post here so I can see where it got used! +// If using on shadertoy, do link to this project on yours :) + +// A copy of the camera static shader, but takes a screen texture, and an amount to mix by. + +uniform sampler2D SCREEN_TEXTURE; +uniform highp float mixAmount; + +highp float noise(highp vec2 pos, highp float evolve) { + + // Loop the evolution (over a very long period of time). + highp float e = fract((evolve*0.01)); + + // Coordinates + highp float cx = pos.x*e; + highp float cy = sin(pos.y*e * 376.0); // is this close enough to a 60hz interference? :smol: + + highp float v2_2 = cx*2.4/cy*23.0+pow(abs(cy/22.4),3.3); + highp float v2_1 = fract(fract(v2_2)); + highp float v2 = fract(2.0/v2_1); + highp float v3 = fract(cx*evolve/pow(abs(cy),0.050)); + + // Generate a "random" black or white value + return fract(0.1*v2*v3); +} + + +void fragment() { + highp vec4 color = zTextureSpec(SCREEN_TEXTURE, UV); + highp vec2 coords = FRAGCOORD.xy; + + highp vec3 staticAmount; + for (int i = 0; i < 1; i++) + { + // Generate a black to white pixel + staticAmount = vec3(noise(coords,TIME)); + } + + // Output to screen + COLOR = mix(color, vec4(staticAmount, 1.0), mixAmount); +}